Initial import from the monolithic Qt.
[profile/ivi/qtdeclarative.git] / src / declarative / graphicsitems / qdeclarativemousearea.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "private/qdeclarativemousearea_p.h"
43 #include "private/qdeclarativemousearea_p_p.h"
44
45 #include "private/qdeclarativeevents_p_p.h"
46
47 #include <QGraphicsSceneMouseEvent>
48
49 #include <float.h>
50
51 QT_BEGIN_NAMESPACE
52 static const int PressAndHoldDelay = 800;
53
54 QDeclarativeDrag::QDeclarativeDrag(QObject *parent)
55 : QObject(parent), _target(0), _axis(XandYAxis), _xmin(-FLT_MAX), _xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX),
56 _active(false), _filterChildren(false)
57 {
58 }
59
60 QDeclarativeDrag::~QDeclarativeDrag()
61 {
62 }
63
64 QGraphicsObject *QDeclarativeDrag::target() const
65 {
66     return _target;
67 }
68
69 void QDeclarativeDrag::setTarget(QGraphicsObject *t)
70 {
71     if (_target == t)
72         return;
73     _target = t;
74     emit targetChanged();
75 }
76
77 void QDeclarativeDrag::resetTarget()
78 {
79     if (!_target)
80         return;
81     _target = 0;
82     emit targetChanged();
83 }
84
85 QDeclarativeDrag::Axis QDeclarativeDrag::axis() const
86 {
87     return _axis;
88 }
89
90 void QDeclarativeDrag::setAxis(QDeclarativeDrag::Axis a)
91 {
92     if (_axis == a)
93         return;
94     _axis = a;
95     emit axisChanged();
96 }
97
98 qreal QDeclarativeDrag::xmin() const
99 {
100     return _xmin;
101 }
102
103 void QDeclarativeDrag::setXmin(qreal m)
104 {
105     if (_xmin == m)
106         return;
107     _xmin = m;
108     emit minimumXChanged();
109 }
110
111 qreal QDeclarativeDrag::xmax() const
112 {
113     return _xmax;
114 }
115
116 void QDeclarativeDrag::setXmax(qreal m)
117 {
118     if (_xmax == m)
119         return;
120     _xmax = m;
121     emit maximumXChanged();
122 }
123
124 qreal QDeclarativeDrag::ymin() const
125 {
126     return _ymin;
127 }
128
129 void QDeclarativeDrag::setYmin(qreal m)
130 {
131     if (_ymin == m)
132         return;
133     _ymin = m;
134     emit minimumYChanged();
135 }
136
137 qreal QDeclarativeDrag::ymax() const
138 {
139     return _ymax;
140 }
141
142 void QDeclarativeDrag::setYmax(qreal m)
143 {
144     if (_ymax == m)
145         return;
146     _ymax = m;
147     emit maximumYChanged();
148 }
149
150 bool QDeclarativeDrag::active() const
151 {
152     return _active;
153 }
154
155 void QDeclarativeDrag::setActive(bool drag)
156 {
157     if (_active == drag)
158         return;
159     _active = drag;
160     emit activeChanged();
161 }
162
163 bool QDeclarativeDrag::filterChildren() const
164 {
165     return _filterChildren;
166 }
167
168 void QDeclarativeDrag::setFilterChildren(bool filter)
169 {
170     if (_filterChildren == filter)
171         return;
172     _filterChildren = filter;
173     emit filterChildrenChanged();
174 }
175
176 QDeclarativeMouseAreaPrivate::~QDeclarativeMouseAreaPrivate()
177 {
178     delete drag;
179 }
180
181 /*!
182     \qmlclass MouseArea QDeclarativeMouseArea
183     \ingroup qml-basic-interaction-elements
184     \since 4.7
185     \brief The MouseArea item enables simple mouse handling.
186     \inherits Item
187
188     A MouseArea is an invisible item that is typically used in conjunction with
189     a visible item in order to provide mouse handling for that item.
190     By effectively acting as a proxy, the logic for mouse handling can be
191     contained within a MouseArea item.
192
193     For basic key handling, see the \l{Keys}{Keys attached property}.
194
195     The \l enabled property is used to enable and disable mouse handling for
196     the proxied item. When disabled, the mouse area becomes transparent to
197     mouse events.
198
199     The \l pressed read-only property indicates whether or not the user is
200     holding down a mouse button over the mouse area. This property is often
201     used in bindings between properties in a user interface. The containsMouse
202     read-only property indicates the presence of the mouse cursor over the
203     mouse area but, by default, only when a mouse button is held down; see below
204     for further details.
205
206     Information about the mouse position and button clicks are provided via
207     signals for which event handler properties are defined. The most commonly
208     used involved handling mouse presses and clicks: onClicked, onDoubleClicked,
209     onPressed, onReleased and onPressAndHold.
210
211     By default, MouseArea items only report mouse clicks and not changes to the
212     position of the mouse cursor. Setting the hoverEnabled property ensures that
213     handlers defined for onPositionChanged, onEntered and onExited are used and
214     that the containsMouse property is updated even when no mouse buttons are
215     pressed.
216
217     \section1 Example Usage
218
219     \div {class="float-right"}
220     \inlineimage qml-mousearea-snippet.png
221     \enddiv
222
223     The following example uses a MouseArea in a \l Rectangle that changes
224     the \l Rectangle color to red when clicked:
225
226     \snippet doc/src/snippets/declarative/mousearea/mousearea.qml import
227     \codeline
228     \snippet doc/src/snippets/declarative/mousearea/mousearea.qml intro
229
230     \clearfloat
231     Many MouseArea signals pass a \l{MouseEvent}{mouse} parameter that contains
232     additional information about the mouse event, such as the position, button,
233     and any key modifiers.
234
235     Here is an extension of the previous example that produces a different
236     color when the area is right clicked:
237
238     \snippet doc/src/snippets/declarative/mousearea/mousearea.qml intro-extended
239
240     \sa MouseEvent, {declarative/touchinteraction/mousearea}{MouseArea example}
241 */
242
243 /*!
244     \qmlsignal MouseArea::onEntered()
245
246     This handler is called when the mouse enters the mouse area.
247
248     By default the onEntered handler is only called while a button is
249     pressed. Setting hoverEnabled to true enables handling of
250     onEntered when no mouse button is pressed.
251
252     \sa hoverEnabled
253 */
254
255 /*!
256     \qmlsignal MouseArea::onExited()
257
258     This handler is called when the mouse exists the mouse area.
259
260     By default the onExited handler is only called while a button is
261     pressed. Setting hoverEnabled to true enables handling of
262     onExited when no mouse button is pressed.
263
264     \sa hoverEnabled
265 */
266
267 /*!
268     \qmlsignal MouseArea::onPositionChanged(MouseEvent mouse)
269
270     This handler is called when the mouse position changes.
271
272     The \l {MouseEvent}{mouse} parameter provides information about the mouse, including the x and y
273     position, and any buttons currently pressed.
274
275     The \e accepted property of the MouseEvent parameter is ignored in this handler.
276
277     By default the onPositionChanged handler is only called while a button is
278     pressed.  Setting hoverEnabled to true enables handling of
279     onPositionChanged when no mouse button is pressed.
280 */
281
282 /*!
283     \qmlsignal MouseArea::onClicked(MouseEvent mouse)
284
285     This handler is called when there is a click. A click is defined as a press followed by a release,
286     both inside the MouseArea (pressing, moving outside the MouseArea, and then moving back inside and
287     releasing is also considered a click).
288
289     The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
290     position of the release of the click, and whether the click was held.
291
292     The \e accepted property of the MouseEvent parameter is ignored in this handler.
293 */
294
295 /*!
296     \qmlsignal MouseArea::onPressed(MouseEvent mouse)
297
298     This handler is called when there is a press.
299     The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
300     position and which button was pressed.
301
302     The \e accepted property of the MouseEvent parameter determines whether this MouseArea
303     will handle the press and all future mouse events until release.  The default is to accept
304     the event and not allow other MouseArea beneath this one to handle the event.  If \e accepted
305     is set to false, no further events will be sent to this MouseArea until the button is next
306     pressed.
307 */
308
309 /*!
310     \qmlsignal MouseArea::onReleased(MouseEvent mouse)
311
312     This handler is called when there is a release.
313     The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
314     position of the release of the click, and whether the click was held.
315
316     The \e accepted property of the MouseEvent parameter is ignored in this handler.
317
318     \sa onCanceled
319 */
320
321 /*!
322     \qmlsignal MouseArea::onPressAndHold(MouseEvent mouse)
323
324     This handler is called when there is a long press (currently 800ms).
325     The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
326     position of the press, and which button is pressed.
327
328     The \e accepted property of the MouseEvent parameter is ignored in this handler.
329 */
330
331 /*!
332     \qmlsignal MouseArea::onDoubleClicked(MouseEvent mouse)
333
334     This handler is called when there is a double-click (a press followed by a release followed by a press).
335     The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
336     position of the release of the click, and whether the click was held.
337
338     If the \e accepted property of the \l {MouseEvent}{mouse} parameter is set to false
339     in the handler, the onPressed/onReleased/onClicked handlers will be called for the second
340     click; otherwise they are suppressed.  The accepted property defaults to true.
341 */
342
343 /*!
344     \qmlsignal MouseArea::onCanceled()
345
346     This handler is called when mouse events have been canceled, either because an event was not accepted, or
347     because another element stole the mouse event handling.
348
349     This signal is for advanced use: it is useful when there is more than one MouseArea
350     that is handling input, or when there is a MouseArea inside a \l Flickable. In the latter
351     case, if you execute some logic on the pressed signal and then start dragging, the
352     \l Flickable will steal the mouse handling from the MouseArea. In these cases, to reset
353     the logic when the MouseArea has lost the mouse handling to the \l Flickable,
354     \c onCanceled should be used in addition to onReleased.
355 */
356
357 QDeclarativeMouseArea::QDeclarativeMouseArea(QDeclarativeItem *parent)
358   : QDeclarativeItem(*(new QDeclarativeMouseAreaPrivate), parent)
359 {
360     Q_D(QDeclarativeMouseArea);
361     d->init();
362 }
363
364 QDeclarativeMouseArea::~QDeclarativeMouseArea()
365 {
366 }
367
368 /*!
369     \qmlproperty real MouseArea::mouseX
370     \qmlproperty real MouseArea::mouseY
371     These properties hold the coordinates of the mouse cursor.
372
373     If the hoverEnabled property is false then these properties will only be valid
374     while a button is pressed, and will remain valid as long as the button is held
375     down even if the mouse is moved outside the area.
376
377     By default, this property is false.
378
379     If hoverEnabled is true then these properties will be valid when:
380     \list
381         \i no button is pressed, but the mouse is within the MouseArea (containsMouse is true).
382         \i a button is pressed and held, even if it has since moved out of the area.
383     \endlist
384
385     The coordinates are relative to the MouseArea.
386 */
387 qreal QDeclarativeMouseArea::mouseX() const
388 {
389     Q_D(const QDeclarativeMouseArea);
390     return d->lastPos.x();
391 }
392
393 qreal QDeclarativeMouseArea::mouseY() const
394 {
395     Q_D(const QDeclarativeMouseArea);
396     return d->lastPos.y();
397 }
398
399 /*!
400     \qmlproperty bool MouseArea::enabled
401     This property holds whether the item accepts mouse events.
402
403     By default, this property is true.
404 */
405 bool QDeclarativeMouseArea::isEnabled() const
406 {
407     Q_D(const QDeclarativeMouseArea);
408     return d->absorb;
409 }
410
411 void QDeclarativeMouseArea::setEnabled(bool a)
412 {
413     Q_D(QDeclarativeMouseArea);
414     if (a != d->absorb) {
415         d->absorb = a;
416         emit enabledChanged();
417     }
418 }
419
420 /*!
421     \qmlproperty bool MouseArea::preventStealing
422     \since Quick 1.1
423     This property holds whether the mouse events may be stolen from this
424     MouseArea.
425
426     If a MouseArea is placed within an item that filters child mouse
427     events, such as Flickable, the mouse
428     events may be stolen from the MouseArea if a gesture is recognized
429     by the parent element, e.g. a flick gesture.  If preventStealing is
430     set to true, no element will steal the mouse events.
431
432     Note that setting preventStealing to true once an element has started
433     stealing events will have no effect until the next press event.
434
435     By default this property is false.
436 */
437 bool QDeclarativeMouseArea::preventStealing() const
438 {
439     Q_D(const QDeclarativeMouseArea);
440     return d->preventStealing;
441 }
442
443 void QDeclarativeMouseArea::setPreventStealing(bool prevent)
444 {
445     Q_D(QDeclarativeMouseArea);
446     if (prevent != d->preventStealing) {
447         d->preventStealing = prevent;
448         setKeepMouseGrab(d->preventStealing && d->absorb);
449         emit preventStealingChanged();
450     }
451 }
452
453 /*!
454     \qmlproperty MouseButtons MouseArea::pressedButtons
455     This property holds the mouse buttons currently pressed.
456
457     It contains a bitwise combination of:
458     \list
459     \o Qt.LeftButton
460     \o Qt.RightButton
461     \o Qt.MiddleButton
462     \endlist
463
464     The code below displays "right" when the right mouse buttons is pressed:
465
466     \snippet doc/src/snippets/declarative/mousearea/mousearea.qml mousebuttons
467
468     \sa acceptedButtons
469 */
470 Qt::MouseButtons QDeclarativeMouseArea::pressedButtons() const
471 {
472     Q_D(const QDeclarativeMouseArea);
473     return d->lastButtons;
474 }
475
476 void QDeclarativeMouseArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
477 {
478     Q_D(QDeclarativeMouseArea);
479     d->moved = false;
480     d->stealMouse = d->preventStealing;
481     if (!d->absorb)
482         QDeclarativeItem::mousePressEvent(event);
483     else {
484         d->longPress = false;
485         d->saveEvent(event);
486         if (d->drag) {
487             d->dragX = drag()->axis() & QDeclarativeDrag::XAxis;
488             d->dragY = drag()->axis() & QDeclarativeDrag::YAxis;
489         }
490         if (d->drag)
491             d->drag->setActive(false);
492         setHovered(true);
493         d->startScene = event->scenePos();
494         // we should only start timer if pressAndHold is connected to.
495         if (d->isPressAndHoldConnected())
496             d->pressAndHoldTimer.start(PressAndHoldDelay, this);
497         setKeepMouseGrab(d->stealMouse);
498         event->setAccepted(setPressed(true));
499
500         if(!event->isAccepted() && d->forwardToList.count())
501            d->forwardEvent(event);
502     }
503 }
504
505 void QDeclarativeMouseArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
506 {
507     Q_D(QDeclarativeMouseArea);
508     if (!d->absorb) {
509         QDeclarativeItem::mouseMoveEvent(event);
510         return;
511     }
512
513     d->saveEvent(event);
514
515     // ### we should skip this if these signals aren't used
516     // ### can GV handle this for us?
517     bool contains = boundingRect().contains(d->lastPos);
518     if (d->hovered && !contains)
519         setHovered(false);
520     else if (!d->hovered && contains)
521         setHovered(true);
522
523     if (d->drag && d->drag->target()) {
524         if (!d->moved) {
525             d->startX = drag()->target()->x();
526             d->startY = drag()->target()->y();
527         }
528
529         QPointF startLocalPos;
530         QPointF curLocalPos;
531         if (drag()->target()->parentItem()) {
532             startLocalPos = drag()->target()->parentItem()->mapFromScene(d->startScene);
533             curLocalPos = drag()->target()->parentItem()->mapFromScene(event->scenePos());
534         } else {
535             startLocalPos = d->startScene;
536             curLocalPos = event->scenePos();
537         }
538
539         const int dragThreshold = QApplication::startDragDistance();
540         qreal dx = qAbs(curLocalPos.x() - startLocalPos.x());
541         qreal dy = qAbs(curLocalPos.y() - startLocalPos.y());
542
543         if (keepMouseGrab() && d->stealMouse)
544             d->drag->setActive(true);
545
546         if (d->dragX && d->drag->active()) {
547             qreal x = (curLocalPos.x() - startLocalPos.x()) + d->startX;
548             if (x < drag()->xmin())
549                 x = drag()->xmin();
550             else if (x > drag()->xmax())
551                 x = drag()->xmax();
552             drag()->target()->setX(x);
553         }
554         if (d->dragY && d->drag->active()) {
555             qreal y = (curLocalPos.y() - startLocalPos.y()) + d->startY;
556             if (y < drag()->ymin())
557                 y = drag()->ymin();
558             else if (y > drag()->ymax())
559                 y = drag()->ymax();
560             drag()->target()->setY(y);
561         }
562
563         if (!keepMouseGrab()) {
564             if ((!d->dragY && dy < dragThreshold && d->dragX && dx > dragThreshold)
565                 || (!d->dragX && dx < dragThreshold && d->dragY && dy > dragThreshold)
566                 || (d->dragX && d->dragY && (dx > dragThreshold || dy > dragThreshold))) {
567                 setKeepMouseGrab(true);
568                 d->stealMouse = true;
569             }
570         }
571
572         d->moved = true;
573     }
574     QDeclarativeMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
575     emit mousePositionChanged(&me);
576     me.setX(d->lastPos.x());
577     me.setY(d->lastPos.y());
578     emit positionChanged(&me);
579
580     if(!event->isAccepted() && d->forwardToList.count())
581         d->forwardEvent(event);
582 }
583
584
585 void QDeclarativeMouseArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
586 {
587     Q_D(QDeclarativeMouseArea);
588     d->stealMouse = false;
589     if (!d->absorb) {
590         QDeclarativeItem::mouseReleaseEvent(event);
591     } else {
592         d->saveEvent(event);
593         setPressed(false);
594         if (d->drag)
595             d->drag->setActive(false);
596         // If we don't accept hover, we need to reset containsMouse.
597         if (!acceptHoverEvents())
598             setHovered(false);
599         QGraphicsScene *s = scene();
600         if (s && s->mouseGrabberItem() == this)
601             ungrabMouse();
602         setKeepMouseGrab(false);
603
604         if(!event->isAccepted() && d->forwardToList.count())
605             d->forwardEvent(event);
606     }
607     d->doubleClick = false;
608 }
609
610 void QDeclarativeMouseArea::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
611 {
612     Q_D(QDeclarativeMouseArea);
613     if (!d->absorb) {
614         QDeclarativeItem::mouseDoubleClickEvent(event);
615     } else {
616         if (d->isDoubleClickConnected())
617             d->doubleClick = true;
618         d->saveEvent(event);
619         QDeclarativeMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false);
620         me.setAccepted(d->isDoubleClickConnected());
621         emit this->doubleClicked(&me);
622         QDeclarativeItem::mouseDoubleClickEvent(event);
623     }
624 }
625
626 void QDeclarativeMouseArea::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
627 {
628     Q_D(QDeclarativeMouseArea);
629     if (!d->absorb)
630         QDeclarativeItem::hoverEnterEvent(event);
631     else {
632         d->lastPos = event->pos();
633         setHovered(true);
634         QDeclarativeMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, event->modifiers(), false, false);
635         emit mousePositionChanged(&me);
636     }
637 }
638
639 void QDeclarativeMouseArea::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
640 {
641     Q_D(QDeclarativeMouseArea);
642     if (!d->absorb) {
643         QDeclarativeItem::hoverMoveEvent(event);
644     } else {
645         d->lastPos = event->pos();
646         QDeclarativeMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, event->modifiers(), false, false);
647         emit mousePositionChanged(&me);
648         me.setX(d->lastPos.x());
649         me.setY(d->lastPos.y());
650         emit positionChanged(&me);
651     }
652 }
653
654 void QDeclarativeMouseArea::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
655 {
656     Q_D(QDeclarativeMouseArea);
657     if (!d->absorb)
658         QDeclarativeItem::hoverLeaveEvent(event);
659     else
660         setHovered(false);
661 }
662
663 bool QDeclarativeMouseArea::sceneEvent(QEvent *event)
664 {
665     bool rv = QDeclarativeItem::sceneEvent(event);
666     if (event->type() == QEvent::UngrabMouse) {
667         Q_D(QDeclarativeMouseArea);
668         if (d->pressed) {
669             // if our mouse grab has been removed (probably by Flickable), fix our
670             // state
671             d->pressed = false;
672             d->stealMouse = false;
673             setKeepMouseGrab(false);
674             emit canceled();
675             emit pressedChanged();
676             if (d->hovered) {
677                 d->hovered = false;
678                 emit hoveredChanged();
679             }
680         }
681     }
682     return rv;
683 }
684
685 bool QDeclarativeMouseArea::sendMouseEvent(QGraphicsSceneMouseEvent *event)
686 {
687     Q_D(QDeclarativeMouseArea);
688     QGraphicsSceneMouseEvent mouseEvent(event->type());
689     QRectF myRect = mapToScene(QRectF(0, 0, width(), height())).boundingRect();
690
691     QGraphicsScene *s = scene();
692     QDeclarativeItem *grabber = s ? qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem()) : 0;
693     bool stealThisEvent = d->stealMouse;
694     if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
695         mouseEvent.setAccepted(false);
696         for (int i = 0x1; i <= 0x10; i <<= 1) {
697             if (event->buttons() & i) {
698                 Qt::MouseButton button = Qt::MouseButton(i);
699                 mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
700             }
701         }
702         mouseEvent.setScenePos(event->scenePos());
703         mouseEvent.setLastScenePos(event->lastScenePos());
704         mouseEvent.setPos(mapFromScene(event->scenePos()));
705         mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
706
707         switch(mouseEvent.type()) {
708         case QEvent::GraphicsSceneMouseMove:
709             mouseMoveEvent(&mouseEvent);
710             break;
711         case QEvent::GraphicsSceneMousePress:
712             mousePressEvent(&mouseEvent);
713             break;
714         case QEvent::GraphicsSceneMouseRelease:
715             mouseReleaseEvent(&mouseEvent);
716             break;
717         default:
718             break;
719         }
720         grabber = qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem());
721         if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
722             grabMouse();
723
724         return stealThisEvent;
725     }
726     if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
727         if (d->pressed) {
728             d->pressed = false;
729             d->stealMouse = false;
730             if (s && s->mouseGrabberItem() == this)
731                 ungrabMouse();
732             emit canceled();
733             emit pressedChanged();
734             if (d->hovered) {
735                 d->hovered = false;
736                 emit hoveredChanged();
737             }
738         }
739     }
740     return false;
741 }
742
743 bool QDeclarativeMouseArea::sceneEventFilter(QGraphicsItem *i, QEvent *e)
744 {
745     Q_D(QDeclarativeMouseArea);
746     if (!d->absorb || !isVisible() || !d->drag || !d->drag->filterChildren())
747         return QDeclarativeItem::sceneEventFilter(i, e);
748     switch (e->type()) {
749     case QEvent::GraphicsSceneMousePress:
750     case QEvent::GraphicsSceneMouseMove:
751     case QEvent::GraphicsSceneMouseRelease:
752         return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
753     default:
754         break;
755     }
756
757     return QDeclarativeItem::sceneEventFilter(i, e);
758 }
759
760 void QDeclarativeMouseArea::timerEvent(QTimerEvent *event)
761 {
762     Q_D(QDeclarativeMouseArea);
763     if (event->timerId() == d->pressAndHoldTimer.timerId()) {
764         d->pressAndHoldTimer.stop();
765         bool dragged = d->drag && d->drag->active();
766         if (d->pressed && dragged == false && d->hovered == true) {
767             d->longPress = true;
768             QDeclarativeMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
769             emit pressAndHold(&me);
770         }
771     }
772 }
773
774 void QDeclarativeMouseArea::geometryChanged(const QRectF &newGeometry,
775                                             const QRectF &oldGeometry)
776 {
777     Q_D(QDeclarativeMouseArea);
778     QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
779
780     if (d->lastScenePos.isNull)
781         d->lastScenePos = mapToScene(d->lastPos);
782     else if (newGeometry.x() != oldGeometry.x() || newGeometry.y() != oldGeometry.y())
783         d->lastPos = mapFromScene(d->lastScenePos);
784 }
785
786 QVariant QDeclarativeMouseArea::itemChange(GraphicsItemChange change,
787                                        const QVariant &value)
788 {
789     Q_D(QDeclarativeMouseArea);
790     switch (change) {
791     case ItemVisibleHasChanged:
792         if (acceptHoverEvents() && d->hovered != (isVisible() && isUnderMouse()))
793             setHovered(!d->hovered);
794         break;
795     default:
796         break;
797     }
798
799     return QDeclarativeItem::itemChange(change, value);
800 }
801
802 /*!
803     \qmlproperty bool MouseArea::hoverEnabled
804     This property holds whether hover events are handled.
805
806     By default, mouse events are only handled in response to a button event, or when a button is
807     pressed.  Hover enables handling of all mouse events even when no mouse button is
808     pressed.
809
810     This property affects the containsMouse property and the onEntered, onExited and
811     onPositionChanged signals.
812 */
813 bool QDeclarativeMouseArea::hoverEnabled() const
814 {
815     return acceptHoverEvents();
816 }
817
818 void QDeclarativeMouseArea::setHoverEnabled(bool h)
819 {
820     Q_D(QDeclarativeMouseArea);
821     if (h == acceptHoverEvents())
822         return;
823
824     setAcceptHoverEvents(h);
825     emit hoverEnabledChanged();
826     if (d->hovered != isUnderMouse())
827         setHovered(!d->hovered);
828 }
829
830 /*!
831     \qmlproperty bool MouseArea::containsMouse
832     This property holds whether the mouse is currently inside the mouse area.
833
834     \warning This property is not updated if the area moves under the mouse: \e containsMouse will not change.
835     In addition, if hoverEnabled is false, containsMouse will only be valid when the mouse is pressed.
836 */
837 bool QDeclarativeMouseArea::hovered() const
838 {
839     Q_D(const QDeclarativeMouseArea);
840     return d->hovered;
841 }
842
843 /*!
844     \qmlproperty bool MouseArea::pressed
845     This property holds whether the mouse area is currently pressed.
846 */
847 bool QDeclarativeMouseArea::pressed() const
848 {
849     Q_D(const QDeclarativeMouseArea);
850     return d->pressed;
851 }
852
853 void QDeclarativeMouseArea::setHovered(bool h)
854 {
855     Q_D(QDeclarativeMouseArea);
856     if (d->hovered != h) {
857         d->hovered = h;
858         emit hoveredChanged();
859         d->hovered ? emit entered() : emit exited();
860     }
861 }
862
863 /*!
864     \qmlproperty Qt::MouseButtons MouseArea::acceptedButtons
865     This property holds the mouse buttons that the mouse area reacts to.
866
867     The available buttons are:
868     \list
869     \o Qt.LeftButton
870     \o Qt.RightButton
871     \o Qt.MiddleButton
872     \endlist
873
874     To accept more than one button the flags can be combined with the
875     "|" (or) operator:
876
877     \code
878     MouseArea { acceptedButtons: Qt.LeftButton | Qt.RightButton }
879     \endcode
880
881     The default value is \c Qt.LeftButton.
882 */
883 Qt::MouseButtons QDeclarativeMouseArea::acceptedButtons() const
884 {
885     return acceptedMouseButtons();
886 }
887
888 void QDeclarativeMouseArea::setAcceptedButtons(Qt::MouseButtons buttons)
889 {
890     if (buttons != acceptedMouseButtons()) {
891         setAcceptedMouseButtons(buttons);
892         emit acceptedButtonsChanged();
893     }
894 }
895
896 bool QDeclarativeMouseArea::setPressed(bool p)
897 {
898     Q_D(QDeclarativeMouseArea);
899     bool dragged = d->drag && d->drag->active();
900     bool isclick = d->pressed == true && p == false && dragged == false && d->hovered == true;
901
902     if (d->pressed != p) {
903         d->pressed = p;
904         QDeclarativeMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
905         if (d->pressed) {
906             if (!d->doubleClick)
907                 emit pressed(&me);
908             me.setX(d->lastPos.x());
909             me.setY(d->lastPos.y());
910             emit mousePositionChanged(&me);
911             emit pressedChanged();
912         } else {
913             emit released(&me);
914             me.setX(d->lastPos.x());
915             me.setY(d->lastPos.y());
916             emit pressedChanged();
917             if (isclick && !d->longPress && !d->doubleClick)
918                 emit clicked(&me);
919         }
920
921         return me.isAccepted();
922     }
923     return false;
924 }
925
926 QDeclarativeDrag *QDeclarativeMouseArea::drag()
927 {
928     Q_D(QDeclarativeMouseArea);
929     if (!d->drag)
930         d->drag = new QDeclarativeDrag;
931     return d->drag;
932 }
933
934 /*!
935     \qmlproperty Item MouseArea::drag.target
936     \qmlproperty bool MouseArea::drag.active
937     \qmlproperty enumeration MouseArea::drag.axis
938     \qmlproperty real MouseArea::drag.minimumX
939     \qmlproperty real MouseArea::drag.maximumX
940     \qmlproperty real MouseArea::drag.minimumY
941     \qmlproperty real MouseArea::drag.maximumY
942     \qmlproperty bool MouseArea::drag.filterChildren
943
944     \c drag provides a convenient way to make an item draggable.
945
946     \list
947     \i \c drag.target specifies the id of the item to drag.
948     \i \c drag.active specifies if the target item is currently being dragged.
949     \i \c drag.axis specifies whether dragging can be done horizontally (\c Drag.XAxis), vertically (\c Drag.YAxis), or both (\c Drag.XandYAxis)
950     \i \c drag.minimum and \c drag.maximum limit how far the target can be dragged along the corresponding axes.
951     \endlist
952
953     The following example displays a \l Rectangle that can be dragged along the X-axis. The opacity
954     of the rectangle is reduced when it is dragged to the right.
955
956     \snippet doc/src/snippets/declarative/mousearea/mousearea.qml drag
957
958     \note Items cannot be dragged if they are anchored for the requested 
959     \c drag.axis. For example, if \c anchors.left or \c anchors.right was set
960     for \c rect in the above example, it cannot be dragged along the X-axis.
961     This can be avoided by settng the anchor value to \c undefined in 
962     an \l onPressed handler.
963
964     If \c drag.filterChildren is set to true, a drag can override descendant MouseAreas.  This
965     enables a parent MouseArea to handle drags, for example, while descendants handle clicks:
966
967     \snippet doc/src/snippets/declarative/mousearea/mouseareadragfilter.qml dragfilter
968
969 */
970
971 QDeclarativeListProperty<QGraphicsObject> QDeclarativeMouseArea::forwardTo()
972 {
973     Q_D(QDeclarativeMouseArea);
974     return d->forwardTo;
975 }
976
977
978 QT_END_NAMESPACE