Add tst_qquickflickable::nestedSliderUsingTouch

to verify that when a touch-handling component is inside the Flickable,
it can control whether the flickable can steal the grab by means of
setKeepTouchGrab.

Task-number: QTBUG-59416
Task-number: QTBUG-59707
Change-Id: I93cf3abb07a96a69290c3b5b055b688a62fe8fff
Reviewed-by: J-P Nurmi <jpnurmi@qt.io>
This commit is contained in:
Shawn Rutledge 2017-03-24 15:59:28 +01:00
parent 6d7c3c0743
commit 1f9c7b065f
2 changed files with 197 additions and 0 deletions

View File

@ -0,0 +1,36 @@
import QtQuick 2.0
import Test 1.0
Flickable {
width: 240
height: 320
contentWidth: width * 1.5
contentHeight: height * 1.5
contentY: height * 0.25
Rectangle {
id: slider
width: 50
height: 200
color: "lightgray"
border.color: drag.active ? "green" : "black"
anchors.centerIn: parent
radius: 4
TouchDragArea {
id: drag
objectName: "drag"
anchors.fill: parent
}
Rectangle {
width: parent.width - 2
height: 20
radius: 5
color: "darkgray"
border.color: "black"
x: 1
y: Math.min(slider.height - height, Math.max(0, drag.pos.y - height / 2))
}
}
}

View File

