1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <QtTest/QtTest>
43 #include <QtTest/QSignalSpy>
44 #include <QtQuick/private/qquickmousearea_p.h>
45 #include <QtQuick/private/qquickrectangle_p.h>
46 #include <private/qquickflickable_p.h>
47 #include <QtQuick/qquickview.h>
48 #include <QtQml/qqmlcontext.h>
49 #include <QtQml/qqmlengine.h>
50 #include "../../shared/util.h"
51 #include <QtGui/qstylehints.h>
53 class tst_QQuickMouseArea: public QQmlDataTest
57 void dragProperties();
59 void dragging_data() { acceptedButton_data(); }
61 void invalidDrag_data() { rejectedButton_data(); }
63 void setDragOnPressed();
64 void updateMouseAreaPosOnClick();
65 void updateMouseAreaPosOnResize();
66 void noOnClickedWithPressAndHold();
67 void onMousePressRejected();
68 void pressedCanceledOnWindowDeactivate();
69 void doubleClick_data() { acceptedButton_data(); }
71 void clickTwice_data() { acceptedButton_data(); }
73 void invalidClick_data() { rejectedButton_data(); }
75 void pressedOrdering();
76 void preventStealing();
79 void hoverPropagation();
81 void disableAfterPress();
83 void transformedMouseArea_data();
84 void transformedMouseArea();
87 void acceptedButton_data();
88 void rejectedButton_data();
90 QQuickView *createView();
93 Q_DECLARE_METATYPE(Qt::MouseButton)
94 Q_DECLARE_METATYPE(Qt::MouseButtons)
96 void tst_QQuickMouseArea::acceptedButton_data()
98 QTest::addColumn<Qt::MouseButtons>("acceptedButtons");
99 QTest::addColumn<Qt::MouseButton>("button");
101 QTest::newRow("left") << Qt::MouseButtons(Qt::LeftButton) << Qt::LeftButton;
102 QTest::newRow("right") << Qt::MouseButtons(Qt::RightButton) << Qt::RightButton;
103 QTest::newRow("middle") << Qt::MouseButtons(Qt::MiddleButton) << Qt::MiddleButton;
105 QTest::newRow("left (left|right)") << Qt::MouseButtons(Qt::LeftButton | Qt::RightButton) << Qt::LeftButton;
106 QTest::newRow("right (right|middle)") << Qt::MouseButtons(Qt::RightButton | Qt::MiddleButton) << Qt::RightButton;
107 QTest::newRow("middle (left|middle)") << Qt::MouseButtons(Qt::LeftButton | Qt::MiddleButton) << Qt::MiddleButton;
110 void tst_QQuickMouseArea::rejectedButton_data()
112 QTest::addColumn<Qt::MouseButtons>("acceptedButtons");
113 QTest::addColumn<Qt::MouseButton>("button");
115 QTest::newRow("middle (left|right)") << Qt::MouseButtons(Qt::LeftButton | Qt::RightButton) << Qt::MiddleButton;
116 QTest::newRow("left (right|middle)") << Qt::MouseButtons(Qt::RightButton | Qt::MiddleButton) << Qt::LeftButton;
117 QTest::newRow("right (left|middle)") << Qt::MouseButtons(Qt::LeftButton | Qt::MiddleButton) << Qt::RightButton;
120 void tst_QQuickMouseArea::dragProperties()
122 QQuickView *canvas = createView();
124 canvas->setSource(testFileUrl("dragproperties.qml"));
126 canvas->requestActivateWindow();
127 QVERIFY(canvas->rootObject() != 0);
129 QQuickMouseArea *mouseRegion = canvas->rootObject()->findChild<QQuickMouseArea*>("mouseregion");
130 QQuickDrag *drag = mouseRegion->drag();
131 QVERIFY(mouseRegion != 0);
135 QQuickItem *blackRect = canvas->rootObject()->findChild<QQuickItem*>("blackrect");
136 QVERIFY(blackRect != 0);
137 QVERIFY(blackRect == drag->target());
138 QQuickItem *rootItem = qobject_cast<QQuickItem*>(canvas->rootObject());
139 QVERIFY(rootItem != 0);
140 QSignalSpy targetSpy(drag, SIGNAL(targetChanged()));
141 drag->setTarget(rootItem);
142 QCOMPARE(targetSpy.count(),1);
143 drag->setTarget(rootItem);
144 QCOMPARE(targetSpy.count(),1);
147 QCOMPARE(drag->axis(), QQuickDrag::XandYAxis);
148 QSignalSpy axisSpy(drag, SIGNAL(axisChanged()));
149 drag->setAxis(QQuickDrag::XAxis);
150 QCOMPARE(drag->axis(), QQuickDrag::XAxis);
151 QCOMPARE(axisSpy.count(),1);
152 drag->setAxis(QQuickDrag::XAxis);
153 QCOMPARE(axisSpy.count(),1);
155 // minimum and maximum properties
156 QSignalSpy xminSpy(drag, SIGNAL(minimumXChanged()));
157 QSignalSpy xmaxSpy(drag, SIGNAL(maximumXChanged()));
158 QSignalSpy yminSpy(drag, SIGNAL(minimumYChanged()));
159 QSignalSpy ymaxSpy(drag, SIGNAL(maximumYChanged()));
161 QCOMPARE(drag->xmin(), 0.0);
162 QCOMPARE(drag->xmax(), rootItem->width()-blackRect->width());
163 QCOMPARE(drag->ymin(), 0.0);
164 QCOMPARE(drag->ymax(), rootItem->height()-blackRect->height());
171 QCOMPARE(drag->xmin(), 10.0);
172 QCOMPARE(drag->xmax(), 10.0);
173 QCOMPARE(drag->ymin(), 10.0);
174 QCOMPARE(drag->ymax(), 10.0);
176 QCOMPARE(xminSpy.count(),1);
177 QCOMPARE(xmaxSpy.count(),1);
178 QCOMPARE(yminSpy.count(),1);
179 QCOMPARE(ymaxSpy.count(),1);
186 QCOMPARE(xminSpy.count(),1);
187 QCOMPARE(xmaxSpy.count(),1);
188 QCOMPARE(yminSpy.count(),1);
189 QCOMPARE(ymaxSpy.count(),1);
192 QSignalSpy filterChildrenSpy(drag, SIGNAL(filterChildrenChanged()));
194 drag->setFilterChildren(true);
196 QVERIFY(drag->filterChildren());
197 QCOMPARE(filterChildrenSpy.count(), 1);
199 drag->setFilterChildren(true);
200 QCOMPARE(filterChildrenSpy.count(), 1);
205 void tst_QQuickMouseArea::resetDrag()
207 QQuickView *canvas = createView();
209 canvas->rootContext()->setContextProperty("haveTarget", QVariant(true));
210 canvas->setSource(testFileUrl("dragreset.qml"));
212 canvas->requestActivateWindow();
213 QVERIFY(canvas->rootObject() != 0);
215 QQuickMouseArea *mouseRegion = canvas->rootObject()->findChild<QQuickMouseArea*>("mouseregion");
216 QQuickDrag *drag = mouseRegion->drag();
217 QVERIFY(mouseRegion != 0);
221 QQuickItem *blackRect = canvas->rootObject()->findChild<QQuickItem*>("blackrect");
222 QVERIFY(blackRect != 0);
223 QVERIFY(blackRect == drag->target());
224 QQuickItem *rootItem = qobject_cast<QQuickItem*>(canvas->rootObject());
225 QVERIFY(rootItem != 0);
226 QSignalSpy targetSpy(drag, SIGNAL(targetChanged()));
227 QVERIFY(drag->target() != 0);
228 canvas->rootContext()->setContextProperty("haveTarget", QVariant(false));
229 QCOMPARE(targetSpy.count(),1);
230 QVERIFY(drag->target() == 0);
235 void tst_QQuickMouseArea::dragging()
237 QFETCH(Qt::MouseButtons, acceptedButtons);
238 QFETCH(Qt::MouseButton, button);
240 QQuickView *canvas = createView();
242 canvas->setSource(testFileUrl("dragging.qml"));
244 canvas->requestActivateWindow();
246 QVERIFY(canvas->rootObject() != 0);
248 QQuickMouseArea *mouseRegion = canvas->rootObject()->findChild<QQuickMouseArea*>("mouseregion");
249 QQuickDrag *drag = mouseRegion->drag();
250 QVERIFY(mouseRegion != 0);
253 mouseRegion->setAcceptedButtons(acceptedButtons);
256 QQuickItem *blackRect = canvas->rootObject()->findChild<QQuickItem*>("blackrect");
257 QVERIFY(blackRect != 0);
258 QVERIFY(blackRect == drag->target());
260 QVERIFY(!drag->active());
262 QTest::mousePress(canvas, button, 0, QPoint(100,100));
264 QVERIFY(!drag->active());
265 QCOMPARE(blackRect->x(), 50.0);
266 QCOMPARE(blackRect->y(), 50.0);
268 // First move event triggers drag, second is acted upon.
269 // This is due to possibility of higher stacked area taking precedence.
271 QTest::mouseMove(canvas, QPoint(111,111));
273 QTest::mouseMove(canvas, QPoint(122,122));
276 QVERIFY(drag->active());
277 QCOMPARE(blackRect->x(), 72.0);
278 QCOMPARE(blackRect->y(), 72.0);
280 QTest::mouseRelease(canvas, button, 0, QPoint(122,122));
283 QVERIFY(!drag->active());
284 QCOMPARE(blackRect->x(), 72.0);
285 QCOMPARE(blackRect->y(), 72.0);
290 void tst_QQuickMouseArea::invalidDrag()
292 QFETCH(Qt::MouseButtons, acceptedButtons);
293 QFETCH(Qt::MouseButton, button);
295 QQuickView *canvas = createView();
297 canvas->setSource(testFileUrl("dragging.qml"));
299 canvas->requestActivateWindow();
301 QVERIFY(canvas->rootObject() != 0);
303 QQuickMouseArea *mouseRegion = canvas->rootObject()->findChild<QQuickMouseArea*>("mouseregion");
304 QQuickDrag *drag = mouseRegion->drag();
305 QVERIFY(mouseRegion != 0);
308 mouseRegion->setAcceptedButtons(acceptedButtons);
311 QQuickItem *blackRect = canvas->rootObject()->findChild<QQuickItem*>("blackrect");
312 QVERIFY(blackRect != 0);
313 QVERIFY(blackRect == drag->target());
315 QVERIFY(!drag->active());
317 QTest::mousePress(canvas, button, 0, QPoint(100,100));
319 QVERIFY(!drag->active());
320 QCOMPARE(blackRect->x(), 50.0);
321 QCOMPARE(blackRect->y(), 50.0);
323 // First move event triggers drag, second is acted upon.
324 // This is due to possibility of higher stacked area taking precedence.
326 QTest::mouseMove(canvas, QPoint(111,111));
328 QTest::mouseMove(canvas, QPoint(122,122));
331 QVERIFY(!drag->active());
332 QCOMPARE(blackRect->x(), 50.0);
333 QCOMPARE(blackRect->y(), 50.0);
335 QTest::mouseRelease(canvas, button, 0, QPoint(122,122));
338 QVERIFY(!drag->active());
339 QCOMPARE(blackRect->x(), 50.0);
340 QCOMPARE(blackRect->y(), 50.0);
345 void tst_QQuickMouseArea::setDragOnPressed()
347 QQuickView *canvas = createView();
349 canvas->setSource(testFileUrl("setDragOnPressed.qml"));
351 canvas->requestActivateWindow();
353 QVERIFY(canvas->rootObject() != 0);
355 QQuickMouseArea *mouseArea = qobject_cast<QQuickMouseArea *>(canvas->rootObject());
359 QQuickItem *target = mouseArea->findChild<QQuickItem*>("target");
362 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(100,100));
364 QQuickDrag *drag = mouseArea->drag();
366 QVERIFY(!drag->active());
368 QCOMPARE(target->x(), 50.0);
369 QCOMPARE(target->y(), 50.0);
371 // First move event triggers drag, second is acted upon.
372 // This is due to possibility of higher stacked area taking precedence.
374 QTest::mouseMove(canvas, QPoint(111,102));
376 QTest::mouseMove(canvas, QPoint(122,122));
379 QVERIFY(drag->active());
380 QCOMPARE(target->x(), 72.0);
381 QCOMPARE(target->y(), 50.0);
383 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(122,122));
386 QVERIFY(!drag->active());
387 QCOMPARE(target->x(), 72.0);
388 QCOMPARE(target->y(), 50.0);
393 QQuickView *tst_QQuickMouseArea::createView()
395 QQuickView *canvas = new QQuickView(0);
396 canvas->setBaseSize(QSize(240,320));
401 void tst_QQuickMouseArea::updateMouseAreaPosOnClick()
403 QQuickView *canvas = createView();
404 canvas->setSource(testFileUrl("updateMousePosOnClick.qml"));
406 canvas->requestActivateWindow();
407 QVERIFY(canvas->rootObject() != 0);
409 QQuickMouseArea *mouseRegion = canvas->rootObject()->findChild<QQuickMouseArea*>("mouseregion");
410 QVERIFY(mouseRegion != 0);
412 QQuickRectangle *rect = canvas->rootObject()->findChild<QQuickRectangle*>("ball");
415 QCOMPARE(mouseRegion->mouseX(), rect->x());
416 QCOMPARE(mouseRegion->mouseY(), rect->y());
418 QMouseEvent event(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
419 QGuiApplication::sendEvent(canvas, &event);
421 QCOMPARE(mouseRegion->mouseX(), 100.0);
422 QCOMPARE(mouseRegion->mouseY(), 100.0);
424 QCOMPARE(mouseRegion->mouseX(), rect->x());
425 QCOMPARE(mouseRegion->mouseY(), rect->y());
430 void tst_QQuickMouseArea::updateMouseAreaPosOnResize()
432 QQuickView *canvas = createView();
433 canvas->setSource(testFileUrl("updateMousePosOnResize.qml"));
435 canvas->requestActivateWindow();
436 QVERIFY(canvas->rootObject() != 0);
438 QQuickMouseArea *mouseRegion = canvas->rootObject()->findChild<QQuickMouseArea*>("mouseregion");
439 QVERIFY(mouseRegion != 0);
441 QQuickRectangle *rect = canvas->rootObject()->findChild<QQuickRectangle*>("brother");
444 QCOMPARE(mouseRegion->mouseX(), 0.0);
445 QCOMPARE(mouseRegion->mouseY(), 0.0);
447 QMouseEvent event(QEvent::MouseButtonPress, rect->pos().toPoint(), Qt::LeftButton, Qt::LeftButton, 0);
448 QGuiApplication::sendEvent(canvas, &event);
450 QVERIFY(!mouseRegion->property("emitPositionChanged").toBool());
451 QVERIFY(mouseRegion->property("mouseMatchesPos").toBool());
453 QCOMPARE(mouseRegion->property("x1").toReal(), 0.0);
454 QCOMPARE(mouseRegion->property("y1").toReal(), 0.0);
456 QCOMPARE(mouseRegion->property("x2").toReal(), rect->x());
457 QCOMPARE(mouseRegion->property("y2").toReal(), rect->y());
459 QCOMPARE(mouseRegion->mouseX(), rect->x());
460 QCOMPARE(mouseRegion->mouseY(), rect->y());
465 void tst_QQuickMouseArea::noOnClickedWithPressAndHold()
468 // We handle onPressAndHold, therefore no onClicked
469 QQuickView *canvas = createView();
470 canvas->setSource(testFileUrl("clickandhold.qml"));
472 canvas->requestActivateWindow();
473 QVERIFY(canvas->rootObject() != 0);
475 QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
476 QGuiApplication::sendEvent(canvas, &pressEvent);
478 QVERIFY(!canvas->rootObject()->property("clicked").toBool());
479 QVERIFY(!canvas->rootObject()->property("held").toBool());
483 QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
484 QGuiApplication::sendEvent(canvas, &releaseEvent);
486 QVERIFY(!canvas->rootObject()->property("clicked").toBool());
487 QVERIFY(canvas->rootObject()->property("held").toBool());
493 // We do not handle onPressAndHold, therefore we get onClicked
494 QQuickView *canvas = createView();
495 canvas->setSource(testFileUrl("noclickandhold.qml"));
497 canvas->requestActivateWindow();
498 QVERIFY(canvas->rootObject() != 0);
500 QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
501 QGuiApplication::sendEvent(canvas, &pressEvent);
503 QVERIFY(!canvas->rootObject()->property("clicked").toBool());
507 QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
508 QGuiApplication::sendEvent(canvas, &releaseEvent);
510 QVERIFY(canvas->rootObject()->property("clicked").toBool());
516 void tst_QQuickMouseArea::onMousePressRejected()
518 QQuickView *canvas = createView();
519 canvas->setSource(testFileUrl("rejectEvent.qml"));
521 canvas->requestActivateWindow();
522 QVERIFY(canvas->rootObject() != 0);
523 QVERIFY(canvas->rootObject()->property("enabled").toBool());
525 QVERIFY(!canvas->rootObject()->property("mr1_pressed").toBool());
526 QVERIFY(!canvas->rootObject()->property("mr1_released").toBool());
527 QVERIFY(!canvas->rootObject()->property("mr1_canceled").toBool());
528 QVERIFY(!canvas->rootObject()->property("mr2_pressed").toBool());
529 QVERIFY(!canvas->rootObject()->property("mr2_released").toBool());
530 QVERIFY(!canvas->rootObject()->property("mr2_canceled").toBool());
532 QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
533 QGuiApplication::sendEvent(canvas, &pressEvent);
535 QVERIFY(canvas->rootObject()->property("mr1_pressed").toBool());
536 QVERIFY(!canvas->rootObject()->property("mr1_released").toBool());
537 QVERIFY(!canvas->rootObject()->property("mr1_canceled").toBool());
538 QVERIFY(canvas->rootObject()->property("mr2_pressed").toBool());
539 QVERIFY(!canvas->rootObject()->property("mr2_released").toBool());
540 QVERIFY(canvas->rootObject()->property("mr2_canceled").toBool());
544 QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
545 QGuiApplication::sendEvent(canvas, &releaseEvent);
547 QVERIFY(canvas->rootObject()->property("mr1_released").toBool());
548 QVERIFY(!canvas->rootObject()->property("mr1_canceled").toBool());
549 QVERIFY(!canvas->rootObject()->property("mr2_released").toBool());
553 void tst_QQuickMouseArea::pressedCanceledOnWindowDeactivate()
555 QQuickView *canvas = createView();
556 canvas->setSource(testFileUrl("pressedCanceled.qml"));
558 canvas->requestActivateWindow();
559 QVERIFY(canvas->rootObject() != 0);
560 QVERIFY(!canvas->rootObject()->property("pressed").toBool());
561 QVERIFY(!canvas->rootObject()->property("canceled").toBool());
562 QVERIFY(!canvas->rootObject()->property("released").toBool());
564 QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
565 QGuiApplication::sendEvent(canvas, &pressEvent);
567 QVERIFY(canvas->rootObject()->property("pressed").toBool());
568 QVERIFY(!canvas->rootObject()->property("canceled").toBool());
569 QVERIFY(!canvas->rootObject()->property("released").toBool());
573 QEvent windowDeactivateEvent(QEvent::WindowDeactivate);
574 QGuiApplication::sendEvent(canvas, &windowDeactivateEvent);
575 QVERIFY(!canvas->rootObject()->property("pressed").toBool());
576 QVERIFY(canvas->rootObject()->property("canceled").toBool());
577 QVERIFY(!canvas->rootObject()->property("released").toBool());
582 QGuiApplication::sendEvent(canvas, &pressEvent);
583 QVERIFY(canvas->rootObject()->property("pressed").toBool());
584 QVERIFY(!canvas->rootObject()->property("canceled").toBool());
585 QVERIFY(!canvas->rootObject()->property("released").toBool());
590 QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
591 QGuiApplication::sendEvent(canvas, &releaseEvent);
592 QVERIFY(!canvas->rootObject()->property("pressed").toBool());
593 QVERIFY(!canvas->rootObject()->property("canceled").toBool());
594 QVERIFY(canvas->rootObject()->property("released").toBool());
599 void tst_QQuickMouseArea::doubleClick()
601 QFETCH(Qt::MouseButtons, acceptedButtons);
602 QFETCH(Qt::MouseButton, button);
604 QQuickView *canvas = createView();
605 canvas->setSource(testFileUrl("doubleclick.qml"));
607 canvas->requestActivateWindow();
608 QVERIFY(canvas->rootObject() != 0);
610 QQuickMouseArea *mouseArea = canvas->rootObject()->findChild<QQuickMouseArea *>("mousearea");
612 mouseArea->setAcceptedButtons(acceptedButtons);
614 // The sequence for a double click is:
615 // press, release, (click), press, double click, release
616 QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), button, button, 0);
617 QGuiApplication::sendEvent(canvas, &pressEvent);
619 QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), button, button, 0);
620 QGuiApplication::sendEvent(canvas, &releaseEvent);
622 QCOMPARE(canvas->rootObject()->property("released").toInt(), 1);
624 QGuiApplication::sendEvent(canvas, &pressEvent);
625 pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), button, button, 0);
626 QGuiApplication::sendEvent(canvas, &pressEvent);
627 QGuiApplication::sendEvent(canvas, &releaseEvent);
629 QCOMPARE(canvas->rootObject()->property("clicked").toInt(), 1);
630 QCOMPARE(canvas->rootObject()->property("doubleClicked").toInt(), 1);
631 QCOMPARE(canvas->rootObject()->property("released").toInt(), 2);
637 void tst_QQuickMouseArea::clickTwice()
639 QFETCH(Qt::MouseButtons, acceptedButtons);
640 QFETCH(Qt::MouseButton, button);
642 QQuickView *canvas = createView();
643 canvas->setSource(testFileUrl("clicktwice.qml"));
645 canvas->requestActivateWindow();
646 QVERIFY(canvas->rootObject() != 0);
648 QQuickMouseArea *mouseArea = canvas->rootObject()->findChild<QQuickMouseArea *>("mousearea");
650 mouseArea->setAcceptedButtons(acceptedButtons);
652 QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), button, button, 0);
653 QGuiApplication::sendEvent(canvas, &pressEvent);
655 QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), button, button, 0);
656 QGuiApplication::sendEvent(canvas, &releaseEvent);
658 QCOMPARE(canvas->rootObject()->property("pressed").toInt(), 1);
659 QCOMPARE(canvas->rootObject()->property("released").toInt(), 1);
660 QCOMPARE(canvas->rootObject()->property("clicked").toInt(), 1);
662 QGuiApplication::sendEvent(canvas, &pressEvent);
663 pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), button, button, 0);
664 QGuiApplication::sendEvent(canvas, &pressEvent);
665 QGuiApplication::sendEvent(canvas, &releaseEvent);
667 QCOMPARE(canvas->rootObject()->property("pressed").toInt(), 2);
668 QCOMPARE(canvas->rootObject()->property("released").toInt(), 2);
669 QCOMPARE(canvas->rootObject()->property("clicked").toInt(), 2);
674 void tst_QQuickMouseArea::invalidClick()
676 QFETCH(Qt::MouseButtons, acceptedButtons);
677 QFETCH(Qt::MouseButton, button);
679 QQuickView *canvas = createView();
680 canvas->setSource(testFileUrl("doubleclick.qml"));
682 canvas->requestActivateWindow();
683 QVERIFY(canvas->rootObject() != 0);
685 QQuickMouseArea *mouseArea = canvas->rootObject()->findChild<QQuickMouseArea *>("mousearea");
687 mouseArea->setAcceptedButtons(acceptedButtons);
689 // The sequence for a double click is:
690 // press, release, (click), press, double click, release
691 QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), button, button, 0);
692 QGuiApplication::sendEvent(canvas, &pressEvent);
694 QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), button, button, 0);
695 QGuiApplication::sendEvent(canvas, &releaseEvent);
697 QCOMPARE(canvas->rootObject()->property("released").toInt(), 0);
699 QGuiApplication::sendEvent(canvas, &pressEvent);
700 pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), button, button, 0);
701 QGuiApplication::sendEvent(canvas, &pressEvent);
702 QGuiApplication::sendEvent(canvas, &releaseEvent);
704 QCOMPARE(canvas->rootObject()->property("clicked").toInt(), 0);
705 QCOMPARE(canvas->rootObject()->property("doubleClicked").toInt(), 0);
706 QCOMPARE(canvas->rootObject()->property("released").toInt(), 0);
711 void tst_QQuickMouseArea::pressedOrdering()
713 QQuickView *canvas = createView();
714 canvas->setSource(testFileUrl("pressedOrdering.qml"));
716 canvas->requestActivateWindow();
717 QVERIFY(canvas->rootObject() != 0);
719 QCOMPARE(canvas->rootObject()->property("value").toString(), QLatin1String("base"));
721 QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
722 QGuiApplication::sendEvent(canvas, &pressEvent);
724 QCOMPARE(canvas->rootObject()->property("value").toString(), QLatin1String("pressed"));
726 QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0);
727 QGuiApplication::sendEvent(canvas, &releaseEvent);
729 QCOMPARE(canvas->rootObject()->property("value").toString(), QLatin1String("toggled"));
731 QGuiApplication::sendEvent(canvas, &pressEvent);
733 QCOMPARE(canvas->rootObject()->property("value").toString(), QLatin1String("pressed"));
738 void tst_QQuickMouseArea::preventStealing()
740 QQuickView *canvas = createView();
742 canvas->setSource(testFileUrl("preventstealing.qml"));
744 canvas->requestActivateWindow();
745 QVERIFY(canvas->rootObject() != 0);
747 QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(canvas->rootObject());
748 QVERIFY(flickable != 0);
750 QQuickMouseArea *mouseArea = canvas->rootObject()->findChild<QQuickMouseArea*>("mousearea");
751 QVERIFY(mouseArea != 0);
753 QSignalSpy mousePositionSpy(mouseArea, SIGNAL(positionChanged(QQuickMouseEvent*)));
755 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(80, 80));
757 // Without preventStealing, mouse movement over MouseArea would
758 // cause the Flickable to steal mouse and trigger content movement.
760 QTest::mouseMove(canvas,QPoint(69,69));
761 QTest::mouseMove(canvas,QPoint(58,58));
762 QTest::mouseMove(canvas,QPoint(47,47));
764 // We should have received all three move events
765 QCOMPARE(mousePositionSpy.count(), 3);
766 QVERIFY(mouseArea->pressed());
768 // Flickable content should not have moved.
769 QCOMPARE(flickable->contentX(), 0.);
770 QCOMPARE(flickable->contentY(), 0.);
772 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(47, 47));
774 // Now allow stealing and confirm Flickable does its thing.
775 canvas->rootObject()->setProperty("stealing", false);
777 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(80, 80));
779 // Without preventStealing, mouse movement over MouseArea would
780 // cause the Flickable to steal mouse and trigger content movement.
782 QTest::mouseMove(canvas,QPoint(69,69));
783 QTest::mouseMove(canvas,QPoint(58,58));
784 QTest::mouseMove(canvas,QPoint(47,47));
786 // We should only have received the first move event
787 QCOMPARE(mousePositionSpy.count(), 4);
788 // Our press should be taken away
789 QVERIFY(!mouseArea->pressed());
791 // Flickable content should have moved.
793 QCOMPARE(flickable->contentX(), 11.);
794 QCOMPARE(flickable->contentY(), 11.);
796 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(50, 50));
801 void tst_QQuickMouseArea::clickThrough()
803 QSKIP("QTBUG-23976 Unstable");
804 //With no handlers defined click, doubleClick and PressAndHold should propagate to those with handlers
805 QQuickView *canvas = createView();
806 canvas->setSource(testFileUrl("clickThrough.qml"));
808 canvas->requestActivateWindow();
809 QVERIFY(canvas->rootObject() != 0);
811 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(100,100));
812 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(100,100));
814 QTRY_COMPARE(canvas->rootObject()->property("presses").toInt(), 0);
815 QTRY_COMPARE(canvas->rootObject()->property("clicks").toInt(), 1);
817 // to avoid generating a double click.
818 int doubleClickInterval = qApp->styleHints()->mouseDoubleClickInterval() + 10;
819 QTest::qWait(doubleClickInterval);
821 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(100,100));
823 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(100,100));
825 QTRY_COMPARE(canvas->rootObject()->property("presses").toInt(), 0);
826 QTRY_COMPARE(canvas->rootObject()->property("clicks").toInt(), 1);
827 QTRY_COMPARE(canvas->rootObject()->property("pressAndHolds").toInt(), 1);
829 QTest::mouseDClick(canvas, Qt::LeftButton, 0, QPoint(100,100));
832 QCOMPARE(canvas->rootObject()->property("presses").toInt(), 0);
833 QTRY_COMPARE(canvas->rootObject()->property("clicks").toInt(), 2);
834 QTRY_COMPARE(canvas->rootObject()->property("doubleClicks").toInt(), 1);
835 QCOMPARE(canvas->rootObject()->property("pressAndHolds").toInt(), 1);
839 //With handlers defined click, doubleClick and PressAndHold should propagate only when explicitly ignored
840 canvas = createView();
841 canvas->setSource(testFileUrl("clickThrough2.qml"));
843 canvas->requestActivateWindow();
844 QVERIFY(canvas->rootObject() != 0);
846 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(100,100));
847 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(100,100));
849 QCOMPARE(canvas->rootObject()->property("presses").toInt(), 0);
850 QCOMPARE(canvas->rootObject()->property("clicks").toInt(), 0);
852 QTest::qWait(doubleClickInterval); // to avoid generating a double click.
854 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(100,100));
856 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(100,100));
859 QCOMPARE(canvas->rootObject()->property("presses").toInt(), 0);
860 QCOMPARE(canvas->rootObject()->property("clicks").toInt(), 0);
861 QCOMPARE(canvas->rootObject()->property("pressAndHolds").toInt(), 0);
863 QTest::mouseDClick(canvas, Qt::LeftButton, 0, QPoint(100,100));
866 QCOMPARE(canvas->rootObject()->property("presses").toInt(), 0);
867 QCOMPARE(canvas->rootObject()->property("clicks").toInt(), 0);
868 QCOMPARE(canvas->rootObject()->property("doubleClicks").toInt(), 0);
869 QCOMPARE(canvas->rootObject()->property("pressAndHolds").toInt(), 0);
871 canvas->rootObject()->setProperty("letThrough", QVariant(true));
873 QTest::qWait(doubleClickInterval); // to avoid generating a double click.
874 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(100,100));
875 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(100,100));
877 QCOMPARE(canvas->rootObject()->property("presses").toInt(), 0);
878 QTRY_COMPARE(canvas->rootObject()->property("clicks").toInt(), 1);
880 QTest::qWait(doubleClickInterval); // to avoid generating a double click.
881 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(100,100));
883 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(100,100));
886 QCOMPARE(canvas->rootObject()->property("presses").toInt(), 0);
887 QCOMPARE(canvas->rootObject()->property("clicks").toInt(), 1);
888 QCOMPARE(canvas->rootObject()->property("pressAndHolds").toInt(), 1);
890 QTest::mouseDClick(canvas, Qt::LeftButton, 0, QPoint(100,100));
893 QCOMPARE(canvas->rootObject()->property("presses").toInt(), 0);
894 QTRY_COMPARE(canvas->rootObject()->property("clicks").toInt(), 2);
895 QCOMPARE(canvas->rootObject()->property("doubleClicks").toInt(), 1);
896 QCOMPARE(canvas->rootObject()->property("pressAndHolds").toInt(), 1);
898 canvas->rootObject()->setProperty("noPropagation", QVariant(true));
900 QTest::qWait(doubleClickInterval); // to avoid generating a double click.
901 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(100,100));
902 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(100,100));
904 QTest::qWait(doubleClickInterval); // to avoid generating a double click.
905 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(100,100));
907 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(100,100));
910 QTest::mouseDClick(canvas, Qt::LeftButton, 0, QPoint(100,100));
913 QCOMPARE(canvas->rootObject()->property("presses").toInt(), 0);
914 QTRY_COMPARE(canvas->rootObject()->property("clicks").toInt(), 2);
915 QCOMPARE(canvas->rootObject()->property("doubleClicks").toInt(), 1);
916 QCOMPARE(canvas->rootObject()->property("pressAndHolds").toInt(), 1);
921 void tst_QQuickMouseArea::hoverPosition()
923 QQuickView *canvas = createView();
924 canvas->setSource(testFileUrl("hoverPosition.qml"));
926 QQuickItem *root = canvas->rootObject();
929 QCOMPARE(root->property("mouseX").toReal(), qreal(0));
930 QCOMPARE(root->property("mouseY").toReal(), qreal(0));
932 QTest::mouseMove(canvas,QPoint(10,32));
935 QCOMPARE(root->property("mouseX").toReal(), qreal(10));
936 QCOMPARE(root->property("mouseY").toReal(), qreal(32));
941 void tst_QQuickMouseArea::hoverPropagation()
943 //QTBUG-18175, to behave like GV did.
944 QQuickView *canvas = createView();
945 canvas->setSource(testFileUrl("hoverPropagation.qml"));
947 QQuickItem *root = canvas->rootObject();
950 QCOMPARE(root->property("point1").toBool(), false);
951 QCOMPARE(root->property("point2").toBool(), false);
953 QMouseEvent moveEvent(QEvent::MouseMove, QPoint(32, 32), Qt::NoButton, Qt::NoButton, 0);
954 QGuiApplication::sendEvent(canvas, &moveEvent);
956 QCOMPARE(root->property("point1").toBool(), true);
957 QCOMPARE(root->property("point2").toBool(), false);
959 QMouseEvent moveEvent2(QEvent::MouseMove, QPoint(232, 32), Qt::NoButton, Qt::NoButton, 0);
960 QGuiApplication::sendEvent(canvas, &moveEvent2);
961 QCOMPARE(root->property("point1").toBool(), false);
962 QCOMPARE(root->property("point2").toBool(), true);
967 void tst_QQuickMouseArea::hoverVisible()
969 QQuickView *canvas = createView();
970 canvas->setSource(testFileUrl("hoverVisible.qml"));
972 QQuickItem *root = canvas->rootObject();
975 QQuickMouseArea *mouseTracker = canvas->rootObject()->findChild<QQuickMouseArea*>("mousetracker");
976 QVERIFY(mouseTracker != 0);
978 QSignalSpy enteredSpy(mouseTracker, SIGNAL(entered()));
980 // Note: We need to use a position that is different from the position in the last event
981 // generated in the previous test case. Otherwise it is not interpreted as a move.
982 QTest::mouseMove(canvas,QPoint(11,33));
984 QCOMPARE(mouseTracker->hovered(), false);
985 QCOMPARE(enteredSpy.count(), 0);
987 mouseTracker->setVisible(true);
989 QCOMPARE(mouseTracker->hovered(), true);
990 QCOMPARE(enteredSpy.count(), 1);
992 QCOMPARE(QPointF(mouseTracker->mouseX(), mouseTracker->mouseY()), QPointF(11,33));
997 void tst_QQuickMouseArea::disableAfterPress()
999 QQuickView *canvas = createView();
1000 canvas->setSource(testFileUrl("dragging.qml"));
1002 canvas->requestActivateWindow();
1004 QVERIFY(canvas->rootObject() != 0);
1006 QQuickMouseArea *mouseArea = canvas->rootObject()->findChild<QQuickMouseArea*>("mouseregion");
1007 QQuickDrag *drag = mouseArea->drag();
1008 QVERIFY(mouseArea != 0);
1011 QSignalSpy mousePositionSpy(mouseArea, SIGNAL(positionChanged(QQuickMouseEvent*)));
1012 QSignalSpy mousePressSpy(mouseArea, SIGNAL(pressed(QQuickMouseEvent*)));
1013 QSignalSpy mouseReleaseSpy(mouseArea, SIGNAL(released(QQuickMouseEvent*)));
1016 QQuickItem *blackRect = canvas->rootObject()->findChild<QQuickItem*>("blackrect");
1017 QVERIFY(blackRect != 0);
1018 QVERIFY(blackRect == drag->target());
1020 QVERIFY(!drag->active());
1022 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(100,100));
1024 QTRY_COMPARE(mousePressSpy.count(), 1);
1026 QVERIFY(!drag->active());
1027 QCOMPARE(blackRect->x(), 50.0);
1028 QCOMPARE(blackRect->y(), 50.0);
1030 // First move event triggers drag, second is acted upon.
1031 // This is due to possibility of higher stacked area taking precedence.
1033 QTest::mouseMove(canvas, QPoint(111,111));
1035 QTest::mouseMove(canvas, QPoint(122,122));
1037 QTRY_COMPARE(mousePositionSpy.count(), 2);
1039 QVERIFY(drag->active());
1040 QCOMPARE(blackRect->x(), 72.0);
1041 QCOMPARE(blackRect->y(), 72.0);
1043 mouseArea->setEnabled(false);
1045 // move should still be acted upon
1046 QTest::mouseMove(canvas, QPoint(133,133));
1048 QTest::mouseMove(canvas, QPoint(144,144));
1050 QTRY_COMPARE(mousePositionSpy.count(), 4);
1052 QVERIFY(drag->active());
1053 QCOMPARE(blackRect->x(), 94.0);
1054 QCOMPARE(blackRect->y(), 94.0);
1056 QVERIFY(mouseArea->pressed());
1057 QVERIFY(mouseArea->hovered());
1059 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(144,144));
1061 QTRY_COMPARE(mouseReleaseSpy.count(), 1);
1063 QVERIFY(!drag->active());
1064 QCOMPARE(blackRect->x(), 94.0);
1065 QCOMPARE(blackRect->y(), 94.0);
1067 QVERIFY(!mouseArea->pressed());
1068 QVERIFY(!mouseArea->hovered()); // since hover is not enabled
1070 // Next press will be ignored
1071 blackRect->setX(50);
1072 blackRect->setY(50);
1074 mousePressSpy.clear();
1075 mousePositionSpy.clear();
1076 mouseReleaseSpy.clear();
1078 QTest::mousePress(canvas, Qt::LeftButton, 0, QPoint(100,100));
1080 QCOMPARE(mousePressSpy.count(), 0);
1082 QTest::mouseMove(canvas, QPoint(111,111));
1084 QTest::mouseMove(canvas, QPoint(122,122));
1087 QCOMPARE(mousePositionSpy.count(), 0);
1089 QVERIFY(!drag->active());
1090 QCOMPARE(blackRect->x(), 50.0);
1091 QCOMPARE(blackRect->y(), 50.0);
1093 QTest::mouseRelease(canvas, Qt::LeftButton, 0, QPoint(122,122));
1096 QCOMPARE(mouseReleaseSpy.count(), 0);
1101 void tst_QQuickMouseArea::onWheel()
1103 QQuickView *canvas = createView();
1104 canvas->setSource(testFileUrl("wheel.qml"));
1106 QQuickItem *root = canvas->rootObject();
1109 QWheelEvent wheelEvent(QPoint(10, 32), QPoint(10, 32), QPoint(60, 20), QPoint(0, 120),
1110 0, Qt::Vertical,Qt::NoButton, Qt::ControlModifier);
1111 QGuiApplication::sendEvent(canvas, &wheelEvent);
1113 QCOMPARE(root->property("angleDeltaY").toInt(), 120);
1114 QCOMPARE(root->property("mouseX").toReal(), qreal(10));
1115 QCOMPARE(root->property("mouseY").toReal(), qreal(32));
1116 QCOMPARE(root->property("controlPressed").toBool(), true);
1121 void tst_QQuickMouseArea::transformedMouseArea_data()
1123 QTest::addColumn<bool>("insideTarget");
1124 QTest::addColumn<QList<QPoint> >("points");
1126 QList<QPoint> pointsInside;
1127 pointsInside << QPoint(200, 140)
1131 << QPoint(200, 260);
1132 QTest::newRow("checking points inside") << true << pointsInside;
1134 QList<QPoint> pointsOutside;
1135 pointsOutside << QPoint(140, 140)
1140 << QPoint(260, 260);
1141 QTest::newRow("checking points outside") << false << pointsOutside;
1144 void tst_QQuickMouseArea::transformedMouseArea()
1146 QFETCH(bool, insideTarget);
1147 QFETCH(QList<QPoint>, points);
1149 QQuickView *canvas = createView();
1150 canvas->setSource(testFileUrl("transformedMouseArea.qml"));
1152 canvas->requestActivateWindow();
1153 QVERIFY(canvas->rootObject() != 0);
1155 QQuickMouseArea *mouseArea = canvas->rootObject()->findChild<QQuickMouseArea *>("mouseArea");
1156 QVERIFY(mouseArea != 0);
1158 foreach (const QPoint &point, points) {
1160 QTest::mouseMove(canvas, point);
1162 QCOMPARE(mouseArea->property("containsMouse").toBool(), insideTarget);
1164 // check mouse press
1165 QTest::mousePress(canvas, Qt::LeftButton, 0, point);
1167 QCOMPARE(mouseArea->property("pressed").toBool(), insideTarget);
1169 // check mouse release
1170 QTest::mouseRelease(canvas, Qt::LeftButton, 0, point);
1172 QCOMPARE(mouseArea->property("pressed").toBool(), false);
1178 QTEST_MAIN(tst_QQuickMouseArea)
1180 #include "tst_qquickmousearea.moc"