aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/quick/qquickitem2/tst_qquickitem.cpp')
-rw-r--r--tests/auto/quick/qquickitem2/tst_qquickitem.cpp1315
1 files changed, 1079 insertions, 236 deletions
diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
index 3170fb5918..267be73ec9 100644
--- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
@@ -1,30 +1,6 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
#include <qtest.h>
#include <QtTest/QSignalSpy>
#include <QtQml/qqmlengine.h>
@@ -33,16 +9,29 @@
#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 <QtQuick/private/qquickanchors_p.h>
#include <QtGui/qstylehints.h>
#include <private/qquickitem_p.h>
-#include "../../shared/util.h"
-#include "../shared/visualtestutil.h"
-#include "../../shared/platforminputcontext.h"
+#include <QtQuickTest/QtQuickTest>
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/platforminputcontext_p.h>
+#include <QtTest/private/qpropertytesthelper_p.h>
+#ifdef QT_WIDGETS_LIB
+#include <QtWidgets/qwidget.h>
+#include <QtWidgets/qboxlayout.h>
+#include <QtWidgets/qlineedit.h>
+#endif
+
+using namespace QQuickVisualTestUtils;
-using namespace QQuickVisualTestUtil;
+Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
class tst_QQuickItem : public QQmlDataTest
{
@@ -66,6 +55,7 @@ private slots:
void activeFocusOnTab10();
void activeFocusOnTab_infiniteLoop_data();
void activeFocusOnTab_infiniteLoop();
+ void activeFocusOnTab_infiniteLoopControls();
void nextItemInFocusChain();
void nextItemInFocusChain2();
@@ -75,6 +65,7 @@ private slots:
void qtbug_50516();
void qtbug_50516_2_data();
void qtbug_50516_2();
+ void focusableItemReparentedToLoadedComponent();
void keys();
#if QT_CONFIG(shortcut)
@@ -103,6 +94,7 @@ private slots:
void mapCoordinates_data();
void mapCoordinatesRect();
void mapCoordinatesRect_data();
+ void mapCoordinatesWithWindows();
void propertyChanges();
void nonexistentPropertyConnection();
void transforms();
@@ -115,6 +107,8 @@ private slots:
void childrenProperty();
void resourcesProperty();
+ void bindableProperties_data();
+ void bindableProperties();
void changeListener();
void transformCrash();
@@ -129,6 +123,26 @@ private slots:
void grab();
+ void colorGroup();
+ void paletteAllocated();
+
+ void undefinedIsInvalidForWidthAndHeight();
+
+ void viewport_data();
+ void viewport();
+
+ void qobject_castOnDestruction();
+ void signalsOnDestruction_data();
+ void signalsOnDestruction();
+ void visibleChanged();
+
+ void lastFocusChangeReason();
+ void focusInScopeChanges();
+
+#ifdef QT_WIDGETS_LIB
+ void embeddedInWidgetsFocus();
+#endif
+
private:
QQmlEngine engine;
bool qt_tab_all_widgets() {
@@ -202,7 +216,7 @@ public:
KeyTestItem(QQuickItem *parent=nullptr) : QQuickItem(parent), mKey(0) {}
protected:
- void keyPressEvent(QKeyEvent *e) {
+ void keyPressEvent(QKeyEvent *e) override {
mKey = e->key();
if (e->key() == Qt::Key_A)
@@ -211,7 +225,7 @@ protected:
e->ignore();
}
- void keyReleaseEvent(QKeyEvent *e) {
+ void keyReleaseEvent(QKeyEvent *e) override {
if (e->key() == Qt::Key_B)
e->accept();
else
@@ -225,7 +239,7 @@ public:
class FocusEventFilter : public QObject
{
protected:
- bool eventFilter(QObject *watched, QEvent *event) {
+ 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();
@@ -242,8 +256,8 @@ 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)
+ Q_PROPERTY(bool circle READ isCircle WRITE setCircle NOTIFY circleChanged)
+ Q_PROPERTY(qreal holeRadius READ holeRadius WRITE setHoleRadius NOTIFY holeRadiusChanged)
public:
HollowTestItem(QQuickItem *parent = nullptr)
@@ -261,12 +275,12 @@ public:
bool isHovered() const { return m_isHovered; }
bool isCircle() const { return m_isCircle; }
- void setCircle(bool circle) { m_isCircle = circle; }
+ void setCircle(bool circle) { m_isCircle = circle; emit circleChanged(); }
qreal holeRadius() const { return m_holeRadius; }
- void setHoleRadius(qreal radius) { m_holeRadius = radius; }
+ void setHoleRadius(qreal radius) { m_holeRadius = radius; emit holeRadiusChanged(); }
- bool contains(const QPointF &point) const {
+ bool contains(const QPointF &point) const override {
const qreal w = width();
const qreal h = height();
const qreal r = m_holeRadius;
@@ -287,11 +301,15 @@ public:
return dd > (r * r) && dd <= outerRadius * outerRadius;
}
+signals:
+ void circleChanged();
+ void holeRadiusChanged();
+
protected:
- void hoverEnterEvent(QHoverEvent *) { m_isHovered = true; }
- void hoverLeaveEvent(QHoverEvent *) { m_isHovered = false; }
- void mousePressEvent(QMouseEvent *) { m_isPressed = true; }
- void mouseReleaseEvent(QMouseEvent *) { m_isPressed = false; }
+ 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;
@@ -302,6 +320,22 @@ private:
QML_DECLARE_TYPE(HollowTestItem);
+class ViewportTestItem : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QRectF viewport READ viewport NOTIFY viewportChanged)
+
+public:
+ ViewportTestItem(QQuickItem *parent = nullptr) : QQuickItem(parent) { }
+
+ QRectF viewport() const { return clipRect(); }
+
+signals:
+ void viewportChanged();
+};
+
+QML_DECLARE_TYPE(ViewportTestItem);
+
class TabFenceItem : public QQuickItem
{
Q_OBJECT
@@ -334,6 +368,7 @@ public:
QML_DECLARE_TYPE(TabFenceItem2);
tst_QQuickItem::tst_QQuickItem()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
}
@@ -342,6 +377,7 @@ void tst_QQuickItem::initTestCase()
QQmlDataTest::initTestCase();
qmlRegisterType<KeyTestItem>("Test",1,0,"KeyTestItem");
qmlRegisterType<HollowTestItem>("Test", 1, 0, "HollowTestItem");
+ qmlRegisterType<ViewportTestItem>("Test", 1, 0, "ViewportTestItem");
qmlRegisterType<TabFenceItem>("Test", 1, 0, "TabFence");
qmlRegisterType<TabFenceItem2>("Test", 1, 0, "TabFence2");
}
@@ -1143,6 +1179,17 @@ void tst_QQuickItem::activeFocusOnTab_infiniteLoop()
QCOMPARE(item, window->rootObject());
}
+
+void tst_QQuickItem::activeFocusOnTab_infiniteLoopControls()
+{
+ auto source = testFileUrl("activeFocusOnTab_infiniteLoop3.qml");
+ QScopedPointer<QQuickView>window(new QQuickView());
+ window->setSource(source);
+ window->show();
+ QVERIFY(window->errors().isEmpty());
+ QTest::keyClick(window.get(), Qt::Key_Tab); // should not hang
+}
+
void tst_QQuickItem::nextItemInFocusChain()
{
if (!qt_tab_all_widgets())
@@ -1284,14 +1331,13 @@ void verifyTabFocusChain(QQuickView *window, const char **focusChain, bool forwa
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);
+ QVERIFY2(key.isAccepted(), qPrintable(descrStr));
QQuickItem *item = findItem<QQuickItem>(window->rootObject(), *objectName);
- QVERIFY2(item, descr);
- QVERIFY2(item->hasActiveFocus(), descr);
+ QVERIFY2(item, qPrintable(descrStr));
+ QVERIFY2(item->hasActiveFocus(), qPrintable(descrStr));
}
}
@@ -1400,6 +1446,35 @@ void tst_QQuickItem::qtbug_50516_2()
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);
@@ -1813,90 +1888,90 @@ void tst_QQuickItem::layoutMirroring()
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);
+ QVERIFY(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "mirrored2")->effectiveLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "notMirrored2")->effectiveLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror);
+
+ QVERIFY(anchorsMirrored(rootItem, "mirrored1"));
+ QVERIFY(anchorsMirrored(rootItem, "mirrored2"));
+ QVERIFY(!anchorsMirrored(rootItem, "notMirrored1"));
+ QVERIFY(!anchorsMirrored(rootItem, "notMirrored2"));
+ QVERIFY(anchorsMirrored(rootItem, "inheritedMirror1"));
+ QVERIFY(anchorsMirrored(rootItem, "inheritedMirror2"));
+
+ QVERIFY(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "mirrored2")->inheritedLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "notMirrored2")->inheritedLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror);
+
+ QVERIFY(!childPrivate(rootItem, "mirrored1")->isMirrorImplicit);
+ QVERIFY(!childPrivate(rootItem, "mirrored2")->isMirrorImplicit);
+ QVERIFY(!childPrivate(rootItem, "notMirrored1")->isMirrorImplicit);
+ QVERIFY(childPrivate(rootItem, "notMirrored2")->isMirrorImplicit);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror1")->isMirrorImplicit);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror2")->isMirrorImplicit);
+
+ QVERIFY(childPrivate(rootItem, "mirrored1")->inheritMirrorFromParent);
+ QVERIFY(!childPrivate(rootItem, "mirrored2")->inheritMirrorFromParent);
+ QVERIFY(childPrivate(rootItem, "notMirrored1")->inheritMirrorFromParent);
+ QVERIFY(!childPrivate(rootItem, "notMirrored2")->inheritMirrorFromParent);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror1")->inheritMirrorFromParent);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror2")->inheritMirrorFromParent);
+
+ QVERIFY(childPrivate(rootItem, "mirrored1")->inheritMirrorFromItem);
+ QVERIFY(!childPrivate(rootItem, "mirrored2")->inheritMirrorFromItem);
+ QVERIFY(!childPrivate(rootItem, "notMirrored1")->inheritMirrorFromItem);
+ QVERIFY(!childPrivate(rootItem, "notMirrored2")->inheritMirrorFromItem);
+ QVERIFY(!childPrivate(rootItem, "inheritedMirror1")->inheritMirrorFromItem);
+ QVERIFY(!childPrivate(rootItem, "inheritedMirror2")->inheritMirrorFromItem);
// 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);
+ QVERIFY(!childPrivate(rootItem, "notMirrored3")->effectiveLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror3")->effectiveLayoutMirror);
- QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritedLayoutMirror, true);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->inheritedLayoutMirror, true);
+ QVERIFY(childPrivate(rootItem, "notMirrored3")->inheritedLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror3")->inheritedLayoutMirror);
- QCOMPARE(childPrivate(rootItem, "notMirrored3")->isMirrorImplicit, false);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->isMirrorImplicit, true);
+ QVERIFY(!childPrivate(rootItem, "notMirrored3")->isMirrorImplicit);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror3")->isMirrorImplicit);
- QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromParent, true);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->inheritMirrorFromParent, true);
+ QVERIFY(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromParent);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror3")->inheritMirrorFromParent);
- QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromItem, false);
- QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromItem, false);
+ QVERIFY(!childPrivate(rootItem, "notMirrored3")->inheritMirrorFromItem);
+ QVERIFY(!childPrivate(rootItem, "notMirrored3")->inheritMirrorFromItem);
// 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);
+ QVERIFY(!childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror, false);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror, false);
- QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror, false);
- QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror, false);
+ QVERIFY(!childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror);
// 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);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror, true);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror, true);
- QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror, true);
- QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror, true);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror);
//
// dynamic parenting
@@ -1909,24 +1984,24 @@ void tst_QQuickItem::layoutMirroring()
// inherit in constructor
QQuickItem *childItem1 = new QQuickItem(parentItem1);
- QCOMPARE(QQuickItemPrivate::get(childItem1)->effectiveLayoutMirror, true);
- QCOMPARE(QQuickItemPrivate::get(childItem1)->inheritMirrorFromParent, true);
+ QVERIFY(QQuickItemPrivate::get(childItem1)->effectiveLayoutMirror);
+ QVERIFY(QQuickItemPrivate::get(childItem1)->inheritMirrorFromParent);
// inherit through a parent change
QQuickItem *childItem2 = new QQuickItem();
- QCOMPARE(QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror, false);
- QCOMPARE(QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent, false);
+ QVERIFY(!QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror);
+ QVERIFY(!QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent);
childItem2->setParentItem(parentItem1);
- QCOMPARE(QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror, true);
- QCOMPARE(QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent, true);
+ QVERIFY(QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror);
+ QVERIFY(QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent);
// 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);
+ QVERIFY(!QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror);
+ QVERIFY(!QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent);
delete parentItem1;
delete parentItem2;
@@ -1942,11 +2017,11 @@ void tst_QQuickItem::layoutMirroringWindow()
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);
+ QVERIFY(content->effectiveLayoutMirror);
+ QVERIFY(content->inheritedLayoutMirror);
+ QVERIFY(!content->isMirrorImplicit);
+ QVERIFY(content->inheritMirrorFromParent);
+ QVERIFY(content->inheritMirrorFromItem);
}
void tst_QQuickItem::layoutMirroringIllegalParent()
@@ -2491,19 +2566,19 @@ void tst_QQuickItem::smooth()
item->setSmooth(true);
QVERIFY(item->smooth());
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
QList<QVariant> arguments = spy.first();
- QCOMPARE(arguments.count(), 1);
+ QCOMPARE(arguments.size(), 1);
QVERIFY(arguments.at(0).toBool());
item->setSmooth(true);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
item->setSmooth(false);
QVERIFY(!item->smooth());
- QCOMPARE(spy.count(),2);
+ QCOMPARE(spy.size(),2);
item->setSmooth(false);
- QCOMPARE(spy.count(),2);
+ QCOMPARE(spy.size(),2);
delete item;
}
@@ -2520,19 +2595,19 @@ void tst_QQuickItem::antialiasing()
item->setAntialiasing(true);
QVERIFY(item->antialiasing());
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
QList<QVariant> arguments = spy.first();
- QCOMPARE(arguments.count(), 1);
+ QCOMPARE(arguments.size(), 1);
QVERIFY(arguments.at(0).toBool());
item->setAntialiasing(true);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
item->setAntialiasing(false);
QVERIFY(!item->antialiasing());
- QCOMPARE(spy.count(),2);
+ QCOMPARE(spy.size(),2);
item->setAntialiasing(false);
- QCOMPARE(spy.count(),2);
+ QCOMPARE(spy.size(),2);
delete item;
}
@@ -2551,18 +2626,18 @@ void tst_QQuickItem::clip()
QVERIFY(item->clip());
QList<QVariant> arguments = spy.first();
- QCOMPARE(arguments.count(), 1);
+ QCOMPARE(arguments.size(), 1);
QVERIFY(arguments.at(0).toBool());
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
item->setClip(true);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
item->setClip(false);
QVERIFY(!item->clip());
- QCOMPARE(spy.count(),2);
+ QCOMPARE(spy.size(),2);
item->setClip(false);
- QCOMPARE(spy.count(),2);
+ QCOMPARE(spy.size(),2);
delete item;
}
@@ -2637,15 +2712,17 @@ void tst_QQuickItem::mapCoordinates()
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";
+ QRegularExpression warning1 = QRegularExpression(".*Could not convert argument 0 at.*");
+ QRegularExpression warning2 = QRegularExpression(".*checkMapA.*Invalid@.*");
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
+ QTest::ignoreMessage(QtWarningMsg, warning1);
+ QTest::ignoreMessage(QtWarningMsg, warning2);
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));
+ QTest::ignoreMessage(QtWarningMsg, warning1);
+ QTest::ignoreMessage(QtWarningMsg, warning2);
QVERIFY(QMetaObject::invokeMethod(root, "checkMapAFromInvalid",
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
QVERIFY(result.toBool());
@@ -2669,7 +2746,7 @@ void tst_QQuickItem::mapCoordinatesRect()
QFETCH(int, width);
QFETCH(int, height);
- QQuickView *window = new QQuickView(nullptr);
+ std::unique_ptr<QQuickView> window = std::make_unique<QQuickView>();
window->setBaseSize(QSize(300, 300));
window->setSource(testFileUrl("mapCoordinatesRect.qml"));
window->show();
@@ -2708,20 +2785,20 @@ void tst_QQuickItem::mapCoordinatesRect()
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";
+ QRegularExpression warning1 = QRegularExpression(".*Could not convert argument 0 at.*");
+ QRegularExpression warning2 = QRegularExpression(".*checkMapA.*Invalid@.*");
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
+ QTest::ignoreMessage(QtWarningMsg, warning1);
+ QTest::ignoreMessage(QtWarningMsg, warning2);
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));
+ QTest::ignoreMessage(QtWarningMsg, warning1);
+ QTest::ignoreMessage(QtWarningMsg, 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()
@@ -2735,6 +2812,76 @@ void tst_QQuickItem::mapCoordinatesRect_data()
QTest::newRow(QTest::toString(i)) << i << i << i << i;
}
+void tst_QQuickItem::mapCoordinatesWithWindows()
+{
+ QQmlComponent component(&engine, testFileUrl("mapCoordinatesWithWindows.qml"));
+ std::unique_ptr<QObject> root(component.create());
+ QVERIFY(root);
+
+ auto *windowA = root->property("windowA").value<QQuickWindow*>();
+ QVERIFY(windowA);
+
+ // The window container geometry, parenting, etc, is applied
+ // during polish, so to test these we need to wait for one.
+ QVERIFY(QQuickTest::qWaitForPolish(windowA));
+
+ auto *childItem = windowA->findChild<QQuickItem*>("childItem");
+ QVERIFY(childItem);
+
+ QPoint itemPos = childItem->position().toPoint();
+ QCOMPARE(childItem->mapToScene({0, 0}), itemPos);
+ QCOMPARE(childItem->mapToGlobal({0, 0}), windowA->position() + itemPos);
+
+ auto *childItemInChildWindow = windowA->findChild<QQuickItem*>("childItemInChildWindow");
+ QVERIFY(childItemInChildWindow);
+
+ QPoint windowItemPos = childItemInChildWindow->position().toPoint();
+ QCOMPARE(childItemInChildWindow->mapToScene({0, 0}), windowItemPos);
+ QCOMPARE(childItemInChildWindow->mapToGlobal({0, 0}), windowA->position()
+ + childItemInChildWindow->window()->position() + windowItemPos);
+
+ QCOMPARE(childItemInChildWindow->mapToItem(nullptr, {0, 0}), windowItemPos);
+
+ auto globalItemOffset = [](QQuickItem *a, QQuickItem *b) {
+ return a->mapToGlobal({0, 0}) - b->mapToGlobal({0, 0});
+ };
+
+ QCOMPARE(childItemInChildWindow->mapToItem(childItem, {0, 0}),
+ globalItemOffset(childItemInChildWindow, childItem));
+ QCOMPARE(childItemInChildWindow->mapFromItem(childItem, {0, 0}),
+ globalItemOffset(childItem, childItemInChildWindow));
+
+ QCOMPARE(childItem->mapToItem(childItemInChildWindow, {0, 0}),
+ globalItemOffset(childItem, childItemInChildWindow));
+ QCOMPARE(childItem->mapFromItem(childItemInChildWindow, {0, 0}),
+ globalItemOffset(childItemInChildWindow, childItem));
+
+ auto *windowB = root->property("windowB").value<QQuickWindow*>();
+ QVERIFY(windowA);
+ auto *childItemInOtherWindow = windowB->findChild<QQuickItem*>("childItem");
+ QVERIFY(childItemInOtherWindow);
+
+ QCOMPARE(childItemInOtherWindow->mapToItem(childItem, {0, 0}),
+ globalItemOffset(childItemInOtherWindow, childItem));
+ QCOMPARE(childItemInOtherWindow->mapFromItem(childItem, {0, 0}),
+ globalItemOffset(childItem, childItemInOtherWindow));
+
+ QCOMPARE(childItem->mapToItem(childItemInOtherWindow, {0, 0}),
+ globalItemOffset(childItem, childItemInOtherWindow));
+ QCOMPARE(childItem->mapFromItem(childItemInOtherWindow, {0, 0}),
+ globalItemOffset(childItemInOtherWindow, childItem));
+
+ QCOMPARE(childItemInOtherWindow->mapToItem(childItemInChildWindow, {0, 0}),
+ globalItemOffset(childItemInOtherWindow, childItemInChildWindow));
+ QCOMPARE(childItemInOtherWindow->mapFromItem(childItemInChildWindow, {0, 0}),
+ globalItemOffset(childItemInChildWindow, childItemInOtherWindow));
+
+ QCOMPARE(childItemInChildWindow->mapToItem(childItemInOtherWindow, {0, 0}),
+ globalItemOffset(childItemInChildWindow, childItemInOtherWindow));
+ QCOMPARE(childItemInChildWindow->mapFromItem(childItemInOtherWindow, {0, 0}),
+ globalItemOffset(childItemInOtherWindow, childItemInChildWindow));
+}
+
void tst_QQuickItem::transforms_data()
{
QTest::addColumn<QByteArray>("qml");
@@ -2812,6 +2959,30 @@ void tst_QQuickItem::resourcesProperty()
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);
@@ -2846,50 +3017,50 @@ void tst_QQuickItem::propertyChanges()
item->setBaselineOffset(10.0);
QCOMPARE(item->parentItem(), parentItem);
- QCOMPARE(parentSpy.count(),1);
+ QCOMPARE(parentSpy.size(),1);
QList<QVariant> parentArguments = parentSpy.first();
- QCOMPARE(parentArguments.count(), 1);
+ QCOMPARE(parentArguments.size(), 1);
QCOMPARE(item->parentItem(), qvariant_cast<QQuickItem *>(parentArguments.at(0)));
- QCOMPARE(childrenChangedSpy.count(),1);
+ QCOMPARE(childrenChangedSpy.size(),1);
item->setParentItem(parentItem);
- QCOMPARE(childrenChangedSpy.count(),1);
+ QCOMPARE(childrenChangedSpy.size(),1);
QCOMPARE(item->width(), 100.0);
- QCOMPARE(widthSpy.count(),1);
+ QCOMPARE(widthSpy.size(),1);
QCOMPARE(item->height(), 200.0);
- QCOMPARE(heightSpy.count(),1);
+ QCOMPARE(heightSpy.size(),1);
QCOMPARE(item->baselineOffset(), 10.0);
- QCOMPARE(baselineOffsetSpy.count(),1);
+ QCOMPARE(baselineOffsetSpy.size(),1);
QList<QVariant> baselineOffsetArguments = baselineOffsetSpy.first();
- QCOMPARE(baselineOffsetArguments.count(), 1);
+ QCOMPARE(baselineOffsetArguments.size(), 1);
QCOMPARE(item->baselineOffset(), baselineOffsetArguments.at(0).toReal());
QCOMPARE(parentItem->childrenRect(), QRectF(0.0,0.0,100.0,200.0));
- QCOMPARE(childrenRectSpy.count(),1);
+ QCOMPARE(childrenRectSpy.size(),1);
QList<QVariant> childrenRectArguments = childrenRectSpy.at(0);
- QCOMPARE(childrenRectArguments.count(), 1);
+ QCOMPARE(childrenRectArguments.size(), 1);
QCOMPARE(parentItem->childrenRect(), childrenRectArguments.at(0).toRectF());
QCOMPARE(item->hasActiveFocus(), true);
- QCOMPARE(focusSpy.count(),1);
+ QCOMPARE(focusSpy.size(),1);
QList<QVariant> focusArguments = focusSpy.first();
- QCOMPARE(focusArguments.count(), 1);
+ QCOMPARE(focusArguments.size(), 1);
QCOMPARE(focusArguments.at(0).toBool(), true);
QCOMPARE(parentItem->hasActiveFocus(), false);
QCOMPARE(parentItem->hasFocus(), false);
- QCOMPARE(wantsFocusSpy.count(),0);
+ QCOMPARE(wantsFocusSpy.size(),0);
item->setX(10.0);
QCOMPARE(item->x(), 10.0);
- QCOMPARE(xSpy.count(), 1);
+ QCOMPARE(xSpy.size(), 1);
item->setY(10.0);
QCOMPARE(item->y(), 10.0);
- QCOMPARE(ySpy.count(), 1);
+ QCOMPARE(ySpy.size(), 1);
delete window;
}
@@ -2936,7 +3107,7 @@ void tst_QQuickItem::childrenRectBug()
{
QQuickView *window = new QQuickView(nullptr);
- QString warning = testFileUrl("childrenRectBug.qml").toString() + ":7:5: QML Item: Binding loop detected for property \"height\"";
+ 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));
@@ -2957,11 +3128,11 @@ void tst_QQuickItem::childrenRectBug2()
{
QQuickView *window = new QQuickView(nullptr);
- QString warning1 = testFileUrl("childrenRectBug2.qml").toString() + ":7:5: QML Item: Binding loop detected for property \"width\"";
+ 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() + ":7:5: QML Item: Binding loop detected for property \"height\"";
+ 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));
@@ -3174,7 +3345,7 @@ void tst_QQuickItem::changeListener()
QCOMPARE(child2Listener.count(QQuickItemPrivate::Destroyed), 1);
QQuickItemPrivate::get(parent)->removeItemChangeListener(&parentListener, QQuickItemPrivate::Children);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0);
// QTBUG-54732: all listeners should get invoked even if they remove themselves while iterating the listeners
QList<TestListener *> listeners;
@@ -3182,93 +3353,93 @@ void tst_QQuickItem::changeListener()
listeners << new TestListener(true);
// itemVisibilityChanged x 5
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Visibility);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size());
parent->setVisible(false);
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::Visibility), 1);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0);
// itemRotationChanged x 5
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Rotation);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size());
parent->setRotation(90);
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::Rotation), 1);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0);
// itemOpacityChanged x 5
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Opacity);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size());
parent->setOpacity(0.5);
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::Opacity), 1);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0);
// itemChildAdded() x 5
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Children);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size());
child1 = new QQuickItem(parent);
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::Children), 1);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0);
// itemParentChanged() x 5
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(child1)->addItemChangeListener(listener, QQuickItemPrivate::Parent);
- QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.size(), listeners.size());
child1->setParentItem(nullptr);
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::Parent), 1);
- QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.size(), 0);
// itemImplicitWidthChanged() x 5
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::ImplicitWidth);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size());
parent->setImplicitWidth(parent->implicitWidth() + 1);
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::ImplicitWidth), 1);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0);
// itemImplicitHeightChanged() x 5
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::ImplicitHeight);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size());
parent->setImplicitHeight(parent->implicitHeight() + 1);
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::ImplicitHeight), 1);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0);
// itemGeometryChanged() x 5
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Geometry);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size());
parent->setWidth(parent->width() + 1);
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::Geometry), 1);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0);
// itemChildRemoved() x 5
child1->setParentItem(parent);
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Children);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size());
delete child1;
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::Children), 2);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0);
// itemDestroyed() x 5
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Destroyed);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size());
delete parent;
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::Destroyed), 1);
}
@@ -3512,39 +3683,35 @@ void tst_QQuickItem::contains()
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());
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("hollowTestItem.qml")));
+ QQuickItem *root = qobject_cast<QQuickItem *>(window.rootObject());
QVERIFY(root);
+ // Ensure that we don't get extra hover events delivered on the side.
+ QQuickWindowPrivate::get(&window)->deliveryAgentPrivate()->frameSynchronousHoverEnabled = false;
+ // Flush out any mouse events that might be queued up
+ qGuiApp->processEvents();
+
HollowTestItem *hollowItem = root->findChild<HollowTestItem *>("hollowItem");
QVERIFY(hollowItem);
+ hollowItem->setCircle(circleTest);
+
+ for (const QPoint &point : points) {
+ qCDebug(lcTests) << "hover and click @" << point;
- foreach (const QPoint &point, points) {
// check mouse hover
- QTest::mouseMove(window, point);
- QTest::qWait(10);
- QCOMPARE(hollowItem->isHovered(), insideTarget);
+ QTest::mouseMove(&window, point);
+ QTRY_COMPARE(hollowItem->isHovered(), insideTarget);
// check mouse press
- QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, point);
- QTest::qWait(10);
- QCOMPARE(hollowItem->isPressed(), insideTarget);
+ QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, point);
+ QTRY_COMPARE(hollowItem->isPressed(), insideTarget);
// check mouse release
- QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, point);
- QTest::qWait(10);
- QCOMPARE(hollowItem->isPressed(), false);
+ QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, point);
+ QTRY_COMPARE(hollowItem->isPressed(), false);
}
-
- delete window;
}
void tst_QQuickItem::childAt()
@@ -3586,9 +3753,8 @@ void tst_QQuickItem::childAt()
void tst_QQuickItem::grab()
{
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QSKIP("Skipping due to grabToImage not functional on offscreen/minimal platforms");
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabToImage not functional on minimal platforms");
QQuickView view;
view.setSource(testFileUrl("grabToImage.qml"));
@@ -3661,6 +3827,683 @@ void tst_QQuickItem::isAncestorOf()
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());
+
+ activationThief.hide();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+ QCOMPARE(palette->currentColorGroup(), QPalette::Active);
+ QCOMPARE(foreground->property("color").value<QColor>(), palette->active()->base());
+
+ activationThief.show();
+ activationThief.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&activationThief));
+ QCOMPARE(palette->currentColorGroup(), QPalette::Inactive);
+ QCOMPARE(foreground->property("color").value<QColor>(), palette->inactive()->base());
+}
+
+/*!
+ Verify that items don't allocate their own QQuickPalette instance
+ unnecessarily.
+*/
+void tst_QQuickItem::paletteAllocated()
+{
+ QQuickView view;
+
+ view.setSource(testFileUrl("paletteAllocate.qml"));
+
+ QQuickItem *root = qobject_cast<QQuickItem *>(view.rootObject());
+ QQuickItem *background = root->findChild<QQuickItem *>("background");
+ QVERIFY(background);
+ QQuickItem *foreground = root->findChild<QQuickItem *>("foreground");
+ QVERIFY(foreground);
+
+ bool backgroundHasPalette = false;
+ bool foregroundHasPalette = false;
+ QObject::connect(background, &QQuickItem::paletteCreated, this, [&]{ backgroundHasPalette = true; });
+ QObject::connect(foreground, &QQuickItem::paletteCreated, this, [&]{ foregroundHasPalette = true; });
+
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QVERIFY(!backgroundHasPalette);
+ QVERIFY(!foregroundHasPalette);
+
+ view.close();
+
+ QVERIFY(!backgroundHasPalette);
+ QVERIFY(!foregroundHasPalette);
+
+ auto quickpalette = foreground->property("palette").value<QQuickPalette*>();
+ QVERIFY(!backgroundHasPalette);
+ QVERIFY(quickpalette);
+ QVERIFY(foregroundHasPalette);
+}
+
+void tst_QQuickItem::undefinedIsInvalidForWidthAndHeight()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("undefinedInvalid.qml"));
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(root);
+ auto item = qobject_cast<QQuickItem *>(root.get());
+ auto priv = QQuickItemPrivate::get(item);
+ QVERIFY(item);
+ QCOMPARE(item->height(), 300);
+ QCOMPARE(item->width(), 200);
+ QVERIFY(!priv->widthValid());
+ QVERIFY(!priv->heightValid());
+}
+
+void tst_QQuickItem::viewport_data()
+{
+ QTest::addColumn<bool>("contentObservesViewport");
+
+ QTest::addColumn<bool>("innerClip");
+ QTest::addColumn<bool>("innerViewport");
+ QTest::addColumn<bool>("innerObservesViewport");
+
+ QTest::addColumn<bool>("outerClip");
+ QTest::addColumn<bool>("outerViewport");
+ QTest::addColumn<bool>("outerObservesViewport");
+
+ QTest::addColumn<QPoint>("innerViewportOffset");
+ QTest::addColumn<QPoint>("outerViewportOffset");
+
+ QTest::addColumn<QRect>("expectedViewportTestRect");
+ QTest::addColumn<QRect>("expectedContentClipRect");
+
+ QTest::newRow("default") << false
+ << false << false << false
+ << false << false << false
+ << QPoint() << QPoint() << QRect(0, 0, 290, 290) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp, clipping and observing") << true
+ << true << true << true
+ << true << true << true
+ << QPoint() << QPoint() << QRect(55, 55, 200, 200) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp, clipping and observing; content not observing") << false
+ << true << true << true
+ << true << true << true
+ << QPoint() << QPoint() << QRect(0, 0, 290, 290) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp and observing") << true
+ << false << true << true
+ << false << true << true
+ << QPoint() << QPoint() << QRect(55, 55, 200, 200) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp and observing, inner pos offset") << true
+ << false << true << true
+ << false << true << true
+ << QPoint(120, 120) << QPoint() << QRect(55, 55, 80, 80) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp and observing, inner neg offset") << true
+ << false << true << true
+ << false << true << true
+ << QPoint(-70, -50) << QPoint() << QRect(105, 85, 170, 190) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp and observing, outer pos offset") << true
+ << false << true << true
+ << false << true << true
+ << QPoint() << QPoint(220, 220) << QRect(55, 55, 20, 20) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp and observing, outer neg offset") << true
+ << false << true << true
+ << false << true << true
+ << QPoint() << QPoint(-70, -50) << QRect(65, 55, 190, 200) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp and observing, pos and neg offset") << true
+ << false << true << true
+ << false << true << true
+ << QPoint(150, 150) << QPoint(-170, -150) << QRect(55, 55, 50, 50) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp and observing, neg and pos offset") << true
+ << false << true << true
+ << false << true << true
+ << QPoint(-180, -210) << QPoint(100, 115) << QRect(215, 245, 60, 30) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp not observing") << true
+ << false << true << false
+ << false << true << false
+ << QPoint() << QPoint() << QRect(55, 55, 220, 220) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp not observing, inner pos offset") << true
+ << false << true << false
+ << false << true << false
+ << QPoint(120, 120) << QPoint() << QRect(55, 55, 220, 220) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp not observing, inner neg offset") << true
+ << false << true << false
+ << false << true << false
+ << QPoint(-70, -50) << QPoint() << QRect(55, 55, 220, 220) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp not observing, outer pos offset") << true
+ << false << true << false
+ << false << true << false
+ << QPoint() << QPoint(220, 220) << QRect(55, 55, 220, 220) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp not observing, outer neg offset") << true
+ << false << true << false
+ << false << true << false
+ << QPoint() << QPoint(-70, -50) << QRect(55, 55, 220, 220) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner clipping and observing") << true
+ << true << true << true
+ << false << false << false
+ << QPoint() << QPoint() << QRect(55, 55, 220, 220) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner clipping and observing only outer") << true
+ << true << true << true
+ << false << true << false
+ << QPoint() << QPoint() << QRect(55, 55, 200, 200) << QRect(0, 0, 290, 290);
+}
+
+void tst_QQuickItem::viewport()
+{
+ QFETCH(bool, contentObservesViewport);
+ QFETCH(bool, innerClip);
+ QFETCH(bool, innerViewport);
+ QFETCH(bool, innerObservesViewport);
+ QFETCH(bool, outerClip);
+ QFETCH(bool, outerViewport);
+ QFETCH(bool, outerObservesViewport);
+ QFETCH(QPoint, innerViewportOffset);
+ QFETCH(QPoint, outerViewportOffset);
+ QFETCH(QRect, expectedViewportTestRect);
+ QFETCH(QRect, expectedContentClipRect);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("viewports.qml")));
+
+ QQuickItem *root = qobject_cast<QQuickItem *>(window.rootObject());
+ QQuickItem *outer = root->findChild<QQuickItem *>("outerViewport");
+ QVERIFY(outer);
+ QQuickItem *inner = root->findChild<QQuickItem *>("innerViewport");
+ QVERIFY(inner);
+ QQuickItem *contentItem = root->findChild<QQuickItem *>("innerRect");
+ QVERIFY(contentItem);
+ ViewportTestItem *viewportTestItem = root->findChild<ViewportTestItem *>();
+ QVERIFY(viewportTestItem);
+
+ inner->setPosition(inner->position() + innerViewportOffset);
+ outer->setPosition(outer->position() + outerViewportOffset);
+ outer->setClip(outerClip);
+ QCOMPARE(outer->flags().testFlag(QQuickItem::ItemIsViewport), outerClip);
+ outer->setFlag(QQuickItem::ItemIsViewport, outerViewport);
+ outer->setFlag(QQuickItem::ItemObservesViewport, outerObservesViewport);
+ inner->setClip(innerClip);
+ QCOMPARE(inner->flags().testFlag(QQuickItem::ItemIsViewport), innerClip);
+ inner->setFlag(QQuickItem::ItemIsViewport, innerViewport);
+ inner->setFlag(QQuickItem::ItemObservesViewport, innerObservesViewport);
+ viewportTestItem->setFlag(QQuickItem::ItemObservesViewport, contentObservesViewport);
+ emit viewportTestItem->viewportChanged();
+
+ if (lcTests().isDebugEnabled())
+ QTest::qWait(1000);
+ if (contentObservesViewport) {
+ if (innerViewport)
+ QCOMPARE(viewportTestItem->viewportItem(), inner);
+ else if (outerViewport)
+ QCOMPARE(viewportTestItem->viewportItem(), outer);
+ else
+ QCOMPARE(viewportTestItem->viewportItem(), root->parentItem()); // QQuickRootItem
+ } else {
+ QCOMPARE(viewportTestItem->viewportItem(), root->parentItem()); // QQuickRootItem
+ }
+
+ QCOMPARE(contentItem->clipRect().toRect(), expectedContentClipRect);
+ QCOMPARE(viewportTestItem->clipRect().toRect(), expectedViewportTestRect);
+}
+
+// Test that in a slot connected to destroyed() the emitter is
+// is no longer a QQuickItem.
+void tst_QQuickItem::qobject_castOnDestruction()
+{
+ QQuickItem item;
+ QObject::connect(&item, &QObject::destroyed, [](QObject *object)
+ {
+ QVERIFY(!qobject_cast<QQuickItem *>(object));
+ QVERIFY(!dynamic_cast<QQuickItem *>(object));
+ QVERIFY(!object->isQuickItemType());
+ });
+}
+
+/*
+ Items that are getting destroyed should not emit property change notifications.
+*/
+void tst_QQuickItem::signalsOnDestruction_data()
+{
+ QTest::addColumn<bool>("childVisible");
+ QTest::addColumn<bool>("grandChildVisible");
+
+ QTest::addRow("Both visible") << true << true;
+ QTest::addRow("Child visible") << true << false;
+ QTest::addRow("Grand child visible") << false << true;
+ QTest::addRow("Both hidden") << false << false;
+}
+
+void tst_QQuickItem::signalsOnDestruction()
+{
+ QFETCH(bool, childVisible);
+ QFETCH(bool, grandChildVisible);
+
+ QQuickWindow window;
+ window.show();
+
+ int expectedChildVisibleCount = 0;
+ int expectedGrandChildVisibleCount = 0;
+
+ // Visual children, but not QObject children.
+ // Note: QQuickItem's visible property defaults to true after creation, as visual
+ // items are always expected to be added to a visual hierarchy. So for the sake
+ // of this test we first add, and then remove the item from a parent. This explicitly
+ // sets the effective visibility to false.
+ std::unique_ptr<QQuickItem> parent(new QQuickItem(window.contentItem()));
+ QVERIFY(parent->isVisible());
+ std::unique_ptr<QQuickItem> child(new QQuickItem);
+ child->setVisible(childVisible);
+ child->setParentItem(parent.get());
+ child->setParentItem(nullptr);
+ QVERIFY(!child->isVisible());
+ std::unique_ptr<QQuickItem> grandChild(new QQuickItem);
+ grandChild->setVisible(grandChildVisible);
+ grandChild->setParentItem(child.get());
+ grandChild->setParentItem(nullptr);
+ QVERIFY(!grandChild->isVisible());
+
+ QSignalSpy childrenSpy(parent.get(), &QQuickItem::childrenChanged);
+ QSignalSpy visibleChildrenSpy(parent.get(), &QQuickItem::visibleChildrenChanged);
+ QSignalSpy childParentSpy(child.get(), &QQuickItem::parentChanged);
+ QSignalSpy childVisibleSpy(child.get(), &QQuickItem::visibleChanged);
+ QSignalSpy childChildrenSpy(child.get(), &QQuickItem::childrenChanged);
+ QSignalSpy childVisibleChildrenSpy(child.get(), &QQuickItem::visibleChildrenChanged);
+ QSignalSpy grandChildParentSpy(grandChild.get(), &QQuickItem::parentChanged);
+ QSignalSpy grandChildVisibleSpy(grandChild.get(), &QQuickItem::visibleChanged);
+
+ child->setParentItem(parent.get());
+ QCOMPARE(childrenSpy.count(), 1);
+ if (childVisible)
+ ++expectedChildVisibleCount;
+ QCOMPARE(visibleChildrenSpy.count(), expectedChildVisibleCount);
+ QCOMPARE(childParentSpy.count(), 1);
+ QCOMPARE(childVisibleSpy.count(), expectedChildVisibleCount);
+ QCOMPARE(childChildrenSpy.count(), 0);
+ QCOMPARE(childVisibleChildrenSpy.count(), 0);
+
+ grandChild->setParentItem(child.get());
+ QCOMPARE(childrenSpy.count(), 1);
+ QCOMPARE(visibleChildrenSpy.count(), expectedChildVisibleCount);
+ QCOMPARE(childParentSpy.count(), 1);
+ QCOMPARE(childVisibleSpy.count(), expectedChildVisibleCount);
+ QCOMPARE(childChildrenSpy.count(), 1);
+ if (grandChildVisible && childVisible)
+ ++expectedGrandChildVisibleCount;
+ QCOMPARE(childVisibleChildrenSpy.count(), expectedGrandChildVisibleCount);
+ QCOMPARE(grandChildParentSpy.count(), 1);
+ QCOMPARE(grandChildVisibleSpy.count(), expectedGrandChildVisibleCount);
+
+ parent.reset();
+
+ QVERIFY(!child->parentItem());
+ QVERIFY(grandChild->parentItem());
+ QCOMPARE(childrenSpy.count(), 1);
+ QCOMPARE(visibleChildrenSpy.count(), expectedChildVisibleCount);
+ QCOMPARE(childParentSpy.count(), 2);
+ QCOMPARE(childChildrenSpy.count(), 1);
+ if (childVisible)
+ ++expectedChildVisibleCount;
+ QCOMPARE(childVisibleSpy.count(), expectedChildVisibleCount);
+ if (childVisible && grandChildVisible)
+ ++expectedGrandChildVisibleCount;
+ QCOMPARE(childVisibleChildrenSpy.count(), expectedGrandChildVisibleCount);
+ QCOMPARE(grandChildParentSpy.count(), 1);
+ QCOMPARE(grandChildVisibleSpy.count(), expectedGrandChildVisibleCount);
+}
+
+void tst_QQuickItem::visibleChanged()
+{
+ QQuickView window;
+ window.setSource(testFileUrl("visiblechanged.qml"));
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+
+ QQuickItem *root = qobject_cast<QQuickItem*>(window.rootObject());
+ QVERIFY(root);
+
+ QPointer<QQuickItem> parentItem = root->findChild<QQuickItem *>("parentItem");
+ QPointer<QQuickItem> childItem = root->findChild<QQuickItem *>("childItem");
+ QPointer<QQuickItem> loader = root->findChild<QQuickItem *>("loader");
+ QPointer<QQuickItem> loaderChild = root->findChild<QQuickItem *>("loaderChild");
+ QVERIFY(parentItem);
+ QVERIFY(childItem);
+ QVERIFY(loader);
+ QVERIFY(loaderChild);
+
+ QSignalSpy parentItemSpy(parentItem.data(), &QQuickItem::visibleChanged);
+ QSignalSpy childItemSpy(childItem.data(), &QQuickItem::visibleChanged);
+ QSignalSpy loaderChildSpy(loaderChild.data(), &QQuickItem::visibleChanged);
+
+ loader->setProperty("active", false);
+ QCOMPARE(parentItemSpy.count(), 0);
+ QCOMPARE(childItemSpy.count(), 0);
+ QVERIFY(!loaderChild->parentItem());
+ QCOMPARE(loaderChildSpy.count(), 1);
+ QCOMPARE(loaderChild->isVisible(), false);
+
+ delete parentItem.data();
+ QVERIFY(!parentItem);
+ QVERIFY(childItem);
+ QVERIFY(!childItem->parentItem());
+
+ QCOMPARE(parentItemSpy.count(), 0);
+ QCOMPARE(childItemSpy.count(), 1);
+}
+
+void tst_QQuickItem::lastFocusChangeReason()
+{
+ std::unique_ptr<QQuickView> window = std::make_unique<QQuickView>();
+ window->setSource(testFileUrl("focusReason.qml"));
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window.get()));
+
+ QQuickItem *item = window->findChild<QQuickItem *>("item");
+ QQuickItem *customText = window->findChild<QQuickItem *>("customText");
+ QQuickItem *customItem = window->findChild<QQuickItem *>("customItem");
+ QQuickItem *hyperlink = window->findChild<QQuickItem *>("hyperlink");
+ QQuickItem *textInputChild = window->findChild<QQuickItem *>("textInputChild");
+
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ QQuickItemPrivate *customTextPrivate = QQuickItemPrivate::get(customText);
+ QQuickItemPrivate *customItemPrivate = QQuickItemPrivate::get(customItem);
+ QQuickItemPrivate *hyperlinkPrivate = QQuickItemPrivate::get(hyperlink);
+ QQuickItemPrivate *textInputChildPrivate = QQuickItemPrivate::get(textInputChild);
+
+ QVERIFY(item);
+ QVERIFY(customText);
+ QVERIFY(customItem);
+ QVERIFY(hyperlink);
+ QVERIFY(textInputChild);
+
+ QGuiApplication::styleHints()->setTabFocusBehavior(Qt::TabFocusAllControls);
+ auto resetTabFocusBehavior = qScopeGuard([]{
+ QGuiApplication::styleHints()->setTabFocusBehavior(Qt::TabFocusBehavior(-1));
+ });
+
+ // helper for clicking into an item
+ const auto itemCenter = [](const QQuickItem *item) -> QPoint {
+ return item->mapToScene(item->clipRect().center()).toPoint();
+ };
+
+ // setting focusPolicy to Strong/WheelFocus doesn't implicitly turn on event delivery
+ customText->setAcceptedMouseButtons(Qt::LeftButton);
+ customItem->setAcceptedMouseButtons(Qt::LeftButton);
+ customItem->setAcceptTouchEvents(true);
+ customText->setAcceptTouchEvents(true);
+ hyperlink->setAcceptTouchEvents(true);
+
+ // window activation -> ActiveWindowFocusReason
+ QVERIFY(item->hasFocus());
+ QVERIFY(item->hasActiveFocus());
+ if (itemPrivate->lastFocusChangeReason() != Qt::ActiveWindowFocusReason
+ && QStringList{"windows", "offscreen"}.contains(QGuiApplication::platformName())) {
+ QEXPECT_FAIL("", "On Windows and offscreen platforms, window activation does not set focus reason", Continue);
+ }
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::ActiveWindowFocusReason);
+
+ // test setter/getter
+ item->setFocus(false, Qt::MouseFocusReason);
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+ item->setFocus(true, Qt::TabFocusReason);
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::TabFocusReason);
+ item->setFocus(false, Qt::BacktabFocusReason);
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason);
+ item->forceActiveFocus(Qt::ShortcutFocusReason);
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::ShortcutFocusReason);
+ item->setFocus(false, Qt::NoFocusReason);
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::NoFocusReason);
+ QVERIFY(!item->hasFocus());
+
+ // programmatic focus changes
+ item->setFocus(true, Qt::OtherFocusReason);
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::OtherFocusReason);
+
+ QVERIFY(item->hasFocus());
+ QVERIFY(item->hasActiveFocus());
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::OtherFocusReason);
+
+ // tab focus -> TabFocusReason
+ QTest::keyClick(window.get(), Qt::Key_Tab);
+ QVERIFY(customText->hasFocus());
+ QVERIFY(customText->hasActiveFocus());
+ QCOMPARE(qApp->focusObject(), customText);
+ QCOMPARE(customTextPrivate->lastFocusChangeReason(), Qt::TabFocusReason);
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::TabFocusReason);
+
+ QTest::keyClick(window.get(), Qt::Key_Tab);
+ QVERIFY(customItem->hasFocus());
+ QVERIFY(customItem->hasActiveFocus());
+ QCOMPARE(qApp->focusObject(), customItem);
+ QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::TabFocusReason);
+ QCOMPARE(customTextPrivate->lastFocusChangeReason(), Qt::TabFocusReason);
+
+ QTest::keyClick(window.get(), Qt::Key_Tab);
+ QVERIFY(hyperlink->hasFocus());
+ QVERIFY(hyperlink->hasActiveFocus());
+ QCOMPARE(qApp->focusObject(), hyperlink);
+ QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::TabFocusReason);
+ QCOMPARE(customTextPrivate->lastFocusChangeReason(), Qt::TabFocusReason);
+
+ QTest::keyClick(window.get(), Qt::Key_Tab);
+ QVERIFY(item->hasFocus());
+ QVERIFY(item->hasActiveFocus());
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::TabFocusReason);
+ QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::TabFocusReason);
+
+ // backtab -> BacktabFocusReason
+ QTest::keyClick(window.get(), Qt::Key_Tab, Qt::ShiftModifier);
+ QVERIFY(hyperlink->hasFocus());
+ QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason);
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason);
+
+ QTest::keyClick(window.get(), Qt::Key_Tab, Qt::ShiftModifier);
+ QVERIFY(customItem->hasFocus());
+ QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason);
+ QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason);
+
+ QTest::keyClick(window.get(), Qt::Key_Tab, Qt::ShiftModifier);
+ QVERIFY(customText->hasFocus());
+ QCOMPARE(customTextPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason);
+ QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason);
+
+ // click focus -> MouseFocusReason
+ QTest::mouseClick(window.get(), Qt::LeftButton, {}, itemCenter(customItem));
+ QVERIFY(customItem->hasFocus());
+ QVERIFY(customItem->hasActiveFocus());
+ QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+ QCOMPARE(customTextPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+
+ QTest::mouseClick(window.get(), Qt::LeftButton, {}, itemCenter(hyperlink));
+ QVERIFY(hyperlink->hasFocus());
+ QVERIFY(hyperlink->hasActiveFocus());
+ QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+ QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+
+ QTest::mouseClick(window.get(), Qt::LeftButton, {}, itemCenter(customText));
+ QCOMPARE(textInputChild, textInputChild);
+ QVERIFY(textInputChild->hasFocus());
+ QVERIFY(textInputChild->hasActiveFocus());
+ QCOMPARE(textInputChildPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+ QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+
+ // touch focus -> MouseFocusReason
+ std::unique_ptr<QPointingDevice> touchDevice(QTest::createTouchDevice());
+
+ QTest::touchEvent(window.get(), touchDevice.get()).press(0, itemCenter(customItem));
+ QTest::touchEvent(window.get(), touchDevice.get()).press(0, itemCenter(customItem));
+ QTest::touchEvent(window.get(), touchDevice.get()).release(0, itemCenter(customItem));
+ QVERIFY(customItem->hasFocus());
+ QVERIFY(customItem->hasActiveFocus());
+ QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+ QCOMPARE(textInputChildPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+
+ QTest::touchEvent(window.get(), touchDevice.get()).press(0, itemCenter(hyperlink));
+ QTest::touchEvent(window.get(), touchDevice.get()).release(0, itemCenter(hyperlink));
+ QVERIFY(hyperlink->hasFocus());
+ QVERIFY(hyperlink->hasActiveFocus());
+ QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+ QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+
+ // Wheel focus -> MouseFocusReason
+ QWheelEvent wheelEvent(QPointF(customItem->width() / 2, customItem->height() / 2), QPointF(),
+ QPoint(), QPoint(0, 10), Qt::NoButton, Qt::NoModifier,
+ Qt::NoScrollPhase, false);
+ QGuiApplication::sendEvent(customItem, &wheelEvent);
+ QVERIFY(customItem->hasActiveFocus());
+ QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+}
+
+void tst_QQuickItem::focusInScopeChanges()
+{
+ std::unique_ptr<QQuickView> window = std::make_unique<QQuickView>();
+ window->setSource(testFileUrl("focusInScopeChanges.qml"));
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowFocused(window.get()));
+
+ QQuickItem *main = window->rootObject();
+ QVERIFY(main);
+ QQuickItem *focusScope = main->findChild<QQuickItem *>("focusScope");
+ QQuickItem *rect = main->findChild<QQuickItem *>("rect");
+ QQuickItem *textInput = main->findChild<QQuickItem *>("textInput");
+
+ QVERIFY(focusScope);
+ QVERIFY(rect);
+ QVERIFY(textInput);
+ QVERIFY(window->contentItem());
+
+ QSignalSpy fsActiveFocusSpy(focusScope, SIGNAL(activeFocusChanged(bool)));
+ QSignalSpy rectActiveFocusSpy(rect, SIGNAL(activeFocusChanged(bool)));
+ QSignalSpy textInputActiveFocusSpy(textInput, SIGNAL(activeFocusChanged(bool)));
+
+ // The window's content item will have activeFocus if window is focused
+ QTRY_VERIFY(window->contentItem()->hasActiveFocus());
+
+ QVERIFY(!focusScope->hasActiveFocus());
+ QVERIFY(!rect->hasActiveFocus());
+ QVERIFY(!textInput->hasActiveFocus());
+ QCOMPARE(fsActiveFocusSpy.size(), 0);
+ QCOMPARE(rectActiveFocusSpy.size(), 0);
+ QCOMPARE(textInputActiveFocusSpy.size(), 0);
+
+ // setting focus to rect shouldn't affect activeFocus as long as its
+ // parent focus scope doesn't have the activeFocus
+ rect->setFocus(true);
+ QCOMPARE(fsActiveFocusSpy.size(), 0);
+ QCOMPARE(rectActiveFocusSpy.size(), 0);
+ QCOMPARE(textInputActiveFocusSpy.size(), 0);
+
+ // focusScope is the only child with focus in the parent
+ // scope, so it will gain activeFocus
+ focusScope->setFocus(true);
+ QCOMPARE(fsActiveFocusSpy.size(), 1);
+ QVERIFY(fsActiveFocusSpy.first().at(0).toBool());
+ // rect loses activeFocus because textInput gains it (as a result of code in signal handler)
+ QCOMPARE(rectActiveFocusSpy.size(), 2);
+ QVERIFY(!rect->hasActiveFocus());
+ QCOMPARE(textInputActiveFocusSpy.size(), 1);
+ QVERIFY(textInput->hasActiveFocus());
+}
+
+#ifdef QT_WIDGETS_LIB
+void tst_QQuickItem::embeddedInWidgetsFocus()
+{
+ QWidget root;
+ QVBoxLayout *layout = new QVBoxLayout(&root);
+
+ QLineEdit *lineEdit1 = new QLineEdit(&root);
+ lineEdit1->setFocusPolicy(Qt::FocusPolicy::TabFocus);
+
+ QQuickView *quickView = new QQuickView;
+ quickView->setSource(testFileUrl("embedded.qml"));
+ QWidget *container = QWidget::createWindowContainer(quickView, &root);
+ container->setMinimumSize(quickView->size());
+ container->setFocusPolicy(Qt::TabFocus);
+
+ QLineEdit *lineEdit2 = new QLineEdit(&root);
+ lineEdit2->setFocusPolicy(Qt::FocusPolicy::TabFocus);
+
+ layout->addWidget(lineEdit1);
+ layout->addWidget(container);
+ layout->addWidget(lineEdit2);
+
+ QQuickItem *rect1 = findItem<QQuickItem>(quickView->rootObject(), "rect1");
+ QQuickItem *rect2 = findItem<QQuickItem>(quickView->rootObject(), "rect2");
+ QVERIFY(rect1);
+ QVERIFY(rect2);
+
+ root.show();
+ QTRY_VERIFY(root.isVisible());
+ QVERIFY(QTest::qWaitForWindowExposed(&root));
+ QVERIFY(QTest::qWaitForWindowFocused(root.windowHandle()));
+
+ lineEdit1->setFocus();
+ QTRY_VERIFY(lineEdit1->hasFocus());
+
+ // Tab forward
+ QTest::keyClick(QGuiApplication::focusWindow(), Qt::Key_Tab);
+ QTRY_VERIFY(container->hasFocus());
+ QVERIFY(QTest::qWaitForWindowFocused(quickView));
+ QVERIFY(rect1->hasActiveFocus());
+
+ QTest::keyClick(QGuiApplication::focusWindow(), Qt::Key_Tab);
+ QTRY_VERIFY(rect2->hasActiveFocus());
+
+ QTest::keyClick(QGuiApplication::focusWindow(), Qt::Key_Tab);
+ QVERIFY(QTest::qWaitForWindowFocused(root.windowHandle()));
+ QVERIFY(lineEdit2->hasFocus());
+ QVERIFY(!rect2->hasActiveFocus());
+
+ // Tab backwards
+ QTest::keyClick(QGuiApplication::focusWindow(), Qt::Key_Tab, Qt::ShiftModifier);
+ QTRY_VERIFY(container->hasFocus());
+ QVERIFY(QTest::qWaitForWindowFocused(quickView));
+ QVERIFY(rect2->hasActiveFocus());
+
+ QTest::keyClick(QGuiApplication::focusWindow(), Qt::Key_Tab, Qt::ShiftModifier);
+ QVERIFY(rect1->hasActiveFocus());
+
+ QTest::keyClick(QGuiApplication::focusWindow(), Qt::Key_Tab, Qt::ShiftModifier);
+ QVERIFY(QTest::qWaitForWindowFocused(root.windowHandle()));
+ QVERIFY(lineEdit1->hasFocus());
+}
+#endif
+
QTEST_MAIN(tst_QQuickItem)
#include "tst_qquickitem.moc"