@ -46,6 +46,99 @@
using namespace QQuickViewTestUtil;
using namespace QQuickVisualTestUtil;
// an abstract Slider which only handles touch events
class TouchDragArea : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(QPointF pos READ pos NOTIFY posChanged)
Q_PROPERTY(bool active READ active NOTIFY activeChanged)
Q_PROPERTY(bool keepMouseGrab READ keepMouseGrab WRITE setKeepMouseGrab NOTIFY keepMouseGrabChanged)
Q_PROPERTY(bool keepTouchGrab READ keepTouchGrab WRITE setKeepTouchGrab NOTIFY keepTouchGrabChanged)
public:
TouchDragArea(QQuickItem *parent = 0)
: QQuickItem(parent)
, touchEvents(0)
, touchUpdates(0)
, touchReleases(0)
, ungrabs(0)
, m_active(false)
{
setFlags(ItemAcceptsDrops);
}
QPointF pos() const { return m_pos; }
bool active() const { return m_active; }
void setKeepMouseGrab(bool keepMouseGrab)
{
QQuickItem::setKeepMouseGrab(keepMouseGrab);
emit keepMouseGrabChanged();
}
void setKeepTouchGrab(bool keepTouchGrab)
{
QQuickItem::setKeepTouchGrab(keepTouchGrab);
emit keepTouchGrabChanged();
}
int touchEvents;
int touchUpdates;
int touchReleases;
int ungrabs;
QVector<Qt::TouchPointState> touchPointStates;
protected:
void touchEvent(QTouchEvent *ev) override
{
QCOMPARE(ev->touchPoints().count(), 1);
auto touchpoint = ev->touchPoints().first();
switch (touchpoint.state()) {
case Qt::TouchPointPressed:
QVERIFY(!m_active);
m_active = true;
emit activeChanged();
grabTouchPoints(QVector<int>() << touchpoint.id());
break;
case Qt::TouchPointMoved:
++touchUpdates;
break;
case Qt::TouchPointReleased:
QVERIFY(m_active);
m_active = false;
++touchReleases;
emit activeChanged();
case Qt::TouchPointStationary:
break;
}
touchPointStates << touchpoint.state();
++touchEvents;
m_pos = touchpoint.pos();
emit posChanged();
}
void touchUngrabEvent() override
{
++ungrabs;
QVERIFY(m_active);
emit ungrabbed();
m_active = false;
emit activeChanged();
}
signals:
void ungrabbed();
void posChanged();
void keepMouseGrabChanged();
void keepTouchGrabChanged();
void activeChanged();
private:
QPointF m_pos;
bool m_active;
};
class tst_qquickflickable : public QQmlDataTest
{
Q_OBJECT
@ -55,6 +148,7 @@ public:
{}
private slots:
void initTestCase() override;
void create();
void horizontalViewportSize();
void verticalViewportSize();
@ -92,6 +186,8 @@ private slots:
void stopAtBounds();
void stopAtBounds_data();
void nestedMouseAreaUsingTouch();
void nestedSliderUsingTouch();
void nestedSliderUsingTouch_data();
void pressDelayWithLoader();
void movementFromProgrammaticFlick();
void cleanup();
@ -108,6 +204,12 @@ private:
QTouchDevice *touchDevice;
};
void tst_qquickflickable::initTestCase()
{
QQmlDataTest::initTestCase();
qmlRegisterType<TouchDragArea>("Test",1,0,"TouchDragArea");
}
void tst_qquickflickable::cleanup()
{
QVERIFY(QGuiApplication::topLevelWindows().isEmpty());
@ -1889,6 +1991,65 @@ void tst_qquickflickable::nestedMouseAreaUsingTouch()
QVERIFY(nested->y() < 100.0);
}
void tst_qquickflickable::nestedSliderUsingTouch_data()
{
QTest::addColumn<bool>("keepMouseGrab");
QTest::addColumn<bool>("keepTouchGrab");
QTest::addColumn<int>("updates");
QTest::addColumn<int>("releases");
QTest::addColumn<int>("ungrabs");
QTest::newRow("keepBoth") << true << true << 8 << 1 << 0;
QTest::newRow("keepMouse") << true << false << 8 << 1 << 0;
QTest::newRow("keepTouch") << false << true << 8 << 1 << 0;
QTest::newRow("keepNeither") << false << false << 6 << 0 << 1;
}
void tst_qquickflickable::nestedSliderUsingTouch()
{
QFETCH(bool, keepMouseGrab);
QFETCH(bool, keepTouchGrab);
QFETCH(int, updates);
QFETCH(int, releases);
QFETCH(int, ungrabs);
QQuickView *window = new QQuickView;
QScopedPointer<QQuickView> windowPtr(window);
windowPtr->setSource(testFileUrl("nestedSlider.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
QQuickViewTestUtil::centerOnScreen(window);
QQuickViewTestUtil::moveMouseAway(window);
window->show();
QVERIFY(QTest::qWaitForWindowActive(window));
QVERIFY(window->rootObject() != 0);
QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
QVERIFY(flickable);
TouchDragArea *tda = flickable->findChild<TouchDragArea*>("drag");
QVERIFY(tda);
// Drag down and a little to the right: flickable will steal the grab only if tda allows it
const int dragThreshold = qApp->styleHints()->startDragDistance();
tda->setKeepMouseGrab(keepMouseGrab);
tda->setKeepTouchGrab(keepTouchGrab);
QPoint p0 = tda->mapToScene(QPoint(20, 20)).toPoint();
QTest::touchEvent(window, touchDevice).press(0, p0, window);
QQuickTouchUtils::flush(window);
for (int i = 0; i < 8; ++i) {
p0 += QPoint(dragThreshold / 6, dragThreshold / 4);
QTest::touchEvent(window, touchDevice).move(0, p0, window);
QQuickTouchUtils::flush(window);
}
QCOMPARE(tda->active(), !ungrabs);
QTest::touchEvent(window, touchDevice).release(0, p0, window);
QQuickTouchUtils::flush(window);
QCOMPARE(tda->touchPointStates.first(), Qt::TouchPointPressed);
QCOMPARE(tda->touchUpdates, updates);
QCOMPARE(tda->touchReleases, releases);
QCOMPARE(tda->ungrabs, ungrabs);
}
// QTBUG-31328
void tst_qquickflickable::pressDelayWithLoader()
{