273 lines
10 KiB
C++
273 lines
10 KiB
C++
|
/****************************************************************************
|
||
|
**
|
||
|
** Copyright (C) 2015 The Qt Company Ltd.
|
||
|
** Contact: http://www.qt.io/licensing/
|
||
|
**
|
||
|
** This file is part of the test suite of the Qt Toolkit.
|
||
|
**
|
||
|
** $QT_BEGIN_LICENSE:LGPL3$
|
||
|
** Commercial License Usage
|
||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||
|
** accordance with the commercial license agreement provided with the
|
||
|
** Software or, alternatively, in accordance with the terms contained in
|
||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||
|
** and conditions see http://www.qt.io/terms-conditions. For further
|
||
|
** information use the contact form at http://www.qt.io/contact-us.
|
||
|
**
|
||
|
** GNU Lesser General Public License Usage
|
||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||
|
** General Public License version 3 as published by the Free Software
|
||
|
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
|
||
|
** packaging of this file. Please review the following information to
|
||
|
** ensure the GNU Lesser General Public License version 3 requirements
|
||
|
** will be met: https://www.gnu.org/licenses/lgpl.html.
|
||
|
**
|
||
|
** GNU General Public License Usage
|
||
|
** Alternatively, this file may be used under the terms of the GNU
|
||
|
** General Public License version 2.0 or later as published by the Free
|
||
|
** Software Foundation and appearing in the file LICENSE.GPL included in
|
||
|
** the packaging of this file. Please review the following information to
|
||
|
** ensure the GNU General Public License version 2.0 requirements will be
|
||
|
** met: http://www.gnu.org/licenses/gpl-2.0.html.
|
||
|
**
|
||
|
** $QT_END_LICENSE$
|
||
|
**
|
||
|
****************************************************************************/
|
||
|
|
||
|
#include <qtest.h>
|
||
|
#include <QtTest/QSignalSpy>
|
||
|
#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"
|
||
|
|
||
|
#include <QtLabsTemplates/private/qquickapplicationwindow_p.h>
|
||
|
#include <QtLabsTemplates/private/qquickbutton_p.h>
|
||
|
#include <QtLabsTemplates/private/qquickmenu_p.h>
|
||
|
#include <QtLabsTemplates/private/qquickmenuitem_p.h>
|
||
|
|
||
|
using namespace QQuickVisualTestUtil;
|
||
|
|
||
|
class ApplicationHelper
|
||
|
{
|
||
|
public:
|
||
|
ApplicationHelper(QQmlDataTest *testCase, const QString &testFilePath = QLatin1String("applicationwindow.qml")) :
|
||
|
component(&engine)
|
||
|
{
|
||
|
component.loadUrl(testCase->testFileUrl(testFilePath));
|
||
|
QObject *rootObject = component.create();
|
||
|
cleanup.reset(rootObject);
|
||
|
QVERIFY2(rootObject, qPrintable(QString::fromLatin1("Failed to create ApplicationWindow: %1").arg(component.errorString())));
|
||
|
|
||
|
window = qobject_cast<QQuickApplicationWindow*>(rootObject);
|
||
|
QVERIFY(window);
|
||
|
QVERIFY(!window->isVisible());
|
||
|
}
|
||
|
|
||
|
QQmlEngine engine;
|
||
|
QQmlComponent component;
|
||
|
QScopedPointer<QObject> cleanup;
|
||
|
QQuickApplicationWindow *window;
|
||
|
};
|
||
|
|
||
|
class tst_menu : public QQmlDataTest
|
||
|
{
|
||
|
Q_OBJECT
|
||
|
|
||
|
public:
|
||
|
|
||
|
private slots:
|
||
|
void defaults();
|
||
|
void mouse();
|
||
|
void contextMenuKeyboard();
|
||
|
void menuButton();
|
||
|
};
|
||
|
|
||
|
void tst_menu::defaults()
|
||
|
{
|
||
|
ApplicationHelper helper(this);
|
||
|
|
||
|
QQuickMenu *emptyMenu = helper.window->property("emptyMenu").value<QQuickMenu*>();
|
||
|
QCOMPARE(emptyMenu->isVisible(), false);
|
||
|
QCOMPARE(emptyMenu->contentItem()->property("currentIndex"), QVariant(-1));
|
||
|
}
|
||
|
|
||
|
void tst_menu::mouse()
|
||
|
{
|
||
|
ApplicationHelper helper(this);
|
||
|
|
||
|
QQuickApplicationWindow *window = helper.window;
|
||
|
window->show();
|
||
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
||
|
|
||
|
QQuickMenu *menu = window->property("menu").value<QQuickMenu*>();
|
||
|
menu->show();
|
||
|
QVERIFY(menu->isVisible());
|
||
|
QVERIFY(window->overlay()->childItems().contains(menu->contentItem()));
|
||
|
|
||
|
QQuickItem *firstItem = menu->itemAt(0);
|
||
|
QSignalSpy clickedSpy(firstItem, SIGNAL(clicked(QQuickMouseEvent*)));
|
||
|
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());
|
||
|
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()));
|
||
|
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1));
|
||
|
|
||
|
menu->show();
|
||
|
QCOMPARE(visibleSpy.count(), 2);
|
||
|
QVERIFY(menu->isVisible());
|
||
|
QVERIFY(window->overlay()->childItems().contains(menu->contentItem()));
|
||
|
|
||
|
// 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());
|
||
|
QVERIFY(!window->overlay()->childItems().contains(menu->contentItem()));
|
||
|
|
||
|
menu->show();
|
||
|
QCOMPARE(visibleSpy.count(), 4);
|
||
|
QVERIFY(menu->isVisible());
|
||
|
QVERIFY(window->overlay()->childItems().contains(menu->contentItem()));
|
||
|
|
||
|
// Try pressing within the menu and releasing outside of it; it should close.
|
||
|
// TODO: won't work until QQuickPanel::releasedOutside() actually gets emitted
|
||
|
// 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));
|
||
|
}
|
||
|
|
||
|
void tst_menu::contextMenuKeyboard()
|
||
|
{
|
||
|
if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls)
|
||
|
QSKIP("This platform only allows tab focus for text controls");
|
||
|
|
||
|
ApplicationHelper helper(this);
|
||
|
|
||
|
QQuickApplicationWindow *window = helper.window;
|
||
|
window->show();
|
||
|
window->requestActivate();
|
||
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
||
|
QVERIFY(QGuiApplication::focusWindow() == window);
|
||
|
|
||
|
QQuickMenu *menu = window->property("menu").value<QQuickMenu*>();
|
||
|
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1));
|
||
|
|
||
|
QQuickItem *firstItem = menu->itemAt(0);
|
||
|
QSignalSpy visibleSpy(menu, SIGNAL(visibleChanged()));
|
||
|
|
||
|
menu->setFocus(true);
|
||
|
menu->show();
|
||
|
QCOMPARE(visibleSpy.count(), 1);
|
||
|
QVERIFY(menu->isVisible());
|
||
|
QVERIFY(window->overlay()->childItems().contains(menu->contentItem()));
|
||
|
QVERIFY(!firstItem->hasActiveFocus());
|
||
|
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1));
|
||
|
|
||
|
QTest::keyClick(window, Qt::Key_Tab);
|
||
|
QVERIFY(firstItem->hasActiveFocus());
|
||
|
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(0));
|
||
|
|
||
|
QQuickItem *secondItem = menu->itemAt(1);
|
||
|
QTest::keyClick(window, Qt::Key_Tab);
|
||
|
QVERIFY(!firstItem->hasActiveFocus());
|
||
|
QVERIFY(secondItem->hasActiveFocus());
|
||
|
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());
|
||
|
QVERIFY(!secondItem->hasActiveFocus());
|
||
|
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1));
|
||
|
|
||
|
menu->show();
|
||
|
QCOMPARE(visibleSpy.count(), 3);
|
||
|
QVERIFY(menu->isVisible());
|
||
|
QVERIFY(window->overlay()->childItems().contains(menu->contentItem()));
|
||
|
QVERIFY(!firstItem->hasActiveFocus());
|
||
|
QVERIFY(!secondItem->hasActiveFocus());
|
||
|
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1));
|
||
|
|
||
|
QTest::keyClick(window, Qt::Key_Down);
|
||
|
QVERIFY(firstItem->hasActiveFocus());
|
||
|
|
||
|
QTest::keyClick(window, Qt::Key_Down);
|
||
|
QVERIFY(secondItem->hasActiveFocus());
|
||
|
|
||
|
QTest::keyClick(window, Qt::Key_Down);
|
||
|
QQuickItem *thirdItem = menu->itemAt(2);
|
||
|
QVERIFY(!firstItem->hasActiveFocus());
|
||
|
QVERIFY(!secondItem->hasActiveFocus());
|
||
|
QVERIFY(thirdItem->hasActiveFocus());
|
||
|
|
||
|
// Key navigation shouldn't wrap by default.
|
||
|
QTest::keyClick(window, Qt::Key_Down);
|
||
|
QVERIFY(!firstItem->hasActiveFocus());
|
||
|
QVERIFY(!secondItem->hasActiveFocus());
|
||
|
QVERIFY(thirdItem->hasActiveFocus());
|
||
|
}
|
||
|
|
||
|
void tst_menu::menuButton()
|
||
|
{
|
||
|
if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls)
|
||
|
QSKIP("This platform only allows tab focus for text controls");
|
||
|
|
||
|
ApplicationHelper helper(this);
|
||
|
|
||
|
QQuickApplicationWindow *window = helper.window;
|
||
|
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());
|
||
|
}
|
||
|
|
||
|
QTEST_MAIN(tst_menu)
|
||
|
|
||
|
#include "tst_menu.moc"
|