1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_slideshow.hxx"
26
27 // must be first
28 #include <canvas/debug.hxx>
29 #include <tools/diagnose_ex.h>
30
31 #include <comphelper/anytostring.hxx>
32 #include <cppuhelper/exc_hlp.hxx>
33
34 #include <com/sun/star/awt/SystemPointer.hpp>
35 #include <com/sun/star/awt/MouseButton.hpp>
36 #include <com/sun/star/awt/MouseEvent.hpp>
37
38 #include <boost/bind.hpp>
39
40 #include "delayevent.hxx"
41 #include "usereventqueue.hxx"
42 #include "cursormanager.hxx"
43 #include "slideshowexceptions.hxx"
44
45 #include <vector>
46 #include <queue>
47 #include <map>
48 #include <functional>
49 #include <algorithm>
50
51
52 using namespace com::sun::star;
53
54 /* Implementation of UserEventQueue class */
55
56 namespace slideshow {
57 namespace internal {
58
59 namespace {
60
61 typedef std::vector<EventSharedPtr> ImpEventVector;
62 typedef std::queue<EventSharedPtr> ImpEventQueue;
63 typedef std::map<uno::Reference<animations::XAnimationNode>,
64 ImpEventVector> ImpAnimationEventMap;
65 typedef std::map<ShapeSharedPtr, ImpEventQueue,
66 Shape::lessThanShape> ImpShapeEventMap;
67
68 // MouseEventHandler base class, not consuming any event:
69 class MouseEventHandler_ : public MouseEventHandler
70 {
71 public:
handleMousePressed(awt::MouseEvent const &)72 virtual bool handleMousePressed( awt::MouseEvent const& /*e*/ ) { return false;}
handleMouseReleased(awt::MouseEvent const &)73 virtual bool handleMouseReleased( awt::MouseEvent const& /*e*/) { return false;}
handleMouseEntered(awt::MouseEvent const &)74 virtual bool handleMouseEntered( awt::MouseEvent const& /*e*/ ) { return false;}
handleMouseExited(awt::MouseEvent const &)75 virtual bool handleMouseExited( awt::MouseEvent const& /*e*/ ) { return false; }
handleMouseDragged(awt::MouseEvent const &)76 virtual bool handleMouseDragged( awt::MouseEvent const& /*e*/ ) { return false;}
handleMouseMoved(awt::MouseEvent const &)77 virtual bool handleMouseMoved( awt::MouseEvent const& /*e*/ ) { return false; }
78 };
79
80 /** @return one event has been posted
81 */
82 template <typename ContainerT>
fireSingleEvent(ContainerT & rQueue,EventQueue & rEventQueue)83 bool fireSingleEvent( ContainerT & rQueue, EventQueue & rEventQueue )
84 {
85 // post next event in given queue:
86 while (! rQueue.empty())
87 {
88 EventSharedPtr const pEvent(rQueue.front());
89 rQueue.pop();
90
91 // skip all inactive events (as the purpose of
92 // nextEventFromQueue() is to activate the next
93 // event, and events which return false on
94 // isCharged() will never be activated by the
95 // EventQueue)
96 if(pEvent->isCharged())
97 return rEventQueue.addEvent( pEvent );
98 }
99 return false; // no more (active) events in queue
100 }
101
102 /** @return at least one event has been posted
103 */
104 template <typename ContainerT>
fireAllEvents(ContainerT & rQueue,EventQueue & rEventQueue)105 bool fireAllEvents( ContainerT & rQueue, EventQueue & rEventQueue )
106 {
107 bool bFiredAny = false;
108 while (fireSingleEvent( rQueue, rEventQueue ))
109 bFiredAny = true;
110 return bFiredAny;
111 }
112
113 class EventContainer
114 {
115 public:
EventContainer()116 EventContainer() :
117 maEvents()
118 {}
119
clearContainer()120 void clearContainer()
121 {
122 maEvents = ImpEventQueue();
123 }
124
addEvent(const EventSharedPtr & rEvent)125 void addEvent( const EventSharedPtr& rEvent )
126 {
127 maEvents.push( rEvent );
128 }
129
isEmpty()130 bool isEmpty()
131 {
132 return maEvents.empty();
133 }
134
135 protected:
136 ImpEventQueue maEvents;
137 };
138
139 } // anon namespace
140
141 class PlainEventHandler : public EventHandler,
142 public EventContainer
143 {
144 public:
PlainEventHandler(EventQueue & rEventQueue)145 PlainEventHandler( EventQueue & rEventQueue )
146 : EventContainer(), mrEventQueue(rEventQueue) {}
147
dispose()148 virtual void dispose()
149 {
150 clearContainer();
151 }
152
handleEvent()153 virtual bool handleEvent()
154 {
155 return fireAllEvents( maEvents, mrEventQueue );
156 }
157
158 private:
159 EventQueue & mrEventQueue;
160 };
161
162 class AllAnimationEventHandler : public AnimationEventHandler
163 {
164 public:
AllAnimationEventHandler(EventQueue & rEventQueue)165 AllAnimationEventHandler( EventQueue& rEventQueue ) :
166 mrEventQueue( rEventQueue ),
167 maAnimationEventMap()
168 {}
169
dispose()170 virtual void dispose()
171 {
172 maAnimationEventMap.clear();
173 }
174
handleAnimationEvent(const AnimationNodeSharedPtr & rNode)175 virtual bool handleAnimationEvent( const AnimationNodeSharedPtr& rNode )
176 {
177 ENSURE_OR_RETURN_FALSE(
178 rNode,
179 "AllAnimationEventHandler::handleAnimationEvent(): Invalid node" );
180
181 bool bRet( false );
182
183 ImpAnimationEventMap::iterator aIter;
184 if( (aIter=maAnimationEventMap.find(
185 rNode->getXAnimationNode() )) != maAnimationEventMap.end() )
186 {
187 ImpEventVector& rVec( aIter->second );
188
189 bRet = !rVec.empty();
190
191 // registered node found -> fire all events in the vector
192 std::for_each( rVec.begin(), rVec.end(),
193 boost::bind( &EventQueue::addEvent,
194 boost::ref( mrEventQueue ), _1 ) );
195
196 rVec.clear();
197 }
198
199 return bRet;
200 }
201
addEvent(const EventSharedPtr & rEvent,const uno::Reference<animations::XAnimationNode> & xNode)202 void addEvent( const EventSharedPtr& rEvent,
203 const uno::Reference< animations::XAnimationNode >& xNode )
204 {
205 ImpAnimationEventMap::iterator aIter;
206 if( (aIter=maAnimationEventMap.find( xNode )) ==
207 maAnimationEventMap.end() )
208 {
209 // no entry for this animation -> create one
210 aIter = maAnimationEventMap.insert(
211 ImpAnimationEventMap::value_type( xNode,
212 ImpEventVector() ) ).first;
213 }
214
215 // add new event to queue
216 aIter->second.push_back( rEvent );
217 }
218
isEmpty()219 bool isEmpty()
220 {
221 // find at least one animation with a non-empty vector
222 ImpAnimationEventMap::const_iterator aCurr( maAnimationEventMap.begin() );
223 const ImpAnimationEventMap::const_iterator aEnd( maAnimationEventMap.end() );
224 while( aCurr != aEnd )
225 {
226 if( !aCurr->second.empty() )
227 return false; // at least one non-empty entry found
228
229 ++aCurr;
230 }
231
232 return true; // not a single non-empty entry found
233 }
234
235 private:
236 EventQueue& mrEventQueue;
237 ImpAnimationEventMap maAnimationEventMap;
238 };
239
240 class ClickEventHandler : public MouseEventHandler_,
241 public EventHandler,
242 public EventContainer
243 {
244 public:
ClickEventHandler(EventQueue & rEventQueue)245 ClickEventHandler( EventQueue& rEventQueue ) :
246 EventContainer(),
247 mrEventQueue( rEventQueue ),
248 mbAdvanceOnClick( true )
249 {}
250
setAdvanceOnClick(bool bAdvanceOnClick)251 void setAdvanceOnClick( bool bAdvanceOnClick )
252 {
253 mbAdvanceOnClick = bAdvanceOnClick;
254 }
255
256 private:
dispose()257 virtual void dispose()
258 {
259 clearContainer();
260 }
261
262 // triggered by API calls, e.g. space bar
handleEvent()263 virtual bool handleEvent()
264 {
265 return handleEvent_impl();
266 }
267
268 // triggered by mouse release:
handleMouseReleased(const awt::MouseEvent & evt)269 virtual bool handleMouseReleased( const awt::MouseEvent& evt )
270 {
271 if(evt.Buttons != awt::MouseButton::LEFT)
272 return false;
273
274 if( mbAdvanceOnClick ) {
275 // fire next event
276 return handleEvent_impl();
277 }
278 else {
279 return false; // advance-on-click disabled
280 }
281 }
282
283 // triggered by both:
handleEvent_impl()284 virtual bool handleEvent_impl()
285 {
286 // fire next event:
287 return fireSingleEvent( maEvents, mrEventQueue );
288 }
289
290 private:
291 EventQueue& mrEventQueue;
292 bool mbAdvanceOnClick;
293 };
294
295 class SkipEffectEventHandler : public ClickEventHandler
296 {
297 public:
SkipEffectEventHandler(EventQueue & rEventQueue,EventMultiplexer & rEventMultiplexer)298 SkipEffectEventHandler( EventQueue & rEventQueue,
299 EventMultiplexer & rEventMultiplexer )
300 : ClickEventHandler(rEventQueue),
301 mrEventQueue(rEventQueue),
302 mrEventMultiplexer(rEventMultiplexer),
303 mbSkipTriggersNextEffect(true) {}
304
305 /** Remember to trigger (or not to trigger) the next effect after the
306 current effect is skiped.
307 */
setSkipTriggersNextEffect(const bool bSkipTriggersNextEffect)308 void setSkipTriggersNextEffect (const bool bSkipTriggersNextEffect)
309 { mbSkipTriggersNextEffect = bSkipTriggersNextEffect; }
310
311 /// Skip the current effect but do not triggere the next effect.
skipEffect(void)312 void skipEffect (void) { handleEvent_impl(false); }
313
314 private:
handleEvent_impl()315 virtual bool handleEvent_impl()
316 {
317 return handleEvent_impl(true);
318 }
319
handleEvent_impl(bool bNotifyNextEffect)320 bool handleEvent_impl (bool bNotifyNextEffect)
321 {
322 // fire all events, so animation nodes can register their
323 // next effect listeners:
324 if(fireAllEvents( maEvents, mrEventQueue ))
325 {
326 if (mbSkipTriggersNextEffect && bNotifyNextEffect)
327 {
328 // then simulate a next effect event: this skip effect
329 // handler is triggered upon next effect events (multiplexer
330 // prio=-1)! Posting a notifyNextEffect() here is only safe
331 // (we don't run into busy loop), because we assume that
332 // someone has registerered above for next effects
333 // (multiplexer prio=0) at the user event queue.
334 return mrEventQueue.addEventWhenQueueIsEmpty(
335 makeEvent( boost::bind( &EventMultiplexer::notifyNextEffect,
336 boost::ref(mrEventMultiplexer) ),
337 "EventMultiplexer::notifyNextEffect") );
338 }
339 else
340 return true;
341 }
342 return false;
343 }
344
345 private:
346 EventQueue & mrEventQueue;
347 EventMultiplexer & mrEventMultiplexer;
348 bool mbSkipTriggersNextEffect;
349 };
350
351 class RewindEffectEventHandler : public MouseEventHandler_,
352 public EventContainer
353 {
354 public:
RewindEffectEventHandler(EventQueue & rEventQueue)355 RewindEffectEventHandler( EventQueue & rEventQueue )
356 : EventContainer(), mrEventQueue(rEventQueue) {}
357
358 private:
dispose()359 virtual void dispose()
360 {
361 clearContainer();
362 }
363
handleMouseReleased(awt::MouseEvent const & evt)364 virtual bool handleMouseReleased( awt::MouseEvent const& evt )
365 {
366 if(evt.Buttons != awt::MouseButton::RIGHT)
367 return false;
368
369 return fireAllEvents( maEvents, mrEventQueue );
370 }
371
372 private:
373 EventQueue & mrEventQueue;
374 };
375
376 /** Base class to share some common code between
377 ShapeClickEventHandler and MouseMoveHandler
378
379 @derive override necessary MouseEventHandler interface methods,
380 call sendEvent() method to actually process the event.
381 */
382 class MouseHandlerBase : public MouseEventHandler_
383 {
384 public:
MouseHandlerBase(EventQueue & rEventQueue)385 MouseHandlerBase( EventQueue& rEventQueue ) :
386 mrEventQueue( rEventQueue ),
387 maShapeEventMap()
388 {}
389
dispose()390 virtual void dispose()
391 {
392 // TODO(Q1): Check whether plain vector with swap idiom is
393 // okay here
394 maShapeEventMap = ImpShapeEventMap();
395 }
396
addEvent(const EventSharedPtr & rEvent,const ShapeSharedPtr & rShape)397 void addEvent( const EventSharedPtr& rEvent,
398 const ShapeSharedPtr& rShape )
399 {
400 ImpShapeEventMap::iterator aIter;
401 if( (aIter=maShapeEventMap.find( rShape )) == maShapeEventMap.end() )
402 {
403 // no entry for this shape -> create one
404 aIter = maShapeEventMap.insert(
405 ImpShapeEventMap::value_type( rShape,
406 ImpEventQueue() ) ).first;
407 }
408
409 // add new event to queue
410 aIter->second.push( rEvent );
411 }
412
isEmpty()413 bool isEmpty()
414 {
415 // find at least one shape with a non-empty queue
416 ImpShapeEventMap::reverse_iterator aCurrShape( maShapeEventMap.begin());
417 ImpShapeEventMap::reverse_iterator aEndShape( maShapeEventMap.end() );
418 while( aCurrShape != aEndShape )
419 {
420 if( !aCurrShape->second.empty() )
421 return false; // at least one non-empty entry found
422
423 ++aCurrShape;
424 }
425
426 return true; // not a single non-empty entry found
427 }
428
429 protected:
hitTest(const awt::MouseEvent & e,ImpShapeEventMap::reverse_iterator & o_rHitShape)430 bool hitTest( const awt::MouseEvent& e,
431 ImpShapeEventMap::reverse_iterator& o_rHitShape )
432 {
433 // find hit shape in map
434 const basegfx::B2DPoint aPosition( e.X, e.Y );
435
436 // find matching shape (scan reversely, to coarsely match
437 // paint order)
438 ImpShapeEventMap::reverse_iterator aCurrShape(maShapeEventMap.rbegin());
439 const ImpShapeEventMap::reverse_iterator aEndShape( maShapeEventMap.rend() );
440 while( aCurrShape != aEndShape )
441 {
442 // TODO(F2): Get proper geometry polygon from the
443 // shape, to avoid having areas outside the shape
444 // react on the mouse
445 if( aCurrShape->first->getBounds().isInside( aPosition ) &&
446 aCurrShape->first->isVisible() )
447 {
448 // shape hit, and shape is visible - report a
449 // hit
450 o_rHitShape = aCurrShape;
451 return true;
452 }
453
454 ++aCurrShape;
455 }
456
457 return false; // nothing hit
458 }
459
sendEvent(ImpShapeEventMap::reverse_iterator & io_rHitShape)460 bool sendEvent( ImpShapeEventMap::reverse_iterator& io_rHitShape )
461 {
462 // take next event from queue
463 const bool bRet( fireSingleEvent( io_rHitShape->second,
464 mrEventQueue ) );
465
466 // clear shape entry, if its queue is
467 // empty. This is important, since the shapes
468 // are held by shared ptr, and might otherwise
469 // not get released, even after their owning
470 // slide is long gone.
471 if( io_rHitShape->second.empty() )
472 {
473 // this looks funny, since ::std::map does
474 // provide an erase( iterator )
475 // method. Unfortunately, stlport does not
476 // declare the obvious erase(
477 // reverse_iterator ) needed here (missing
478 // orthogonality, eh?)
479 maShapeEventMap.erase( io_rHitShape->first );
480 }
481
482 return bRet;
483 }
484
processEvent(const awt::MouseEvent & e)485 bool processEvent( const awt::MouseEvent& e )
486 {
487 ImpShapeEventMap::reverse_iterator aCurrShape;
488
489 if( hitTest( e, aCurrShape ) )
490 return sendEvent( aCurrShape );
491
492 return false; // did not handle the event
493 }
494
495 private:
496 EventQueue& mrEventQueue;
497 ImpShapeEventMap maShapeEventMap;
498 };
499
500 class ShapeClickEventHandler : public MouseHandlerBase
501 {
502 public:
ShapeClickEventHandler(CursorManager & rCursorManager,EventQueue & rEventQueue)503 ShapeClickEventHandler( CursorManager& rCursorManager,
504 EventQueue& rEventQueue ) :
505 MouseHandlerBase( rEventQueue ),
506 mrCursorManager( rCursorManager )
507 {}
508
handleMouseReleased(const awt::MouseEvent & e)509 virtual bool handleMouseReleased( const awt::MouseEvent& e )
510 {
511 if(e.Buttons != awt::MouseButton::LEFT)
512 return false;
513 return processEvent( e );
514 }
515
handleMouseMoved(const awt::MouseEvent & e)516 virtual bool handleMouseMoved( const awt::MouseEvent& e )
517 {
518 // TODO(P2): Maybe buffer last shape touched
519
520 // if we have a shape click event, and the mouse
521 // hovers over this shape, change cursor to hand
522 ImpShapeEventMap::reverse_iterator aDummy;
523 if( hitTest( e, aDummy ) )
524 mrCursorManager.requestCursor( awt::SystemPointer::REFHAND );
525
526 return false; // we don't /eat/ this event. Lower prio
527 // handler should see it, too.
528 }
529
530 private:
531 CursorManager& mrCursorManager;
532 };
533
534 class MouseEnterHandler : public MouseHandlerBase
535 {
536 public:
MouseEnterHandler(EventQueue & rEventQueue)537 MouseEnterHandler( EventQueue& rEventQueue )
538 : MouseHandlerBase( rEventQueue ),
539 mpLastShape() {}
540
handleMouseMoved(const awt::MouseEvent & e)541 virtual bool handleMouseMoved( const awt::MouseEvent& e )
542 {
543 // TODO(P2): Maybe buffer last shape touched, and
544 // check against that _first_
545
546 ImpShapeEventMap::reverse_iterator aCurr;
547 if( hitTest( e, aCurr ) )
548 {
549 if( aCurr->first != mpLastShape )
550 {
551 // we actually hit a shape, and it's different
552 // from the previous one - thus we just
553 // entered it, raise event
554 sendEvent( aCurr );
555 mpLastShape = aCurr->first;
556 }
557 }
558 else
559 {
560 // don't hit no shape - thus, last shape is NULL
561 mpLastShape.reset();
562 }
563
564 return false; // we don't /eat/ this event. Lower prio
565 // handler should see it, too.
566 }
567
568 private:
569 ShapeSharedPtr mpLastShape;
570 };
571
572 class MouseLeaveHandler : public MouseHandlerBase
573 {
574 public:
MouseLeaveHandler(EventQueue & rEventQueue)575 MouseLeaveHandler( EventQueue& rEventQueue )
576 : MouseHandlerBase( rEventQueue ),
577 maLastIter() {}
578
handleMouseMoved(const awt::MouseEvent & e)579 virtual bool handleMouseMoved( const awt::MouseEvent& e )
580 {
581 // TODO(P2): Maybe buffer last shape touched, and
582 // check against that _first_
583
584 ImpShapeEventMap::reverse_iterator aCurr;
585 if( hitTest( e, aCurr ) )
586 {
587 maLastIter = aCurr;
588 }
589 else
590 {
591 if( maLastIter->first )
592 {
593 // last time, we were over a shape, now we're
594 // not - we thus just left that shape, raise
595 // event
596 sendEvent( maLastIter );
597 }
598
599 // in any case, when we hit this else-branch: no
600 // shape hit, thus have to clear maLastIter
601 maLastIter = ImpShapeEventMap::reverse_iterator();
602 }
603
604 return false; // we don't /eat/ this event. Lower prio
605 // handler should see it, too.
606 }
607
608 private:
609 ImpShapeEventMap::reverse_iterator maLastIter;
610 };
611
612 template< typename Handler, typename Functor >
registerEvent(boost::shared_ptr<Handler> & rHandler,const EventSharedPtr & rEvent,const Functor & rRegistrationFunctor)613 void UserEventQueue::registerEvent(
614 boost::shared_ptr< Handler >& rHandler,
615 const EventSharedPtr& rEvent,
616 const Functor& rRegistrationFunctor )
617 {
618 ENSURE_OR_THROW( rEvent,
619 "UserEventQueue::registerEvent(): Invalid event" );
620
621 if( !rHandler ) {
622 // create handler
623 rHandler.reset( new Handler( mrEventQueue ) );
624 // register handler on EventMultiplexer
625 rRegistrationFunctor( rHandler );
626 }
627
628 rHandler->addEvent( rEvent );
629 }
630
631 template< typename Handler, typename Arg, typename Functor >
registerEvent(boost::shared_ptr<Handler> & rHandler,const EventSharedPtr & rEvent,const Arg & rArg,const Functor & rRegistrationFunctor)632 void UserEventQueue::registerEvent(
633 boost::shared_ptr< Handler >& rHandler,
634 const EventSharedPtr& rEvent,
635 const Arg& rArg,
636 const Functor& rRegistrationFunctor )
637 {
638 ENSURE_OR_THROW( rEvent,
639 "UserEventQueue::registerEvent(): Invalid event" );
640
641 if( !rHandler ) {
642 // create handler
643 rHandler.reset( new Handler( mrEventQueue ) );
644
645 // register handler on EventMultiplexer
646 rRegistrationFunctor( rHandler );
647 }
648
649 rHandler->addEvent( rEvent, rArg );
650 }
651
652
653 // Public methods
654 // =====================================================
655
UserEventQueue(EventMultiplexer & rMultiplexer,EventQueue & rEventQueue,CursorManager & rCursorManager)656 UserEventQueue::UserEventQueue( EventMultiplexer& rMultiplexer,
657 EventQueue& rEventQueue,
658 CursorManager& rCursorManager )
659 : mrMultiplexer( rMultiplexer ),
660 mrEventQueue( rEventQueue ),
661 mrCursorManager( rCursorManager ),
662 mpStartEventHandler(),
663 mpEndEventHandler(),
664 mpAnimationStartEventHandler(),
665 mpAnimationEndEventHandler(),
666 mpAudioStoppedEventHandler(),
667 mpClickEventHandler(),
668 mpSkipEffectEventHandler(),
669 mpRewindEffectEventHandler(),
670 mpDoubleClickEventHandler(),
671 mpMouseEnterHandler(),
672 mpMouseLeaveHandler(),
673 mbAdvanceOnClick( true )
674 {
675 }
676
~UserEventQueue()677 UserEventQueue::~UserEventQueue()
678 {
679 try
680 {
681 // unregister all handlers
682 clear();
683 }
684 catch (uno::Exception &) {
685 OSL_ENSURE( false, rtl::OUStringToOString(
686 comphelper::anyToString(
687 cppu::getCaughtException() ),
688 RTL_TEXTENCODING_UTF8 ).getStr() );
689 }
690 }
691
isEmpty() const692 bool UserEventQueue::isEmpty() const
693 {
694 // TODO(T2): This is not thread safe, the handlers are all
695 // only separately synchronized. This poses the danger of
696 // generating false empty status on XSlideShow::update(), such
697 // that the last events of a slide are not triggered.
698
699 // we're empty iff all handler queues are empty
700 return
701 (mpStartEventHandler ? mpStartEventHandler->isEmpty() : true) &&
702 (mpEndEventHandler ? mpEndEventHandler->isEmpty() : true) &&
703 (mpAnimationStartEventHandler ? mpAnimationStartEventHandler->isEmpty() : true) &&
704 (mpAnimationEndEventHandler ? mpAnimationEndEventHandler->isEmpty() : true) &&
705 (mpAudioStoppedEventHandler ? mpAudioStoppedEventHandler->isEmpty() : true) &&
706 (mpShapeClickEventHandler ? mpShapeClickEventHandler->isEmpty() : true) &&
707 (mpClickEventHandler ? mpClickEventHandler->isEmpty() : true) &&
708 (mpSkipEffectEventHandler ? mpSkipEffectEventHandler->isEmpty() : true) &&
709 (mpRewindEffectEventHandler ? mpRewindEffectEventHandler->isEmpty() : true) &&
710 (mpShapeDoubleClickEventHandler ? mpShapeDoubleClickEventHandler->isEmpty() : true) &&
711 (mpDoubleClickEventHandler ? mpDoubleClickEventHandler->isEmpty() : true) &&
712 (mpMouseEnterHandler ? mpMouseEnterHandler->isEmpty() : true) &&
713 (mpMouseLeaveHandler ? mpMouseLeaveHandler->isEmpty() : true);
714 }
715
clear()716 void UserEventQueue::clear()
717 {
718 // unregister and delete all handlers
719 if( mpStartEventHandler ) {
720 mrMultiplexer.removeSlideStartHandler( mpStartEventHandler );
721 mpStartEventHandler.reset();
722 }
723 if( mpEndEventHandler ) {
724 mrMultiplexer.removeSlideEndHandler( mpEndEventHandler );
725 mpEndEventHandler.reset();
726 }
727 if( mpAnimationStartEventHandler ) {
728 mrMultiplexer.removeAnimationStartHandler(
729 mpAnimationStartEventHandler );
730 mpAnimationStartEventHandler.reset();
731 }
732 if( mpAnimationEndEventHandler ) {
733 mrMultiplexer.removeAnimationEndHandler( mpAnimationEndEventHandler );
734 mpAnimationEndEventHandler.reset();
735 }
736 if( mpAudioStoppedEventHandler ) {
737 mrMultiplexer.removeAudioStoppedHandler( mpAudioStoppedEventHandler );
738 mpAudioStoppedEventHandler.reset();
739 }
740 if( mpShapeClickEventHandler ) {
741 mrMultiplexer.removeClickHandler( mpShapeClickEventHandler );
742 mrMultiplexer.removeMouseMoveHandler( mpShapeClickEventHandler );
743 mpShapeClickEventHandler.reset();
744 }
745 if( mpClickEventHandler ) {
746 mrMultiplexer.removeClickHandler( mpClickEventHandler );
747 mrMultiplexer.removeNextEffectHandler( mpClickEventHandler );
748 mpClickEventHandler.reset();
749 }
750 if(mpSkipEffectEventHandler) {
751 mrMultiplexer.removeClickHandler( mpSkipEffectEventHandler );
752 mrMultiplexer.removeNextEffectHandler( mpSkipEffectEventHandler );
753 mpSkipEffectEventHandler.reset();
754 }
755 if(mpRewindEffectEventHandler) {
756 mrMultiplexer.removeClickHandler( mpRewindEffectEventHandler );
757 mpRewindEffectEventHandler.reset();
758 }
759 if( mpShapeDoubleClickEventHandler ) {
760 mrMultiplexer.removeDoubleClickHandler( mpShapeDoubleClickEventHandler );
761 mrMultiplexer.removeMouseMoveHandler( mpShapeDoubleClickEventHandler );
762 mpShapeDoubleClickEventHandler.reset();
763 }
764 if( mpDoubleClickEventHandler ) {
765 mrMultiplexer.removeDoubleClickHandler( mpDoubleClickEventHandler );
766 mpDoubleClickEventHandler.reset();
767 }
768 if( mpMouseEnterHandler ) {
769 mrMultiplexer.removeMouseMoveHandler( mpMouseEnterHandler );
770 mpMouseEnterHandler.reset();
771 }
772 if( mpMouseLeaveHandler ) {
773 mrMultiplexer.removeMouseMoveHandler( mpMouseLeaveHandler );
774 mpMouseLeaveHandler.reset();
775 }
776 }
777
setAdvanceOnClick(bool bAdvanceOnClick)778 void UserEventQueue::setAdvanceOnClick( bool bAdvanceOnClick )
779 {
780 mbAdvanceOnClick = bAdvanceOnClick;
781
782 // forward to handler, if existing. Otherwise, the handler
783 // creation will do the forwarding.
784 if( mpClickEventHandler )
785 mpClickEventHandler->setAdvanceOnClick( bAdvanceOnClick );
786 }
787
788
registerSlideStartEvent(const EventSharedPtr & rEvent)789 void UserEventQueue::registerSlideStartEvent( const EventSharedPtr& rEvent )
790 {
791 registerEvent( mpStartEventHandler,
792 rEvent,
793 boost::bind( &EventMultiplexer::addSlideStartHandler,
794 boost::ref( mrMultiplexer ), _1 ) );
795 }
796
registerSlideEndEvent(const EventSharedPtr & rEvent)797 void UserEventQueue::registerSlideEndEvent( const EventSharedPtr& rEvent )
798 {
799 registerEvent( mpEndEventHandler,
800 rEvent,
801 boost::bind( &EventMultiplexer::addSlideEndHandler,
802 boost::ref( mrMultiplexer ), _1 ) );
803 }
804
registerAnimationStartEvent(const EventSharedPtr & rEvent,const uno::Reference<animations::XAnimationNode> & xNode)805 void UserEventQueue::registerAnimationStartEvent(
806 const EventSharedPtr& rEvent,
807 const uno::Reference< animations::XAnimationNode>& xNode )
808 {
809 registerEvent( mpAnimationStartEventHandler,
810 rEvent,
811 xNode,
812 boost::bind( &EventMultiplexer::addAnimationStartHandler,
813 boost::ref( mrMultiplexer ), _1 ) );
814 }
815
registerAnimationEndEvent(const EventSharedPtr & rEvent,const uno::Reference<animations::XAnimationNode> & xNode)816 void UserEventQueue::registerAnimationEndEvent(
817 const EventSharedPtr& rEvent,
818 const uno::Reference<animations::XAnimationNode>& xNode )
819 {
820 registerEvent( mpAnimationEndEventHandler,
821 rEvent,
822 xNode,
823 boost::bind( &EventMultiplexer::addAnimationEndHandler,
824 boost::ref( mrMultiplexer ), _1 ) );
825 }
826
registerAudioStoppedEvent(const EventSharedPtr & rEvent,const uno::Reference<animations::XAnimationNode> & xNode)827 void UserEventQueue::registerAudioStoppedEvent(
828 const EventSharedPtr& rEvent,
829 const uno::Reference<animations::XAnimationNode>& xNode )
830 {
831 registerEvent( mpAudioStoppedEventHandler,
832 rEvent,
833 xNode,
834 boost::bind( &EventMultiplexer::addAudioStoppedHandler,
835 boost::ref( mrMultiplexer ), _1 ) );
836 }
837
registerShapeClickEvent(const EventSharedPtr & rEvent,const ShapeSharedPtr & rShape)838 void UserEventQueue::registerShapeClickEvent( const EventSharedPtr& rEvent,
839 const ShapeSharedPtr& rShape )
840 {
841 ENSURE_OR_THROW(
842 rEvent,
843 "UserEventQueue::registerShapeClickEvent(): Invalid event" );
844
845 if( !mpShapeClickEventHandler )
846 {
847 // create handler
848 mpShapeClickEventHandler.reset(
849 new ShapeClickEventHandler(mrCursorManager,
850 mrEventQueue) );
851
852 // register handler on EventMultiplexer
853 mrMultiplexer.addClickHandler( mpShapeClickEventHandler, 1.0 );
854 mrMultiplexer.addMouseMoveHandler( mpShapeClickEventHandler, 1.0 );
855 }
856
857 mpShapeClickEventHandler->addEvent( rEvent, rShape );
858 }
859
860 namespace {
861 class ClickEventRegistrationFunctor
862 {
863 public:
ClickEventRegistrationFunctor(EventMultiplexer & rMultiplexer,double nPrio,bool bAdvanceOnClick)864 ClickEventRegistrationFunctor( EventMultiplexer& rMultiplexer,
865 double nPrio,
866 bool bAdvanceOnClick )
867 : mrMultiplexer( rMultiplexer ),
868 mnPrio(nPrio),
869 mbAdvanceOnClick( bAdvanceOnClick ) {}
870
operator ()(const boost::shared_ptr<ClickEventHandler> & rHandler) const871 void operator()( const boost::shared_ptr<ClickEventHandler>& rHandler )const
872 {
873 // register the handler on _two_ sources: we want the
874 // nextEffect events, e.g. space bar, to trigger clicks, as well!
875 mrMultiplexer.addClickHandler( rHandler, mnPrio );
876 mrMultiplexer.addNextEffectHandler( rHandler, mnPrio );
877
878 // forward advance-on-click state to newly
879 // generated handler (that's the only reason why
880 // we're called here)
881 rHandler->setAdvanceOnClick( mbAdvanceOnClick );
882 }
883
884 private:
885 EventMultiplexer& mrMultiplexer;
886 double const mnPrio;
887 bool const mbAdvanceOnClick;
888 };
889 } // anon namespace
890
registerNextEffectEvent(const EventSharedPtr & rEvent)891 void UserEventQueue::registerNextEffectEvent( const EventSharedPtr& rEvent )
892 {
893 // TODO: better name may be mpNextEffectEventHandler? then we have
894 // next effect (=> waiting to be started)
895 // skip effect (skipping the currently running one)
896 // rewind effect (rewinding back running one and waiting (again)
897 // to be started)
898 registerEvent( mpClickEventHandler,
899 rEvent,
900 ClickEventRegistrationFunctor( mrMultiplexer,
901 0.0 /* default prio */,
902 mbAdvanceOnClick ) );
903 }
904
registerSkipEffectEvent(EventSharedPtr const & pEvent,const bool bSkipTriggersNextEffect)905 void UserEventQueue::registerSkipEffectEvent(
906 EventSharedPtr const & pEvent,
907 const bool bSkipTriggersNextEffect)
908 {
909 if(!mpSkipEffectEventHandler)
910 {
911 mpSkipEffectEventHandler.reset(
912 new SkipEffectEventHandler( mrEventQueue, mrMultiplexer ) );
913 // register the handler on _two_ sources: we want the
914 // nextEffect events, e.g. space bar, to trigger clicks, as well!
915 mrMultiplexer.addClickHandler( mpSkipEffectEventHandler,
916 -1.0 /* prio below default */ );
917 mrMultiplexer.addNextEffectHandler( mpSkipEffectEventHandler,
918 -1.0 /* prio below default */ );
919 // forward advance-on-click state to newly
920 // generated handler (that's the only reason why
921 // we're called here)
922 mpSkipEffectEventHandler->setAdvanceOnClick( mbAdvanceOnClick );
923 }
924 mpSkipEffectEventHandler->setSkipTriggersNextEffect(bSkipTriggersNextEffect);
925 mpSkipEffectEventHandler->addEvent( pEvent );
926 }
927
registerRewindEffectEvent(EventSharedPtr const & pEvent)928 void UserEventQueue::registerRewindEffectEvent( EventSharedPtr const& pEvent )
929 {
930 registerEvent( mpRewindEffectEventHandler,
931 pEvent,
932 boost::bind( &EventMultiplexer::addClickHandler,
933 boost::ref(mrMultiplexer), _1,
934 -1.0 /* prio below default */ ) );
935 }
936
registerShapeDoubleClickEvent(const EventSharedPtr & rEvent,const ShapeSharedPtr & rShape)937 void UserEventQueue::registerShapeDoubleClickEvent(
938 const EventSharedPtr& rEvent,
939 const ShapeSharedPtr& rShape )
940 {
941 ENSURE_OR_THROW(
942 rEvent,
943 "UserEventQueue::registerShapeDoubleClickEvent(): Invalid event" );
944
945 if( !mpShapeDoubleClickEventHandler )
946 {
947 // create handler
948 mpShapeDoubleClickEventHandler.reset(
949 new ShapeClickEventHandler(mrCursorManager,
950 mrEventQueue) );
951
952 // register handler on EventMultiplexer
953 mrMultiplexer.addDoubleClickHandler( mpShapeDoubleClickEventHandler,
954 1.0 );
955 mrMultiplexer.addMouseMoveHandler( mpShapeDoubleClickEventHandler,
956 1.0 );
957 }
958
959 mpShapeDoubleClickEventHandler->addEvent( rEvent, rShape );
960 }
961
registerDoubleClickEvent(const EventSharedPtr & rEvent)962 void UserEventQueue::registerDoubleClickEvent( const EventSharedPtr& rEvent )
963 {
964 registerEvent( mpDoubleClickEventHandler,
965 rEvent,
966 boost::bind( &EventMultiplexer::addDoubleClickHandler,
967 boost::ref( mrMultiplexer ), _1,
968 0.0 /* default prio */ ) );
969 }
970
registerMouseEnterEvent(const EventSharedPtr & rEvent,const ShapeSharedPtr & rShape)971 void UserEventQueue::registerMouseEnterEvent( const EventSharedPtr& rEvent,
972 const ShapeSharedPtr& rShape )
973 {
974 registerEvent( mpMouseEnterHandler,
975 rEvent,
976 rShape,
977 boost::bind( &EventMultiplexer::addMouseMoveHandler,
978 boost::ref( mrMultiplexer ), _1,
979 0.0 /* default prio */ ) );
980 }
981
registerMouseLeaveEvent(const EventSharedPtr & rEvent,const ShapeSharedPtr & rShape)982 void UserEventQueue::registerMouseLeaveEvent( const EventSharedPtr& rEvent,
983 const ShapeSharedPtr& rShape )
984 {
985 registerEvent( mpMouseLeaveHandler,
986 rEvent,
987 rShape,
988 boost::bind( &EventMultiplexer::addMouseMoveHandler,
989 boost::ref( mrMultiplexer ), _1,
990 0.0 /* default prio */ ) );
991 }
992
callSkipEffectEventHandler(void)993 void UserEventQueue::callSkipEffectEventHandler (void)
994 {
995 ::boost::shared_ptr<SkipEffectEventHandler> pHandler (
996 ::boost::dynamic_pointer_cast<SkipEffectEventHandler>(mpSkipEffectEventHandler));
997 if (pHandler)
998 pHandler->skipEffect();
999 }
1000
1001 } // namespace internal
1002 } // namespace presentation
1003
1004