diff options
author | Jan Arve Sæther <jan-arve.saether@qt.io> | 2017-09-05 13:46:18 +0200 |
---|---|---|
committer | Shawn Rutledge <shawn.rutledge@qt.io> | 2017-09-08 13:17:46 +0000 |
commit | 1337c54caec3c8f905b11f06a275eca12fdf6a00 (patch) | |
tree | e415deb1448d30a0ba90decd8a3b45e48f3ff24e /tests | |
parent | 19054b5449755e27d54793492c41095cc630cb91 (diff) |
Add test for mouse event propagation and filtering
Change-Id: I190936abda0900822e758a19be5308a5e1da586f
Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/quick/qquickwindow/tst_qquickwindow.cpp | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index 692e01c125..0c3e580828 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -392,6 +392,9 @@ private slots: void findChild(); + void testChildMouseEventFilter(); + void testChildMouseEventFilter_data(); + private: QTouchDevice *touchDevice; QTouchDevice *touchDeviceWithVelocity; @@ -2999,6 +3002,352 @@ void tst_qquickwindow::findChild() QCOMPARE(window.contentItem()->findChild<QObject *>("contentItemChild"), contentItemChild); } +class DeliveryRecord : public QPair<QString, QString> +{ +public: + DeliveryRecord(const QString &filter, const QString &receiver) : QPair(filter, receiver) { } + DeliveryRecord(const QString &receiver) : QPair(QString(), receiver) { } + DeliveryRecord() : QPair() { } + QString toString() const { + if (second.isEmpty()) + return QLatin1String("Delivery(no receiver)"); + else if (first.isEmpty()) + return QString(QLatin1String("Delivery(to '%1')")).arg(second); + else + return QString(QLatin1String("Delivery('%1' filtering for '%2')")).arg(first).arg(second); + } +}; + +Q_DECLARE_METATYPE(DeliveryRecord) + +QDebug operator<<(QDebug dbg, const DeliveryRecord &pair) +{ + dbg << pair.toString(); + return dbg; +} + +typedef QVector<DeliveryRecord> DeliveryRecordVector; + +class EventItem : public QQuickRectangle +{ + Q_OBJECT +public: + EventItem(QQuickItem *parent) + : QQuickRectangle(parent) + , m_eventAccepts(true) + , m_filterReturns(true) + , m_filterAccepts(true) + { + QSizeF psize(parent->width(), parent->height()); + psize -= QSizeF(20, 20); + setWidth(psize.width()); + setHeight(psize.height()); + setPosition(QPointF(10, 10)); + } + + void setFilterReturns(bool filterReturns) { m_filterReturns = filterReturns; } + void setFilterAccepts(bool accepts) { m_filterAccepts = accepts; } + void setEventAccepts(bool accepts) { m_eventAccepts = accepts; } + static QVector<DeliveryRecord> &deliveryList() { return m_deliveryList; } + static QSet<QEvent::Type> &includedEventTypes() + { + if (m_includedEventTypes.isEmpty()) + m_includedEventTypes << QEvent::MouseButtonPress; + return m_includedEventTypes; + } + static void setExpectedDeliveryList(const QVector<DeliveryRecord> &v) { m_expectedDeliveryList = v; } + +protected: + bool childMouseEventFilter(QQuickItem *i, QEvent *e) override + { + appendEvent(this, i, e); + switch (e->type()) { + case QEvent::MouseButtonPress: + e->setAccepted(m_filterAccepts); + // qCDebug(lcTests) << objectName() << i->objectName(); + return m_filterReturns; + default: + break; + } + return QQuickRectangle::childMouseEventFilter(i, e); + } + + bool event(QEvent *e) override + { + appendEvent(nullptr, this, e); + switch (e->type()) { + case QEvent::MouseButtonPress: + // qCDebug(lcTests) << objectName(); + e->setAccepted(m_eventAccepts); + return true; + default: + break; + } + return QQuickRectangle::event(e); + } + +private: + static void appendEvent(QQuickItem *filter, QQuickItem *receiver, QEvent *event) { + if (includedEventTypes().contains(event->type())) { + auto record = DeliveryRecord(filter ? filter->objectName() : QString(), receiver ? receiver->objectName() : QString()); + int i = m_deliveryList.count(); + if (m_expectedDeliveryList.count() > i && m_expectedDeliveryList[i] == record) + qCDebug(lcTests).noquote().nospace() << i << ": " << record; + else + qCDebug(lcTests).noquote().nospace() << i << ": " << record + << ", expected " << (m_expectedDeliveryList.count() > i ? m_expectedDeliveryList[i].toString() : QLatin1String("nothing")) << " <---"; + m_deliveryList << record; + } + } + bool m_eventAccepts; + bool m_filterReturns; + bool m_filterAccepts; + + // list of (filtering-parent . receiver) pairs + static DeliveryRecordVector m_expectedDeliveryList; + static DeliveryRecordVector m_deliveryList; + static QSet<QEvent::Type> m_includedEventTypes; +}; + +DeliveryRecordVector EventItem::m_expectedDeliveryList; +DeliveryRecordVector EventItem::m_deliveryList; +QSet<QEvent::Type> EventItem::m_includedEventTypes; + +typedef QVector<const char*> CharStarVector; + +Q_DECLARE_METATYPE(CharStarVector) + +struct InputState { + struct { + // event() behavior + bool eventAccepts; + // filterChildMouse behavior + bool returns; + bool accepts; + bool filtersChildMouseEvent; + } r[4]; +}; + +Q_DECLARE_METATYPE(InputState) + +void tst_qquickwindow::testChildMouseEventFilter_data() +{ + // HIERARCHY: + // r0->r1->r2->r3 + // + QTest::addColumn<QPoint>("mousePos"); + QTest::addColumn<InputState>("inputState"); + QTest::addColumn<DeliveryRecordVector>("expectedDeliveryOrder"); + + /* + // (This is an intended behavior change in progress: I24003f72875b309fa10b2d316916c5f86702cb57) + QTest::newRow("if filtered and rejected, do not deliver it to the item that filtered it") + << QPoint(100, 100) + << InputState({ + // | event() | child mouse filter + // +---------+---------+---------+--------- + { // | accepts | returns | accepts | filtersChildMouseEvent + { false, false, false, false}, + { true, false, false, false}, + { false, true, false, true}, + { false, false, false, false} + } + }) + << (DeliveryRecordVector() + << DeliveryRecord("r2", "r3") + //<< DeliveryRecord("r3") // it got filtered -> do not deliver + // DeliveryRecord("r2") // r2 filtered it -> do not deliver + << DeliveryRecord("r1") + ); + */ + + QTest::newRow("no filtering, no accepting") + << QPoint(100, 100) + << InputState({ + // | event() | child mouse filter + // +---------+---------+---------+--------- + { // | accepts | returns | accepts | filtersChildMouseEvent + { false, false, false, false}, + { false , false, false, false}, + { false, false, false, false}, + { false, false, false, false} + } + }) + << (DeliveryRecordVector() + << DeliveryRecord("r3") + << DeliveryRecord("r2") + << DeliveryRecord("r1") + << DeliveryRecord("r0") + << DeliveryRecord("root") + ); + + QTest::newRow("all filtering, no accepting") + << QPoint(100, 100) + << InputState({ + // | event() | child mouse filter + // +---------+---------+---------+--------- + { // | accepts | returns | accepts | filtersChildMouseEvent + { false, false, false, true}, + { false, false, false, true}, + { false, false, false, true}, + { false, false, false, true} + } + }) + << (DeliveryRecordVector() + << DeliveryRecord("r2", "r3") + << DeliveryRecord("r1", "r3") + << DeliveryRecord("r0", "r3") + << DeliveryRecord("r3") + << DeliveryRecord("r1", "r2") + << DeliveryRecord("r0", "r2") + << DeliveryRecord("r2") + << DeliveryRecord("r0", "r1") + << DeliveryRecord("r1") + << DeliveryRecord("r0") + << DeliveryRecord("root") + ); + + + QTest::newRow("some filtering, no accepting") + << QPoint(100, 100) + << InputState({ + // | event() | child mouse filter + // +---------+---------+---------+--------- + { // | accepts | returns | accepts | filtersChildMouseEvent + { false, false, false, true}, + { false, false, false, true}, + { false, false, false, false}, + { false, false, false, false} + } + }) + << (DeliveryRecordVector() + << DeliveryRecord("r1", "r3") + << DeliveryRecord("r0", "r3") + << DeliveryRecord("r3") + << DeliveryRecord("r1", "r2") + << DeliveryRecord("r0", "r2") + << DeliveryRecord("r2") + << DeliveryRecord("r0", "r1") + << DeliveryRecord("r1") + << DeliveryRecord("r0") + << DeliveryRecord("root") + ); + + QTest::newRow("r1 accepts") + << QPoint(100, 100) + << InputState({ + // | event() | child mouse filter + // +---------+---------+---------+--------- + { // | accepts | returns | accepts | filtersChildMouseEvent + { false, false, false, true}, + { true , false, false, true}, + { false, false, false, false}, + { false, false, false, false} + } + }) + << (DeliveryRecordVector() + << DeliveryRecord("r1", "r3") + << DeliveryRecord("r0", "r3") + << DeliveryRecord("r3") + << DeliveryRecord("r1", "r2") + << DeliveryRecord("r0", "r2") + << DeliveryRecord("r2") + << DeliveryRecord("r0", "r1") + << DeliveryRecord("r1") + ); + + QTest::newRow("r1 rejects and filters") + << QPoint(100, 100) + << InputState({ + // | event() | child mouse filter + // +---------+---------+---------+--------- + { // | accepts | returns | accepts | filtersChildMouseEvent + { false, false, false, true}, + { false , true, false, true}, + { false, false, false, false}, + { false, false, false, false} + } + }) + << (DeliveryRecordVector() + << DeliveryRecord("r1", "r3") + << DeliveryRecord("r0", "r3") +// << DeliveryRecord("r3") // since it got filtered we don't deliver to r3 + << DeliveryRecord("r1", "r2") + << DeliveryRecord("r0", "r2") +// << DeliveryRecord("r2" // since it got filtered we don't deliver to r2 + << DeliveryRecord("r0", "r1") + << DeliveryRecord("r1") + << DeliveryRecord("r0") + << DeliveryRecord("root") + ); + +} + +void tst_qquickwindow::testChildMouseEventFilter() +{ + QFETCH(QPoint, mousePos); + QFETCH(InputState, inputState); + QFETCH(DeliveryRecordVector, expectedDeliveryOrder); + + EventItem::setExpectedDeliveryList(expectedDeliveryOrder); + + QQuickWindow window; + window.resize(500, 809); + QQuickItem *root = window.contentItem(); + root->setAcceptedMouseButtons(Qt::LeftButton); + + root->setObjectName("root"); + EventFilter *rootFilter = new EventFilter; + root->installEventFilter(rootFilter); + + // Create 4 items; each item a child of the previous item. + EventItem *r[4]; + r[0] = new EventItem(root); + r[0]->setColor(QColor(0x404040)); + r[0]->setWidth(200); + r[0]->setHeight(200); + + r[1] = new EventItem(r[0]); + r[1]->setColor(QColor(0x606060)); + + r[2] = new EventItem(r[1]); + r[2]->setColor(Qt::red); + + r[3] = new EventItem(r[2]); + r[3]->setColor(Qt::green); + + for (uint i = 0; i < sizeof(r)/sizeof(EventItem*); ++i) { + r[i]->setEventAccepts(inputState.r[i].eventAccepts); + r[i]->setFilterReturns(inputState.r[i].returns); + r[i]->setFilterAccepts(inputState.r[i].accepts); + r[i]->setFiltersChildMouseEvents(inputState.r[i].filtersChildMouseEvent); + r[i]->setObjectName(QString::fromLatin1("r%1").arg(i)); + r[i]->setAcceptedMouseButtons(Qt::LeftButton); + } + + window.show(); + window.requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(&window)); + + DeliveryRecordVector &actualDeliveryOrder = EventItem::deliveryList(); + actualDeliveryOrder.clear(); + QTest::mousePress(&window, Qt::LeftButton, 0, mousePos); + + // Check if event got delivered to the root item. If so, append it to the list of items the event got delivered to + if (rootFilter->events.contains(QEvent::MouseButtonPress)) + actualDeliveryOrder.append(DeliveryRecord("root")); + + for (int i = 0; i < qMax(actualDeliveryOrder.count(), expectedDeliveryOrder.count()); ++i) { + const DeliveryRecord expectedNames = expectedDeliveryOrder.value(i); + const DeliveryRecord actualNames = actualDeliveryOrder.value(i); + QCOMPARE(actualNames.toString(), expectedNames.toString()); + } + + // "restore" mouse state + QTest::mouseRelease(&window, Qt::LeftButton, 0, mousePos); +} + + QTEST_MAIN(tst_qquickwindow) #include "tst_qquickwindow.moc" |