Rename WebKitTools to Tools
[WebKit-https.git] / Tools / DumpRenderTree / qt / EventSenderQt.cpp
1 /*
2  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
3  * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 #include "config.h"
30 #include "EventSenderQt.h"
31
32 #include <QGraphicsSceneMouseEvent>
33 #include <QtTest/QtTest>
34
35 #define KEYCODE_DEL         127
36 #define KEYCODE_BACKSPACE   8
37 #define KEYCODE_LEFTARROW   0xf702
38 #define KEYCODE_RIGHTARROW  0xf703
39 #define KEYCODE_UPARROW     0xf700
40 #define KEYCODE_DOWNARROW   0xf701
41
42 // Ports like Gtk and Windows expose a different approach for their zooming
43 // API if compared to Qt: they have specific methods for zooming in and out,
44 // as well as a settable zoom factor, while Qt has only a 'setZoomValue' method.
45 // Hence Qt DRT adopts a fixed zoom-factor (1.2) for compatibility.
46 #define ZOOM_STEP           1.2
47
48 #define DRT_MESSAGE_DONE (QEvent::User + 1)
49
50 struct DRTEventQueue {
51     QEvent* m_event;
52     int m_delay;
53 };
54
55 static DRTEventQueue eventQueue[1024];
56 static unsigned endOfQueue;
57 static unsigned startOfQueue;
58
59 EventSender::EventSender(QWebPage* parent)
60     : QObject(parent)
61 {
62     m_page = parent;
63     m_mouseButtonPressed = false;
64     m_drag = false;
65     memset(eventQueue, 0, sizeof(eventQueue));
66     endOfQueue = 0;
67     startOfQueue = 0;
68     m_eventLoop = 0;
69     m_currentButton = 0;
70     resetClickCount();
71     m_page->view()->installEventFilter(this);
72     // So that we can match Scrollbar::pixelsPerLineStep() in WheelEventQt.cpp and
73     // pass fast/events/platform-wheelevent-in-scrolling-div.html
74     QApplication::setWheelScrollLines(2);
75 }
76
77 void EventSender::mouseDown(int button)
78 {
79     Qt::MouseButton mouseButton;
80     switch (button) {
81     case 0:
82         mouseButton = Qt::LeftButton;
83         break;
84     case 1:
85         mouseButton = Qt::MidButton;
86         break;
87     case 2:
88         mouseButton = Qt::RightButton;
89         break;
90     case 3:
91         // fast/events/mouse-click-events expects the 4th button to be treated as the middle button
92         mouseButton = Qt::MidButton;
93         break;
94     default:
95         mouseButton = Qt::LeftButton;
96         break;
97     }
98
99     // only consider a click to count, an event originated by the
100     // same previous button and at the same position.
101     if (m_currentButton == button
102         && m_mousePos == m_clickPos
103         && m_clickTimer.isActive())
104         m_clickCount++;
105     else
106         m_clickCount = 1;
107
108     m_currentButton = button;
109     m_clickPos = m_mousePos;
110     m_mouseButtons |= mouseButton;
111
112 //     qDebug() << "EventSender::mouseDown" << frame;
113     QEvent* event;
114     if (isGraphicsBased()) {
115         event = createGraphicsSceneMouseEvent((m_clickCount == 2) ?
116                     QEvent::GraphicsSceneMouseDoubleClick : QEvent::GraphicsSceneMousePress,
117                     m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier);
118     } else {
119         event = new QMouseEvent((m_clickCount == 2) ? QEvent::MouseButtonDblClick :
120                     QEvent::MouseButtonPress, m_mousePos, m_mousePos,
121                     mouseButton, m_mouseButtons, Qt::NoModifier);
122     }
123
124     sendOrQueueEvent(event);
125
126     m_clickTimer.start(QApplication::doubleClickInterval(), this);
127 }
128
129 void EventSender::mouseUp(int button)
130 {
131     Qt::MouseButton mouseButton;
132     switch (button) {
133     case 0:
134         mouseButton = Qt::LeftButton;
135         break;
136     case 1:
137         mouseButton = Qt::MidButton;
138         break;
139     case 2:
140         mouseButton = Qt::RightButton;
141         break;
142     case 3:
143         // fast/events/mouse-click-events expects the 4th button to be treated as the middle button
144         mouseButton = Qt::MidButton;
145         break;
146     default:
147         mouseButton = Qt::LeftButton;
148         break;
149     }
150
151     m_mouseButtons &= ~mouseButton;
152
153 //     qDebug() << "EventSender::mouseUp" << frame;
154     QEvent* event;
155     if (isGraphicsBased()) {
156         event = createGraphicsSceneMouseEvent(QEvent::GraphicsSceneMouseRelease,
157                     m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier);
158     } else {
159         event = new QMouseEvent(QEvent::MouseButtonRelease,
160                     m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier);
161     }
162
163     sendOrQueueEvent(event);
164 }
165
166 void EventSender::mouseMoveTo(int x, int y)
167 {
168 //     qDebug() << "EventSender::mouseMoveTo" << x << y;
169     m_mousePos = QPoint(x, y);
170
171     QEvent* event;
172     if (isGraphicsBased()) {
173         event = createGraphicsSceneMouseEvent(QEvent::GraphicsSceneMouseMove,
174                     m_mousePos, m_mousePos, Qt::NoButton, m_mouseButtons, Qt::NoModifier);
175     } else {
176         event = new QMouseEvent(QEvent::MouseMove,
177                     m_mousePos, m_mousePos, Qt::NoButton, m_mouseButtons, Qt::NoModifier);
178     }
179
180     sendOrQueueEvent(event);
181 }
182
183 #ifndef QT_NO_WHEELEVENT
184 void EventSender::mouseScrollBy(int x, int y)
185 {
186     continuousMouseScrollBy((x*120), (y*120));
187 }
188
189 void EventSender::continuousMouseScrollBy(int x, int y)
190 {
191     // continuousMouseScrollBy() mimics devices that send fine-grained scroll events where the 'delta' specified is not the usual
192     // multiple of 120. See http://doc.qt.nokia.com/4.6/qwheelevent.html#delta for a good explanation of this.
193     if (x) {
194         QEvent* event;
195         if (isGraphicsBased()) {
196             event = createGraphicsSceneWheelEvent(QEvent::GraphicsSceneWheel,
197                         m_mousePos, m_mousePos, x, Qt::NoModifier, Qt::Horizontal);
198         } else
199             event = new QWheelEvent(m_mousePos, m_mousePos, x, m_mouseButtons, Qt::NoModifier, Qt::Horizontal);
200
201         sendOrQueueEvent(event);
202     }
203     if (y) {
204         QEvent* event;
205         if (isGraphicsBased()) {
206             event = createGraphicsSceneWheelEvent(QEvent::GraphicsSceneWheel,
207                         m_mousePos, m_mousePos, y, Qt::NoModifier, Qt::Vertical);
208         } else
209             event = new QWheelEvent(m_mousePos, m_mousePos, y, m_mouseButtons, Qt::NoModifier, Qt::Vertical);
210
211         sendOrQueueEvent(event);
212     }
213 }
214 #endif
215
216 void EventSender::leapForward(int ms)
217 {
218     eventQueue[endOfQueue].m_delay = ms;
219     //qDebug() << "EventSender::leapForward" << ms;
220 }
221
222 void EventSender::keyDown(const QString& string, const QStringList& modifiers, unsigned int location)
223 {
224     QString s = string;
225     Qt::KeyboardModifiers modifs = 0;
226     for (int i = 0; i < modifiers.size(); ++i) {
227         const QString& m = modifiers.at(i);
228         if (m == "ctrlKey")
229             modifs |= Qt::ControlModifier;
230         else if (m == "shiftKey")
231             modifs |= Qt::ShiftModifier;
232         else if (m == "altKey")
233             modifs |= Qt::AltModifier;
234         else if (m == "metaKey")
235             modifs |= Qt::MetaModifier;
236     }
237     if (location == 3)
238         modifs |= Qt::KeypadModifier;
239     int code = 0;
240     if (string.length() == 1) {
241         code = string.unicode()->unicode();
242         //qDebug() << ">>>>>>>>> keyDown" << code << (char)code;
243         // map special keycodes used by the tests to something that works for Qt/X11
244         if (code == '\r') {
245             code = Qt::Key_Return;
246         } else if (code == '\t') {
247             code = Qt::Key_Tab;
248             if (modifs == Qt::ShiftModifier)
249                 code = Qt::Key_Backtab;
250             s = QString();
251         } else if (code == KEYCODE_DEL || code == KEYCODE_BACKSPACE) {
252             code = Qt::Key_Backspace;
253             if (modifs == Qt::AltModifier)
254                 modifs = Qt::ControlModifier;
255             s = QString();
256         } else if (code == 'o' && modifs == Qt::ControlModifier) {
257             // Mimic the emacs ctrl-o binding on Mac by inserting a paragraph
258             // separator and then putting the cursor back to its original
259             // position. Allows us to pass emacs-ctrl-o.html
260             s = QLatin1String("\n");
261             code = '\n';
262             modifs = 0;
263             QKeyEvent event(QEvent::KeyPress, code, modifs, s);
264             sendEvent(m_page, &event);
265             QKeyEvent event2(QEvent::KeyRelease, code, modifs, s);
266             sendEvent(m_page, &event2);
267             s = QString();
268             code = Qt::Key_Left;
269         } else if (code == 'y' && modifs == Qt::ControlModifier) {
270             s = QLatin1String("c");
271             code = 'c';
272         } else if (code == 'k' && modifs == Qt::ControlModifier) {
273             s = QLatin1String("x");
274             code = 'x';
275         } else if (code == 'a' && modifs == Qt::ControlModifier) {
276             s = QString();
277             code = Qt::Key_Home;
278             modifs = 0;
279         } else if (code == KEYCODE_LEFTARROW) {
280             s = QString();
281             code = Qt::Key_Left;
282             if (modifs & Qt::MetaModifier) {
283                 code = Qt::Key_Home;
284                 modifs &= ~Qt::MetaModifier;
285             }
286         } else if (code == KEYCODE_RIGHTARROW) {
287             s = QString();
288             code = Qt::Key_Right;
289             if (modifs & Qt::MetaModifier) {
290                 code = Qt::Key_End;
291                 modifs &= ~Qt::MetaModifier;
292             }
293         } else if (code == KEYCODE_UPARROW) {
294             s = QString();
295             code = Qt::Key_Up;
296             if (modifs & Qt::MetaModifier) {
297                 code = Qt::Key_PageUp;
298                 modifs &= ~Qt::MetaModifier;
299             }
300         } else if (code == KEYCODE_DOWNARROW) {
301             s = QString();
302             code = Qt::Key_Down;
303             if (modifs & Qt::MetaModifier) {
304                 code = Qt::Key_PageDown;
305                 modifs &= ~Qt::MetaModifier;
306             }
307         } else if (code == 'a' && modifs == Qt::ControlModifier) {
308             s = QString();
309             code = Qt::Key_Home;
310             modifs = 0;
311         } else
312             code = string.unicode()->toUpper().unicode();
313     } else {
314         //qDebug() << ">>>>>>>>> keyDown" << string;
315
316         if (string.startsWith(QLatin1Char('F')) && string.count() <= 3) {
317             s = s.mid(1);
318             int functionKey = s.toInt();
319             Q_ASSERT(functionKey >= 1 && functionKey <= 35);
320             code = Qt::Key_F1 + (functionKey - 1);
321         // map special keycode strings used by the tests to something that works for Qt/X11
322         } else if (string == QLatin1String("leftArrow")) {
323             s = QString();
324             code = Qt::Key_Left;
325         } else if (string == QLatin1String("rightArrow")) {
326             s = QString();
327             code = Qt::Key_Right;
328         } else if (string == QLatin1String("upArrow")) {
329             s = QString();
330             code = Qt::Key_Up;
331         } else if (string == QLatin1String("downArrow")) {
332             s = QString();
333             code = Qt::Key_Down;
334         } else if (string == QLatin1String("pageUp")) {
335             s = QString();
336             code = Qt::Key_PageUp;
337         } else if (string == QLatin1String("pageDown")) {
338             s = QString();
339             code = Qt::Key_PageDown;
340         } else if (string == QLatin1String("home")) {
341             s = QString();
342             code = Qt::Key_Home;
343         } else if (string == QLatin1String("end")) {
344             s = QString();
345             code = Qt::Key_End;
346         } else if (string == QLatin1String("insert")) {
347             s = QString();
348             code = Qt::Key_Insert;
349         } else if (string == QLatin1String("delete")) {
350             s = QString();
351             code = Qt::Key_Delete;
352         } else if (string == QLatin1String("printScreen")) {
353             s = QString();
354             code = Qt::Key_Print;
355         }
356     }
357     QKeyEvent event(QEvent::KeyPress, code, modifs, s);
358     sendEvent(m_page, &event);
359     QKeyEvent event2(QEvent::KeyRelease, code, modifs, s);
360     sendEvent(m_page, &event2);
361 }
362
363 void EventSender::contextClick()
364 {
365     QMouseEvent event(QEvent::MouseButtonPress, m_mousePos, Qt::RightButton, Qt::RightButton, Qt::NoModifier);
366     sendEvent(m_page, &event);
367     QMouseEvent event2(QEvent::MouseButtonRelease, m_mousePos, Qt::RightButton, Qt::RightButton, Qt::NoModifier);
368     sendEvent(m_page, &event2);
369
370     if (isGraphicsBased()) {
371         QGraphicsSceneContextMenuEvent ctxEvent(QEvent::GraphicsSceneContextMenu);
372         ctxEvent.setReason(QGraphicsSceneContextMenuEvent::Mouse);
373         ctxEvent.setPos(m_mousePos);
374         WebCore::WebViewGraphicsBased* view = qobject_cast<WebCore::WebViewGraphicsBased*>(m_page->view());
375         if (view)
376             sendEvent(view->graphicsView(), &ctxEvent);
377     } else {
378         QContextMenuEvent ctxEvent(QContextMenuEvent::Mouse, m_mousePos);
379         sendEvent(m_page->view(), &ctxEvent);
380     }
381 }
382
383 void EventSender::scheduleAsynchronousClick()
384 {
385     QMouseEvent* event = new QMouseEvent(QEvent::MouseButtonPress, m_mousePos, Qt::LeftButton, Qt::RightButton, Qt::NoModifier);
386     postEvent(m_page, event);
387     QMouseEvent* event2 = new QMouseEvent(QEvent::MouseButtonRelease, m_mousePos, Qt::LeftButton, Qt::RightButton, Qt::NoModifier);
388     postEvent(m_page, event2);
389 }
390
391 void EventSender::addTouchPoint(int x, int y)
392 {
393     // Use index to refer to the position in the vector that this touch
394     // is stored. We then create a unique id for the touch that will be
395     // passed into WebCore.
396     int index = m_touchPoints.count();
397     int id = m_touchPoints.isEmpty() ? 0 : m_touchPoints.last().id() + 1;
398     QTouchEvent::TouchPoint point(id);
399     m_touchPoints.append(point);
400     updateTouchPoint(index, x, y);
401     m_touchPoints[index].setState(Qt::TouchPointPressed);
402 }
403
404 void EventSender::updateTouchPoint(int index, int x, int y)
405 {
406     if (index < 0 || index >= m_touchPoints.count())
407         return;
408
409     QTouchEvent::TouchPoint &p = m_touchPoints[index];
410     p.setPos(QPointF(x, y));
411     p.setState(Qt::TouchPointMoved);
412 }
413
414 void EventSender::setTouchModifier(const QString &modifier, bool enable)
415 {
416     Qt::KeyboardModifier mod = Qt::NoModifier;
417     if (!modifier.compare(QLatin1String("shift"), Qt::CaseInsensitive))
418         mod = Qt::ShiftModifier;
419     else if (!modifier.compare(QLatin1String("alt"), Qt::CaseInsensitive))
420         mod = Qt::AltModifier;
421     else if (!modifier.compare(QLatin1String("meta"), Qt::CaseInsensitive))
422         mod = Qt::MetaModifier;
423     else if (!modifier.compare(QLatin1String("ctrl"), Qt::CaseInsensitive))
424         mod = Qt::ControlModifier;
425
426     if (enable)
427         m_touchModifiers |= mod;
428     else
429         m_touchModifiers &= ~mod;
430 }
431
432 void EventSender::touchStart()
433 {
434     if (!m_touchActive) {
435         sendTouchEvent(QEvent::TouchBegin);
436         m_touchActive = true;
437     } else
438         sendTouchEvent(QEvent::TouchUpdate);
439 }
440
441 void EventSender::touchMove()
442 {
443     sendTouchEvent(QEvent::TouchUpdate);
444 }
445
446 void EventSender::touchEnd()
447 {
448     for (int i = 0; i < m_touchPoints.count(); ++i)
449         if (m_touchPoints[i].state() != Qt::TouchPointReleased) {
450             sendTouchEvent(QEvent::TouchUpdate);
451             return;
452         }
453     sendTouchEvent(QEvent::TouchEnd);
454     m_touchActive = false;
455 }
456
457 void EventSender::clearTouchPoints()
458 {
459     m_touchPoints.clear();
460     m_touchModifiers = Qt::KeyboardModifiers();
461     m_touchActive = false;
462 }
463
464 void EventSender::releaseTouchPoint(int index)
465 {
466     if (index < 0 || index >= m_touchPoints.count())
467         return;
468
469     m_touchPoints[index].setState(Qt::TouchPointReleased);
470 }
471
472 void EventSender::sendTouchEvent(QEvent::Type type)
473 {
474     QTouchEvent event(type, QTouchEvent::TouchScreen, m_touchModifiers);
475     event.setTouchPoints(m_touchPoints);
476     sendEvent(m_page, &event);
477     QList<QTouchEvent::TouchPoint>::Iterator it = m_touchPoints.begin();
478     while (it != m_touchPoints.end()) {
479         if (it->state() == Qt::TouchPointReleased)
480             it = m_touchPoints.erase(it);
481         else {
482             it->setState(Qt::TouchPointStationary);
483             ++it;
484         }
485     }
486 }
487
488 void EventSender::zoomPageIn()
489 {
490     if (QWebFrame* frame = m_page->mainFrame())
491         frame->setZoomFactor(frame->zoomFactor() * ZOOM_STEP);
492 }
493
494 void EventSender::zoomPageOut()
495 {
496     if (QWebFrame* frame = m_page->mainFrame())
497         frame->setZoomFactor(frame->zoomFactor() / ZOOM_STEP);
498 }
499
500 void EventSender::textZoomIn()
501 {
502     if (QWebFrame* frame = m_page->mainFrame())
503         frame->setTextSizeMultiplier(frame->textSizeMultiplier() * ZOOM_STEP);
504 }
505
506 void EventSender::textZoomOut()
507 {
508     if (QWebFrame* frame = m_page->mainFrame())
509         frame->setTextSizeMultiplier(frame->textSizeMultiplier() / ZOOM_STEP);
510 }
511
512 QWebFrame* EventSender::frameUnderMouse() const
513 {
514     QWebFrame* frame = m_page->mainFrame();
515
516 redo:
517     QList<QWebFrame*> children = frame->childFrames();
518     for (int i = 0; i < children.size(); ++i) {
519         if (children.at(i)->geometry().contains(m_mousePos)) {
520             frame = children.at(i);
521             goto redo;
522         }
523     }
524     if (frame->geometry().contains(m_mousePos))
525         return frame;
526     return 0;
527 }
528
529 void EventSender::sendOrQueueEvent(QEvent* event)
530 {
531     // Mouse move events are queued if 
532     // 1. A previous event was queued.
533     // 2. A delay was set-up by leapForward().
534     // 3. A call to mouseMoveTo while the mouse button is pressed could initiate a drag operation, and that does not return until mouseUp is processed. 
535     // To be safe and avoid a deadlock, this event is queued.
536     if (endOfQueue == startOfQueue && !eventQueue[endOfQueue].m_delay && (!(m_mouseButtonPressed && (m_eventLoop && event->type() == QEvent::MouseButtonRelease)))) {
537         sendEvent(m_page->view(), event);
538         delete event;
539         return;
540     }
541     eventQueue[endOfQueue++].m_event = event;
542     eventQueue[endOfQueue].m_delay = 0;
543     replaySavedEvents(event->type() != QEvent::MouseMove);
544 }
545
546 void EventSender::replaySavedEvents(bool flush)
547 {
548     if (startOfQueue < endOfQueue) {
549         // First send all the events that are ready to be sent
550         while (!eventQueue[startOfQueue].m_delay && startOfQueue < endOfQueue) {
551             QEvent* ev = eventQueue[startOfQueue++].m_event;
552             postEvent(m_page->view(), ev);
553         }
554         if (startOfQueue == endOfQueue) {
555             // Reset the queue
556             startOfQueue = 0;
557             endOfQueue = 0;
558         } else {
559             QTest::qWait(eventQueue[startOfQueue].m_delay);
560             eventQueue[startOfQueue].m_delay = 0;
561         }
562     }
563     if (!flush)
564         return;
565
566     // Send a marker event, it will tell us when it is safe to exit the new event loop
567     QEvent* drtEvent = new QEvent((QEvent::Type)DRT_MESSAGE_DONE);
568     QApplication::postEvent(m_page->view(), drtEvent);
569
570     // Start an event loop for async handling of Drag & Drop
571     m_eventLoop = new QEventLoop;
572     m_eventLoop->exec();
573     delete m_eventLoop;
574     m_eventLoop = 0;
575 }
576
577 bool EventSender::eventFilter(QObject* watched, QEvent* event)
578 {
579     if (watched != m_page->view())
580         return false;
581     switch (event->type()) {
582     case QEvent::Leave:
583         return true;
584     case QEvent::MouseButtonPress:
585     case QEvent::GraphicsSceneMousePress:
586         m_mouseButtonPressed = true;
587         break;
588     case QEvent::MouseMove:
589     case QEvent::GraphicsSceneMouseMove:
590         if (m_mouseButtonPressed)
591             m_drag = true;
592         break;
593     case QEvent::MouseButtonRelease:
594     case QEvent::GraphicsSceneMouseRelease:
595         m_mouseButtonPressed = false;
596         m_drag = false;
597         break;
598     case DRT_MESSAGE_DONE:
599         m_eventLoop->exit();
600         return true;
601     }
602     return false;
603 }
604
605 void EventSender::timerEvent(QTimerEvent* ev)
606 {
607     m_clickTimer.stop();
608 }
609
610 QGraphicsSceneMouseEvent* EventSender::createGraphicsSceneMouseEvent(QEvent::Type type, const QPoint& pos, const QPoint& screenPos, Qt::MouseButton button, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
611 {
612     QGraphicsSceneMouseEvent* event;
613     event = new QGraphicsSceneMouseEvent(type);
614     event->setPos(pos);
615     event->setScreenPos(screenPos);
616     event->setButton(button);
617     event->setButtons(buttons);
618     event->setModifiers(modifiers);
619
620     return event;
621 }
622
623 QGraphicsSceneWheelEvent* EventSender::createGraphicsSceneWheelEvent(QEvent::Type type, const QPoint& pos, const QPoint& screenPos, int delta, Qt::KeyboardModifiers modifiers, Qt::Orientation orientation)
624 {
625     QGraphicsSceneWheelEvent* event;
626     event = new QGraphicsSceneWheelEvent(type);
627     event->setPos(pos);
628     event->setScreenPos(screenPos);
629     event->setDelta(delta);
630     event->setModifiers(modifiers);
631     event->setOrientation(orientation);
632
633     return event;
634 }
635
636 void EventSender::sendEvent(QObject* receiver, QEvent* event)
637 {
638     if (WebCore::WebViewGraphicsBased* view = qobject_cast<WebCore::WebViewGraphicsBased*>(receiver))
639         view->scene()->sendEvent(view->graphicsView(), event);
640     else
641         QApplication::sendEvent(receiver, event);
642 }
643
644 void EventSender::postEvent(QObject* receiver, QEvent* event)
645 {
646     // QGraphicsScene does not have a postEvent method, so send the event in this case
647     // and delete it after that.
648     if (WebCore::WebViewGraphicsBased* view = qobject_cast<WebCore::WebViewGraphicsBased*>(receiver)) {
649         view->scene()->sendEvent(view->graphicsView(), event);
650         delete event;
651     } else
652         QApplication::postEvent(receiver, event); // event deleted by the system
653 }