1
// krazy:excludeall=qclasses
3
//////////////////////////////////////////////////////////////////////////////
5
// simulates event chain passed to the application
8
// Copyright (c) 2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org>
10
// Permission is hereby granted, free of charge, to any person obtaining a copy
11
// of this software and associated documentation files (the "Software"), to
12
// deal in the Software without restriction, including without limitation the
13
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
14
// sell copies of the Software, and to permit persons to whom the Software is
15
// furnished to do so, subject to the following conditions:
17
// The above copyright notice and this permission notice shall be included in
18
// all copies or substantial portions of the Software.
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27
//////////////////////////////////////////////////////////////////////////////
29
#include "oxygensimulator.h"
30
#include "oxygensimulator.moc"
33
#include <QtGui/QAbstractItemView>
34
#include <QtGui/QApplication>
35
#include <QtGui/QCheckBox>
36
#include <QtGui/QComboBox>
37
#include <QtGui/QCursor>
38
#include <QtGui/QFocusEvent>
39
#include <QtGui/QHoverEvent>
40
#include <QtGui/QMdiSubWindow>
41
#include <QtGui/QMenu>
42
#include <QtGui/QMouseEvent>
43
#include <QtGui/QPushButton>
44
#include <QtGui/QRadioButton>
45
#include <QtGui/QScrollBar>
46
#include <QtGui/QSlider>
47
#include <QtGui/QStyle>
48
#include <QtGui/QStyleOptionComboBox>
49
#include <QtGui/QStyleOptionSlider>
50
#include <QtGui/QToolButton>
53
/* need windows.h include for Sleep function*/
64
//_______________________________________________________________________
65
bool Simulator::_grabMouse = true;
66
int Simulator::_defaultDelay = 250;
68
//_______________________________________________________________________
69
Simulator::~Simulator( void )
72
//_______________________________________________________________________
73
void Simulator::wait( int delay )
74
{ _events.push_back( Event( Event::Wait, 0, delay ) ); }
76
//_______________________________________________________________________
77
void Simulator::click( QWidget* receiver, int delay )
81
if( QCheckBox* checkbox = qobject_cast<QCheckBox*>( receiver ) )
84
QStyleOptionButton option;
85
option.initFrom( checkbox );
86
position = checkbox->style()->subElementRect(
87
QStyle::SE_CheckBoxIndicator,
91
} else if( QRadioButton* radiobutton = qobject_cast<QRadioButton*>( receiver ) ) {
93
QStyleOptionButton option;
94
option.initFrom( radiobutton );
95
position = radiobutton->style()->subElementRect(
96
QStyle::SE_RadioButtonIndicator,
98
radiobutton).center();
100
} else if( const QMdiSubWindow* window = qobject_cast<QMdiSubWindow*>( receiver ) ) {
102
QStyleOptionTitleBar option;
103
option.initFrom( window );
104
int titleBarHeight( window->style()->pixelMetric( QStyle::PM_TitleBarHeight, &option, window ) );
105
QRect titleBarRect( QPoint(0,0), QSize( window->width(), titleBarHeight ) );
106
if( !titleBarRect.isValid() ) return;
107
position = titleBarRect.center();
111
position = receiver->rect().center();
115
click( receiver, position, delay );
119
//_______________________________________________________________________
120
void Simulator::click( QWidget* receiver, const QPoint& position, int delay )
122
Event event( Event::Click, receiver, delay );
123
event._position = position;
124
_events.push_back( event );
127
//_______________________________________________________________________
128
void Simulator::slide( QWidget* receiver, const QPoint& position, int delay )
130
Event event( Event::Slide, receiver, delay );
131
event._position = position;
132
_events.push_back( event );
136
//_______________________________________________________________________
137
void Simulator::selectItem( QWidget* receiver, int row, int column, int delay )
139
Event event( Event::SelectItem, receiver, delay );
140
event._position = QPoint( column, row );
141
_events.push_back( event );
144
//_______________________________________________________________________
145
void Simulator::selectComboBoxItem( QWidget* receiver, int index, int delay )
147
Event event( Event::SelectComboBoxItem, receiver, delay );
148
event._position.setX( index );
149
_events.push_back( event );
152
//_______________________________________________________________________
153
void Simulator::selectMenuItem( QWidget* receiver, int index, int delay )
155
Event event( Event::SelectMenuItem, receiver, delay );
156
event._position.setX( index );
157
_events.push_back( event );
160
//_______________________________________________________________________
161
void Simulator::selectTab( QTabWidget* tabwidget, int index, int delay )
163
foreach( QObject* child, tabwidget->children() )
165
if( QTabBar* tabbar = qobject_cast<QTabBar*>( child ) )
167
selectTab( tabbar, index, delay );
173
//_______________________________________________________________________
174
void Simulator::selectTab( QTabBar* receiver, int index, int delay )
176
Event event( Event::SelectTab, receiver, delay );
177
event._position.setX( index );
178
_events.push_back( event );
181
//_______________________________________________________________________
182
void Simulator::writeText( QWidget* receiver, QString text, int delay )
184
Event event( Event::WriteText, receiver, delay );
186
_events.push_back( event );
189
//_______________________________________________________________________
190
void Simulator::clearText( QWidget* receiver, int delay )
191
{ _events.push_back( Event( Event::ClearText, receiver, delay ) ); }
193
//_______________________________________________________________________
194
void Simulator::run( void )
197
if( _events.isEmpty() ) return;
202
emit stateChanged( true );
203
foreach( const Event& event, _events )
211
processEvent( event );
214
// add last event to reset previousWidget and previousPosition
215
if( _previousWidget )
218
postEvent( _previousWidget.data(), QEvent::Leave );
219
if( _previousWidget.data()->testAttribute( Qt::WA_Hover ) )
221
const QPoint oldPosition( _previousWidget.data()->mapFromGlobal( _previousPosition ) );
222
const QPoint newPosition( _previousWidget.data()->mapFromGlobal( QPoint( -1, -1 ) ) );
223
postHoverEvent( _previousWidget.data(), QEvent::HoverLeave, newPosition, oldPosition );
226
_previousWidget.clear();
227
_previousPosition = QPoint(-1, -1 );
232
emit stateChanged( false );
237
//_______________________________________________________________________
238
void Simulator::abort( void )
241
emit stateChanged( true );
245
//_______________________________________________________________________
246
void Simulator::timerEvent( QTimerEvent* event )
248
if( event->timerId() == _timer.timerId() )
253
} else if( event->timerId() == _pendingEventsTimer.timerId() ) {
258
foreach( QEvent* event, _pendingEvents )
261
_pendingEvents.clear();
262
_pendingWidget.clear();
264
} else if( _pendingWidget && _pendingWidget.data()->isVisible() ) {
266
_pendingEventsTimer.stop();
267
foreach( QEvent* event, _pendingEvents )
270
if( event->type() == QEvent::MouseMove )
272
QPoint position( static_cast<QMouseEvent*>( event )->pos() );
273
moveCursor( _pendingWidget.data()->mapToGlobal( position ) );
276
postQEvent( _pendingWidget.data(), event );
281
_pendingEvents.clear();
282
_pendingWidget.clear();
286
} else return QObject::timerEvent( event );
290
//_______________________________________________________________________
291
void Simulator::processEvent( const Event& event )
294
if( _aborted ) return;
295
if( !event._receiver )
298
if( event._type == Event::Wait )
299
{ postDelay( event._delay ); }
305
QWidget* receiver( event._receiver.data() );
306
switch( event._type )
313
// enter widget or move cursor to relevant position
314
if( !enter( receiver, event._position, event._delay ) )
316
moveCursor( receiver->mapToGlobal( event._position ) );
317
postMouseEvent( receiver, QEvent::MouseMove, Qt::NoButton, event._position );
320
postMouseClickEvent( receiver, Qt::LeftButton, event._position );
327
const QPoint& delta( event._position );
329
// calculate begin position depending on widget type
331
if( const QSlider* slider = qobject_cast<QSlider*>( receiver ) )
334
// this is copied from QSlider::initStyleOption
335
QStyleOptionSlider option;
336
option.initFrom( slider );
337
option.orientation = slider->orientation();
338
option.sliderPosition = slider->sliderPosition();
339
option.minimum = slider->minimum();
340
option.maximum = slider->maximum();
341
option.upsideDown = (slider->orientation() == Qt::Horizontal) ?
342
( slider->invertedAppearance() != (option.direction == Qt::RightToLeft))
343
: (!slider->invertedAppearance() );
345
QRect handleRect( slider->style()->subControlRect(
346
QStyle::CC_Slider, &option, QStyle::SC_SliderHandle,
349
if( !handleRect.isValid() ) break;
350
begin = handleRect.center();
352
} else if( const QScrollBar* scrollbar = qobject_cast<QScrollBar*>( receiver ) ) {
354
// this is copied from QSlider::initStyleOption
355
QStyleOptionSlider option;
356
option.initFrom( scrollbar );
357
option.orientation = scrollbar->orientation();
358
option.sliderPosition = scrollbar->sliderPosition();
359
option.minimum = scrollbar->minimum();
360
option.maximum = scrollbar->maximum();
361
option.upsideDown = scrollbar->invertedAppearance();
362
if( scrollbar->orientation() == Qt::Horizontal )
363
{ option.state |= QStyle::State_Horizontal; }
365
QRect handleRect( scrollbar->style()->subControlRect(
366
QStyle::CC_ScrollBar, &option, QStyle::SC_ScrollBarSlider,
369
if( !handleRect.isValid() ) break;
370
begin = handleRect.center();
372
} else if( const QMdiSubWindow* window = qobject_cast<QMdiSubWindow*>( receiver ) ) {
374
QStyleOptionTitleBar option;
375
option.initFrom( window );
376
int titleBarHeight( window->style()->pixelMetric( QStyle::PM_TitleBarHeight, &option, window ) );
377
QRect titleBarRect( QPoint(0,0), QSize( window->width(), titleBarHeight ) );
378
if( !titleBarRect.isValid() ) break;
379
begin = titleBarRect.center();
383
begin = receiver->rect().center();
387
// enter widget or move cursor to relevant position
388
if( !enter( receiver, begin, event._delay ) )
390
moveCursor( receiver->mapToGlobal( begin ) );
391
postMouseEvent( receiver, QEvent::MouseMove, Qt::NoButton, begin );
394
const QPoint end( begin + delta );
395
postMouseEvent( receiver, QEvent::MouseButtonPress, Qt::LeftButton, begin, Qt::LeftButton );
396
setFocus( receiver );
398
const int steps = 10;
399
for( int i=0; i<steps; ++i )
402
begin.x() + qreal((i+1)*( end.x()-begin.x() ))/steps,
403
begin.y() + qreal((i+1)*( end.y()-begin.y() ))/steps );
404
moveCursor( receiver->mapToGlobal( current ), 1 );
405
postMouseEvent( receiver, QEvent::MouseMove, Qt::NoButton, current, Qt::LeftButton, Qt::NoModifier );
409
postMouseEvent( receiver, QEvent::MouseButtonRelease, Qt::LeftButton, end );
413
case Event::SelectItem:
416
const QAbstractItemView* view = qobject_cast<QAbstractItemView*>( receiver );
417
if( !( view && view->model() ) ) break;
419
const int column( event._position.x() );
420
const int row( event._position.y() );
423
const QModelIndex modelIndex( view->model()->index( row, column ) );
424
if( !modelIndex.isValid() ) break;
427
QRect r( view->visualRect( modelIndex ) );
428
if( !r.isValid() ) break;
430
// enter widget or move cursor to relevant position
431
const QPoint position( r.center() );
432
if( !enter( view->viewport(), position, event._delay ) )
434
moveCursor( view->viewport()->mapToGlobal( position ) );
435
postMouseEvent( view->viewport(), QEvent::MouseMove, Qt::NoButton, position );
436
postDelay( event._delay );
439
postMouseClickEvent( view->viewport(), Qt::LeftButton, position );
444
case Event::SelectComboBoxItem:
447
QComboBox* combobox = qobject_cast<QComboBox*>( receiver );
448
if( !combobox ) break;
451
QStyleOptionComboBox option;
452
option.initFrom( combobox );
453
QRect arrowRect( combobox->style()->subControlRect( QStyle::CC_ComboBox, &option, QStyle::SC_ComboBoxArrow, combobox ) );
455
// enter widget or move cursor to relevant position
456
QPoint position( arrowRect.center() );
457
if( !enter( combobox, position, event._delay ) )
459
moveCursor( combobox->mapToGlobal( position ) );
460
postMouseEvent( combobox, QEvent::MouseMove, Qt::NoButton, position );
461
postDelay( event._delay );
464
postMouseClickEvent( combobox, Qt::LeftButton, position );
466
// select item in view
467
QAbstractItemView* view = combobox->view();
468
const int row( event._position.x() );
469
const int column( 0 );
472
const QModelIndex modelIndex( view->model()->index( row, column ) );
473
if( !modelIndex.isValid() ) break;
476
QRect r( view->visualRect( modelIndex ) );
477
if( !r.isValid() ) break;
480
position = QPoint( r.center() );
481
moveCursor( view->viewport()->mapToGlobal( position ) );
482
postMouseEvent( view->viewport(), QEvent::MouseMove, Qt::NoButton, position, Qt::NoButton, Qt::NoModifier );
484
postMouseClickEvent( view->viewport(), Qt::LeftButton, position );
490
case Event::SelectMenuItem:
495
if( const QToolButton* button = qobject_cast<QToolButton*>( receiver ) ) menu = button->menu();
496
else if( const QPushButton* button = qobject_cast<QPushButton*>( receiver ) ) menu = button->menu();
498
// abort if not found
501
// get action and geometry
502
const int row( event._position.x() );
503
QList<QAction*> actions( menu->actions() );
504
if( row >= actions.size() ) break;
507
QRect r( menu->actionGeometry( actions[row] ) );
508
if( !r.isValid() ) break;
511
HACK: As soon as leftMouseButton is pressed on a button with menu,
512
the menu is shown and code is interrupted until an action is selected in the menu.
513
As a consequence, one must first generate the events, execute them with a delay, and then
514
click on the button (before delay is expired). This way, the menu events will be executed
515
even if the menu is visible (and blocking further code execution).
517
QPoint position( r.center() );
518
_pendingWidget = menu;
519
_pendingEvents.push_back( new QMouseEvent(
526
_pendingEvents.push_back( new QMouseEvent(
527
QEvent::MouseButtonPress,
533
_pendingEvents.push_back( new QMouseEvent(
534
QEvent::MouseButtonRelease,
540
_pendingEventsTimer.start( 10, this );
542
// enter widget or move cursor to relevant position
543
position = receiver->rect().center();
544
if( !enter( receiver, position, event._delay ) )
546
moveCursor( receiver->mapToGlobal( position ) );
547
postMouseEvent( receiver, QEvent::MouseMove, Qt::NoButton, position );
548
postDelay( event._delay );
552
postMouseEvent( receiver, QEvent::MouseButtonPress, Qt::LeftButton, position, Qt::NoButton, Qt::NoModifier );
557
case Event::SelectTab:
560
const QTabBar* tabbar = qobject_cast<QTabBar*>( receiver );
563
const int index( event._position.x() );
565
const QRect r( tabbar->tabRect( index ) );
566
if( !r.isValid() ) break;
568
// enter widget or move cursor to relevant position
569
const QPoint position( r.center() );
570
if( !enter( receiver, position, event._delay ) )
572
moveCursor( receiver->mapToGlobal( position ) );
573
postMouseEvent( receiver, QEvent::MouseMove, Qt::NoButton, position );
574
postDelay( event._delay );
577
postMouseClickEvent( receiver, Qt::LeftButton, position );
582
case Event::WriteText:
585
enter( receiver, receiver->rect().center(), event._delay );
586
setFocus( receiver );
587
const QString& text( event._text );
588
for( int i=0; i < text.length(); ++i )
590
const Qt::Key key( toKey( text.at(i) ) );
591
const QString local( text.at(i) );
592
postKeyEvent( receiver, QEvent::KeyPress, key, local, Qt::NoModifier );
593
postKeyEvent( receiver, QEvent::KeyRelease, key, local, Qt::NoModifier );
600
case Event::ClearText:
603
enter( receiver, receiver->rect().center(), event._delay );
604
setFocus( receiver );
605
postKeyEvent( receiver, QEvent::KeyPress, Qt::Key_A, "a", Qt::ControlModifier );
606
postKeyEvent( receiver, QEvent::KeyRelease, Qt::Key_A, "a", Qt::ControlModifier );
608
postKeyClickEvent( receiver, Qt::Key_Backspace, QString() );
617
postDelay( event._delay );
623
//_______________________________________________________________________
624
void Simulator::postEvent( QWidget* receiver, QEvent::Type type ) const
625
{ postQEvent( receiver, new QEvent( type ) ); }
627
//_______________________________________________________________________
628
void Simulator::postHoverEvent( QWidget* receiver, QEvent::Type type, const QPoint& newPosition, const QPoint& oldPosition ) const
629
{ postQEvent( receiver, new QHoverEvent( type, newPosition, oldPosition ) ); }
632
//_______________________________________________________________________
633
bool Simulator::enter( QWidget* receiver, const QPoint& position, int delay )
636
if( receiver == _previousWidget.data() ) return false;
639
moveCursor( receiver->mapToGlobal( position ) );
641
// leave previous widget
642
if( _previousWidget )
644
postEvent( _previousWidget.data(), QEvent::Leave );
645
if( _previousWidget.data()->testAttribute( Qt::WA_Hover ) )
647
const QPoint oldPosition( _previousWidget.data()->mapFromGlobal( _previousPosition ) );
648
const QPoint newPosition( _previousWidget.data()->mapFromGlobal( receiver->mapToGlobal( position ) ) );
649
postHoverEvent( _previousWidget.data(), QEvent::HoverLeave, newPosition, oldPosition );
653
// enter or move in current widget
654
if( !receiver->rect().contains( receiver->mapFromGlobal( _previousPosition ) ) )
657
// enter current widget if needed
658
postEvent( receiver, QEvent::Enter );
659
if( receiver->testAttribute( Qt::WA_Hover ) )
661
const QPoint oldPosition( receiver->mapFromGlobal( _previousPosition ) );
662
const QPoint newPosition( position );
663
postHoverEvent( receiver, QEvent::HoverEnter, newPosition, oldPosition );
666
} else if( receiver->mapFromGlobal( _previousPosition ) != position ) {
668
// move mouse if needed
669
postMouseEvent( receiver, QEvent::MouseMove, Qt::NoButton, position );
670
if( receiver->testAttribute( Qt::WA_Hover ) )
672
const QPoint oldPosition( receiver->mapFromGlobal( _previousPosition ) );
673
const QPoint newPosition( position );
674
postHoverEvent( receiver, QEvent::HoverMove, newPosition, oldPosition );
679
// update previous widget and position
680
_previousWidget = receiver;
681
_previousPosition = receiver->mapToGlobal( position );
688
//_______________________________________________________________________
689
void Simulator::postMouseClickEvent( QWidget* receiver, Qt::MouseButton button, const QPoint& position )
692
// button press and button release
693
postMouseEvent( receiver, QEvent::MouseButtonPress, button, position, button );
694
setFocus( receiver );
696
postMouseEvent( receiver, QEvent::MouseButtonRelease, button, position, button );
700
//_______________________________________________________________________
701
void Simulator::postMouseEvent(
704
Qt::MouseButton button,
705
const QPoint& position,
706
Qt::MouseButtons buttons,
707
Qt::KeyboardModifiers modifiers ) const
709
postQEvent( receiver, new QMouseEvent(
712
receiver->mapToGlobal( position ),
718
//_______________________________________________________________________
719
void Simulator::postKeyClickEvent( QWidget* receiver, Qt::Key key, QString text, Qt::KeyboardModifiers modifiers ) const
721
postKeyModifiersEvent( receiver, QEvent::KeyPress, modifiers );
722
postKeyEvent( receiver, QEvent::KeyPress, key, text, modifiers );
723
postKeyEvent( receiver, QEvent::KeyRelease, key, text, modifiers );
724
postKeyModifiersEvent( receiver, QEvent::KeyRelease, modifiers );
728
//_______________________________________________________________________
729
void Simulator::postKeyModifiersEvent( QWidget* receiver, QEvent::Type type, Qt::KeyboardModifiers modifiers ) const
732
if( modifiers == Qt::NoModifier ) return;
737
case QEvent::KeyPress:
739
if( modifiers & Qt::ShiftModifier)
740
{ postKeyEvent( receiver, QEvent::KeyPress, Qt::Key_Shift, QString() ); }
742
if( modifiers & Qt::ControlModifier )
743
{ postKeyEvent( receiver, QEvent::KeyPress, Qt::Key_Control, QString(), modifiers & Qt::ShiftModifier ); }
745
if( modifiers & Qt::AltModifier )
746
{ postKeyEvent( receiver, QEvent::KeyPress, Qt::Key_Alt, QString(), modifiers & (Qt::ShiftModifier|Qt::ControlModifier) ); }
748
if( modifiers & Qt::MetaModifier )
749
{ postKeyEvent( receiver, QEvent::KeyPress, Qt::Key_Meta, QString(), modifiers & (Qt::ShiftModifier|Qt::ControlModifier|Qt::AltModifier) ); }
755
case QEvent::KeyRelease:
758
if( modifiers & Qt::MetaModifier )
759
{ postKeyEvent( receiver, QEvent::KeyRelease, Qt::Key_Meta, QString() ); }
761
if( modifiers & Qt::AltModifier )
762
{ postKeyEvent( receiver, QEvent::KeyRelease, Qt::Key_Alt, QString(), modifiers & Qt::MetaModifier ); }
764
if( modifiers & Qt::ControlModifier )
765
{ postKeyEvent( receiver, QEvent::KeyRelease, Qt::Key_Control, QString(), modifiers & (Qt::MetaModifier|Qt::AltModifier) ); }
767
if( modifiers & Qt::ShiftModifier)
768
{ postKeyEvent( receiver, QEvent::KeyRelease, Qt::Key_Shift, QString(), modifiers & (Qt::MetaModifier|Qt::AltModifier|Qt::ControlModifier) ); }
777
//_______________________________________________________________________
778
void Simulator::postKeyEvent( QWidget* receiver, QEvent::Type type, Qt::Key key, QString text, Qt::KeyboardModifiers modifiers ) const
779
{ postQEvent( receiver, new QKeyEvent( type, key, modifiers, text ) ); }
781
//_______________________________________________________________________
782
void Simulator::postDelay( int delay )
786
if( delay == -1 ) delay = _defaultDelay;
787
if( delay <= 0 ) return;
789
// this is largely inspired from qtestlib's qsleep implementation
790
_timer.start( delay, this );
791
while( _timer.isActive() )
794
// flush events in loop
795
QCoreApplication::processEvents(QEventLoop::AllEvents, delay);
802
struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
803
nanosleep(&ts, NULL);
810
//_______________________________________________________________________
811
void Simulator::moveCursor( const QPoint& position, int steps )
814
// do nothing if mouse grab is disabled
815
if( !_grabMouse ) return;
816
if( _aborted ) return;
817
const QPoint begin( QCursor::pos() );
818
const QPoint end( position );
819
if( begin == end ) return;
824
for( int i = 0; i<steps; ++i )
826
const QPoint current(
827
begin.x() + qreal((i+1)*( end.x()-begin.x() ))/steps,
828
begin.y() + qreal((i+1)*( end.y()-begin.y() ))/steps );
829
QCursor::setPos( current );
835
QCursor::setPos( end );
841
//_______________________________________________________________________
842
void Simulator::setFocus( QWidget* receiver )
844
if( receiver->focusPolicy() != Qt::NoFocus )
845
{ receiver->setFocus(); }
848
//_______________________________________________________________________
849
Qt::Key Simulator::toKey( QChar a ) const
850
{ return (Qt::Key) QKeySequence( a )[0]; }
852
//_______________________________________________________________________
853
void Simulator::postQEvent( QWidget* receiver, QEvent* event ) const
855
if( _aborted ) delete event;
856
else qApp->postEvent( receiver, event );