Change copyrights from Nokia to Digia
[profile/ivi/qtdeclarative.git] / tests / auto / quick / touchmouse / tst_touchmouse.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include <QtTest/QtTest>
44
45 #include <QtGui/qstylehints.h>
46
47 #include <QtQuick/qquickview.h>
48 #include <QtQuick/qquickitem.h>
49 #include <QtQuick/private/qquickmousearea_p.h>
50 #include <QtQuick/private/qquickmultipointtoucharea_p.h>
51 #include <QtQuick/private/qquickpincharea_p.h>
52 #include <QtQuick/private/qquickflickable_p.h>
53 #include <qpa/qwindowsysteminterface.h>
54
55 #include <private/qquickwindow_p.h>
56
57 #include <QtQml/qqmlengine.h>
58 #include <QtQml/qqmlproperty.h>
59
60 #include "../../shared/util.h"
61
62 struct Event
63 {
64     Event(QEvent::Type t, QPoint mouse, QPoint global)
65         :type(t), mousePos(mouse), mousePosGlobal(global)
66     {}
67
68     Event(QEvent::Type t, QList<QTouchEvent::TouchPoint> touch)
69         :type(t), points(touch)
70     {}
71
72     QEvent::Type type;
73     QPoint mousePos;
74     QPoint mousePosGlobal;
75     QList<QTouchEvent::TouchPoint> points;
76 };
77
78 class EventItem : public QQuickItem
79 {
80     Q_OBJECT
81 public:
82     EventItem(QQuickItem *parent = 0)
83         : QQuickItem(parent), acceptMouse(false), acceptTouch(false), filterTouch(false)
84     {}
85
86     void touchEvent(QTouchEvent *event)
87     {
88         eventList.append(Event(event->type(), event->touchPoints()));
89         event->setAccepted(acceptTouch);
90     }
91     void mousePressEvent(QMouseEvent *event)
92     {
93         eventList.append(Event(event->type(), event->pos(), event->globalPos()));
94         event->setAccepted(acceptMouse);
95     }
96     void mouseMoveEvent(QMouseEvent *event)
97     {
98         eventList.append(Event(event->type(), event->pos(), event->globalPos()));
99         event->setAccepted(acceptMouse);
100     }
101     void mouseReleaseEvent(QMouseEvent *event)
102     {
103         eventList.append(Event(event->type(), event->pos(), event->globalPos()));
104         event->setAccepted(acceptMouse);
105     }
106     void mouseDoubleClickEvent(QMouseEvent *event)
107     {
108         eventList.append(Event(event->type(), event->pos(), event->globalPos()));
109         event->setAccepted(acceptMouse);
110     }
111     bool event(QEvent *event) {
112         if (event->type() == QEvent::UngrabMouse) {
113             eventList.append(Event(event->type(), QPoint(0,0), QPoint(0,0)));
114         }
115         return QQuickItem::event(event);
116     }
117
118     QList<Event> eventList;
119     bool acceptMouse;
120     bool acceptTouch;
121     bool filterTouch; // when used as event filter
122
123     bool eventFilter(QObject *, QEvent *event)
124     {
125         if (event->type() == QEvent::TouchBegin ||
126                 event->type() == QEvent::TouchUpdate ||
127                 event->type() == QEvent::TouchCancel ||
128                 event->type() == QEvent::TouchEnd) {
129             QTouchEvent *touch = static_cast<QTouchEvent*>(event);
130             eventList.append(Event(event->type(), touch->touchPoints()));
131             if (filterTouch)
132                 event->accept();
133             return true;
134         }
135         return false;
136     }
137 };
138
139 class tst_TouchMouse : public QQmlDataTest
140 {
141     Q_OBJECT
142 public:
143     tst_TouchMouse()
144         :device(0)
145     {}
146
147 private slots:
148     void initTestCase();
149
150     void simpleTouchEvent();
151     void eventFilter();
152     void mouse();
153     void touchOverMouse();
154     void mouseOverTouch();
155
156     void buttonOnFlickable();
157     void buttonOnTouch();
158
159     void pinchOnFlickable();
160     void flickableOnPinch();
161     void mouseOnFlickableOnPinch();
162
163 private:
164     QQuickView *createView();
165     QTouchDevice *device;
166 };
167
168 QQuickView *tst_TouchMouse::createView()
169 {
170     QQuickView *window = new QQuickView(0);
171     window->setGeometry(0,0,240,320);
172
173     return window;
174 }
175
176 void tst_TouchMouse::initTestCase()
177 {
178     // This test assumes that we don't get synthesized mouse events from QGuiApplication
179     qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, false);
180
181     QQmlDataTest::initTestCase();
182     qmlRegisterType<EventItem>("Qt.test", 1, 0, "EventItem");
183     if (!device) {
184         device = new QTouchDevice;
185         device->setType(QTouchDevice::TouchScreen);
186         QWindowSystemInterface::registerTouchDevice(device);
187     }
188 }
189
190 void tst_TouchMouse::simpleTouchEvent()
191 {
192     QQuickView *window = createView();
193
194     window->setSource(testFileUrl("singleitem.qml"));
195     window->show();
196     window->requestActivateWindow();
197     QVERIFY(QTest::qWaitForWindowExposed(window));
198     QVERIFY(window->rootObject() != 0);
199
200     EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1");
201     QVERIFY(eventItem1);
202
203     // Do not accept touch or mouse
204     QPoint p1;
205     p1 = QPoint(20, 20);
206     QTest::touchEvent(window, device).press(0, p1, window);
207     QCOMPARE(eventItem1->eventList.size(), 1);
208     QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
209     p1 += QPoint(10, 0);
210     QTest::touchEvent(window, device).move(0, p1, window);
211     QCOMPARE(eventItem1->eventList.size(), 1);
212     QTest::touchEvent(window, device).release(0, p1, window);
213     QCOMPARE(eventItem1->eventList.size(), 1);
214     eventItem1->eventList.clear();
215
216     // Accept touch
217     eventItem1->acceptTouch = true;
218     p1 = QPoint(20, 20);
219     QTest::touchEvent(window, device).press(0, p1, window);
220     QCOMPARE(eventItem1->eventList.size(), 1);
221     p1 += QPoint(10, 0);
222     QTest::touchEvent(window, device).move(0, p1, window);
223     QCOMPARE(eventItem1->eventList.size(), 2);
224     QTest::touchEvent(window, device).release(0, p1, window);
225     QCOMPARE(eventItem1->eventList.size(), 3);
226     eventItem1->eventList.clear();
227
228     // wait to avoid getting a double click event
229     QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
230
231     // Accept mouse
232     eventItem1->acceptTouch = false;
233     eventItem1->acceptMouse = true;
234     eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
235     p1 = QPoint(20, 20);
236     QTest::touchEvent(window, device).press(0, p1, window);
237     QCOMPARE(eventItem1->eventList.size(), 2);
238     QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
239     QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress);
240     QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window);
241     QCOMPARE(windowPriv->mouseGrabberItem, eventItem1);
242
243     QPoint localPos = eventItem1->mapFromScene(p1).toPoint();
244     QPoint globalPos = window->mapToGlobal(p1);
245     QPoint scenePos = p1; // item is at 0,0
246     QCOMPARE(eventItem1->eventList.at(0).points.at(0).pos().toPoint(), localPos);
247     QCOMPARE(eventItem1->eventList.at(0).points.at(0).scenePos().toPoint(), scenePos);
248     QCOMPARE(eventItem1->eventList.at(0).points.at(0).screenPos().toPoint(), globalPos);
249     QCOMPARE(eventItem1->eventList.at(1).mousePos, localPos);
250     QCOMPARE(eventItem1->eventList.at(1).mousePosGlobal, globalPos);
251
252     p1 += QPoint(10, 0);
253     QTest::touchEvent(window, device).move(0, p1, window);
254     QCOMPARE(eventItem1->eventList.size(), 4);
255     QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchUpdate);
256     QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseMove);
257     QTest::touchEvent(window, device).release(0, p1, window);
258     QCOMPARE(eventItem1->eventList.size(), 6);
259     QCOMPARE(eventItem1->eventList.at(4).type, QEvent::TouchEnd);
260     QCOMPARE(eventItem1->eventList.at(5).type, QEvent::MouseButtonRelease);
261     eventItem1->eventList.clear();
262
263     // wait to avoid getting a double click event
264     QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
265
266     // Accept mouse buttons but not the event
267     eventItem1->acceptTouch = false;
268     eventItem1->acceptMouse = false;
269     eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
270     p1 = QPoint(20, 20);
271     QTest::touchEvent(window, device).press(0, p1, window);
272     QCOMPARE(eventItem1->eventList.size(), 2);
273     QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
274     QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress);
275     p1 += QPoint(10, 0);
276     QTest::touchEvent(window, device).move(0, p1, window);
277     QCOMPARE(eventItem1->eventList.size(), 2);
278     QTest::touchEvent(window, device).release(0, p1, window);
279     QCOMPARE(eventItem1->eventList.size(), 2);
280     eventItem1->eventList.clear();
281
282     // wait to avoid getting a double click event
283     QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
284
285     // Accept touch and mouse
286     eventItem1->acceptTouch = true;
287     eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
288     p1 = QPoint(20, 20);
289     QTest::touchEvent(window, device).press(0, p1, window);
290     QCOMPARE(eventItem1->eventList.size(), 1);
291     QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
292     p1 += QPoint(10, 0);
293     QTest::touchEvent(window, device).move(0, p1, window);
294     QCOMPARE(eventItem1->eventList.size(), 2);
295     QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchUpdate);
296     QTest::touchEvent(window, device).release(0, p1, window);
297     QCOMPARE(eventItem1->eventList.size(), 3);
298     QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchEnd);
299     eventItem1->eventList.clear();
300
301     delete window;
302 }
303
304 void tst_TouchMouse::eventFilter()
305 {
306 //    // install event filter on item and see that it can grab events
307 //    QQuickView *window = createView();
308
309 //    window->setSource(testFileUrl("singleitem.qml"));
310 //    window->show();
311 //    window->requestActivateWindow();
312 //    QVERIFY(window->rootObject() != 0);
313
314 //    EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1");
315 //    QVERIFY(eventItem1);
316 //    eventItem1->acceptTouch = true;
317
318 //    EventItem *filter = new EventItem;
319 //    filter->filterTouch = true;
320 //    eventItem1->installEventFilter(filter);
321
322 //    QPoint p1 = QPoint(20, 20);
323 //    QTest::touchEvent(window, device).press(0, p1, window);
324 //    // QEXPECT_FAIL("", "We do not implement event filters correctly", Abort);
325 //    QCOMPARE(eventItem1->eventList.size(), 0);
326 //    QCOMPARE(filter->eventList.size(), 1);
327 //    QTest::touchEvent(window, device).release(0, p1, window);
328 //    QCOMPARE(eventItem1->eventList.size(), 0);
329 //    QCOMPARE(filter->eventList.size(), 2);
330
331 //    delete filter;
332 //    delete window;
333 }
334
335 void tst_TouchMouse::mouse()
336 {
337     // eventItem1
338     //   - eventItem2
339
340     QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
341     QQuickView *window = createView();
342
343     window->setSource(testFileUrl("twoitems.qml"));
344     window->show();
345     window->requestActivateWindow();
346     QVERIFY(window->rootObject() != 0);
347
348     EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1");
349     QVERIFY(eventItem1);
350     EventItem *eventItem2 = window->rootObject()->findChild<EventItem*>("eventItem2");
351     QVERIFY(eventItem2);
352     QVERIFY(QTest::qWaitForWindowExposed(window));
353
354     // bottom item likes mouse, top likes touch
355     eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
356     eventItem1->acceptMouse = true;
357     // item 2 doesn't accept anything, thus it sees a touch pass by
358     QPoint p1 = QPoint(30, 30);
359     QTest::touchEvent(window, device).press(0, p1, window);
360
361     QCOMPARE(eventItem1->eventList.size(), 2);
362     QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
363     QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress);
364
365     delete window;
366 }
367
368 void tst_TouchMouse::touchOverMouse()
369 {
370     // eventItem1
371     //   - eventItem2
372
373     QQuickView *window = createView();
374
375     window->setSource(testFileUrl("twoitems.qml"));
376     window->show();
377     window->requestActivateWindow();
378     QVERIFY(window->rootObject() != 0);
379
380     EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1");
381     QVERIFY(eventItem1);
382     EventItem *eventItem2 = window->rootObject()->findChild<EventItem*>("eventItem2");
383     QVERIFY(eventItem2);
384
385     // bottom item likes mouse, top likes touch
386     eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
387     eventItem2->acceptTouch = true;
388
389     QVERIFY(QTest::qWaitForWindowExposed(window));
390
391     QCOMPARE(eventItem1->eventList.size(), 0);
392     QPoint p1 = QPoint(20, 20);
393     QTest::touchEvent(window, device).press(0, p1, window);
394     QCOMPARE(eventItem1->eventList.size(), 0);
395     QCOMPARE(eventItem2->eventList.size(), 1);
396     QCOMPARE(eventItem2->eventList.at(0).type, QEvent::TouchBegin);
397     p1 += QPoint(10, 0);
398     QTest::touchEvent(window, device).move(0, p1, window);
399     QCOMPARE(eventItem2->eventList.size(), 2);
400     QCOMPARE(eventItem2->eventList.at(1).type, QEvent::TouchUpdate);
401     QTest::touchEvent(window, device).release(0, p1, window);
402     QCOMPARE(eventItem2->eventList.size(), 3);
403     QCOMPARE(eventItem2->eventList.at(2).type, QEvent::TouchEnd);
404     eventItem2->eventList.clear();
405
406     delete window;
407 }
408
409 void tst_TouchMouse::mouseOverTouch()
410 {
411     // eventItem1
412     //   - eventItem2
413
414     QQuickView *window = createView();
415
416     window->setSource(testFileUrl("twoitems.qml"));
417     window->show();
418     window->requestActivateWindow();
419     QVERIFY(window->rootObject() != 0);
420
421     EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1");
422     QVERIFY(eventItem1);
423     EventItem *eventItem2 = window->rootObject()->findChild<EventItem*>("eventItem2");
424     QVERIFY(eventItem2);
425
426     // bottom item likes mouse, top likes touch
427     eventItem1->acceptTouch = true;
428     eventItem2->setAcceptedMouseButtons(Qt::LeftButton);
429     eventItem2->acceptMouse = true;
430
431     QVERIFY(QTest::qWaitForWindowExposed(window));
432
433     QPoint p1 = QPoint(20, 20);
434     QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
435     QTest::touchEvent(window, device).press(0, p1, window);
436     QCOMPARE(eventItem1->eventList.size(), 0);
437     QCOMPARE(eventItem2->eventList.size(), 2);
438     QCOMPARE(eventItem2->eventList.at(0).type, QEvent::TouchBegin);
439     QCOMPARE(eventItem2->eventList.at(1).type, QEvent::MouseButtonPress);
440
441
442 //    p1 += QPoint(10, 0);
443 //    QTest::touchEvent(window, device).move(0, p1, window);
444 //    QCOMPARE(eventItem2->eventList.size(), 1);
445 //    QTest::touchEvent(window, device).release(0, p1, window);
446 //    QCOMPARE(eventItem2->eventList.size(), 1);
447 //    eventItem2->eventList.clear();
448
449     delete window;
450 }
451
452 void tst_TouchMouse::buttonOnFlickable()
453 {
454     // flickable - height 500 / 1000
455     //   - eventItem1 y: 100, height 100
456     //   - eventItem2 y: 300, height 100
457
458     QQuickView *window = createView();
459
460     window->setSource(testFileUrl("buttononflickable.qml"));
461     window->show();
462     window->requestActivateWindow();
463     QVERIFY(window->rootObject() != 0);
464
465     QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>("flickable");
466     QVERIFY(flickable);
467
468     // should a mouse area button be clickable on top of flickable? yes :)
469     EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1");
470     QVERIFY(eventItem1);
471     eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
472     eventItem1->acceptMouse = true;
473
474     // should a touch button be touchable on top of flickable? yes :)
475     EventItem *eventItem2 = window->rootObject()->findChild<EventItem*>("eventItem2");
476     QVERIFY(eventItem2);
477     QCOMPARE(eventItem2->eventList.size(), 0);
478     eventItem2->acceptTouch = true;
479
480     // wait to avoid getting a double click event
481     QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
482
483     // check that buttons are clickable
484     // mouse button
485     QCOMPARE(eventItem1->eventList.size(), 0);
486     QPoint p1 = QPoint(20, 130);
487     QTest::touchEvent(window, device).press(0, p1, window);
488     QCOMPARE(eventItem1->eventList.size(), 2);
489     QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
490     QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress);
491     QTest::touchEvent(window, device).release(0, p1, window);
492     QCOMPARE(eventItem1->eventList.size(), 4);
493     QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchEnd);
494     QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseButtonRelease);
495     eventItem1->eventList.clear();
496
497     // touch button
498     p1 = QPoint(10, 310);
499     QTest::touchEvent(window, device).press(0, p1, window);
500     QCOMPARE(eventItem2->eventList.size(), 1);
501     QCOMPARE(eventItem2->eventList.at(0).type, QEvent::TouchBegin);
502     QTest::touchEvent(window, device).release(0, p1, window);
503     QCOMPARE(eventItem2->eventList.size(), 2);
504     QCOMPARE(eventItem2->eventList.at(1).type, QEvent::TouchEnd);
505     QCOMPARE(eventItem1->eventList.size(), 0);
506     eventItem2->eventList.clear();
507
508     // wait to avoid getting a double click event
509     QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
510
511     // click above button, no events please
512     p1 = QPoint(10, 90);
513     QTest::touchEvent(window, device).press(0, p1, window);
514     QCOMPARE(eventItem1->eventList.size(), 0);
515     QTest::touchEvent(window, device).release(0, p1, window);
516     QCOMPARE(eventItem1->eventList.size(), 0);
517     eventItem1->eventList.clear();
518
519     // wait to avoid getting a double click event
520     QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
521
522     // check that flickable moves - mouse button
523     QCOMPARE(eventItem1->eventList.size(), 0);
524     p1 = QPoint(10, 110);
525     QTest::touchEvent(window, device).press(0, p1, window);
526     QCOMPARE(eventItem1->eventList.size(), 2);
527     QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
528     QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress);
529
530     QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window);
531     QCOMPARE(windowPriv->touchMouseId, 0);
532     QCOMPARE(windowPriv->itemForTouchPointId[0], eventItem1);
533     QCOMPARE(windowPriv->mouseGrabberItem, eventItem1);
534
535     p1 += QPoint(0, -10);
536     QPoint p2 = p1 + QPoint(0, -10);
537     QPoint p3 = p2 + QPoint(0, -10);
538     QTest::qWait(10);
539     QTest::touchEvent(window, device).move(0, p1, window);
540     QTest::qWait(10);
541     QTest::touchEvent(window, device).move(0, p2, window);
542     QTest::qWait(10);
543     QTest::touchEvent(window, device).move(0, p3, window);
544
545     // we cannot really know when the events get grabbed away
546     QVERIFY(eventItem1->eventList.size() >= 4);
547     QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchUpdate);
548     QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseMove);
549
550     QCOMPARE(windowPriv->mouseGrabberItem, flickable);
551     QVERIFY(flickable->isMovingVertically());
552
553     QTest::touchEvent(window, device).release(0, p3, window);
554     delete window;
555 }
556
557 void tst_TouchMouse::buttonOnTouch()
558 {
559     // 400x800
560     //   PinchArea - height 400
561     //     - eventItem1 y: 100, height 100
562     //     - eventItem2 y: 300, height 100
563     //   MultiPointTouchArea - height 400
564     //     - eventItem1 y: 100, height 100
565     //     - eventItem2 y: 300, height 100
566
567     QQuickView *window = createView();
568     window->setSource(testFileUrl("buttonontouch.qml"));
569     window->show();
570     window->requestActivateWindow();
571     QVERIFY(window->rootObject() != 0);
572
573     QQuickPinchArea *pinchArea = window->rootObject()->findChild<QQuickPinchArea*>("pincharea");
574     QVERIFY(pinchArea);
575     QQuickItem *button1 = window->rootObject()->findChild<QQuickItem*>("button1");
576     QVERIFY(button1);
577     EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1");
578     QVERIFY(eventItem1);
579     EventItem *eventItem2 = window->rootObject()->findChild<EventItem*>("eventItem2");
580     QVERIFY(eventItem2);
581
582     QQuickMultiPointTouchArea *touchArea = window->rootObject()->findChild<QQuickMultiPointTouchArea*>("toucharea");
583     QVERIFY(touchArea);
584     EventItem *eventItem3 = window->rootObject()->findChild<EventItem*>("eventItem3");
585     QVERIFY(eventItem3);
586     EventItem *eventItem4 = window->rootObject()->findChild<EventItem*>("eventItem4");
587     QVERIFY(eventItem4);
588
589
590     // Test the common case of a mouse area on top of pinch
591     eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
592     eventItem1->acceptMouse = true;
593
594
595     // wait to avoid getting a double click event
596     QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
597
598     // Normal touch click
599     QPoint p1 = QPoint(10, 110);
600     QTest::touchEvent(window, device).press(0, p1, window);
601     QTest::touchEvent(window, device).release(0, p1, window);
602     QCOMPARE(eventItem1->eventList.size(), 4);
603     QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
604     QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress);
605     QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchEnd);
606     QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseButtonRelease);
607     eventItem1->eventList.clear();
608
609     // Normal mouse click
610     QTest::mouseClick(window, Qt::LeftButton, 0, p1);
611     QCOMPARE(eventItem1->eventList.size(), 2);
612     QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress);
613     QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonRelease);
614     eventItem1->eventList.clear();
615
616     // Pinch starting on the PinchArea should work
617     p1 = QPoint(40, 10);
618     QPoint p2 = QPoint(60, 10);
619
620     // Start the events after each other
621     QTest::touchEvent(window, device).press(0, p1, window);
622     QTest::touchEvent(window, device).stationary(0).press(1, p2, window);
623
624     QCOMPARE(button1->scale(), 1.0);
625
626     // This event seems to be discarded, let's ignore it for now until someone digs into pincharea
627     p1 -= QPoint(10, 0);
628     p2 += QPoint(10, 0);
629     QTest::touchEvent(window, device).move(0, p1, window).move(1, p2, window);
630
631     p1 -= QPoint(10, 0);
632     p2 += QPoint(10, 0);
633     QTest::touchEvent(window, device).move(0, p1, window).move(1, p2, window);
634 //    QCOMPARE(button1->scale(), 1.5);
635     qDebug() << "Button scale: " << button1->scale();
636
637     p1 -= QPoint(10, 0);
638     p2 += QPoint(10, 0);
639     QTest::touchEvent(window, device).move(0, p1, window).move(1, p2, window);
640 //    QCOMPARE(button1->scale(), 2.0);
641     qDebug() << "Button scale: " << button1->scale();
642
643     QTest::touchEvent(window, device).release(0, p1, window).release(1, p2, window);
644 //    QVERIFY(eventItem1->eventList.isEmpty());
645 //    QCOMPARE(button1->scale(), 2.0);
646     qDebug() << "Button scale: " << button1->scale();
647
648
649     // wait to avoid getting a double click event
650     QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
651
652     // Start pinching while on the button
653     button1->setScale(1.0);
654     p1 = QPoint(40, 110);
655     p2 = QPoint(60, 110);
656     QTest::touchEvent(window, device).press(0, p1, window).press(1, p2, window);
657     QCOMPARE(button1->scale(), 1.0);
658     QCOMPARE(eventItem1->eventList.count(), 2);
659     QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
660     QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress);
661
662     // This event seems to be discarded, let's ignore it for now until someone digs into pincharea
663     p1 -= QPoint(10, 0);
664     p2 += QPoint(10, 0);
665     QTest::touchEvent(window, device).move(0, p1, window).move(1, p2, window);
666
667     p1 -= QPoint(10, 0);
668     p2 += QPoint(10, 0);
669     QTest::touchEvent(window, device).move(0, p1, window).move(1, p2, window);
670     //QCOMPARE(button1->scale(), 1.5);
671     qDebug() << button1->scale();
672
673     p1 -= QPoint(10, 0);
674     p2 += QPoint(10, 0);
675     QTest::touchEvent(window, device).move(0, p1, window).move(1, p2, window);
676     qDebug() << button1->scale();
677     //QCOMPARE(button1->scale(), 2.0);
678
679     QTest::touchEvent(window, device).release(0, p1, window).release(1, p2, window);
680 //    QCOMPARE(eventItem1->eventList.size(), 99);
681     qDebug() << button1->scale();
682     //QCOMPARE(button1->scale(), 2.0);
683
684     delete window;
685 }
686
687 void tst_TouchMouse::pinchOnFlickable()
688 {
689     QQuickView *window = createView();
690     window->setSource(testFileUrl("pinchonflickable.qml"));
691     window->show();
692     window->requestActivateWindow();
693     QVERIFY(window->rootObject() != 0);
694
695     QQuickPinchArea *pinchArea = window->rootObject()->findChild<QQuickPinchArea*>("pincharea");
696     QVERIFY(pinchArea);
697     QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>("flickable");
698     QVERIFY(flickable);
699     QQuickItem *rect = window->rootObject()->findChild<QQuickItem*>("rect");
700     QVERIFY(rect);
701
702     // flickable - single touch point
703     QVERIFY(flickable->contentX() == 0.0);
704     QPoint p = QPoint(100, 100);
705     QTest::touchEvent(window, device).press(0, p, window);
706     QCOMPARE(rect->pos(), QPointF(200.0, 200.0));
707     p -= QPoint(10, 0);
708     QTest::touchEvent(window, device).move(0, p, window);
709     p -= QPoint(10, 0);
710     QTest::touchEvent(window, device).move(0, p, window);
711     QTest::qWait(10);
712     p -= QPoint(10, 0);
713     QTest::touchEvent(window, device).move(0, p, window);
714     QTest::qWait(10);
715     p -= QPoint(10, 0);
716     QTest::touchEvent(window, device).move(0, p, window);
717     QTest::touchEvent(window, device).release(0, p, window);
718
719     QGuiApplication::processEvents();
720     QTest::qWait(10);
721     QVERIFY(!flickable->isAtXBeginning());
722     // wait until flicking is done
723     QTRY_VERIFY(!flickable->isFlicking());
724
725     // pinch
726     QPoint p1 = QPoint(40, 20);
727     QPoint p2 = QPoint(60, 20);
728
729     QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device);
730     pinchSequence.press(0, p1, window).commit();
731     // In order for the stationary point to remember its previous position,
732     // we have to reuse the same pinchSequence object.  Otherwise if we let it
733     // be destroyed and then start a new sequence, point 0 will default to being
734     // stationary at 0, 0, and PinchArea will filter out that touchpoint because
735     // it is outside its bounds.
736     pinchSequence.stationary(0).press(1, p2, window).commit();
737     p1 -= QPoint(10,10);
738     p2 += QPoint(10,10);
739     pinchSequence.move(0, p1, window).move(1, p2, window).commit();
740     QCOMPARE(rect->scale(), 1.0);
741     p1 -= QPoint(10, 0);
742     p2 += QPoint(10, 0);
743     pinchSequence.move(0, p1, window).move(1, p2, window).commit();
744     p1 -= QPoint(10, 0);
745     p2 += QPoint(10, 0);
746     pinchSequence.move(0, p1, window).move(1, p2, window).commit();
747     p1 -= QPoint(10, 0);
748     p2 += QPoint(10, 0);
749     pinchSequence.move(0, p1, window).move(1, p2, window).commit();
750     pinchSequence.release(0, p1, window).release(1, p2, window).commit();
751     QVERIFY(rect->scale() > 1.0);
752 }
753
754 void tst_TouchMouse::flickableOnPinch()
755 {
756     QQuickView *window = createView();
757     window->setSource(testFileUrl("flickableonpinch.qml"));
758     window->show();
759     window->requestActivateWindow();
760     QVERIFY(window->rootObject() != 0);
761
762     QQuickPinchArea *pinchArea = window->rootObject()->findChild<QQuickPinchArea*>("pincharea");
763     QVERIFY(pinchArea);
764     QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>("flickable");
765     QVERIFY(flickable);
766     QQuickItem *rect = window->rootObject()->findChild<QQuickItem*>("rect");
767     QVERIFY(rect);
768
769     // flickable - single touch point
770     QVERIFY(flickable->contentX() == 0.0);
771     QPoint p = QPoint(100, 100);
772     QTest::touchEvent(window, device).press(0, p, window);
773     QCOMPARE(rect->pos(), QPointF(200.0, 200.0));
774     p -= QPoint(10, 0);
775     QTest::touchEvent(window, device).move(0, p, window);
776     p -= QPoint(10, 0);
777     QTest::touchEvent(window, device).move(0, p, window);
778
779     QTest::qWait(1000);
780
781     p -= QPoint(10, 0);
782     QTest::touchEvent(window, device).move(0, p, window);
783     QTest::touchEvent(window, device).release(0, p, window);
784
785     QTest::qWait(1000);
786
787     //QVERIFY(flickable->isMovingHorizontally());
788     qDebug() << "Pos: " << rect->pos();
789     // wait until flicking is done
790     QTRY_VERIFY(!flickable->isFlicking());
791
792     // pinch
793     QPoint p1 = QPoint(40, 20);
794     QPoint p2 = QPoint(60, 20);
795     QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device);
796     pinchSequence.press(0, p1, window).commit();
797     // In order for the stationary point to remember its previous position,
798     // we have to reuse the same pinchSequence object.  Otherwise if we let it
799     // be destroyed and then start a new sequence, point 0 will default to being
800     // stationary at 0, 0, and PinchArea will filter out that touchpoint because
801     // it is outside its bounds.
802     pinchSequence.stationary(0).press(1, p2, window).commit();
803     p1 -= QPoint(10,10);
804     p2 += QPoint(10,10);
805     pinchSequence.move(0, p1, window).move(1, p2, window).commit();
806     QCOMPARE(rect->scale(), 1.0);
807     p1 -= QPoint(10, 0);
808     p2 += QPoint(10, 0);
809     pinchSequence.move(0, p1, window).move(1, p2, window).commit();
810     p1 -= QPoint(10, 0);
811     p2 += QPoint(10, 0);
812     pinchSequence.move(0, p1, window).move(1, p2, window).commit();
813     p1 -= QPoint(10, 0);
814     p2 += QPoint(10, 0);
815     pinchSequence.move(0, p1, window).move(1, p2, window).commit();
816     pinchSequence.release(0, p1, window).release(1, p2, window).commit();
817     QVERIFY(rect->scale() > 1.0);
818 }
819
820 void tst_TouchMouse::mouseOnFlickableOnPinch()
821 {
822     QQuickView *window = createView();
823     window->setSource(testFileUrl("mouseonflickableonpinch.qml"));
824     window->show();
825     window->requestActivateWindow();
826     QVERIFY(window->rootObject() != 0);
827
828     QQuickPinchArea *pinchArea = window->rootObject()->findChild<QQuickPinchArea*>("pincharea");
829     QVERIFY(pinchArea);
830     QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>("flickable");
831     QVERIFY(flickable);
832     QQuickItem *rect = window->rootObject()->findChild<QQuickItem*>("rect");
833     QVERIFY(rect);
834
835     // flickable - single touch point
836     QVERIFY(flickable->contentX() == 0.0);
837     QPoint p = QPoint(100, 100);
838     QTest::touchEvent(window, device).press(0, p, window);
839     QCOMPARE(rect->pos(), QPointF(200.0, 200.0));
840     p -= QPoint(10, 0);
841     QTest::touchEvent(window, device).move(0, p, window);
842     p -= QPoint(10, 0);
843     QTest::touchEvent(window, device).move(0, p, window);
844
845     QTest::qWait(1000);
846
847     p -= QPoint(10, 0);
848     QTest::touchEvent(window, device).move(0, p, window);
849     QTest::touchEvent(window, device).release(0, p, window);
850
851     QTest::qWait(1000);
852
853     //QVERIFY(flickable->isMovingHorizontally());
854     qDebug() << "Pos: " << rect->pos();
855
856     // pinch
857     QPoint p1 = QPoint(40, 20);
858     QPoint p2 = QPoint(60, 20);
859     QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device);
860     pinchSequence.press(0, p1, window).commit();
861     // In order for the stationary point to remember its previous position,
862     // we have to reuse the same pinchSequence object.  Otherwise if we let it
863     // be destroyed and then start a new sequence, point 0 will default to being
864     // stationary at 0, 0, and PinchArea will filter out that touchpoint because
865     // it is outside its bounds.
866     pinchSequence.stationary(0).press(1, p2, window).commit();
867     p1 -= QPoint(10,10);
868     p2 += QPoint(10,10);
869     pinchSequence.move(0, p1, window).move(1, p2, window).commit();
870     QCOMPARE(rect->scale(), 1.0);
871     p1 -= QPoint(10, 0);
872     p2 += QPoint(10, 0);
873     pinchSequence.move(0, p1, window).move(1, p2, window).commit();
874     p1 -= QPoint(10, 0);
875     p2 += QPoint(10, 0);
876     pinchSequence.move(0, p1, window).move(1, p2, window).commit();
877     p1 -= QPoint(10, 0);
878     p2 += QPoint(10, 0);
879     pinchSequence.move(0, p1, window).move(1, p2, window).commit();
880     pinchSequence.release(0, p1, window).release(1, p2, window).commit();
881     QVERIFY(rect->scale() > 1.0);
882
883     // PinchArea should steal the event after flicking started
884     rect->setScale(1.0);
885     flickable->setContentX(0.0);
886     p = QPoint(100, 100);
887     pinchSequence.press(0, p, window).commit();
888     QCOMPARE(rect->pos(), QPointF(200.0, 200.0));
889     p -= QPoint(10, 0);
890     pinchSequence.move(0, p, window).commit();
891     p -= QPoint(10, 0);
892     pinchSequence.move(0, p, window).commit();
893     QTest::qWait(1000);
894     p -= QPoint(10, 0);
895     pinchSequence.move(0, p, window).commit();
896
897     QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window);
898     QCOMPARE(windowPriv->mouseGrabberItem, flickable);
899     qDebug() << "Mouse Grabber: " << windowPriv->mouseGrabberItem << " itemForTouchPointId: " << windowPriv->itemForTouchPointId;
900
901     // Add a second finger, this should lead to stealing
902     p1 = QPoint(40, 100);
903     p2 = QPoint(60, 100);
904     pinchSequence.stationary(0).press(1, p2, window).commit();
905     QCOMPARE(rect->scale(), 1.0);
906
907     p1 -= QPoint(5, 0);
908     p2 += QPoint(5, 0);
909     pinchSequence.move(0, p1, window).move(1, p2, window).commit();
910     p1 -= QPoint(5, 0);
911     p2 += QPoint(5, 0);
912     pinchSequence.move(0, p1, window).move(1, p2, window).commit();
913     p1 -= QPoint(5, 0);
914     p2 += QPoint(5, 0);
915     pinchSequence.move(0, p1, window).move(1, p2, window).commit();
916     pinchSequence.release(0, p1, window).release(1, p2, window).commit();
917     QVERIFY(rect->scale() > 1.0);
918     pinchSequence.release(0, p, window).commit();
919 }
920
921 QTEST_MAIN(tst_TouchMouse)
922
923 #include "tst_touchmouse.moc"
924