3766 lines
131 KiB
C++
3766 lines
131 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
** Contact: https://www.qt.io/licensing/
|
|
**
|
|
** This file is part of the test suite of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
** General Public License version 3 as published by the Free Software
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
** included in the packaging of this file. Please review the following
|
|
** information to ensure the GNU General Public License requirements will
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
**
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
#include <qtest.h>
|
|
#include <QtTest/QSignalSpy>
|
|
#include <QtQml/qqmlengine.h>
|
|
#include <QtQml/qqmlcomponent.h>
|
|
#include <QtQml/qqmlcontext.h>
|
|
#include <QtQuick/qquickitemgrabresult.h>
|
|
#include <QtQuick/qquickview.h>
|
|
#include <QtGui/private/qinputmethod_p.h>
|
|
#include <QtQuick/private/qquickloader_p.h>
|
|
#include <QtQuick/private/qquickpalette_p.h>
|
|
#include <QtQuick/private/qquickrectangle_p.h>
|
|
#include <QtQuick/private/qquicktextinput_p.h>
|
|
#include <QtQuick/private/qquickitemchangelistener_p.h>
|
|
#include <QtGui/qstylehints.h>
|
|
#include <private/qquickitem_p.h>
|
|
#include "../../shared/util.h"
|
|
#include "../shared/visualtestutil.h"
|
|
#include "../../shared/platforminputcontext.h"
|
|
#include <QtTest/private/qpropertytesthelper_p.h>
|
|
|
|
using namespace QQuickVisualTestUtil;
|
|
|
|
class tst_QQuickItem : public QQmlDataTest
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
tst_QQuickItem();
|
|
|
|
private slots:
|
|
void initTestCase() override;
|
|
void cleanup();
|
|
|
|
void activeFocusOnTab();
|
|
void activeFocusOnTab2();
|
|
void activeFocusOnTab3();
|
|
void activeFocusOnTab4();
|
|
void activeFocusOnTab5();
|
|
void activeFocusOnTab6();
|
|
void activeFocusOnTab7();
|
|
void activeFocusOnTab8();
|
|
void activeFocusOnTab9();
|
|
void activeFocusOnTab10();
|
|
void activeFocusOnTab_infiniteLoop_data();
|
|
void activeFocusOnTab_infiniteLoop();
|
|
|
|
void nextItemInFocusChain();
|
|
void nextItemInFocusChain2();
|
|
void nextItemInFocusChain3();
|
|
|
|
void tabFence();
|
|
void qtbug_50516();
|
|
void qtbug_50516_2_data();
|
|
void qtbug_50516_2();
|
|
void focusableItemReparentedToLoadedComponent();
|
|
|
|
void keys();
|
|
#if QT_CONFIG(shortcut)
|
|
void standardKeys_data();
|
|
void standardKeys();
|
|
#endif
|
|
void keysProcessingOrder();
|
|
void keysim();
|
|
void keysForward();
|
|
void keyNavigation_data();
|
|
void keyNavigation();
|
|
void keyNavigation_RightToLeft();
|
|
void keyNavigation_skipNotVisible();
|
|
void keyNavigation_implicitSetting();
|
|
void keyNavigation_implicitDestroy();
|
|
void keyNavigation_focusReason();
|
|
void keyNavigation_loop();
|
|
void keyNavigation_repeater();
|
|
void layoutMirroring();
|
|
void layoutMirroringWindow();
|
|
void layoutMirroringIllegalParent();
|
|
void smooth();
|
|
void antialiasing();
|
|
void clip();
|
|
void mapCoordinates();
|
|
void mapCoordinates_data();
|
|
void mapCoordinatesRect();
|
|
void mapCoordinatesRect_data();
|
|
void propertyChanges();
|
|
void nonexistentPropertyConnection();
|
|
void transforms();
|
|
void transforms_data();
|
|
void childrenRect();
|
|
void childrenRectBug();
|
|
void childrenRectBug2();
|
|
void childrenRectBug3();
|
|
void childrenRectBottomRightCorner();
|
|
|
|
void childrenProperty();
|
|
void resourcesProperty();
|
|
void bindableProperties_data();
|
|
void bindableProperties();
|
|
|
|
void changeListener();
|
|
void transformCrash();
|
|
void implicitSize();
|
|
void qtbug_16871();
|
|
void visibleChildren();
|
|
void parentLoop();
|
|
void contains_data();
|
|
void contains();
|
|
void childAt();
|
|
void isAncestorOf();
|
|
|
|
void grab();
|
|
void colorGroup();
|
|
|
|
private:
|
|
QQmlEngine engine;
|
|
bool qt_tab_all_widgets() {
|
|
return QGuiApplication::styleHints()->tabFocusBehavior() == Qt::TabFocusAllControls;
|
|
}
|
|
};
|
|
|
|
class KeysTestObject : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
Q_PROPERTY(bool processLast READ processLast NOTIFY processLastChanged)
|
|
|
|
public:
|
|
KeysTestObject() : mKey(0), mModifiers(0), mForwardedKey(0), mLast(false), mNativeScanCode(0) {}
|
|
|
|
void reset() {
|
|
mKey = 0;
|
|
mText = QString();
|
|
mModifiers = 0;
|
|
mForwardedKey = 0;
|
|
mNativeScanCode = 0;
|
|
}
|
|
|
|
bool processLast() const { return mLast; }
|
|
void setProcessLast(bool b) {
|
|
if (b != mLast) {
|
|
mLast = b;
|
|
emit processLastChanged();
|
|
}
|
|
}
|
|
|
|
public slots:
|
|
void keyPress(int key, QString text, int modifiers) {
|
|
mKey = key;
|
|
mText = text;
|
|
mModifiers = modifiers;
|
|
}
|
|
void keyRelease(int key, QString text, int modifiers) {
|
|
mKey = key;
|
|
mText = text;
|
|
mModifiers = modifiers;
|
|
}
|
|
void forwardedKey(int key) {
|
|
mForwardedKey = key;
|
|
}
|
|
void specialKey(int key, QString text, quint32 nativeScanCode) {
|
|
mKey = key;
|
|
mText = text;
|
|
mNativeScanCode = nativeScanCode;
|
|
}
|
|
|
|
signals:
|
|
void processLastChanged();
|
|
|
|
public:
|
|
int mKey;
|
|
QString mText;
|
|
int mModifiers;
|
|
int mForwardedKey;
|
|
bool mLast;
|
|
quint32 mNativeScanCode;
|
|
|
|
private:
|
|
};
|
|
|
|
class KeyTestItem : public QQuickItem
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
KeyTestItem(QQuickItem *parent=nullptr) : QQuickItem(parent), mKey(0) {}
|
|
|
|
protected:
|
|
void keyPressEvent(QKeyEvent *e) override {
|
|
mKey = e->key();
|
|
|
|
if (e->key() == Qt::Key_A)
|
|
e->accept();
|
|
else
|
|
e->ignore();
|
|
}
|
|
|
|
void keyReleaseEvent(QKeyEvent *e) override {
|
|
if (e->key() == Qt::Key_B)
|
|
e->accept();
|
|
else
|
|
e->ignore();
|
|
}
|
|
|
|
public:
|
|
int mKey;
|
|
};
|
|
|
|
class FocusEventFilter : public QObject
|
|
{
|
|
protected:
|
|
bool eventFilter(QObject *watched, QEvent *event) override {
|
|
if ((event->type() == QEvent::FocusIn) || (event->type() == QEvent::FocusOut)) {
|
|
QFocusEvent *focusEvent = static_cast<QFocusEvent *>(event);
|
|
lastFocusReason = focusEvent->reason();
|
|
return false;
|
|
} else
|
|
return QObject::eventFilter(watched, event);
|
|
}
|
|
public:
|
|
Qt::FocusReason lastFocusReason;
|
|
};
|
|
|
|
QML_DECLARE_TYPE(KeyTestItem);
|
|
|
|
class HollowTestItem : public QQuickItem
|
|
{
|
|
Q_OBJECT
|
|
Q_PROPERTY(bool circle READ isCircle WRITE setCircle)
|
|
Q_PROPERTY(qreal holeRadius READ holeRadius WRITE setHoleRadius)
|
|
|
|
public:
|
|
HollowTestItem(QQuickItem *parent = nullptr)
|
|
: QQuickItem(parent),
|
|
m_isPressed(false),
|
|
m_isHovered(false),
|
|
m_isCircle(false),
|
|
m_holeRadius(50)
|
|
{
|
|
setAcceptHoverEvents(true);
|
|
setAcceptedMouseButtons(Qt::LeftButton);
|
|
}
|
|
|
|
bool isPressed() const { return m_isPressed; }
|
|
bool isHovered() const { return m_isHovered; }
|
|
|
|
bool isCircle() const { return m_isCircle; }
|
|
void setCircle(bool circle) { m_isCircle = circle; }
|
|
|
|
qreal holeRadius() const { return m_holeRadius; }
|
|
void setHoleRadius(qreal radius) { m_holeRadius = radius; }
|
|
|
|
bool contains(const QPointF &point) const override {
|
|
const qreal w = width();
|
|
const qreal h = height();
|
|
const qreal r = m_holeRadius;
|
|
|
|
// check boundaries
|
|
if (!QRectF(0, 0, w, h).contains(point))
|
|
return false;
|
|
|
|
// square shape
|
|
if (!m_isCircle)
|
|
return !QRectF(w / 2 - r, h / 2 - r, r * 2, r * 2).contains(point);
|
|
|
|
// circle shape
|
|
const qreal dx = point.x() - (w / 2);
|
|
const qreal dy = point.y() - (h / 2);
|
|
const qreal dd = (dx * dx) + (dy * dy);
|
|
const qreal outerRadius = qMin<qreal>(w / 2, h / 2);
|
|
return dd > (r * r) && dd <= outerRadius * outerRadius;
|
|
}
|
|
|
|
protected:
|
|
void hoverEnterEvent(QHoverEvent *) override { m_isHovered = true; }
|
|
void hoverLeaveEvent(QHoverEvent *) override { m_isHovered = false; }
|
|
void mousePressEvent(QMouseEvent *) override { m_isPressed = true; }
|
|
void mouseReleaseEvent(QMouseEvent *) override { m_isPressed = false; }
|
|
|
|
private:
|
|
bool m_isPressed;
|
|
bool m_isHovered;
|
|
bool m_isCircle;
|
|
qreal m_holeRadius;
|
|
};
|
|
|
|
QML_DECLARE_TYPE(HollowTestItem);
|
|
|
|
class TabFenceItem : public QQuickItem
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
TabFenceItem(QQuickItem *parent = nullptr)
|
|
: QQuickItem(parent)
|
|
{
|
|
QQuickItemPrivate *d = QQuickItemPrivate::get(this);
|
|
d->isTabFence = true;
|
|
}
|
|
};
|
|
|
|
QML_DECLARE_TYPE(TabFenceItem);
|
|
|
|
class TabFenceItem2 : public QQuickItem
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
TabFenceItem2(QQuickItem *parent = nullptr)
|
|
: QQuickItem(parent)
|
|
{
|
|
QQuickItemPrivate *d = QQuickItemPrivate::get(this);
|
|
d->isTabFence = true;
|
|
setFlag(ItemIsFocusScope);
|
|
}
|
|
};
|
|
|
|
QML_DECLARE_TYPE(TabFenceItem2);
|
|
|
|
tst_QQuickItem::tst_QQuickItem()
|
|
{
|
|
}
|
|
|
|
void tst_QQuickItem::initTestCase()
|
|
{
|
|
QQmlDataTest::initTestCase();
|
|
qmlRegisterType<KeyTestItem>("Test",1,0,"KeyTestItem");
|
|
qmlRegisterType<HollowTestItem>("Test", 1, 0, "HollowTestItem");
|
|
qmlRegisterType<TabFenceItem>("Test", 1, 0, "TabFence");
|
|
qmlRegisterType<TabFenceItem2>("Test", 1, 0, "TabFence2");
|
|
}
|
|
|
|
void tst_QQuickItem::cleanup()
|
|
{
|
|
QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod());
|
|
inputMethodPrivate->testContext = nullptr;
|
|
}
|
|
|
|
void tst_QQuickItem::activeFocusOnTab()
|
|
{
|
|
if (!qt_tab_all_widgets())
|
|
QSKIP("This function doesn't support NOT iterating all.");
|
|
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(800,600));
|
|
|
|
window->setSource(testFileUrl("activeFocusOnTab.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
// original: button12
|
|
QQuickItem *item = findItem<QQuickItem>(window->rootObject(), "button12");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
|
|
// Tab: button12->sub2
|
|
{
|
|
QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "sub2");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// Tab: sub2->button21
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button21");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// Tab: button21->button22
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button22");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// Tab: button22->edit
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "edit");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
// BackTab: edit->button22
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button22");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
// BackTab: button22->button21
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button21");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// BackTab: button21->sub2
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "sub2");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// BackTab: sub2->button12
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button12");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// BackTab: button12->button11
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button11");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// BackTab: button11->edit
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "edit");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::activeFocusOnTab2()
|
|
{
|
|
if (!qt_tab_all_widgets())
|
|
QSKIP("This function doesn't support NOT iterating all.");
|
|
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(800,600));
|
|
|
|
window->setSource(testFileUrl("activeFocusOnTab.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
// original: button12
|
|
QQuickItem *item = findItem<QQuickItem>(window->rootObject(), "button12");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
|
|
// BackTab: button12->button11
|
|
{
|
|
QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button11");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// BackTab: button11->edit
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "edit");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::activeFocusOnTab3()
|
|
{
|
|
if (!qt_tab_all_widgets())
|
|
QSKIP("This function doesn't support NOT iterating all.");
|
|
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(800,600));
|
|
|
|
window->setSource(testFileUrl("activeFocusOnTab3.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
// original: button1
|
|
QQuickItem *item = findItem<QQuickItem>(window->rootObject(), "button1");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
|
|
// 4 Tabs: button1->button2, through a repeater
|
|
{
|
|
QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);;
|
|
for (int i = 0; i < 4; ++i) {
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button2");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// 4 Tabs: button2->button3, through a row
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);;
|
|
for (int i = 0; i < 4; ++i) {
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button3");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// 4 Tabs: button3->button4, through a flow
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);;
|
|
for (int i = 0; i < 4; ++i) {
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button4");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// 4 Tabs: button4->button5, through a focusscope
|
|
// parent is activeFocusOnTab:false, one of children is focus:true
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);;
|
|
for (int i = 0; i < 4; ++i) {
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button5");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// 4 Tabs: button5->button6, through a focusscope
|
|
// parent is activeFocusOnTab:true, one of children is focus:true
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);;
|
|
for (int i = 0; i < 4; ++i) {
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button6");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// 5 Tabs: button6->button7, through a focusscope
|
|
// parent is activeFocusOnTab:true, none of children is focus:true
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);;
|
|
for (int i = 0; i < 5; ++i) {
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button7");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// 4 BackTabs: button7->button6, through a focusscope
|
|
// parent is activeFocusOnTab:true, one of children got focus:true in previous code
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
for (int i = 0; i < 4; ++i) {
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button6");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// 4 Tabs: button6->button7, through a focusscope
|
|
// parent is activeFocusOnTab:true, one of children got focus:true in previous code
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);;
|
|
for (int i = 0; i < 4; ++i) {
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button7");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// 4 BackTabs: button7->button6, through a focusscope
|
|
// parent is activeFocusOnTab:true, one of children got focus:true in previous code
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
for (int i = 0; i < 4; ++i) {
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button6");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// 4 BackTabs: button6->button5, through a focusscope(parent is activeFocusOnTab: false)
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
for (int i = 0; i < 4; ++i) {
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button5");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// 4 BackTabs: button5->button4, through a focusscope(parent is activeFocusOnTab: false)
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
for (int i = 0; i < 4; ++i) {
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button4");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// 4 BackTabs: button4->button3, through a flow
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
for (int i = 0; i < 4; ++i) {
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button3");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// 4 BackTabs: button3->button2, through a row
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
for (int i = 0; i < 4; ++i) {
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button2");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// 4 BackTabs: button2->button1, through a repeater
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
for (int i = 0; i < 4; ++i) {
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button1");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::activeFocusOnTab4()
|
|
{
|
|
if (!qt_tab_all_widgets())
|
|
QSKIP("This function doesn't support NOT iterating all.");
|
|
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(800,600));
|
|
|
|
window->setSource(testFileUrl("activeFocusOnTab4.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
// original: button11
|
|
QQuickItem *item = findItem<QQuickItem>(window->rootObject(), "button11");
|
|
item->setActiveFocusOnTab(true);
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
|
|
// Tab: button11->button21
|
|
QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button21");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::activeFocusOnTab5()
|
|
{
|
|
if (!qt_tab_all_widgets())
|
|
QSKIP("This function doesn't support NOT iterating all.");
|
|
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(800,600));
|
|
|
|
window->setSource(testFileUrl("activeFocusOnTab4.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
// original: button11 in sub1
|
|
QQuickItem *item = findItem<QQuickItem>(window->rootObject(), "button11");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
|
|
QQuickItem *item2 = findItem<QQuickItem>(window->rootObject(), "sub1");
|
|
item2->setActiveFocusOnTab(true);
|
|
|
|
// Tab: button11->button21
|
|
QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button21");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::activeFocusOnTab6()
|
|
{
|
|
if (qt_tab_all_widgets())
|
|
QSKIP("This function doesn't support iterating all.");
|
|
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(800,600));
|
|
|
|
window->setSource(testFileUrl("activeFocusOnTab6.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
// original: button12
|
|
QQuickItem *item = findItem<QQuickItem>(window->rootObject(), "button12");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
|
|
// Tab: button12->edit
|
|
{
|
|
QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "edit");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// BackTab: edit->button12
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button12");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// BackTab: button12->button11
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "button11");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// BackTab: button11->edit
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "edit");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::activeFocusOnTab7()
|
|
{
|
|
if (qt_tab_all_widgets())
|
|
QSKIP("This function doesn't support iterating all.");
|
|
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(300,300));
|
|
|
|
window->setSource(testFileUrl("activeFocusOnTab7.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
QQuickItem *item = findItem<QQuickItem>(window->rootObject(), "button1");
|
|
QVERIFY(item);
|
|
item->forceActiveFocus();
|
|
QVERIFY(item->hasActiveFocus());
|
|
|
|
// Tab: button1->button1
|
|
{
|
|
QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(!key.isAccepted());
|
|
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// BackTab: button1->button1
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(!key.isAccepted());
|
|
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::activeFocusOnTab8()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(300,300));
|
|
|
|
window->setSource(testFileUrl("activeFocusOnTab8.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
QQuickItem *content = window->contentItem();
|
|
QVERIFY(content);
|
|
QVERIFY(content->hasActiveFocus());
|
|
|
|
QQuickItem *button1 = findItem<QQuickItem>(window->rootObject(), "button1");
|
|
QVERIFY(button1);
|
|
QVERIFY(!button1->hasActiveFocus());
|
|
|
|
QQuickItem *button2 = findItem<QQuickItem>(window->rootObject(), "button2");
|
|
QVERIFY(button2);
|
|
QVERIFY(!button2->hasActiveFocus());
|
|
|
|
// Tab: contentItem->button1
|
|
{
|
|
QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
QVERIFY(button1->hasActiveFocus());
|
|
}
|
|
|
|
// Tab: button1->button2
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
QVERIFY(button2->hasActiveFocus());
|
|
QVERIFY(!button1->hasActiveFocus());
|
|
}
|
|
|
|
// BackTab: button2->button1
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
QVERIFY(button1->hasActiveFocus());
|
|
QVERIFY(!button2->hasActiveFocus());
|
|
}
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::activeFocusOnTab9()
|
|
{
|
|
if (qt_tab_all_widgets())
|
|
QSKIP("This function doesn't support iterating all.");
|
|
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(300,300));
|
|
|
|
window->setSource(testFileUrl("activeFocusOnTab9.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
QQuickItem *content = window->contentItem();
|
|
QVERIFY(content);
|
|
QVERIFY(content->hasActiveFocus());
|
|
|
|
QQuickItem *textinput1 = findItem<QQuickItem>(window->rootObject(), "textinput1");
|
|
QVERIFY(textinput1);
|
|
QQuickItem *textedit1 = findItem<QQuickItem>(window->rootObject(), "textedit1");
|
|
QVERIFY(textedit1);
|
|
|
|
QVERIFY(!textinput1->hasActiveFocus());
|
|
textinput1->forceActiveFocus();
|
|
QVERIFY(textinput1->hasActiveFocus());
|
|
|
|
// Tab: textinput1->textedit1
|
|
{
|
|
QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
QVERIFY(textedit1->hasActiveFocus());
|
|
}
|
|
|
|
// BackTab: textedit1->textinput1
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
QVERIFY(textinput1->hasActiveFocus());
|
|
}
|
|
|
|
// BackTab: textinput1->textedit1
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
QVERIFY(textedit1->hasActiveFocus());
|
|
}
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::activeFocusOnTab10()
|
|
{
|
|
if (!qt_tab_all_widgets())
|
|
QSKIP("This function doesn't support NOT iterating all.");
|
|
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(300,300));
|
|
|
|
window->setSource(testFileUrl("activeFocusOnTab9.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
QQuickItem *content = window->contentItem();
|
|
QVERIFY(content);
|
|
QVERIFY(content->hasActiveFocus());
|
|
|
|
QQuickItem *textinput1 = findItem<QQuickItem>(window->rootObject(), "textinput1");
|
|
QVERIFY(textinput1);
|
|
QQuickItem *textedit1 = findItem<QQuickItem>(window->rootObject(), "textedit1");
|
|
QVERIFY(textedit1);
|
|
QQuickItem *textinput2 = findItem<QQuickItem>(window->rootObject(), "textinput2");
|
|
QVERIFY(textinput2);
|
|
QQuickItem *textedit2 = findItem<QQuickItem>(window->rootObject(), "textedit2");
|
|
QVERIFY(textedit2);
|
|
|
|
QVERIFY(!textinput1->hasActiveFocus());
|
|
textinput1->forceActiveFocus();
|
|
QVERIFY(textinput1->hasActiveFocus());
|
|
|
|
// Tab: textinput1->textinput2
|
|
{
|
|
QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
QVERIFY(textinput2->hasActiveFocus());
|
|
}
|
|
|
|
// Tab: textinput2->textedit1
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
QVERIFY(textedit1->hasActiveFocus());
|
|
}
|
|
|
|
// BackTab: textedit1->textinput2
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
QVERIFY(textinput2->hasActiveFocus());
|
|
}
|
|
|
|
// BackTab: textinput2->textinput1
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
QVERIFY(textinput1->hasActiveFocus());
|
|
}
|
|
|
|
// BackTab: textinput1->textedit2
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
QVERIFY(textedit2->hasActiveFocus());
|
|
}
|
|
|
|
// BackTab: textedit2->textedit1
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
QVERIFY(textedit1->hasActiveFocus());
|
|
}
|
|
|
|
// BackTab: textedit1->textinput2
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
QVERIFY(textinput2->hasActiveFocus());
|
|
}
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::activeFocusOnTab_infiniteLoop_data()
|
|
{
|
|
QTest::addColumn<QUrl>("source");
|
|
QTest::newRow("infiniteLoop") << testFileUrl("activeFocusOnTab_infiniteLoop.qml"); // QTBUG-68271
|
|
QTest::newRow("infiniteLoop2") << testFileUrl("activeFocusOnTab_infiniteLoop2.qml");// QTBUG-81510
|
|
}
|
|
|
|
void tst_QQuickItem::activeFocusOnTab_infiniteLoop()
|
|
{
|
|
QFETCH(QUrl, source);
|
|
|
|
// create a window where the currently focused item is not visible
|
|
QScopedPointer<QQuickView>window(new QQuickView());
|
|
window->setSource(source);
|
|
window->show();
|
|
auto *hiddenChild = findItem<QQuickItem>(window->rootObject(), "hiddenChild");
|
|
QVERIFY(hiddenChild);
|
|
|
|
// move the focus - this used to result in an infinite loop
|
|
auto *item = hiddenChild->nextItemInFocusChain();
|
|
// focus is moved to the root object since there is no other candidate
|
|
QCOMPARE(item, window->rootObject());
|
|
item = hiddenChild->nextItemInFocusChain(false);
|
|
QCOMPARE(item, window->rootObject());
|
|
}
|
|
|
|
void tst_QQuickItem::nextItemInFocusChain()
|
|
{
|
|
if (!qt_tab_all_widgets())
|
|
QSKIP("This function doesn't support NOT iterating all.");
|
|
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(800,600));
|
|
|
|
window->setSource(testFileUrl("activeFocusOnTab.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
QQuickItem *button11 = findItem<QQuickItem>(window->rootObject(), "button11");
|
|
QVERIFY(button11);
|
|
QQuickItem *button12 = findItem<QQuickItem>(window->rootObject(), "button12");
|
|
QVERIFY(button12);
|
|
|
|
QQuickItem *sub2 = findItem<QQuickItem>(window->rootObject(), "sub2");
|
|
QVERIFY(sub2);
|
|
QQuickItem *button21 = findItem<QQuickItem>(window->rootObject(), "button21");
|
|
QVERIFY(button21);
|
|
QQuickItem *button22 = findItem<QQuickItem>(window->rootObject(), "button22");
|
|
QVERIFY(button22);
|
|
|
|
QQuickItem *edit = findItem<QQuickItem>(window->rootObject(), "edit");
|
|
QVERIFY(edit);
|
|
|
|
QQuickItem *next, *prev;
|
|
|
|
next = button11->nextItemInFocusChain(true);
|
|
QVERIFY(next);
|
|
QCOMPARE(next, button12);
|
|
prev = button11->nextItemInFocusChain(false);
|
|
QVERIFY(prev);
|
|
QCOMPARE(prev, edit);
|
|
|
|
next = button12->nextItemInFocusChain();
|
|
QVERIFY(next);
|
|
QCOMPARE(next, sub2);
|
|
prev = button12->nextItemInFocusChain(false);
|
|
QVERIFY(prev);
|
|
QCOMPARE(prev, button11);
|
|
|
|
next = sub2->nextItemInFocusChain(true);
|
|
QVERIFY(next);
|
|
QCOMPARE(next, button21);
|
|
prev = sub2->nextItemInFocusChain(false);
|
|
QVERIFY(prev);
|
|
QCOMPARE(prev, button12);
|
|
|
|
next = button21->nextItemInFocusChain();
|
|
QVERIFY(next);
|
|
QCOMPARE(next, button22);
|
|
prev = button21->nextItemInFocusChain(false);
|
|
QVERIFY(prev);
|
|
QCOMPARE(prev, sub2);
|
|
|
|
next = button22->nextItemInFocusChain(true);
|
|
QVERIFY(next);
|
|
QCOMPARE(next, edit);
|
|
prev = button22->nextItemInFocusChain(false);
|
|
QVERIFY(prev);
|
|
QCOMPARE(prev, button21);
|
|
|
|
next = edit->nextItemInFocusChain();
|
|
QVERIFY(next);
|
|
QCOMPARE(next, button11);
|
|
prev = edit->nextItemInFocusChain(false);
|
|
QVERIFY(prev);
|
|
QCOMPARE(prev, button22);
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::nextItemInFocusChain2()
|
|
{
|
|
if (qt_tab_all_widgets())
|
|
QSKIP("This function doesn't support iterating all.");
|
|
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(800,600));
|
|
|
|
window->setSource(testFileUrl("activeFocusOnTab6.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
QQuickItem *button11 = findItem<QQuickItem>(window->rootObject(), "button11");
|
|
QVERIFY(button11);
|
|
QQuickItem *button12 = findItem<QQuickItem>(window->rootObject(), "button12");
|
|
QVERIFY(button12);
|
|
|
|
QQuickItem *edit = findItem<QQuickItem>(window->rootObject(), "edit");
|
|
QVERIFY(edit);
|
|
|
|
QQuickItem *next, *prev;
|
|
|
|
next = button11->nextItemInFocusChain(true);
|
|
QVERIFY(next);
|
|
QCOMPARE(next, button12);
|
|
prev = button11->nextItemInFocusChain(false);
|
|
QVERIFY(prev);
|
|
QCOMPARE(prev, edit);
|
|
|
|
next = button12->nextItemInFocusChain();
|
|
QVERIFY(next);
|
|
QCOMPARE(next, edit);
|
|
prev = button12->nextItemInFocusChain(false);
|
|
QVERIFY(prev);
|
|
QCOMPARE(prev, button11);
|
|
|
|
next = edit->nextItemInFocusChain();
|
|
QVERIFY(next);
|
|
QCOMPARE(next, button11);
|
|
prev = edit->nextItemInFocusChain(false);
|
|
QVERIFY(prev);
|
|
QCOMPARE(prev, button12);
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::nextItemInFocusChain3()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(800,600));
|
|
|
|
window->setSource(testFileUrl("nextItemInFocusChain3.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
}
|
|
|
|
void verifyTabFocusChain(QQuickView *window, const char **focusChain, bool forward)
|
|
{
|
|
int idx = 0;
|
|
for (const char **objectName = focusChain; *objectName; ++objectName, ++idx) {
|
|
const QString &descrStr = QString("idx=%1 objectName=\"%2\"").arg(idx).arg(*objectName);
|
|
const char *descr = descrStr.toLocal8Bit().data();
|
|
QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, forward ? Qt::NoModifier : Qt::ShiftModifier);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY2(key.isAccepted(), descr);
|
|
|
|
QQuickItem *item = findItem<QQuickItem>(window->rootObject(), *objectName);
|
|
QVERIFY2(item, descr);
|
|
QVERIFY2(item->hasActiveFocus(), descr);
|
|
}
|
|
}
|
|
|
|
void tst_QQuickItem::tabFence()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(800,600));
|
|
|
|
window->setSource(testFileUrl("tabFence.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QVERIFY(QGuiApplication::focusWindow() == window);
|
|
QVERIFY(window->rootObject()->hasActiveFocus());
|
|
|
|
const char *rootTabFocusChain[] = {
|
|
"input1", "input2", "input3", "input1", nullptr
|
|
};
|
|
verifyTabFocusChain(window, rootTabFocusChain, true /* forward */);
|
|
|
|
const char *rootBacktabFocusChain[] = {
|
|
"input3", "input2", "input1", "input3", nullptr
|
|
};
|
|
verifyTabFocusChain(window, rootBacktabFocusChain, false /* forward */);
|
|
|
|
// Give focus to input11 in fence1
|
|
QQuickItem *item = findItem<QQuickItem>(window->rootObject(), "input11");
|
|
item->setFocus(true);
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
|
|
const char *fence1TabFocusChain[] = {
|
|
"input12", "input13", "input11", "input12", nullptr
|
|
};
|
|
verifyTabFocusChain(window, fence1TabFocusChain, true /* forward */);
|
|
|
|
const char *fence1BacktabFocusChain[] = {
|
|
"input11", "input13", "input12", "input11", nullptr
|
|
};
|
|
verifyTabFocusChain(window, fence1BacktabFocusChain, false /* forward */);
|
|
}
|
|
|
|
void tst_QQuickItem::qtbug_50516()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(800,600));
|
|
|
|
window->setSource(testFileUrl("qtbug_50516.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QVERIFY(QGuiApplication::focusWindow() == window);
|
|
QVERIFY(window->rootObject()->hasActiveFocus());
|
|
|
|
QQuickItem *contentItem = window->rootObject();
|
|
QQuickItem *next = contentItem->nextItemInFocusChain(true);
|
|
QCOMPARE(next, contentItem);
|
|
next = contentItem->nextItemInFocusChain(false);
|
|
QCOMPARE(next, contentItem);
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::qtbug_50516_2_data()
|
|
{
|
|
QTest::addColumn<QString>("filename");
|
|
QTest::addColumn<QString>("item1");
|
|
QTest::addColumn<QString>("item2");
|
|
|
|
QTest::newRow("FocusScope TabFence with one Item(focused)")
|
|
<< QStringLiteral("qtbug_50516_2_1.qml") << QStringLiteral("root") << QStringLiteral("root");
|
|
QTest::newRow("FocusScope TabFence with one Item(unfocused)")
|
|
<< QStringLiteral("qtbug_50516_2_2.qml") << QStringLiteral("root") << QStringLiteral("root");
|
|
QTest::newRow("FocusScope TabFence with two Items(focused)")
|
|
<< QStringLiteral("qtbug_50516_2_3.qml") << QStringLiteral("root") << QStringLiteral("root");
|
|
QTest::newRow("FocusScope TabFence with two Items(unfocused)")
|
|
<< QStringLiteral("qtbug_50516_2_4.qml") << QStringLiteral("root") << QStringLiteral("root");
|
|
QTest::newRow("FocusScope TabFence with one Item and one TextInput(unfocused)")
|
|
<< QStringLiteral("qtbug_50516_2_5.qml") << QStringLiteral("item1") << QStringLiteral("item1");
|
|
QTest::newRow("FocusScope TabFence with two TextInputs(unfocused)")
|
|
<< QStringLiteral("qtbug_50516_2_6.qml") << QStringLiteral("item1") << QStringLiteral("item2");
|
|
}
|
|
|
|
void tst_QQuickItem::qtbug_50516_2()
|
|
{
|
|
QFETCH(QString, filename);
|
|
QFETCH(QString, item1);
|
|
QFETCH(QString, item2);
|
|
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(800,600));
|
|
|
|
window->setSource(testFileUrl(filename));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QVERIFY(QGuiApplication::focusWindow() == window);
|
|
QVERIFY(window->rootObject()->hasActiveFocus());
|
|
|
|
QQuickItem *contentItem = window->rootObject();
|
|
QQuickItem *next = contentItem->nextItemInFocusChain(true);
|
|
QCOMPARE(next->objectName(), item1);
|
|
next = contentItem->nextItemInFocusChain(false);
|
|
QCOMPARE(next->objectName(), item2);
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::focusableItemReparentedToLoadedComponent() // QTBUG-89736
|
|
{
|
|
QQuickView window;
|
|
window.setSource(testFileUrl("focusableItemReparentedToLoadedComponent.qml"));
|
|
window.show();
|
|
QVERIFY(QTest::qWaitForWindowActive(&window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), &window);
|
|
QQuickLoader *loader = window.rootObject()->findChild<QQuickLoader *>();
|
|
QVERIFY(loader);
|
|
QTRY_VERIFY(loader->status() == QQuickLoader::Ready);
|
|
QQuickTextInput *textInput = window.rootObject()->findChild<QQuickTextInput *>();
|
|
QVERIFY(textInput);
|
|
|
|
// click to focus
|
|
QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, {10, 10});
|
|
QTRY_VERIFY(textInput->hasActiveFocus());
|
|
|
|
// unload and reload
|
|
auto component = loader->sourceComponent();
|
|
loader->resetSourceComponent();
|
|
QTRY_VERIFY(loader->status() == QQuickLoader::Null);
|
|
loader->setSourceComponent(component);
|
|
QTRY_VERIFY(loader->status() == QQuickLoader::Ready);
|
|
|
|
// click to focus again
|
|
QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, {10, 10});
|
|
QTRY_VERIFY(textInput->hasActiveFocus());
|
|
}
|
|
|
|
void tst_QQuickItem::keys()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(240,320));
|
|
|
|
KeysTestObject *testObject = new KeysTestObject;
|
|
window->rootContext()->setContextProperty("keysTestObject", testObject);
|
|
|
|
window->rootContext()->setContextProperty("enableKeyHanding", QVariant(true));
|
|
window->rootContext()->setContextProperty("forwardeeVisible", QVariant(true));
|
|
|
|
window->setSource(testFileUrl("keystest.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
QVERIFY(window->rootObject());
|
|
QCOMPARE(window->rootObject()->property("isEnabled").toBool(), true);
|
|
|
|
{
|
|
QKeyEvent key(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier, "A", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QCOMPARE(testObject->mKey, int(Qt::Key_A));
|
|
QCOMPARE(testObject->mForwardedKey, int(Qt::Key_A));
|
|
QCOMPARE(testObject->mText, QLatin1String("A"));
|
|
QCOMPARE(testObject->mModifiers, int(Qt::NoModifier));
|
|
QVERIFY(!key.isAccepted());
|
|
}
|
|
|
|
testObject->reset();
|
|
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyRelease, Qt::Key_A, Qt::ShiftModifier, "A", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QCOMPARE(testObject->mKey, int(Qt::Key_A));
|
|
QCOMPARE(testObject->mForwardedKey, int(Qt::Key_A));
|
|
QCOMPARE(testObject->mText, QLatin1String("A"));
|
|
QCOMPARE(testObject->mModifiers, int(Qt::ShiftModifier));
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
testObject->reset();
|
|
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QCOMPARE(testObject->mKey, int(Qt::Key_Return));
|
|
QCOMPARE(testObject->mForwardedKey, int(Qt::Key_Return));
|
|
QCOMPARE(testObject->mText, QLatin1String("Return"));
|
|
QCOMPARE(testObject->mModifiers, int(Qt::NoModifier));
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
testObject->reset();
|
|
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_0, Qt::NoModifier, "0", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QCOMPARE(testObject->mKey, int(Qt::Key_0));
|
|
QCOMPARE(testObject->mForwardedKey, int(Qt::Key_0));
|
|
QCOMPARE(testObject->mText, QLatin1String("0"));
|
|
QCOMPARE(testObject->mModifiers, int(Qt::NoModifier));
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
testObject->reset();
|
|
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_9, Qt::NoModifier, "9", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QCOMPARE(testObject->mKey, int(Qt::Key_9));
|
|
QCOMPARE(testObject->mForwardedKey, int(Qt::Key_9));
|
|
QCOMPARE(testObject->mText, QLatin1String("9"));
|
|
QCOMPARE(testObject->mModifiers, int(Qt::NoModifier));
|
|
QVERIFY(!key.isAccepted());
|
|
}
|
|
|
|
testObject->reset();
|
|
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QCOMPARE(testObject->mKey, int(Qt::Key_Tab));
|
|
QCOMPARE(testObject->mForwardedKey, int(Qt::Key_Tab));
|
|
QCOMPARE(testObject->mText, QLatin1String("Tab"));
|
|
QCOMPARE(testObject->mModifiers, int(Qt::NoModifier));
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
testObject->reset();
|
|
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QCOMPARE(testObject->mKey, int(Qt::Key_Backtab));
|
|
QCOMPARE(testObject->mForwardedKey, int(Qt::Key_Backtab));
|
|
QCOMPARE(testObject->mText, QLatin1String("Backtab"));
|
|
QCOMPARE(testObject->mModifiers, int(Qt::NoModifier));
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
testObject->reset();
|
|
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_VolumeUp, Qt::NoModifier, 1234, 0, 0);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QCOMPARE(testObject->mKey, int(Qt::Key_VolumeUp));
|
|
QCOMPARE(testObject->mForwardedKey, int(Qt::Key_VolumeUp));
|
|
QCOMPARE(testObject->mModifiers, int(Qt::NoModifier));
|
|
QCOMPARE(testObject->mNativeScanCode, quint32(1234));
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
testObject->reset();
|
|
|
|
{
|
|
window->rootContext()->setContextProperty("forwardeeVisible", QVariant(false));
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier, "A", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QCOMPARE(testObject->mKey, int(Qt::Key_A));
|
|
QCOMPARE(testObject->mForwardedKey, 0);
|
|
QCOMPARE(testObject->mText, QLatin1String("A"));
|
|
QCOMPARE(testObject->mModifiers, int(Qt::NoModifier));
|
|
QVERIFY(!key.isAccepted());
|
|
}
|
|
|
|
testObject->reset();
|
|
|
|
{
|
|
window->rootContext()->setContextProperty("enableKeyHanding", QVariant(false));
|
|
QCOMPARE(window->rootObject()->property("isEnabled").toBool(), false);
|
|
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QCOMPARE(testObject->mKey, 0);
|
|
QVERIFY(!key.isAccepted());
|
|
}
|
|
|
|
{
|
|
window->rootContext()->setContextProperty("enableKeyHanding", QVariant(true));
|
|
QCOMPARE(window->rootObject()->property("isEnabled").toBool(), true);
|
|
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QCOMPARE(testObject->mKey, int(Qt::Key_Return));
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
delete window;
|
|
delete testObject;
|
|
}
|
|
|
|
#if QT_CONFIG(shortcut)
|
|
|
|
Q_DECLARE_METATYPE(QEvent::Type);
|
|
Q_DECLARE_METATYPE(QKeySequence::StandardKey);
|
|
|
|
void tst_QQuickItem::standardKeys_data()
|
|
{
|
|
QTest::addColumn<QKeySequence::StandardKey>("standardKey");
|
|
QTest::addColumn<QKeySequence::StandardKey>("contextProperty");
|
|
QTest::addColumn<QEvent::Type>("eventType");
|
|
QTest::addColumn<bool>("pressed");
|
|
QTest::addColumn<bool>("released");
|
|
|
|
QTest::newRow("Press: Open") << QKeySequence::Open << QKeySequence::Open << QEvent::KeyPress << true << false;
|
|
QTest::newRow("Press: Close") << QKeySequence::Close << QKeySequence::Close << QEvent::KeyPress << true << false;
|
|
QTest::newRow("Press: Save") << QKeySequence::Save << QKeySequence::Save << QEvent::KeyPress << true << false;
|
|
QTest::newRow("Press: Quit") << QKeySequence::Quit << QKeySequence::Quit << QEvent::KeyPress << true << false;
|
|
|
|
QTest::newRow("Release: New") << QKeySequence::New << QKeySequence::New << QEvent::KeyRelease << false << true;
|
|
QTest::newRow("Release: Delete") << QKeySequence::Delete << QKeySequence::Delete << QEvent::KeyRelease << false << true;
|
|
QTest::newRow("Release: Undo") << QKeySequence::Undo << QKeySequence::Undo << QEvent::KeyRelease << false << true;
|
|
QTest::newRow("Release: Redo") << QKeySequence::Redo << QKeySequence::Redo << QEvent::KeyRelease << false << true;
|
|
|
|
QTest::newRow("Mismatch: Cut") << QKeySequence::Cut << QKeySequence::Copy << QEvent::KeyPress << false << false;
|
|
QTest::newRow("Mismatch: Copy") << QKeySequence::Copy << QKeySequence::Paste << QEvent::KeyPress << false << false;
|
|
QTest::newRow("Mismatch: Paste") << QKeySequence::Paste << QKeySequence::Cut << QEvent::KeyRelease << false << false;
|
|
QTest::newRow("Mismatch: Quit") << QKeySequence::Quit << QKeySequence::New << QEvent::KeyRelease << false << false;
|
|
}
|
|
|
|
void tst_QQuickItem::standardKeys()
|
|
{
|
|
QFETCH(QKeySequence::StandardKey, standardKey);
|
|
QFETCH(QKeySequence::StandardKey, contextProperty);
|
|
QFETCH(QEvent::Type, eventType);
|
|
QFETCH(bool, pressed);
|
|
QFETCH(bool, released);
|
|
|
|
QKeySequence keySequence(standardKey);
|
|
if (keySequence.isEmpty())
|
|
QSKIP("Undefined key sequence.");
|
|
|
|
QQuickView view;
|
|
view.rootContext()->setContextProperty("standardKey", contextProperty);
|
|
view.setSource(testFileUrl("standardkeys.qml"));
|
|
view.show();
|
|
view.requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(&view));
|
|
|
|
QQuickItem *item = qobject_cast<QQuickItem*>(view.rootObject());
|
|
QVERIFY(item);
|
|
|
|
const int key = keySequence[0].key();
|
|
Qt::KeyboardModifiers modifiers = keySequence[0].keyboardModifiers();
|
|
QKeyEvent keyEvent(eventType, key, modifiers);
|
|
QGuiApplication::sendEvent(&view, &keyEvent);
|
|
|
|
QCOMPARE(item->property("pressed").toBool(), pressed);
|
|
QCOMPARE(item->property("released").toBool(), released);
|
|
}
|
|
|
|
#endif // QT_CONFIG(shortcut)
|
|
|
|
void tst_QQuickItem::keysProcessingOrder()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(240,320));
|
|
|
|
KeysTestObject *testObject = new KeysTestObject;
|
|
window->rootContext()->setContextProperty("keysTestObject", testObject);
|
|
|
|
window->setSource(testFileUrl("keyspriority.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
KeyTestItem *testItem = qobject_cast<KeyTestItem*>(window->rootObject());
|
|
QVERIFY(testItem);
|
|
|
|
QCOMPARE(testItem->property("priorityTest").toInt(), 0);
|
|
|
|
{
|
|
QKeyEvent key(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier, "A", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QCOMPARE(testObject->mKey, int(Qt::Key_A));
|
|
QCOMPARE(testObject->mText, QLatin1String("A"));
|
|
QCOMPARE(testObject->mModifiers, int(Qt::NoModifier));
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
testObject->reset();
|
|
|
|
testObject->setProcessLast(true);
|
|
|
|
QCOMPARE(testItem->property("priorityTest").toInt(), 1);
|
|
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier, "A", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QCOMPARE(testObject->mKey, 0);
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
testObject->reset();
|
|
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_B, Qt::NoModifier, "B", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QCOMPARE(testObject->mKey, int(Qt::Key_B));
|
|
QCOMPARE(testObject->mText, QLatin1String("B"));
|
|
QCOMPARE(testObject->mModifiers, int(Qt::NoModifier));
|
|
QVERIFY(!key.isAccepted());
|
|
}
|
|
|
|
testObject->reset();
|
|
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyRelease, Qt::Key_B, Qt::NoModifier, "B", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QCOMPARE(testObject->mKey, 0);
|
|
QVERIFY(key.isAccepted());
|
|
}
|
|
|
|
delete window;
|
|
delete testObject;
|
|
}
|
|
|
|
void tst_QQuickItem::keysim()
|
|
{
|
|
PlatformInputContext platformInputContext;
|
|
QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod());
|
|
inputMethodPrivate->testContext = &platformInputContext;
|
|
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(240,320));
|
|
|
|
window->setSource(testFileUrl("keysim.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
QVERIFY(window->rootObject());
|
|
QVERIFY(window->rootObject()->hasFocus() && window->rootObject()->hasActiveFocus());
|
|
|
|
QQuickTextInput *input = window->rootObject()->findChild<QQuickTextInput*>();
|
|
QVERIFY(input);
|
|
|
|
QInputMethodEvent ev("Hello world!", QList<QInputMethodEvent::Attribute>());
|
|
QGuiApplication::sendEvent(qGuiApp->focusObject(), &ev);
|
|
|
|
QEXPECT_FAIL("", "QTBUG-24280", Continue);
|
|
QCOMPARE(input->text(), QLatin1String("Hello world!"));
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::keysForward()
|
|
{
|
|
QQuickView window;
|
|
window.setBaseSize(QSize(240,320));
|
|
|
|
window.setSource(testFileUrl("keysforward.qml"));
|
|
window.show();
|
|
window.requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(&window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), &window);
|
|
|
|
QQuickItem *rootItem = qobject_cast<QQuickItem *>(window.rootObject());
|
|
QVERIFY(rootItem);
|
|
QQuickItem *sourceItem = rootItem->property("source").value<QQuickItem *>();
|
|
QVERIFY(sourceItem);
|
|
QQuickItem *primaryTarget = rootItem->property("primaryTarget").value<QQuickItem *>();
|
|
QVERIFY(primaryTarget);
|
|
QQuickItem *secondaryTarget = rootItem->property("secondaryTarget").value<QQuickItem *>();
|
|
QVERIFY(secondaryTarget);
|
|
|
|
// primary target accepts/consumes Key_P
|
|
QKeyEvent pressKeyP(QEvent::KeyPress, Qt::Key_P, Qt::NoModifier, "P");
|
|
QCoreApplication::sendEvent(sourceItem, &pressKeyP);
|
|
QCOMPARE(rootItem->property("pressedKeys").toList(), QVariantList());
|
|
QCOMPARE(sourceItem->property("pressedKeys").toList(), QVariantList());
|
|
QCOMPARE(primaryTarget->property("pressedKeys").toList(), QVariantList() << Qt::Key_P);
|
|
QCOMPARE(secondaryTarget->property("pressedKeys").toList(), QVariantList() << Qt::Key_P);
|
|
QVERIFY(pressKeyP.isAccepted());
|
|
|
|
QKeyEvent releaseKeyP(QEvent::KeyRelease, Qt::Key_P, Qt::NoModifier, "P");
|
|
QCoreApplication::sendEvent(sourceItem, &releaseKeyP);
|
|
QCOMPARE(rootItem->property("releasedKeys").toList(), QVariantList());
|
|
QCOMPARE(sourceItem->property("releasedKeys").toList(), QVariantList());
|
|
QCOMPARE(primaryTarget->property("releasedKeys").toList(), QVariantList() << Qt::Key_P);
|
|
QCOMPARE(secondaryTarget->property("releasedKeys").toList(), QVariantList() << Qt::Key_P);
|
|
QVERIFY(releaseKeyP.isAccepted());
|
|
|
|
// secondary target accepts/consumes Key_S
|
|
QKeyEvent pressKeyS(QEvent::KeyPress, Qt::Key_S, Qt::NoModifier, "S");
|
|
QCoreApplication::sendEvent(sourceItem, &pressKeyS);
|
|
QCOMPARE(rootItem->property("pressedKeys").toList(), QVariantList());
|
|
QCOMPARE(sourceItem->property("pressedKeys").toList(), QVariantList());
|
|
QCOMPARE(primaryTarget->property("pressedKeys").toList(), QVariantList() << Qt::Key_P);
|
|
QCOMPARE(secondaryTarget->property("pressedKeys").toList(), QVariantList() << Qt::Key_P << Qt::Key_S);
|
|
QVERIFY(pressKeyS.isAccepted());
|
|
|
|
QKeyEvent releaseKeyS(QEvent::KeyRelease, Qt::Key_S, Qt::NoModifier, "S");
|
|
QCoreApplication::sendEvent(sourceItem, &releaseKeyS);
|
|
QCOMPARE(rootItem->property("releasedKeys").toList(), QVariantList());
|
|
QCOMPARE(sourceItem->property("releasedKeys").toList(), QVariantList());
|
|
QCOMPARE(primaryTarget->property("releasedKeys").toList(), QVariantList() << Qt::Key_P);
|
|
QCOMPARE(secondaryTarget->property("releasedKeys").toList(), QVariantList() << Qt::Key_P << Qt::Key_S);
|
|
QVERIFY(releaseKeyS.isAccepted());
|
|
|
|
// neither target accepts/consumes Key_Q
|
|
QKeyEvent pressKeyQ(QEvent::KeyPress, Qt::Key_Q, Qt::NoModifier, "Q");
|
|
QCoreApplication::sendEvent(sourceItem, &pressKeyQ);
|
|
QCOMPARE(rootItem->property("pressedKeys").toList(), QVariantList());
|
|
QCOMPARE(sourceItem->property("pressedKeys").toList(), QVariantList() << Qt::Key_Q);
|
|
QCOMPARE(primaryTarget->property("pressedKeys").toList(), QVariantList() << Qt::Key_P << Qt::Key_Q);
|
|
QCOMPARE(secondaryTarget->property("pressedKeys").toList(), QVariantList() << Qt::Key_P << Qt::Key_S << Qt::Key_Q);
|
|
QVERIFY(!pressKeyQ.isAccepted());
|
|
|
|
QKeyEvent releaseKeyQ(QEvent::KeyRelease, Qt::Key_Q, Qt::NoModifier, "Q");
|
|
QCoreApplication::sendEvent(sourceItem, &releaseKeyQ);
|
|
QCOMPARE(rootItem->property("releasedKeys").toList(), QVariantList());
|
|
QCOMPARE(sourceItem->property("releasedKeys").toList(), QVariantList() << Qt::Key_Q);
|
|
QCOMPARE(primaryTarget->property("releasedKeys").toList(), QVariantList() << Qt::Key_P << Qt::Key_Q);
|
|
QCOMPARE(secondaryTarget->property("releasedKeys").toList(), QVariantList() << Qt::Key_P << Qt::Key_S << Qt::Key_Q);
|
|
QVERIFY(!releaseKeyQ.isAccepted());
|
|
}
|
|
|
|
QQuickItemPrivate *childPrivate(QQuickItem *rootItem, const char * itemString)
|
|
{
|
|
QQuickItem *item = findItem<QQuickItem>(rootItem, QString(QLatin1String(itemString)));
|
|
QQuickItemPrivate* itemPrivate = QQuickItemPrivate::get(item);
|
|
return itemPrivate;
|
|
}
|
|
|
|
QVariant childProperty(QQuickItem *rootItem, const char * itemString, const char * property)
|
|
{
|
|
QQuickItem *item = findItem<QQuickItem>(rootItem, QString(QLatin1String(itemString)));
|
|
return item->property(property);
|
|
}
|
|
|
|
bool anchorsMirrored(QQuickItem *rootItem, const char * itemString)
|
|
{
|
|
QQuickItem *item = findItem<QQuickItem>(rootItem, QString(QLatin1String(itemString)));
|
|
QQuickItemPrivate* itemPrivate = QQuickItemPrivate::get(item);
|
|
return itemPrivate->anchors()->mirrored();
|
|
}
|
|
|
|
void tst_QQuickItem::layoutMirroring()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setSource(testFileUrl("layoutmirroring.qml"));
|
|
window->show();
|
|
|
|
QQuickItem *rootItem = qobject_cast<QQuickItem*>(window->rootObject());
|
|
QVERIFY(rootItem);
|
|
QQuickItemPrivate *rootPrivate = QQuickItemPrivate::get(rootItem);
|
|
QVERIFY(rootPrivate);
|
|
|
|
QCOMPARE(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror, true);
|
|
QCOMPARE(childPrivate(rootItem, "mirrored2")->effectiveLayoutMirror, true);
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror, false);
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored2")->effectiveLayoutMirror, false);
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror, true);
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror, true);
|
|
|
|
QCOMPARE(anchorsMirrored(rootItem, "mirrored1"), true);
|
|
QCOMPARE(anchorsMirrored(rootItem, "mirrored2"), true);
|
|
QCOMPARE(anchorsMirrored(rootItem, "notMirrored1"), false);
|
|
QCOMPARE(anchorsMirrored(rootItem, "notMirrored2"), false);
|
|
QCOMPARE(anchorsMirrored(rootItem, "inheritedMirror1"), true);
|
|
QCOMPARE(anchorsMirrored(rootItem, "inheritedMirror2"), true);
|
|
|
|
QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror, true);
|
|
QCOMPARE(childPrivate(rootItem, "mirrored2")->inheritedLayoutMirror, false);
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror, true);
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored2")->inheritedLayoutMirror, false);
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror, true);
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror, true);
|
|
|
|
QCOMPARE(childPrivate(rootItem, "mirrored1")->isMirrorImplicit, false);
|
|
QCOMPARE(childPrivate(rootItem, "mirrored2")->isMirrorImplicit, false);
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored1")->isMirrorImplicit, false);
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored2")->isMirrorImplicit, true);
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->isMirrorImplicit, true);
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->isMirrorImplicit, true);
|
|
|
|
QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritMirrorFromParent, true);
|
|
QCOMPARE(childPrivate(rootItem, "mirrored2")->inheritMirrorFromParent, false);
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritMirrorFromParent, true);
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored2")->inheritMirrorFromParent, false);
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritMirrorFromParent, true);
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritMirrorFromParent, true);
|
|
|
|
QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritMirrorFromItem, true);
|
|
QCOMPARE(childPrivate(rootItem, "mirrored2")->inheritMirrorFromItem, false);
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritMirrorFromItem, false);
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored2")->inheritMirrorFromItem, false);
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritMirrorFromItem, false);
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritMirrorFromItem, false);
|
|
|
|
// load dynamic content using Loader that needs to inherit mirroring
|
|
rootItem->setProperty("state", "newContent");
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored3")->effectiveLayoutMirror, false);
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->effectiveLayoutMirror, true);
|
|
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritedLayoutMirror, true);
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->inheritedLayoutMirror, true);
|
|
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored3")->isMirrorImplicit, false);
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->isMirrorImplicit, true);
|
|
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromParent, true);
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->inheritMirrorFromParent, true);
|
|
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromItem, false);
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromItem, false);
|
|
|
|
// disable inheritance
|
|
rootItem->setProperty("childrenInherit", false);
|
|
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror, false);
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror, false);
|
|
QCOMPARE(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror, true);
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror, false);
|
|
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror, false);
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror, false);
|
|
QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror, false);
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror, false);
|
|
|
|
// re-enable inheritance
|
|
rootItem->setProperty("childrenInherit", true);
|
|
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror, true);
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror, true);
|
|
QCOMPARE(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror, true);
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror, false);
|
|
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror, true);
|
|
QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror, true);
|
|
QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror, true);
|
|
QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror, true);
|
|
|
|
//
|
|
// dynamic parenting
|
|
//
|
|
QQuickItem *parentItem1 = new QQuickItem();
|
|
QQuickItemPrivate::get(parentItem1)->effectiveLayoutMirror = true; // LayoutMirroring.enabled: true
|
|
QQuickItemPrivate::get(parentItem1)->isMirrorImplicit = false;
|
|
QQuickItemPrivate::get(parentItem1)->inheritMirrorFromItem = true; // LayoutMirroring.childrenInherit: true
|
|
QQuickItemPrivate::get(parentItem1)->resolveLayoutMirror();
|
|
|
|
// inherit in constructor
|
|
QQuickItem *childItem1 = new QQuickItem(parentItem1);
|
|
QCOMPARE(QQuickItemPrivate::get(childItem1)->effectiveLayoutMirror, true);
|
|
QCOMPARE(QQuickItemPrivate::get(childItem1)->inheritMirrorFromParent, true);
|
|
|
|
// inherit through a parent change
|
|
QQuickItem *childItem2 = new QQuickItem();
|
|
QCOMPARE(QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror, false);
|
|
QCOMPARE(QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent, false);
|
|
childItem2->setParentItem(parentItem1);
|
|
QCOMPARE(QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror, true);
|
|
QCOMPARE(QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent, true);
|
|
|
|
// stop inherting through a parent change
|
|
QQuickItem *parentItem2 = new QQuickItem();
|
|
QQuickItemPrivate::get(parentItem2)->effectiveLayoutMirror = true; // LayoutMirroring.enabled: true
|
|
QQuickItemPrivate::get(parentItem2)->resolveLayoutMirror();
|
|
childItem2->setParentItem(parentItem2);
|
|
QCOMPARE(QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror, false);
|
|
QCOMPARE(QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent, false);
|
|
|
|
delete parentItem1;
|
|
delete parentItem2;
|
|
}
|
|
|
|
void tst_QQuickItem::layoutMirroringWindow()
|
|
{
|
|
QQmlComponent component(&engine);
|
|
component.loadUrl(testFileUrl("layoutmirroring_window.qml"));
|
|
QScopedPointer<QObject> object(component.create());
|
|
QQuickWindow *window = qobject_cast<QQuickWindow *>(object.data());
|
|
QVERIFY(window);
|
|
window->show();
|
|
|
|
QQuickItemPrivate *content = QQuickItemPrivate::get(window->contentItem());
|
|
QCOMPARE(content->effectiveLayoutMirror, true);
|
|
QCOMPARE(content->inheritedLayoutMirror, true);
|
|
QCOMPARE(content->isMirrorImplicit, false);
|
|
QCOMPARE(content->inheritMirrorFromParent, true);
|
|
QCOMPARE(content->inheritMirrorFromItem, true);
|
|
}
|
|
|
|
void tst_QQuickItem::layoutMirroringIllegalParent()
|
|
{
|
|
QQmlComponent component(&engine);
|
|
component.setData("import QtQuick 2.0; QtObject { LayoutMirroring.enabled: true; LayoutMirroring.childrenInherit: true }", QUrl::fromLocalFile(""));
|
|
QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:1:21: QML QtObject: LayoutDirection attached property only works with Items and Windows");
|
|
QObject *object = component.create();
|
|
QVERIFY(object != nullptr);
|
|
}
|
|
|
|
void tst_QQuickItem::keyNavigation_data()
|
|
{
|
|
QTest::addColumn<QString>("source");
|
|
QTest::newRow("KeyNavigation") << QStringLiteral("keynavigationtest.qml");
|
|
QTest::newRow("KeyNavigation_FocusScope") << QStringLiteral("keynavigationtest_focusscope.qml");
|
|
}
|
|
|
|
void tst_QQuickItem::keyNavigation()
|
|
{
|
|
QFETCH(QString, source);
|
|
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(240,320));
|
|
|
|
window->setSource(testFileUrl(source));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
QQuickItem *item = findItem<QQuickItem>(window->rootObject(), "item1");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
|
|
QVariant result;
|
|
QVERIFY(QMetaObject::invokeMethod(window->rootObject(), "verify",
|
|
Q_RETURN_ARG(QVariant, result)));
|
|
QVERIFY(result.toBool());
|
|
|
|
// right
|
|
{
|
|
QKeyEvent key(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item2");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// down
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item4");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// left
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item3");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// up
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item1");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// tab
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item2");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// backtab
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item1");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::keyNavigation_RightToLeft()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(240,320));
|
|
|
|
window->setSource(testFileUrl("keynavigationtest.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
QQuickItem *rootItem = qobject_cast<QQuickItem*>(window->rootObject());
|
|
QVERIFY(rootItem);
|
|
QQuickItemPrivate* rootItemPrivate = QQuickItemPrivate::get(rootItem);
|
|
|
|
rootItemPrivate->effectiveLayoutMirror = true; // LayoutMirroring.mirror: true
|
|
rootItemPrivate->isMirrorImplicit = false;
|
|
rootItemPrivate->inheritMirrorFromItem = true; // LayoutMirroring.inherit: true
|
|
rootItemPrivate->resolveLayoutMirror();
|
|
|
|
QEvent wa(QEvent::WindowActivate);
|
|
QGuiApplication::sendEvent(window, &wa);
|
|
QFocusEvent fe(QEvent::FocusIn);
|
|
QGuiApplication::sendEvent(window, &fe);
|
|
|
|
QQuickItem *item = findItem<QQuickItem>(window->rootObject(), "item1");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
|
|
QVariant result;
|
|
QVERIFY(QMetaObject::invokeMethod(window->rootObject(), "verify",
|
|
Q_RETURN_ARG(QVariant, result)));
|
|
QVERIFY(result.toBool());
|
|
|
|
// right
|
|
{
|
|
QKeyEvent key(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item2");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// left
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item1");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::keyNavigation_skipNotVisible()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(240,320));
|
|
|
|
window->setSource(testFileUrl("keynavigationtest.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
QQuickItem *item = findItem<QQuickItem>(window->rootObject(), "item1");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
|
|
// Set item 2 to not visible
|
|
item = findItem<QQuickItem>(window->rootObject(), "item2");
|
|
QVERIFY(item);
|
|
item->setVisible(false);
|
|
QVERIFY(!item->isVisible());
|
|
|
|
// right
|
|
{
|
|
QKeyEvent key(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item1");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// tab
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item3");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// backtab
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item1");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
//Set item 3 to not visible
|
|
item = findItem<QQuickItem>(window->rootObject(), "item3");
|
|
QVERIFY(item);
|
|
item->setVisible(false);
|
|
QVERIFY(!item->isVisible());
|
|
|
|
// tab
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item4");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// backtab
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item1");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::keyNavigation_implicitSetting()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(240,320));
|
|
|
|
window->setSource(testFileUrl("keynavigationtest_implicit.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
QEvent wa(QEvent::WindowActivate);
|
|
QGuiApplication::sendEvent(window, &wa);
|
|
QFocusEvent fe(QEvent::FocusIn);
|
|
QGuiApplication::sendEvent(window, &fe);
|
|
|
|
QQuickItem *item = findItem<QQuickItem>(window->rootObject(), "item1");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
|
|
QVariant result;
|
|
QVERIFY(QMetaObject::invokeMethod(window->rootObject(), "verify",
|
|
Q_RETURN_ARG(QVariant, result)));
|
|
QVERIFY(result.toBool());
|
|
|
|
// right
|
|
{
|
|
QKeyEvent key(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item2");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// back to item1
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item1");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// down
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item3");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// move to item4
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item4");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// left
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item3");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// back to item4
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item4");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// up
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item2");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// back to item4
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item4");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// tab
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item1");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// back to item4
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item4");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
// backtab
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
|
|
item = findItem<QQuickItem>(window->rootObject(), "item3");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
}
|
|
|
|
delete window;
|
|
}
|
|
|
|
// QTBUG-75399
|
|
void tst_QQuickItem::keyNavigation_implicitDestroy()
|
|
{
|
|
QQuickView view;
|
|
view.setSource(testFileUrl("keynavigationtest_implicitDestroy.qml"));
|
|
view.show();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(&view));
|
|
|
|
QQuickItem *root = view.rootObject();
|
|
QVERIFY(QMetaObject::invokeMethod(root, "createImplicitKeyNavigation"));
|
|
|
|
// process events is necessary to trigger upcoming memory access violation
|
|
QTest::qWait(0);
|
|
|
|
QVERIFY(root->hasActiveFocus());
|
|
|
|
QKeyEvent keyPress = QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(&view, &keyPress); // <-- access violation happens here
|
|
// this should fail the test, even if the access violation does not occur
|
|
QVERIFY(!keyPress.isAccepted());
|
|
}
|
|
|
|
void tst_QQuickItem::keyNavigation_focusReason()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(240,320));
|
|
|
|
FocusEventFilter focusEventFilter;
|
|
|
|
window->setSource(testFileUrl("keynavigationtest.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
// install event filter on first item
|
|
QQuickItem *item = findItem<QQuickItem>(window->rootObject(), "item1");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
item->installEventFilter(&focusEventFilter);
|
|
|
|
//install event filter on second item
|
|
item = findItem<QQuickItem>(window->rootObject(), "item2");
|
|
QVERIFY(item);
|
|
item->installEventFilter(&focusEventFilter);
|
|
|
|
//install event filter on third item
|
|
item = findItem<QQuickItem>(window->rootObject(), "item3");
|
|
QVERIFY(item);
|
|
item->installEventFilter(&focusEventFilter);
|
|
|
|
//install event filter on last item
|
|
item = findItem<QQuickItem>(window->rootObject(), "item4");
|
|
QVERIFY(item);
|
|
item->installEventFilter(&focusEventFilter);
|
|
|
|
// tab
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
QCOMPARE(focusEventFilter.lastFocusReason, Qt::TabFocusReason);
|
|
}
|
|
|
|
// backtab
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
QCOMPARE(focusEventFilter.lastFocusReason, Qt::BacktabFocusReason);
|
|
}
|
|
|
|
// right - it's also one kind of key navigation
|
|
{
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
QCOMPARE(focusEventFilter.lastFocusReason, Qt::TabFocusReason);
|
|
|
|
item->setFocus(true, Qt::OtherFocusReason);
|
|
QVERIFY(item->hasActiveFocus());
|
|
QCOMPARE(focusEventFilter.lastFocusReason, Qt::OtherFocusReason);
|
|
}
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::keyNavigation_loop()
|
|
{
|
|
// QTBUG-47229
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(240,320));
|
|
|
|
window->setSource(testFileUrl("keynavigationtest_loop.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
QQuickItem *item = findItem<QQuickItem>(window->rootObject(), "item1");
|
|
QVERIFY(item);
|
|
QVERIFY(item->hasActiveFocus());
|
|
|
|
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier, "", false, 1);
|
|
QGuiApplication::sendEvent(window, &key);
|
|
QVERIFY(key.isAccepted());
|
|
QVERIFY(item->hasActiveFocus());
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::keyNavigation_repeater()
|
|
{
|
|
// QTBUG-83356
|
|
QScopedPointer<QQuickView> window(new QQuickView());
|
|
window->setBaseSize(QSize(240,320));
|
|
|
|
window->setSource(testFileUrl("keynavigationtest_repeater.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
|
|
QVariant result;
|
|
QVERIFY(QMetaObject::invokeMethod(window->rootObject(), "verify",
|
|
Q_RETURN_ARG(QVariant, result)));
|
|
QVERIFY(result.toBool());
|
|
}
|
|
|
|
void tst_QQuickItem::smooth()
|
|
{
|
|
QQmlComponent component(&engine);
|
|
component.setData("import QtQuick 2.0; Item { smooth: false; }", QUrl::fromLocalFile(""));
|
|
QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
|
|
QSignalSpy spy(item, SIGNAL(smoothChanged(bool)));
|
|
|
|
QVERIFY(item);
|
|
QVERIFY(!item->smooth());
|
|
|
|
item->setSmooth(true);
|
|
QVERIFY(item->smooth());
|
|
QCOMPARE(spy.count(),1);
|
|
QList<QVariant> arguments = spy.first();
|
|
QCOMPARE(arguments.count(), 1);
|
|
QVERIFY(arguments.at(0).toBool());
|
|
|
|
item->setSmooth(true);
|
|
QCOMPARE(spy.count(),1);
|
|
|
|
item->setSmooth(false);
|
|
QVERIFY(!item->smooth());
|
|
QCOMPARE(spy.count(),2);
|
|
item->setSmooth(false);
|
|
QCOMPARE(spy.count(),2);
|
|
|
|
delete item;
|
|
}
|
|
|
|
void tst_QQuickItem::antialiasing()
|
|
{
|
|
QQmlComponent component(&engine);
|
|
component.setData("import QtQuick 2.0; Item { antialiasing: false; }", QUrl::fromLocalFile(""));
|
|
QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
|
|
QSignalSpy spy(item, SIGNAL(antialiasingChanged(bool)));
|
|
|
|
QVERIFY(item);
|
|
QVERIFY(!item->antialiasing());
|
|
|
|
item->setAntialiasing(true);
|
|
QVERIFY(item->antialiasing());
|
|
QCOMPARE(spy.count(),1);
|
|
QList<QVariant> arguments = spy.first();
|
|
QCOMPARE(arguments.count(), 1);
|
|
QVERIFY(arguments.at(0).toBool());
|
|
|
|
item->setAntialiasing(true);
|
|
QCOMPARE(spy.count(),1);
|
|
|
|
item->setAntialiasing(false);
|
|
QVERIFY(!item->antialiasing());
|
|
QCOMPARE(spy.count(),2);
|
|
item->setAntialiasing(false);
|
|
QCOMPARE(spy.count(),2);
|
|
|
|
delete item;
|
|
}
|
|
|
|
void tst_QQuickItem::clip()
|
|
{
|
|
QQmlComponent component(&engine);
|
|
component.setData("import QtQuick 2.0\nItem { clip: false\n }", QUrl::fromLocalFile(""));
|
|
QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
|
|
QSignalSpy spy(item, SIGNAL(clipChanged(bool)));
|
|
|
|
QVERIFY(item);
|
|
QVERIFY(!item->clip());
|
|
|
|
item->setClip(true);
|
|
QVERIFY(item->clip());
|
|
|
|
QList<QVariant> arguments = spy.first();
|
|
QCOMPARE(arguments.count(), 1);
|
|
QVERIFY(arguments.at(0).toBool());
|
|
|
|
QCOMPARE(spy.count(),1);
|
|
item->setClip(true);
|
|
QCOMPARE(spy.count(),1);
|
|
|
|
item->setClip(false);
|
|
QVERIFY(!item->clip());
|
|
QCOMPARE(spy.count(),2);
|
|
item->setClip(false);
|
|
QCOMPARE(spy.count(),2);
|
|
|
|
delete item;
|
|
}
|
|
|
|
void tst_QQuickItem::mapCoordinates()
|
|
{
|
|
QFETCH(int, x);
|
|
QFETCH(int, y);
|
|
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(300, 300));
|
|
window->setSource(testFileUrl("mapCoordinates.qml"));
|
|
window->show();
|
|
qApp->processEvents();
|
|
|
|
QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject());
|
|
QVERIFY(root != nullptr);
|
|
QQuickItem *a = findItem<QQuickItem>(window->rootObject(), "itemA");
|
|
QVERIFY(a != nullptr);
|
|
QQuickItem *b = findItem<QQuickItem>(window->rootObject(), "itemB");
|
|
QVERIFY(b != nullptr);
|
|
|
|
QVariant result;
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(root, "mapAToB",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
|
|
QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapToItem(b, QPointF(x, y)));
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(root, "mapAToBPoint",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
|
|
QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapToItem(b, QPointF(x, y)));
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(root, "mapAFromB",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
|
|
QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapFromItem(b, QPointF(x, y)));
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(root, "mapAFromBPoint",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
|
|
QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapFromItem(b, QPointF(x, y)));
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(root, "mapAToNull",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
|
|
QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapToScene(QPointF(x, y)));
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(root, "mapAFromNull",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
|
|
QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapFromScene(QPointF(x, y)));
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(root, "mapAToGlobal",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
|
|
QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapToGlobal(QPointF(x, y)));
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(root, "mapAToGlobalPoint",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
|
|
QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapToGlobal(QPointF(x, y)));
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(root, "mapAFromGlobal",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
|
|
QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapFromGlobal(QPointF(x, y)));
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(root, "mapAFromGlobalPoint",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
|
|
QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapFromGlobal(QPointF(x, y)));
|
|
|
|
// for orphans we are primarily testing that we don't crash.
|
|
// when orphaned the final position is the original position of the item translated by x,y
|
|
QVERIFY(QMetaObject::invokeMethod(root, "mapOrphanToGlobal",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
|
|
QCOMPARE(result.value<QPointF>(), QPointF(150,150) + QPointF(x, y));
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(root, "mapOrphanFromGlobal",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
|
|
QCOMPARE(result.value<QPointF>(), -QPointF(150,150) + QPointF(x, y));
|
|
|
|
QString warning1 = testFileUrl("mapCoordinates.qml").toString() + ":35:5: QML Item: mapToItem() given argument \"1122\" which is neither null nor an Item";
|
|
QString warning2 = testFileUrl("mapCoordinates.qml").toString() + ":35:5: QML Item: mapFromItem() given argument \"1122\" which is neither null nor an Item";
|
|
|
|
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
|
|
QVERIFY(QMetaObject::invokeMethod(root, "checkMapAToInvalid",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
|
|
QVERIFY(result.toBool());
|
|
|
|
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
|
|
QVERIFY(QMetaObject::invokeMethod(root, "checkMapAFromInvalid",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
|
|
QVERIFY(result.toBool());
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::mapCoordinates_data()
|
|
{
|
|
QTest::addColumn<int>("x");
|
|
QTest::addColumn<int>("y");
|
|
|
|
for (int i=-20; i<=20; i+=10)
|
|
QTest::newRow(QTest::toString(i)) << i << i;
|
|
}
|
|
|
|
void tst_QQuickItem::mapCoordinatesRect()
|
|
{
|
|
QFETCH(int, x);
|
|
QFETCH(int, y);
|
|
QFETCH(int, width);
|
|
QFETCH(int, height);
|
|
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(300, 300));
|
|
window->setSource(testFileUrl("mapCoordinatesRect.qml"));
|
|
window->show();
|
|
qApp->processEvents();
|
|
|
|
QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject());
|
|
QVERIFY(root != nullptr);
|
|
QQuickItem *a = findItem<QQuickItem>(window->rootObject(), "itemA");
|
|
QVERIFY(a != nullptr);
|
|
QQuickItem *b = findItem<QQuickItem>(window->rootObject(), "itemB");
|
|
QVERIFY(b != nullptr);
|
|
|
|
QVariant result;
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(root, "mapAToB",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height)));
|
|
QCOMPARE(result.value<QRectF>(), qobject_cast<QQuickItem*>(a)->mapRectToItem(b, QRectF(x, y, width, height)));
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(root, "mapAToBRect",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height)));
|
|
QCOMPARE(result.value<QRectF>(), qobject_cast<QQuickItem*>(a)->mapRectToItem(b, QRectF(x, y, width, height)));
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(root, "mapAFromB",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height)));
|
|
QCOMPARE(result.value<QRectF>(), qobject_cast<QQuickItem*>(a)->mapRectFromItem(b, QRectF(x, y, width, height)));
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(root, "mapAFromBRect",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height)));
|
|
QCOMPARE(result.value<QRectF>(), qobject_cast<QQuickItem*>(a)->mapRectFromItem(b, QRectF(x, y, width, height)));
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(root, "mapAToNull",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height)));
|
|
QCOMPARE(result.value<QRectF>(), qobject_cast<QQuickItem*>(a)->mapRectToScene(QRectF(x, y, width, height)));
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(root, "mapAFromNull",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height)));
|
|
QCOMPARE(result.value<QRectF>(), qobject_cast<QQuickItem*>(a)->mapRectFromScene(QRectF(x, y, width, height)));
|
|
|
|
QString warning1 = testFileUrl("mapCoordinatesRect.qml").toString() + ":35:5: QML Item: mapToItem() given argument \"1122\" which is neither null nor an Item";
|
|
QString warning2 = testFileUrl("mapCoordinatesRect.qml").toString() + ":35:5: QML Item: mapFromItem() given argument \"1122\" which is neither null nor an Item";
|
|
|
|
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
|
|
QVERIFY(QMetaObject::invokeMethod(root, "checkMapAToInvalid",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height)));
|
|
QVERIFY(result.toBool());
|
|
|
|
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
|
|
QVERIFY(QMetaObject::invokeMethod(root, "checkMapAFromInvalid",
|
|
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height)));
|
|
QVERIFY(result.toBool());
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::mapCoordinatesRect_data()
|
|
{
|
|
QTest::addColumn<int>("x");
|
|
QTest::addColumn<int>("y");
|
|
QTest::addColumn<int>("width");
|
|
QTest::addColumn<int>("height");
|
|
|
|
for (int i=-20; i<=20; i+=5)
|
|
QTest::newRow(QTest::toString(i)) << i << i << i << i;
|
|
}
|
|
|
|
void tst_QQuickItem::transforms_data()
|
|
{
|
|
QTest::addColumn<QByteArray>("qml");
|
|
QTest::addColumn<QTransform>("transform");
|
|
QTest::newRow("translate") << QByteArray("Translate { x: 10; y: 20 }")
|
|
<< QTransform(1,0,0,0,1,0,10,20,1);
|
|
QTest::newRow("matrix4x4") << QByteArray("Matrix4x4 { matrix: Qt.matrix4x4(1,0,0,10, 0,1,0,15, 0,0,1,0, 0,0,0,1) }")
|
|
<< QTransform(1,0,0,0,1,0,10,15,1);
|
|
QTest::newRow("rotation") << QByteArray("Rotation { angle: 90 }")
|
|
<< QTransform(0,1,0,-1,0,0,0,0,1);
|
|
QTest::newRow("scale") << QByteArray("Scale { xScale: 1.5; yScale: -2 }")
|
|
<< QTransform(1.5,0,0,0,-2,0,0,0,1);
|
|
QTest::newRow("sequence") << QByteArray("[ Translate { x: 10; y: 20 }, Scale { xScale: 1.5; yScale: -2 } ]")
|
|
<< QTransform(1,0,0,0,1,0,10,20,1) * QTransform(1.5,0,0,0,-2,0,0,0,1);
|
|
}
|
|
|
|
void tst_QQuickItem::transforms()
|
|
{
|
|
QFETCH(QByteArray, qml);
|
|
QFETCH(QTransform, transform);
|
|
QQmlComponent component(&engine);
|
|
component.setData("import QtQuick 2.3\nItem { transform: "+qml+"}", QUrl::fromLocalFile(""));
|
|
QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
|
|
QVERIFY(item);
|
|
QCOMPARE(item->itemTransform(nullptr,nullptr), transform);
|
|
}
|
|
|
|
void tst_QQuickItem::childrenProperty()
|
|
{
|
|
QQmlComponent component(&engine, testFileUrl("childrenProperty.qml"));
|
|
|
|
QObject *o = component.create();
|
|
QVERIFY(o != nullptr);
|
|
|
|
QCOMPARE(o->property("test1").toBool(), true);
|
|
QCOMPARE(o->property("test2").toBool(), true);
|
|
QCOMPARE(o->property("test3").toBool(), true);
|
|
QCOMPARE(o->property("test4").toBool(), true);
|
|
QCOMPARE(o->property("test5").toBool(), true);
|
|
delete o;
|
|
}
|
|
|
|
void tst_QQuickItem::resourcesProperty()
|
|
{
|
|
QQmlComponent component(&engine, testFileUrl("resourcesProperty.qml"));
|
|
|
|
QObject *object = component.create();
|
|
QVERIFY(object != nullptr);
|
|
|
|
QQmlProperty property(object, "resources", component.creationContext());
|
|
|
|
QVERIFY(property.isValid());
|
|
QQmlListReference list = qvariant_cast<QQmlListReference>(property.read());
|
|
QVERIFY(list.isValid());
|
|
|
|
QCOMPARE(list.count(), 4);
|
|
|
|
QCOMPARE(object->property("test1").toBool(), true);
|
|
QCOMPARE(object->property("test2").toBool(), true);
|
|
QCOMPARE(object->property("test3").toBool(), true);
|
|
QCOMPARE(object->property("test4").toBool(), true);
|
|
QCOMPARE(object->property("test5").toBool(), true);
|
|
QCOMPARE(object->property("test6").toBool(), true);
|
|
|
|
QObject *subObject = object->findChild<QObject *>("subObject");
|
|
|
|
QVERIFY(subObject);
|
|
|
|
QCOMPARE(object, subObject->parent());
|
|
|
|
delete subObject;
|
|
|
|
QCOMPARE(list.count(), 3);
|
|
|
|
delete object;
|
|
}
|
|
|
|
void tst_QQuickItem::bindableProperties_data()
|
|
{
|
|
QTest::addColumn<qreal>("initialValue");
|
|
QTest::addColumn<qreal>("newValue");
|
|
QTest::addColumn<QString>("property");
|
|
|
|
// can't simply use 3. or 3.0 for the numbers as qreal might
|
|
// be float instead of double...
|
|
QTest::addRow("x") << qreal(3) << qreal(14) << "x";
|
|
QTest::addRow("y") << qreal(10) << qreal(20) << "y";
|
|
QTest::addRow("width") << qreal(100) << qreal(200) << "width";
|
|
QTest::addRow("height") << qreal(50) << qreal(40) << "height";
|
|
}
|
|
|
|
void tst_QQuickItem::bindableProperties()
|
|
{
|
|
QQuickItem item;
|
|
QFETCH(qreal, initialValue);
|
|
QFETCH(qreal, newValue);
|
|
QFETCH(QString, property);
|
|
|
|
QTestPrivate::testReadWritePropertyBasics(item, initialValue, newValue, property.toUtf8().constData());
|
|
}
|
|
|
|
void tst_QQuickItem::propertyChanges()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setBaseSize(QSize(300, 300));
|
|
window->setSource(testFileUrl("propertychanges.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
QQuickItem *item = findItem<QQuickItem>(window->rootObject(), "item");
|
|
QQuickItem *parentItem = findItem<QQuickItem>(window->rootObject(), "parentItem");
|
|
|
|
QVERIFY(item);
|
|
QVERIFY(parentItem);
|
|
|
|
QSignalSpy parentSpy(item, SIGNAL(parentChanged(QQuickItem*)));
|
|
QSignalSpy widthSpy(item, SIGNAL(widthChanged()));
|
|
QSignalSpy heightSpy(item, SIGNAL(heightChanged()));
|
|
QSignalSpy baselineOffsetSpy(item, SIGNAL(baselineOffsetChanged(qreal)));
|
|
QSignalSpy childrenRectSpy(parentItem, SIGNAL(childrenRectChanged(QRectF)));
|
|
QSignalSpy focusSpy(item, SIGNAL(focusChanged(bool)));
|
|
QSignalSpy wantsFocusSpy(parentItem, SIGNAL(activeFocusChanged(bool)));
|
|
QSignalSpy childrenChangedSpy(parentItem, SIGNAL(childrenChanged()));
|
|
QSignalSpy xSpy(item, SIGNAL(xChanged()));
|
|
QSignalSpy ySpy(item, SIGNAL(yChanged()));
|
|
|
|
item->setParentItem(parentItem);
|
|
item->setWidth(100.0);
|
|
item->setHeight(200.0);
|
|
item->setFocus(true);
|
|
item->setBaselineOffset(10.0);
|
|
|
|
QCOMPARE(item->parentItem(), parentItem);
|
|
QCOMPARE(parentSpy.count(),1);
|
|
QList<QVariant> parentArguments = parentSpy.first();
|
|
QCOMPARE(parentArguments.count(), 1);
|
|
QCOMPARE(item->parentItem(), qvariant_cast<QQuickItem *>(parentArguments.at(0)));
|
|
QCOMPARE(childrenChangedSpy.count(),1);
|
|
|
|
item->setParentItem(parentItem);
|
|
QCOMPARE(childrenChangedSpy.count(),1);
|
|
|
|
QCOMPARE(item->width(), 100.0);
|
|
QCOMPARE(widthSpy.count(),1);
|
|
|
|
QCOMPARE(item->height(), 200.0);
|
|
QCOMPARE(heightSpy.count(),1);
|
|
|
|
QCOMPARE(item->baselineOffset(), 10.0);
|
|
QCOMPARE(baselineOffsetSpy.count(),1);
|
|
QList<QVariant> baselineOffsetArguments = baselineOffsetSpy.first();
|
|
QCOMPARE(baselineOffsetArguments.count(), 1);
|
|
QCOMPARE(item->baselineOffset(), baselineOffsetArguments.at(0).toReal());
|
|
|
|
QCOMPARE(parentItem->childrenRect(), QRectF(0.0,0.0,100.0,200.0));
|
|
QCOMPARE(childrenRectSpy.count(),1);
|
|
QList<QVariant> childrenRectArguments = childrenRectSpy.at(0);
|
|
QCOMPARE(childrenRectArguments.count(), 1);
|
|
QCOMPARE(parentItem->childrenRect(), childrenRectArguments.at(0).toRectF());
|
|
|
|
QCOMPARE(item->hasActiveFocus(), true);
|
|
QCOMPARE(focusSpy.count(),1);
|
|
QList<QVariant> focusArguments = focusSpy.first();
|
|
QCOMPARE(focusArguments.count(), 1);
|
|
QCOMPARE(focusArguments.at(0).toBool(), true);
|
|
|
|
QCOMPARE(parentItem->hasActiveFocus(), false);
|
|
QCOMPARE(parentItem->hasFocus(), false);
|
|
QCOMPARE(wantsFocusSpy.count(),0);
|
|
|
|
item->setX(10.0);
|
|
QCOMPARE(item->x(), 10.0);
|
|
QCOMPARE(xSpy.count(), 1);
|
|
|
|
item->setY(10.0);
|
|
QCOMPARE(item->y(), 10.0);
|
|
QCOMPARE(ySpy.count(), 1);
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::nonexistentPropertyConnection()
|
|
{
|
|
// QTBUG-56551: don't crash
|
|
QQmlComponent component(&engine, testFileUrl("nonexistentPropertyConnection.qml"));
|
|
QObject *o = component.create();
|
|
QVERIFY(o);
|
|
delete o;
|
|
}
|
|
|
|
void tst_QQuickItem::childrenRect()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setSource(testFileUrl("childrenRect.qml"));
|
|
window->setBaseSize(QSize(240,320));
|
|
window->show();
|
|
|
|
QQuickItem *o = window->rootObject();
|
|
QQuickItem *item = o->findChild<QQuickItem*>("testItem");
|
|
QCOMPARE(item->width(), qreal(0));
|
|
QCOMPARE(item->height(), qreal(0));
|
|
|
|
o->setProperty("childCount", 1);
|
|
QCOMPARE(item->width(), qreal(10));
|
|
QCOMPARE(item->height(), qreal(20));
|
|
|
|
o->setProperty("childCount", 5);
|
|
QCOMPARE(item->width(), qreal(50));
|
|
QCOMPARE(item->height(), qreal(100));
|
|
|
|
o->setProperty("childCount", 0);
|
|
QCOMPARE(item->width(), qreal(0));
|
|
QCOMPARE(item->height(), qreal(0));
|
|
|
|
delete o;
|
|
delete window;
|
|
}
|
|
|
|
// QTBUG-11383
|
|
void tst_QQuickItem::childrenRectBug()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
|
|
QString warning = testFileUrl("childrenRectBug.qml").toString() + ":11:9: QML Item: Binding loop detected for property \"height\"";
|
|
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
|
|
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
|
|
|
|
window->setSource(testFileUrl("childrenRectBug.qml"));
|
|
window->show();
|
|
|
|
QQuickItem *o = window->rootObject();
|
|
QQuickItem *item = o->findChild<QQuickItem*>("theItem");
|
|
QCOMPARE(item->width(), qreal(200));
|
|
QCOMPARE(item->height(), qreal(100));
|
|
QCOMPARE(item->x(), qreal(100));
|
|
|
|
delete window;
|
|
}
|
|
|
|
// QTBUG-11465
|
|
void tst_QQuickItem::childrenRectBug2()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
|
|
QString warning1 = testFileUrl("childrenRectBug2.qml").toString() + ":10:9: QML Item: Binding loop detected for property \"width\"";
|
|
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
|
|
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
|
|
|
|
QString warning2 = testFileUrl("childrenRectBug2.qml").toString() + ":11:9: QML Item: Binding loop detected for property \"height\"";
|
|
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
|
|
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
|
|
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
|
|
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
|
|
|
|
window->setSource(testFileUrl("childrenRectBug2.qml"));
|
|
window->show();
|
|
|
|
QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(window->rootObject());
|
|
QVERIFY(rect);
|
|
QQuickItem *item = rect->findChild<QQuickItem*>("theItem");
|
|
QCOMPARE(item->width(), qreal(100));
|
|
QCOMPARE(item->height(), qreal(110));
|
|
QCOMPARE(item->x(), qreal(130));
|
|
|
|
QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
|
|
rectPrivate->setState("row");
|
|
QCOMPARE(item->width(), qreal(210));
|
|
QCOMPARE(item->height(), qreal(50));
|
|
QCOMPARE(item->x(), qreal(75));
|
|
|
|
delete window;
|
|
}
|
|
|
|
// QTBUG-12722
|
|
void tst_QQuickItem::childrenRectBug3()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setSource(testFileUrl("childrenRectBug3.qml"));
|
|
window->show();
|
|
|
|
//don't crash on delete
|
|
delete window;
|
|
}
|
|
|
|
// QTBUG-38732
|
|
void tst_QQuickItem::childrenRectBottomRightCorner()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setSource(testFileUrl("childrenRectBottomRightCorner.qml"));
|
|
window->show();
|
|
|
|
QQuickItem *rect = window->rootObject()->findChild<QQuickItem*>("childrenRectProxy");
|
|
QCOMPARE(rect->x(), qreal(-100));
|
|
QCOMPARE(rect->y(), qreal(-100));
|
|
QCOMPARE(rect->width(), qreal(50));
|
|
QCOMPARE(rect->height(), qreal(50));
|
|
|
|
delete window;
|
|
}
|
|
|
|
struct TestListener : public QQuickItemChangeListener
|
|
{
|
|
TestListener(bool remove = false) : remove(remove) { }
|
|
|
|
void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange, const QRectF &oldGeometry) override
|
|
{
|
|
record(item, QQuickItemPrivate::Geometry, oldGeometry);
|
|
}
|
|
void itemSiblingOrderChanged(QQuickItem *item) override
|
|
{
|
|
record(item, QQuickItemPrivate::SiblingOrder);
|
|
}
|
|
void itemVisibilityChanged(QQuickItem *item) override
|
|
{
|
|
record(item, QQuickItemPrivate::Visibility);
|
|
}
|
|
void itemOpacityChanged(QQuickItem *item) override
|
|
{
|
|
record(item, QQuickItemPrivate::Opacity);
|
|
}
|
|
void itemRotationChanged(QQuickItem *item) override
|
|
{
|
|
record(item, QQuickItemPrivate::Rotation);
|
|
}
|
|
void itemImplicitWidthChanged(QQuickItem *item) override
|
|
{
|
|
record(item, QQuickItemPrivate::ImplicitWidth);
|
|
}
|
|
void itemImplicitHeightChanged(QQuickItem *item) override
|
|
{
|
|
record(item, QQuickItemPrivate::ImplicitHeight);
|
|
}
|
|
void itemDestroyed(QQuickItem *item) override
|
|
{
|
|
record(item, QQuickItemPrivate::Destroyed);
|
|
}
|
|
void itemChildAdded(QQuickItem *item, QQuickItem *child) override
|
|
{
|
|
record(item, QQuickItemPrivate::Children, QVariant::fromValue(child));
|
|
}
|
|
void itemChildRemoved(QQuickItem *item, QQuickItem *child) override
|
|
{
|
|
record(item, QQuickItemPrivate::Children, QVariant::fromValue(child));
|
|
}
|
|
void itemParentChanged(QQuickItem *item, QQuickItem *parent) override
|
|
{
|
|
record(item, QQuickItemPrivate::Parent, QVariant::fromValue(parent));
|
|
}
|
|
|
|
QQuickAnchorsPrivate *anchorPrivate() override { return nullptr; }
|
|
|
|
void record(QQuickItem *item, QQuickItemPrivate::ChangeType change, const QVariant &value = QVariant())
|
|
{
|
|
changes += change;
|
|
values[change] = value;
|
|
// QTBUG-54732
|
|
if (remove)
|
|
QQuickItemPrivate::get(item)->removeItemChangeListener(this, change);
|
|
}
|
|
|
|
int count(QQuickItemPrivate::ChangeType change) const
|
|
{
|
|
return changes.count(change);
|
|
}
|
|
|
|
QVariant value(QQuickItemPrivate::ChangeType change) const
|
|
{
|
|
return values.value(change);
|
|
}
|
|
|
|
bool remove;
|
|
QList<QQuickItemPrivate::ChangeType> changes;
|
|
QHash<QQuickItemPrivate::ChangeType, QVariant> values;
|
|
};
|
|
|
|
void tst_QQuickItem::changeListener()
|
|
{
|
|
QQuickWindow window;
|
|
window.show();
|
|
QVERIFY(QTest::qWaitForWindowExposed(&window));
|
|
|
|
QQuickItem *item = new QQuickItem;
|
|
TestListener itemListener;
|
|
QQuickItemPrivate::get(item)->addItemChangeListener(&itemListener, QQuickItemPrivate::ChangeTypes(0xffff));
|
|
|
|
item->setImplicitWidth(10);
|
|
QCOMPARE(itemListener.count(QQuickItemPrivate::ImplicitWidth), 1);
|
|
QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 1);
|
|
QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,0,0)));
|
|
|
|
item->setImplicitHeight(20);
|
|
QCOMPARE(itemListener.count(QQuickItemPrivate::ImplicitHeight), 1);
|
|
QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 2);
|
|
QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,10,0)));
|
|
|
|
item->setWidth(item->width() + 30);
|
|
QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 3);
|
|
QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,10,20)));
|
|
|
|
item->setHeight(item->height() + 40);
|
|
QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 4);
|
|
QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,40,20)));
|
|
|
|
item->setOpacity(0.5);
|
|
QCOMPARE(itemListener.count(QQuickItemPrivate::Opacity), 1);
|
|
|
|
item->setRotation(90);
|
|
QCOMPARE(itemListener.count(QQuickItemPrivate::Rotation), 1);
|
|
|
|
item->setParentItem(window.contentItem());
|
|
QCOMPARE(itemListener.count(QQuickItemPrivate::Parent), 1);
|
|
|
|
item->setVisible(false);
|
|
QCOMPARE(itemListener.count(QQuickItemPrivate::Visibility), 1);
|
|
|
|
QQuickItemPrivate::get(item)->removeItemChangeListener(&itemListener, QQuickItemPrivate::ChangeTypes(0xffff));
|
|
|
|
QQuickItem *parent = new QQuickItem(window.contentItem());
|
|
TestListener parentListener;
|
|
QQuickItemPrivate::get(parent)->addItemChangeListener(&parentListener, QQuickItemPrivate::Children);
|
|
|
|
QQuickItem *child1 = new QQuickItem;
|
|
QQuickItem *child2 = new QQuickItem;
|
|
TestListener child1Listener;
|
|
TestListener child2Listener;
|
|
QQuickItemPrivate::get(child1)->addItemChangeListener(&child1Listener, QQuickItemPrivate::Parent | QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::Destroyed);
|
|
QQuickItemPrivate::get(child2)->addItemChangeListener(&child2Listener, QQuickItemPrivate::Parent | QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::Destroyed);
|
|
|
|
child1->setParentItem(parent);
|
|
QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 1);
|
|
QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child1));
|
|
QCOMPARE(child1Listener.count(QQuickItemPrivate::Parent), 1);
|
|
QCOMPARE(child1Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue(parent));
|
|
|
|
child2->setParentItem(parent);
|
|
QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 2);
|
|
QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child2));
|
|
QCOMPARE(child2Listener.count(QQuickItemPrivate::Parent), 1);
|
|
QCOMPARE(child2Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue(parent));
|
|
|
|
child2->stackBefore(child1);
|
|
QCOMPARE(child1Listener.count(QQuickItemPrivate::SiblingOrder), 1);
|
|
QCOMPARE(child2Listener.count(QQuickItemPrivate::SiblingOrder), 1);
|
|
|
|
child1->setParentItem(nullptr);
|
|
QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 3);
|
|
QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child1));
|
|
QCOMPARE(child1Listener.count(QQuickItemPrivate::Parent), 2);
|
|
QCOMPARE(child1Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue<QQuickItem *>(nullptr));
|
|
|
|
delete child1;
|
|
QCOMPARE(child1Listener.count(QQuickItemPrivate::Destroyed), 1);
|
|
|
|
delete child2;
|
|
QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 4);
|
|
QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child2));
|
|
QCOMPARE(child2Listener.count(QQuickItemPrivate::Parent), 2);
|
|
QCOMPARE(child2Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue<QQuickItem *>(nullptr));
|
|
QCOMPARE(child2Listener.count(QQuickItemPrivate::Destroyed), 1);
|
|
|
|
QQuickItemPrivate::get(parent)->removeItemChangeListener(&parentListener, QQuickItemPrivate::Children);
|
|
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
|
|
|
|
// QTBUG-54732: all listeners should get invoked even if they remove themselves while iterating the listeners
|
|
QList<TestListener *> listeners;
|
|
for (int i = 0; i < 5; ++i)
|
|
listeners << new TestListener(true);
|
|
|
|
// itemVisibilityChanged x 5
|
|
foreach (TestListener *listener, listeners)
|
|
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Visibility);
|
|
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
|
|
parent->setVisible(false);
|
|
foreach (TestListener *listener, listeners)
|
|
QCOMPARE(listener->count(QQuickItemPrivate::Visibility), 1);
|
|
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
|
|
|
|
// itemRotationChanged x 5
|
|
foreach (TestListener *listener, listeners)
|
|
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Rotation);
|
|
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
|
|
parent->setRotation(90);
|
|
foreach (TestListener *listener, listeners)
|
|
QCOMPARE(listener->count(QQuickItemPrivate::Rotation), 1);
|
|
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
|
|
|
|
// itemOpacityChanged x 5
|
|
foreach (TestListener *listener, listeners)
|
|
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Opacity);
|
|
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
|
|
parent->setOpacity(0.5);
|
|
foreach (TestListener *listener, listeners)
|
|
QCOMPARE(listener->count(QQuickItemPrivate::Opacity), 1);
|
|
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
|
|
|
|
// itemChildAdded() x 5
|
|
foreach (TestListener *listener, listeners)
|
|
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Children);
|
|
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
|
|
child1 = new QQuickItem(parent);
|
|
foreach (TestListener *listener, listeners)
|
|
QCOMPARE(listener->count(QQuickItemPrivate::Children), 1);
|
|
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
|
|
|
|
// itemParentChanged() x 5
|
|
foreach (TestListener *listener, listeners)
|
|
QQuickItemPrivate::get(child1)->addItemChangeListener(listener, QQuickItemPrivate::Parent);
|
|
QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.count(), listeners.count());
|
|
child1->setParentItem(nullptr);
|
|
foreach (TestListener *listener, listeners)
|
|
QCOMPARE(listener->count(QQuickItemPrivate::Parent), 1);
|
|
QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.count(), 0);
|
|
|
|
// itemImplicitWidthChanged() x 5
|
|
foreach (TestListener *listener, listeners)
|
|
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::ImplicitWidth);
|
|
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
|
|
parent->setImplicitWidth(parent->implicitWidth() + 1);
|
|
foreach (TestListener *listener, listeners)
|
|
QCOMPARE(listener->count(QQuickItemPrivate::ImplicitWidth), 1);
|
|
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
|
|
|
|
// itemImplicitHeightChanged() x 5
|
|
foreach (TestListener *listener, listeners)
|
|
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::ImplicitHeight);
|
|
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
|
|
parent->setImplicitHeight(parent->implicitHeight() + 1);
|
|
foreach (TestListener *listener, listeners)
|
|
QCOMPARE(listener->count(QQuickItemPrivate::ImplicitHeight), 1);
|
|
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
|
|
|
|
// itemGeometryChanged() x 5
|
|
foreach (TestListener *listener, listeners)
|
|
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Geometry);
|
|
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
|
|
parent->setWidth(parent->width() + 1);
|
|
foreach (TestListener *listener, listeners)
|
|
QCOMPARE(listener->count(QQuickItemPrivate::Geometry), 1);
|
|
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
|
|
|
|
// itemChildRemoved() x 5
|
|
child1->setParentItem(parent);
|
|
foreach (TestListener *listener, listeners)
|
|
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Children);
|
|
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
|
|
delete child1;
|
|
foreach (TestListener *listener, listeners)
|
|
QCOMPARE(listener->count(QQuickItemPrivate::Children), 2);
|
|
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
|
|
|
|
// itemDestroyed() x 5
|
|
foreach (TestListener *listener, listeners)
|
|
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Destroyed);
|
|
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
|
|
delete parent;
|
|
foreach (TestListener *listener, listeners)
|
|
QCOMPARE(listener->count(QQuickItemPrivate::Destroyed), 1);
|
|
}
|
|
|
|
// QTBUG-13893
|
|
void tst_QQuickItem::transformCrash()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setSource(testFileUrl("transformCrash.qml"));
|
|
window->show();
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::implicitSize()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setSource(testFileUrl("implicitsize.qml"));
|
|
window->show();
|
|
|
|
QQuickItem *item = qobject_cast<QQuickItem*>(window->rootObject());
|
|
QVERIFY(item);
|
|
QCOMPARE(item->width(), qreal(80));
|
|
QCOMPARE(item->height(), qreal(60));
|
|
|
|
QCOMPARE(item->implicitWidth(), qreal(200));
|
|
QCOMPARE(item->implicitHeight(), qreal(100));
|
|
|
|
QMetaObject::invokeMethod(item, "resetSize");
|
|
|
|
QCOMPARE(item->width(), qreal(200));
|
|
QCOMPARE(item->height(), qreal(100));
|
|
|
|
QMetaObject::invokeMethod(item, "changeImplicit");
|
|
|
|
QCOMPARE(item->implicitWidth(), qreal(150));
|
|
QCOMPARE(item->implicitHeight(), qreal(80));
|
|
QCOMPARE(item->width(), qreal(150));
|
|
QCOMPARE(item->height(), qreal(80));
|
|
|
|
QMetaObject::invokeMethod(item, "assignImplicitBinding");
|
|
|
|
QCOMPARE(item->implicitWidth(), qreal(150));
|
|
QCOMPARE(item->implicitHeight(), qreal(80));
|
|
QCOMPARE(item->width(), qreal(150));
|
|
QCOMPARE(item->height(), qreal(80));
|
|
|
|
QMetaObject::invokeMethod(item, "increaseImplicit");
|
|
|
|
QCOMPARE(item->implicitWidth(), qreal(200));
|
|
QCOMPARE(item->implicitHeight(), qreal(100));
|
|
QCOMPARE(item->width(), qreal(175));
|
|
QCOMPARE(item->height(), qreal(90));
|
|
|
|
QMetaObject::invokeMethod(item, "changeImplicit");
|
|
|
|
QCOMPARE(item->implicitWidth(), qreal(150));
|
|
QCOMPARE(item->implicitHeight(), qreal(80));
|
|
QCOMPARE(item->width(), qreal(150));
|
|
QCOMPARE(item->height(), qreal(80));
|
|
|
|
QMetaObject::invokeMethod(item, "assignUndefinedBinding");
|
|
|
|
QCOMPARE(item->implicitWidth(), qreal(150));
|
|
QCOMPARE(item->implicitHeight(), qreal(80));
|
|
QCOMPARE(item->width(), qreal(150));
|
|
QCOMPARE(item->height(), qreal(80));
|
|
|
|
QMetaObject::invokeMethod(item, "increaseImplicit");
|
|
|
|
QCOMPARE(item->implicitWidth(), qreal(200));
|
|
QCOMPARE(item->implicitHeight(), qreal(100));
|
|
QCOMPARE(item->width(), qreal(175));
|
|
QCOMPARE(item->height(), qreal(90));
|
|
|
|
QMetaObject::invokeMethod(item, "changeImplicit");
|
|
|
|
QCOMPARE(item->implicitWidth(), qreal(150));
|
|
QCOMPARE(item->implicitHeight(), qreal(80));
|
|
QCOMPARE(item->width(), qreal(150));
|
|
QCOMPARE(item->height(), qreal(80));
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::qtbug_16871()
|
|
{
|
|
QQmlComponent component(&engine, testFileUrl("qtbug_16871.qml"));
|
|
QObject *o = component.create();
|
|
QVERIFY(o != nullptr);
|
|
delete o;
|
|
}
|
|
|
|
|
|
void tst_QQuickItem::visibleChildren()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->setSource(testFileUrl("visiblechildren.qml"));
|
|
window->show();
|
|
|
|
QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject());
|
|
QVERIFY(root);
|
|
|
|
QCOMPARE(root->property("test1_1").toBool(), true);
|
|
QCOMPARE(root->property("test1_2").toBool(), true);
|
|
QCOMPARE(root->property("test1_3").toBool(), true);
|
|
QCOMPARE(root->property("test1_4").toBool(), true);
|
|
|
|
QMetaObject::invokeMethod(root, "hideFirstAndLastRowChild");
|
|
QCOMPARE(root->property("test2_1").toBool(), true);
|
|
QCOMPARE(root->property("test2_2").toBool(), true);
|
|
QCOMPARE(root->property("test2_3").toBool(), true);
|
|
QCOMPARE(root->property("test2_4").toBool(), true);
|
|
|
|
QMetaObject::invokeMethod(root, "showLastRowChildsLastChild");
|
|
QCOMPARE(root->property("test3_1").toBool(), true);
|
|
QCOMPARE(root->property("test3_2").toBool(), true);
|
|
QCOMPARE(root->property("test3_3").toBool(), true);
|
|
QCOMPARE(root->property("test3_4").toBool(), true);
|
|
|
|
QMetaObject::invokeMethod(root, "showLastRowChild");
|
|
QCOMPARE(root->property("test4_1").toBool(), true);
|
|
QCOMPARE(root->property("test4_2").toBool(), true);
|
|
QCOMPARE(root->property("test4_3").toBool(), true);
|
|
QCOMPARE(root->property("test4_4").toBool(), true);
|
|
|
|
QString warning1 = testFileUrl("visiblechildren.qml").toString() + ":87: TypeError: Cannot read property 'visibleChildren' of null";
|
|
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
|
|
QMetaObject::invokeMethod(root, "tryWriteToReadonlyVisibleChildren");
|
|
|
|
QMetaObject::invokeMethod(root, "reparentVisibleItem3");
|
|
QCOMPARE(root->property("test6_1").toBool(), true);
|
|
QCOMPARE(root->property("test6_2").toBool(), true);
|
|
QCOMPARE(root->property("test6_3").toBool(), true);
|
|
QCOMPARE(root->property("test6_4").toBool(), true);
|
|
|
|
QMetaObject::invokeMethod(root, "reparentImlicitlyInvisibleItem4_1");
|
|
QCOMPARE(root->property("test7_1").toBool(), true);
|
|
QCOMPARE(root->property("test7_2").toBool(), true);
|
|
QCOMPARE(root->property("test7_3").toBool(), true);
|
|
QCOMPARE(root->property("test7_4").toBool(), true);
|
|
|
|
// FINALLY TEST THAT EVERYTHING IS AS EXPECTED
|
|
QCOMPARE(root->property("test8_1").toBool(), true);
|
|
QCOMPARE(root->property("test8_2").toBool(), true);
|
|
QCOMPARE(root->property("test8_3").toBool(), true);
|
|
QCOMPARE(root->property("test8_4").toBool(), true);
|
|
QCOMPARE(root->property("test8_5").toBool(), true);
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::parentLoop()
|
|
{
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
|
|
#if QT_CONFIG(regularexpression)
|
|
QRegularExpression msgRegexp = QRegularExpression("QQuickItem::setParentItem: Parent QQuickItem\\(.*\\) is already part of the subtree of QQuickItem\\(.*\\)");
|
|
QTest::ignoreMessage(QtWarningMsg, msgRegexp);
|
|
#endif
|
|
window->setSource(testFileUrl("parentLoop.qml"));
|
|
|
|
QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject());
|
|
QVERIFY(root);
|
|
|
|
QQuickItem *item1 = root->findChild<QQuickItem*>("item1");
|
|
QVERIFY(item1);
|
|
QCOMPARE(item1->parentItem(), root);
|
|
|
|
QQuickItem *item2 = root->findChild<QQuickItem*>("item2");
|
|
QVERIFY(item2);
|
|
QCOMPARE(item2->parentItem(), item1);
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::contains_data()
|
|
{
|
|
QTest::addColumn<bool>("circleTest");
|
|
QTest::addColumn<bool>("insideTarget");
|
|
QTest::addColumn<QList<QPoint> >("points");
|
|
|
|
QList<QPoint> points;
|
|
|
|
points << QPoint(176, 176)
|
|
<< QPoint(176, 226)
|
|
<< QPoint(226, 176)
|
|
<< QPoint(226, 226)
|
|
<< QPoint(150, 200)
|
|
<< QPoint(200, 150)
|
|
<< QPoint(200, 250)
|
|
<< QPoint(250, 200);
|
|
QTest::newRow("hollow square: testing points inside") << false << true << points;
|
|
|
|
points.clear();
|
|
points << QPoint(162, 162)
|
|
<< QPoint(162, 242)
|
|
<< QPoint(242, 162)
|
|
<< QPoint(242, 242)
|
|
<< QPoint(200, 200)
|
|
<< QPoint(175, 200)
|
|
<< QPoint(200, 175)
|
|
<< QPoint(200, 228)
|
|
<< QPoint(228, 200)
|
|
<< QPoint(200, 122)
|
|
<< QPoint(122, 200)
|
|
<< QPoint(200, 280)
|
|
<< QPoint(280, 200);
|
|
QTest::newRow("hollow square: testing points outside") << false << false << points;
|
|
|
|
points.clear();
|
|
points << QPoint(174, 174)
|
|
<< QPoint(174, 225)
|
|
<< QPoint(225, 174)
|
|
<< QPoint(225, 225)
|
|
<< QPoint(165, 200)
|
|
<< QPoint(200, 165)
|
|
<< QPoint(200, 235)
|
|
<< QPoint(235, 200);
|
|
QTest::newRow("hollow circle: testing points inside") << true << true << points;
|
|
|
|
points.clear();
|
|
points << QPoint(160, 160)
|
|
<< QPoint(160, 240)
|
|
<< QPoint(240, 160)
|
|
<< QPoint(240, 240)
|
|
<< QPoint(200, 200)
|
|
<< QPoint(185, 185)
|
|
<< QPoint(185, 216)
|
|
<< QPoint(216, 185)
|
|
<< QPoint(216, 216)
|
|
<< QPoint(145, 200)
|
|
<< QPoint(200, 145)
|
|
<< QPoint(255, 200)
|
|
<< QPoint(200, 255);
|
|
QTest::newRow("hollow circle: testing points outside") << true << false << points;
|
|
}
|
|
|
|
void tst_QQuickItem::contains()
|
|
{
|
|
QFETCH(bool, circleTest);
|
|
QFETCH(bool, insideTarget);
|
|
QFETCH(QList<QPoint>, points);
|
|
|
|
QQuickView *window = new QQuickView(nullptr);
|
|
window->rootContext()->setContextProperty("circleShapeTest", circleTest);
|
|
window->setBaseSize(QSize(400, 400));
|
|
window->setSource(testFileUrl("hollowTestItem.qml"));
|
|
window->show();
|
|
window->requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
QCOMPARE(QGuiApplication::focusWindow(), window);
|
|
|
|
QQuickItem *root = qobject_cast<QQuickItem *>(window->rootObject());
|
|
QVERIFY(root);
|
|
|
|
HollowTestItem *hollowItem = root->findChild<HollowTestItem *>("hollowItem");
|
|
QVERIFY(hollowItem);
|
|
|
|
foreach (const QPoint &point, points) {
|
|
// check mouse hover
|
|
QTest::mouseMove(window, point);
|
|
QTRY_COMPARE(hollowItem->isHovered(), insideTarget);
|
|
|
|
// check mouse press
|
|
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, point);
|
|
QTRY_COMPARE(hollowItem->isPressed(), insideTarget);
|
|
|
|
// check mouse release
|
|
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, point);
|
|
QTRY_COMPARE(hollowItem->isPressed(), false);
|
|
}
|
|
|
|
delete window;
|
|
}
|
|
|
|
void tst_QQuickItem::childAt()
|
|
{
|
|
QQuickItem parent;
|
|
|
|
QQuickItem child1;
|
|
child1.setX(0);
|
|
child1.setY(0);
|
|
child1.setWidth(100);
|
|
child1.setHeight(100);
|
|
child1.setParentItem(&parent);
|
|
|
|
QQuickItem child2;
|
|
child2.setX(50);
|
|
child2.setY(50);
|
|
child2.setWidth(100);
|
|
child2.setHeight(100);
|
|
child2.setParentItem(&parent);
|
|
|
|
QQuickItem child3;
|
|
child3.setX(0);
|
|
child3.setY(200);
|
|
child3.setWidth(50);
|
|
child3.setHeight(50);
|
|
child3.setParentItem(&parent);
|
|
|
|
QCOMPARE(parent.childAt(0, 0), &child1);
|
|
QCOMPARE(parent.childAt(0, 99), &child1);
|
|
QCOMPARE(parent.childAt(25, 25), &child1);
|
|
QCOMPARE(parent.childAt(25, 75), &child1);
|
|
QCOMPARE(parent.childAt(75, 25), &child1);
|
|
QCOMPARE(parent.childAt(75, 75), &child2);
|
|
QCOMPARE(parent.childAt(149, 149), &child2);
|
|
QCOMPARE(parent.childAt(25, 200), &child3);
|
|
QCOMPARE(parent.childAt(0, 150), static_cast<QQuickItem *>(nullptr));
|
|
QCOMPARE(parent.childAt(300, 300), static_cast<QQuickItem *>(nullptr));
|
|
}
|
|
|
|
void tst_QQuickItem::grab()
|
|
{
|
|
if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
|
|
|| (QGuiApplication::platformName() == QLatin1String("minimal")))
|
|
QSKIP("Skipping due to grabToImage not functional on offscreen/minimal platforms");
|
|
|
|
QQuickView view;
|
|
view.setSource(testFileUrl("grabToImage.qml"));
|
|
view.show();
|
|
QVERIFY(QTest::qWaitForWindowExposed(&view));
|
|
|
|
QQuickItem *root = qobject_cast<QQuickItem *>(view.rootObject());
|
|
QVERIFY(root);
|
|
QQuickItem *item = root->findChild<QQuickItem *>("myItem");
|
|
QVERIFY(item);
|
|
#if QT_CONFIG(opengl)
|
|
{ // Default size (item is 100x100)
|
|
QSharedPointer<QQuickItemGrabResult> result = item->grabToImage();
|
|
QSignalSpy spy(result.data(), SIGNAL(ready()));
|
|
QTRY_VERIFY(spy.size() > 0);
|
|
QVERIFY(!result->url().isEmpty());
|
|
QImage image = result->image();
|
|
QCOMPARE(image.pixel(0, 0), qRgb(255, 0, 0));
|
|
QCOMPARE(image.pixel(99, 99), qRgb(0, 0, 255));
|
|
}
|
|
|
|
{ // Smaller size
|
|
QSharedPointer<QQuickItemGrabResult> result = item->grabToImage(QSize(50, 50));
|
|
QVERIFY(!result.isNull());
|
|
QSignalSpy spy(result.data(), SIGNAL(ready()));
|
|
QTRY_VERIFY(spy.size() > 0);
|
|
QVERIFY(!result->url().isEmpty());
|
|
QImage image = result->image();
|
|
QCOMPARE(image.pixel(0, 0), qRgb(255, 0, 0));
|
|
QCOMPARE(image.pixel(49, 49), qRgb(0, 0, 255));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void tst_QQuickItem::isAncestorOf()
|
|
{
|
|
QQuickItem parent;
|
|
|
|
QQuickItem sub1;
|
|
sub1.setParentItem(&parent);
|
|
|
|
QQuickItem child1;
|
|
child1.setParentItem(&sub1);
|
|
QQuickItem child2;
|
|
child2.setParentItem(&sub1);
|
|
|
|
QQuickItem sub2;
|
|
sub2.setParentItem(&parent);
|
|
|
|
QQuickItem child3;
|
|
child3.setParentItem(&sub2);
|
|
QQuickItem child4;
|
|
child4.setParentItem(&sub2);
|
|
|
|
QVERIFY(parent.isAncestorOf(&sub1));
|
|
QVERIFY(parent.isAncestorOf(&sub2));
|
|
QVERIFY(parent.isAncestorOf(&child1));
|
|
QVERIFY(parent.isAncestorOf(&child2));
|
|
QVERIFY(parent.isAncestorOf(&child3));
|
|
QVERIFY(parent.isAncestorOf(&child4));
|
|
QVERIFY(sub1.isAncestorOf(&child1));
|
|
QVERIFY(sub1.isAncestorOf(&child2));
|
|
QVERIFY(!sub1.isAncestorOf(&child3));
|
|
QVERIFY(!sub1.isAncestorOf(&child4));
|
|
QVERIFY(sub2.isAncestorOf(&child3));
|
|
QVERIFY(sub2.isAncestorOf(&child4));
|
|
QVERIFY(!sub2.isAncestorOf(&child1));
|
|
QVERIFY(!sub2.isAncestorOf(&child2));
|
|
QVERIFY(!sub1.isAncestorOf(&sub1));
|
|
QVERIFY(!sub2.isAncestorOf(&sub2));
|
|
}
|
|
|
|
/*
|
|
Verify that a nested item's palette responds to changes of the enabled state
|
|
and of the window's activation state by switching the current color group.
|
|
*/
|
|
void tst_QQuickItem::colorGroup()
|
|
{
|
|
QQuickView view;
|
|
|
|
view.setSource(testFileUrl("colorgroup.qml"));
|
|
view.show();
|
|
QVERIFY(QTest::qWaitForWindowExposed(&view));
|
|
|
|
QQuickItem *root = qobject_cast<QQuickItem *>(view.rootObject());
|
|
QQuickItem *background = root->findChild<QQuickItem *>("background");
|
|
QVERIFY(background);
|
|
QQuickItem *foreground = root->findChild<QQuickItem *>("foreground");
|
|
QVERIFY(foreground);
|
|
|
|
QQuickPalette *palette = foreground->property("palette").value<QQuickPalette*>();
|
|
QVERIFY(palette);
|
|
view.show();
|
|
QVERIFY(QTest::qWaitForWindowActive(&view));
|
|
|
|
QCOMPARE(palette->currentColorGroup(), QPalette::Active);
|
|
QCOMPARE(foreground->property("color").value<QColor>(), palette->active()->base());
|
|
|
|
background->setEnabled(false);
|
|
QCOMPARE(palette->currentColorGroup(), QPalette::Disabled);
|
|
QCOMPARE(foreground->property("color").value<QColor>(), palette->disabled()->base());
|
|
|
|
QWindow activationThief;
|
|
activationThief.show();
|
|
activationThief.requestActivate();
|
|
QVERIFY(QTest::qWaitForWindowActive(&activationThief));
|
|
QCOMPARE(palette->currentColorGroup(), QPalette::Disabled);
|
|
QCOMPARE(foreground->property("color").value<QColor>(), palette->disabled()->base());
|
|
|
|
background->setEnabled(true);
|
|
QCOMPARE(palette->currentColorGroup(), QPalette::Inactive);
|
|
QCOMPARE(foreground->property("color").value<QColor>(), palette->inactive()->base());
|
|
}
|
|
|
|
QTEST_MAIN(tst_QQuickItem)
|
|
|
|
#include "tst_qquickitem.moc"
|