aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2021-04-29 16:47:23 +0200
committerShawn Rutledge <shawn.rutledge@qt.io>2021-05-06 00:40:09 +0200
commit152e12dc22cc0fd07cf90bcd35ae0e05b8b46fa0 (patch)
tree86c0baf106c945805848bb33e40b385900a7ace6 /tests
parent1dc4bdbabfed1eb73b563a77810ceb00a8fd6fca (diff)
Begin testing QQDeliveryAgent subscenes
The first test is passiveGrabberOrder(), to verify that if the user interacts with handlers in a subscene and the root scene simultaneously, the passive grab order and the order of the signals from the handlers is deterministic: the subscene goes first because it's conceptually "on top". Change-Id: Id00ab1497fbd3c9d7afa02f8098699bd569ded70 Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/quick/CMakeLists.txt1
-rw-r--r--tests/auto/quick/qquickdeliveryagent/CMakeLists.txt42
-rw-r--r--tests/auto/quick/qquickdeliveryagent/data/tapHandler.qml14
-rw-r--r--tests/auto/quick/qquickdeliveryagent/tst_qquickdeliveryagent.cpp186
-rw-r--r--tests/auto/quick/shared/visualtestutil.h27
5 files changed, 270 insertions, 0 deletions
diff --git a/tests/auto/quick/CMakeLists.txt b/tests/auto/quick/CMakeLists.txt
index f75201515d..b4e34734c4 100644
--- a/tests/auto/quick/CMakeLists.txt
+++ b/tests/auto/quick/CMakeLists.txt
@@ -30,6 +30,7 @@ if(QT_FEATURE_private_tests)
add_subdirectory(qquickdynamicpropertyanimation)
add_subdirectory(qquickborderimage)
add_subdirectory(qquickwindow)
+ add_subdirectory(qquickdeliveryagent)
add_subdirectory(qquickdrag)
add_subdirectory(qquickdroparea)
add_subdirectory(qquickflickable)
diff --git a/tests/auto/quick/qquickdeliveryagent/CMakeLists.txt b/tests/auto/quick/qquickdeliveryagent/CMakeLists.txt
new file mode 100644
index 0000000000..1a5490effa
--- /dev/null
+++ b/tests/auto/quick/qquickdeliveryagent/CMakeLists.txt
@@ -0,0 +1,42 @@
+#####################################################################
+## tst_qquickdeliveryagent Test:
+#####################################################################
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ data/*)
+list(APPEND test_data ${test_data_glob})
+
+qt_internal_add_test(tst_qquickdeliveryagent
+ SOURCES
+ ../../shared/util.cpp ../../shared/util.h
+ ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
+ ../shared/viewtestutil.cpp ../shared/viewtestutil.h
+ ../shared/visualtestutil.cpp ../shared/visualtestutil.h
+ tst_qquickdeliveryagent.cpp
+ DEFINES
+ QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ INCLUDE_DIRECTORIES
+ ../../shared
+ PUBLIC_LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickPrivate
+ TESTDATA ${test_data}
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_qquickdeliveryagent CONDITION ANDROID OR IOS
+ DEFINES
+ QT_QMLTEST_DATADIR=\\\":/data\\\"
+)
+
+qt_internal_extend_target(tst_qquickdeliveryagent CONDITION NOT ANDROID AND NOT IOS
+ DEFINES
+ QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+)
diff --git a/tests/auto/quick/qquickdeliveryagent/data/tapHandler.qml b/tests/auto/quick/qquickdeliveryagent/data/tapHandler.qml
new file mode 100644
index 0000000000..e2ba88dcde
--- /dev/null
+++ b/tests/auto/quick/qquickdeliveryagent/data/tapHandler.qml
@@ -0,0 +1,14 @@
+import QtQuick
+
+Rectangle {
+ id: root
+ objectName: "root"
+ color: th.pressed ? "goldenrod" : "khaki"
+ border.color: "black"
+ width: 100; height: 100
+ TapHandler {
+ id: th
+ objectName: root.objectName + "Tap"
+ onTapped: console.log(this, objectName)
+ }
+}
diff --git a/tests/auto/quick/qquickdeliveryagent/tst_qquickdeliveryagent.cpp b/tests/auto/quick/qquickdeliveryagent/tst_qquickdeliveryagent.cpp
new file mode 100644
index 0000000000..324ad9cd33
--- /dev/null
+++ b/tests/auto/quick/qquickdeliveryagent/tst_qquickdeliveryagent.cpp
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 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 <QSignalSpy>
+#include <QDebug>
+#include <QtQml/QQmlEngine>
+#include <QtQml/QQmlComponent>
+#include <QtQuick/QQuickItem>
+#include <QtQuick/QQuickView>
+#include <QtQuick/QQuickWindow>
+#include <QtQuick/private/qquickshadereffectsource_p.h>
+#include <QtQuick/private/qquicktaphandler_p.h>
+#include <QtQuick/private/qquickwindow_p.h>
+#include "../../shared/util.h"
+#include "../shared/visualtestutil.h"
+#include "../shared/viewtestutil.h"
+
+Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
+
+struct ViewportTransformHelper : public QQuickDeliveryAgent::Transform
+{
+ QPointF offset = QPointF(50, 50);
+
+ // Transforms window coordinates to subscene coordinates.
+ QPointF map(const QPointF &viewportPoint) override {
+ qCDebug(lcTests) << viewportPoint << "->" << viewportPoint - offset;
+ return viewportPoint - offset;
+ }
+};
+
+// A QQuick3DViewport simulator
+class SubsceneRootItem : public QQuickShaderEffectSource
+{
+public:
+ SubsceneRootItem(QQuickItem *source, QRectF bounds, QQuickItem *parent = nullptr)
+ : QQuickShaderEffectSource(parent),
+ deliveryAgent(QQuickItemPrivate::get(source)->ensureSubsceneDeliveryAgent())
+ {
+ setAcceptedMouseButtons(Qt::AllButtons);
+ setAcceptTouchEvents(true);
+ setAcceptHoverEvents(true);
+ setSourceItem(source);
+ setSize(bounds.size());
+ setPosition(bounds.topLeft());
+ setOpacity(0.5);
+ deliveryAgent->setObjectName("subscene");
+ }
+
+ QQuickDeliveryAgent *deliveryAgent = nullptr;
+
+protected:
+ bool event(QEvent *e) override {
+ if (e->isPointerEvent()) {
+ bool ret = false;
+ auto pe = static_cast<QPointerEvent *>(e);
+
+ QVarLengthArray<QPointF, 16> originalScenePositions;
+ originalScenePositions.resize(pe->pointCount());
+ for (int pointIndex = 0; pointIndex < pe->pointCount(); ++pointIndex)
+ originalScenePositions[pointIndex] = pe->point(pointIndex).scenePosition();
+
+ for (int pointIndex = 0; pointIndex < pe->pointCount(); ++pointIndex) {
+ QMutableEventPoint &mut = QMutableEventPoint::from(pe->point(pointIndex));
+ mut.setScenePosition(vxh->map(mut.scenePosition()));
+ mut.setPosition(mut.position());
+ }
+
+ qCDebug(lcTests) << "forwarding to subscene DA" << pe;
+ if (deliveryAgent->event(pe)) {
+ ret = true;
+ if (QQuickDeliveryAgentPrivate::anyPointGrabbed(pe))
+ deliveryAgent->setSceneTransform(vxh); // takes ownership
+ }
+
+ // restore original scene positions
+ for (int pointIndex = 0; pointIndex < pe->pointCount(); ++pointIndex)
+ QMutableEventPoint::from(pe->point(pointIndex)).setScenePosition(originalScenePositions.at(pointIndex));
+
+ pe->setAccepted(false); // reject implicit grab and let it keep propagating
+ qCDebug(lcTests) << e << "returning" << ret;
+ return ret;
+ } else {
+ return QQuickShaderEffectSource::event(e);
+ }
+ }
+
+ ViewportTransformHelper *vxh = new ViewportTransformHelper;
+};
+
+class tst_qquickdeliveryagent : public QQmlDataTest
+{
+ Q_OBJECT
+public:
+ tst_qquickdeliveryagent()
+ {
+ }
+
+private slots:
+ void passiveGrabberOrder();
+
+private:
+ QScopedPointer<QPointingDevice> touchDevice = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
+};
+
+void tst_qquickdeliveryagent::passiveGrabberOrder()
+{
+ QQuickView view;
+ QQmlComponent component(view.engine());
+ component.loadUrl(testFileUrl("tapHandler.qml"));
+ view.setContent(QUrl(), &component, component.create());
+ view.resize(160, 160);
+ QQuickItem *root = qobject_cast<QQuickItem*>(view.rootObject());
+ QVERIFY(root);
+ QQuickTapHandler *rootTap = root->findChild<QQuickTapHandler *>();
+ QVERIFY(rootTap);
+
+ QScopedPointer<QQuickItem> subsceneRect(qobject_cast<QQuickItem *>(component.createWithInitialProperties({{"objectName", "child"}})));
+ QVERIFY(subsceneRect);
+ QQuickTapHandler *subsceneTap = subsceneRect->findChild<QQuickTapHandler *>();
+ QVERIFY(subsceneTap);
+
+ SubsceneRootItem subscene(subsceneRect.data(), {50, 50, 100, 100}, view.rootObject());
+ QCOMPARE(subsceneRect->parentItem(), nullptr);
+ QQuickDeliveryAgent *windowAgent = QQuickWindowPrivate::get(&view)->deliveryAgent;
+ windowAgent->setObjectName("window");
+ QVERIFY(subscene.deliveryAgent);
+ QVERIFY(subscene.deliveryAgent != windowAgent);
+ QQuickVisualTestUtil::SignalMultiSpy spy;
+ QVERIFY(spy.connectToSignal(rootTap, &QQuickTapHandler::tapped));
+ QVERIFY(spy.connectToSignal(subsceneTap, &QQuickTapHandler::tapped));
+
+ view.show();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QPoint pos(75, 75);
+ QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, pos);
+ QTest::qWait(1000);
+ auto devPriv = QPointingDevicePrivate::get(QPointingDevice::primaryPointingDevice());
+ const auto &persistentPoint = devPriv->activePoints.values().first();
+ qCDebug(lcTests) << "passive grabbers" << persistentPoint.passiveGrabbers << "contexts" << persistentPoint.passiveGrabbersContext;
+ QCOMPARE(persistentPoint.passiveGrabbers.count(), 2);
+ QCOMPARE(persistentPoint.passiveGrabbers.first(), subsceneTap);
+ QCOMPARE(persistentPoint.passiveGrabbersContext.first(), subscene.deliveryAgent);
+ QCOMPARE(persistentPoint.passiveGrabbers.last(), rootTap);
+
+ QTest::mouseRelease(&view, Qt::LeftButton);
+ QTest::qWait(100);
+ // QQuickWindow::event() has failsafe: clear all grabbers after release
+ QCOMPARE(persistentPoint.passiveGrabbers.count(), 0);
+
+ qCDebug(lcTests) << "TapHandlers emitted tapped in this order:" << spy.senders;
+ QCOMPARE(spy.senders.count(), 2);
+ // passive grabbers are visited in order, and emit tapped() at that time
+ QCOMPARE(spy.senders.first(), subsceneTap);
+ QCOMPARE(spy.senders.last(), rootTap);
+}
+
+QTEST_MAIN(tst_qquickdeliveryagent)
+
+#include "tst_qquickdeliveryagent.moc"
diff --git a/tests/auto/quick/shared/visualtestutil.h b/tests/auto/quick/shared/visualtestutil.h
index e623e3e225..c07cecfa47 100644
--- a/tests/auto/quick/shared/visualtestutil.h
+++ b/tests/auto/quick/shared/visualtestutil.h
@@ -98,6 +98,33 @@ namespace QQuickVisualTestUtil
}
bool compareImages(const QImage &ia, const QImage &ib, QString *errorMessage);
+
+ struct SignalMultiSpy : public QObject
+ {
+ Q_OBJECT
+ public:
+ QList<QObject *> senders;
+ QList<QByteArray> signalNames;
+
+ template <typename Func1>
+ QMetaObject::Connection connectToSignal(const typename QtPrivate::FunctionPointer<Func1>::Object *obj, Func1 signal,
+ Qt::ConnectionType type = Qt::AutoConnection)
+ {
+ return connect(obj, signal, this, &SignalMultiSpy::receive, type);
+ }
+
+ void clear() {
+ senders.clear();
+ signalNames.clear();
+ }
+
+ public slots:
+ void receive() {
+ QMetaMethod m = sender()->metaObject()->method(senderSignalIndex());
+ senders << sender();
+ signalNames << m.name();
+ }
+ };
}
#endif // QQUICKVISUALTESTUTIL_H