Update ooo320-m1
[ooovba.git] / slideshow / source / engine / usereventqueue.cxx
blob774fd0acb73e8e2b1ccacf5b83eb5d75189835e5
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: usereventqueue.cxx,v $
10 * $Revision: 1.13 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_slideshow.hxx"
34 // must be first
35 #include <canvas/debug.hxx>
36 #include <tools/diagnose_ex.h>
38 #include <comphelper/anytostring.hxx>
39 #include <cppuhelper/exc_hlp.hxx>
41 #include <com/sun/star/awt/SystemPointer.hpp>
42 #include <com/sun/star/awt/MouseButton.hpp>
43 #include <com/sun/star/awt/MouseEvent.hpp>
45 #include <boost/bind.hpp>
47 #include "delayevent.hxx"
48 #include "usereventqueue.hxx"
49 #include "cursormanager.hxx"
50 #include "slideshowexceptions.hxx"
52 #include <vector>
53 #include <queue>
54 #include <map>
55 #include <functional>
56 #include <algorithm>
59 using namespace com::sun::star;
61 /* Implementation of UserEventQueue class */
63 namespace slideshow {
64 namespace internal {
66 namespace {
68 typedef std::vector<EventSharedPtr> ImpEventVector;
69 typedef std::queue<EventSharedPtr> ImpEventQueue;
70 typedef std::map<uno::Reference<animations::XAnimationNode>,
71 ImpEventVector> ImpAnimationEventMap;
72 typedef std::map<ShapeSharedPtr, ImpEventQueue,
73 Shape::lessThanShape> ImpShapeEventMap;
75 // MouseEventHandler base class, not consuming any event:
76 class MouseEventHandler_ : public MouseEventHandler
78 public:
79 virtual bool handleMousePressed( awt::MouseEvent const& /*e*/ ) { return false;}
80 virtual bool handleMouseReleased( awt::MouseEvent const& /*e*/) { return false;}
81 virtual bool handleMouseEntered( awt::MouseEvent const& /*e*/ ) { return false;}
82 virtual bool handleMouseExited( awt::MouseEvent const& /*e*/ ) { return false; }
83 virtual bool handleMouseDragged( awt::MouseEvent const& /*e*/ ) { return false;}
84 virtual bool handleMouseMoved( awt::MouseEvent const& /*e*/ ) { return false; }
87 /** @return one event has been posted
89 template <typename ContainerT>
90 bool fireSingleEvent( ContainerT & rQueue, EventQueue & rEventQueue )
92 // post next event in given queue:
93 while (! rQueue.empty())
95 EventSharedPtr const pEvent(rQueue.front());
96 rQueue.pop();
98 // skip all inactive events (as the purpose of
99 // nextEventFromQueue() is to activate the next
100 // event, and events which return false on
101 // isCharged() will never be activated by the
102 // EventQueue)
103 if(pEvent->isCharged())
104 return rEventQueue.addEvent( pEvent );
106 return false; // no more (active) events in queue
109 /** @return at least one event has been posted
111 template <typename ContainerT>
112 bool fireAllEvents( ContainerT & rQueue, EventQueue & rEventQueue )
114 bool bFiredAny = false;
115 while (fireSingleEvent( rQueue, rEventQueue ))
116 bFiredAny = true;
117 return bFiredAny;
120 class EventContainer
122 public:
123 EventContainer() :
124 maEvents()
127 void clearContainer()
129 maEvents = ImpEventQueue();
132 void addEvent( const EventSharedPtr& rEvent )
134 maEvents.push( rEvent );
137 bool isEmpty()
139 return maEvents.empty();
142 protected:
143 ImpEventQueue maEvents;
146 } // anon namespace
148 class PlainEventHandler : public EventHandler,
149 public EventContainer
151 public:
152 PlainEventHandler( EventQueue & rEventQueue )
153 : EventContainer(), mrEventQueue(rEventQueue) {}
155 virtual void dispose()
157 clearContainer();
160 virtual bool handleEvent()
162 return fireAllEvents( maEvents, mrEventQueue );
165 private:
166 EventQueue & mrEventQueue;
169 class AllAnimationEventHandler : public AnimationEventHandler
171 public:
172 AllAnimationEventHandler( EventQueue& rEventQueue ) :
173 mrEventQueue( rEventQueue ),
174 maAnimationEventMap()
177 virtual void dispose()
179 maAnimationEventMap.clear();
182 virtual bool handleAnimationEvent( const AnimationNodeSharedPtr& rNode )
184 ENSURE_OR_RETURN(
185 rNode,
186 "AllAnimationEventHandler::handleAnimationEvent(): Invalid node" );
188 bool bRet( false );
190 ImpAnimationEventMap::iterator aIter;
191 if( (aIter=maAnimationEventMap.find(
192 rNode->getXAnimationNode() )) != maAnimationEventMap.end() )
194 ImpEventVector& rVec( aIter->second );
196 bRet = !rVec.empty();
198 // registered node found -> fire all events in the vector
199 std::for_each( rVec.begin(), rVec.end(),
200 boost::bind( &EventQueue::addEvent,
201 boost::ref( mrEventQueue ), _1 ) );
203 rVec.clear();
206 return bRet;
209 void addEvent( const EventSharedPtr& rEvent,
210 const uno::Reference< animations::XAnimationNode >& xNode )
212 ImpAnimationEventMap::iterator aIter;
213 if( (aIter=maAnimationEventMap.find( xNode )) ==
214 maAnimationEventMap.end() )
216 // no entry for this animation -> create one
217 aIter = maAnimationEventMap.insert(
218 ImpAnimationEventMap::value_type( xNode,
219 ImpEventVector() ) ).first;
222 // add new event to queue
223 aIter->second.push_back( rEvent );
226 bool isEmpty()
228 // find at least one animation with a non-empty vector
229 ImpAnimationEventMap::const_iterator aCurr( maAnimationEventMap.begin() );
230 const ImpAnimationEventMap::const_iterator aEnd( maAnimationEventMap.end() );
231 while( aCurr != aEnd )
233 if( !aCurr->second.empty() )
234 return false; // at least one non-empty entry found
236 ++aCurr;
239 return true; // not a single non-empty entry found
242 private:
243 EventQueue& mrEventQueue;
244 ImpAnimationEventMap maAnimationEventMap;
247 class ClickEventHandler : public MouseEventHandler_,
248 public EventHandler,
249 public EventContainer
251 public:
252 ClickEventHandler( EventQueue& rEventQueue ) :
253 EventContainer(),
254 mrEventQueue( rEventQueue ),
255 mbAdvanceOnClick( true )
258 void setAdvanceOnClick( bool bAdvanceOnClick )
260 mbAdvanceOnClick = bAdvanceOnClick;
263 private:
264 virtual void dispose()
266 clearContainer();
269 // triggered by API calls, e.g. space bar
270 virtual bool handleEvent()
272 return handleEvent_impl();
275 // triggered by mouse release:
276 virtual bool handleMouseReleased( const awt::MouseEvent& evt )
278 if(evt.Buttons != awt::MouseButton::LEFT)
279 return false;
281 if( mbAdvanceOnClick ) {
282 // fire next event
283 return handleEvent_impl();
285 else {
286 return false; // advance-on-click disabled
290 // triggered by both:
291 virtual bool handleEvent_impl()
293 // fire next event:
294 return fireSingleEvent( maEvents, mrEventQueue );
297 private:
298 EventQueue& mrEventQueue;
299 bool mbAdvanceOnClick;
302 class SkipEffectEventHandler : public ClickEventHandler
304 public:
305 SkipEffectEventHandler( EventQueue & rEventQueue,
306 EventMultiplexer & rEventMultiplexer )
307 : ClickEventHandler(rEventQueue),
308 mrEventQueue(rEventQueue),
309 mrEventMultiplexer(rEventMultiplexer),
310 mbSkipTriggersNextEffect(true) {}
312 /** Remember to trigger (or not to trigger) the next effect after the
313 current effect is skiped.
315 void setSkipTriggersNextEffect (const bool bSkipTriggersNextEffect)
316 { mbSkipTriggersNextEffect = bSkipTriggersNextEffect; }
318 /// Skip the current effect but do not triggere the next effect.
319 void skipEffect (void) { handleEvent_impl(false); }
321 private:
322 virtual bool handleEvent_impl()
324 return handleEvent_impl(true);
327 bool handleEvent_impl (bool bNotifyNextEffect)
329 // fire all events, so animation nodes can register their
330 // next effect listeners:
331 if(fireAllEvents( maEvents, mrEventQueue ))
333 makeEvent(::boost::bind(&EventQueue::forceEmpty, ::boost::ref(mrEventQueue)));
334 if (mbSkipTriggersNextEffect && bNotifyNextEffect)
336 // then simulate a next effect event: this skip effect
337 // handler is triggered upon next effect events (multiplexer
338 // prio=-1)! Posting a notifyNextEffect() here is only safe
339 // (we don't run into busy loop), because we assume that
340 // someone has registerered above for next effects
341 // (multiplexer prio=0) at the user event queue.
342 return mrEventQueue.addEventWhenQueueIsEmpty(
343 makeEvent( boost::bind(
344 &EventMultiplexer::notifyNextEffect,
345 boost::ref(mrEventMultiplexer) ) ) );
347 else
348 return true;
350 return false;
353 private:
354 EventQueue & mrEventQueue;
355 EventMultiplexer & mrEventMultiplexer;
356 bool mbSkipTriggersNextEffect;
359 class RewindEffectEventHandler : public MouseEventHandler_,
360 public EventContainer
362 public:
363 RewindEffectEventHandler( EventQueue & rEventQueue )
364 : EventContainer(), mrEventQueue(rEventQueue) {}
366 private:
367 virtual void dispose()
369 clearContainer();
372 virtual bool handleMouseReleased( awt::MouseEvent const& evt )
374 if(evt.Buttons != awt::MouseButton::RIGHT)
375 return false;
377 return fireAllEvents( maEvents, mrEventQueue );
380 private:
381 EventQueue & mrEventQueue;
384 /** Base class to share some common code between
385 ShapeClickEventHandler and MouseMoveHandler
387 @derive override necessary MouseEventHandler interface methods,
388 call sendEvent() method to actually process the event.
390 class MouseHandlerBase : public MouseEventHandler_
392 public:
393 MouseHandlerBase( EventQueue& rEventQueue ) :
394 mrEventQueue( rEventQueue ),
395 maShapeEventMap()
398 virtual void dispose()
400 // TODO(Q1): Check whether plain vector with swap idiom is
401 // okay here
402 maShapeEventMap = ImpShapeEventMap();
405 void addEvent( const EventSharedPtr& rEvent,
406 const ShapeSharedPtr& rShape )
408 ImpShapeEventMap::iterator aIter;
409 if( (aIter=maShapeEventMap.find( rShape )) == maShapeEventMap.end() )
411 // no entry for this shape -> create one
412 aIter = maShapeEventMap.insert(
413 ImpShapeEventMap::value_type( rShape,
414 ImpEventQueue() ) ).first;
417 // add new event to queue
418 aIter->second.push( rEvent );
421 bool isEmpty()
423 // find at least one shape with a non-empty queue
424 ImpShapeEventMap::reverse_iterator aCurrShape( maShapeEventMap.begin());
425 ImpShapeEventMap::reverse_iterator aEndShape( maShapeEventMap.end() );
426 while( aCurrShape != aEndShape )
428 if( !aCurrShape->second.empty() )
429 return false; // at least one non-empty entry found
431 ++aCurrShape;
434 return true; // not a single non-empty entry found
437 protected:
438 bool hitTest( const awt::MouseEvent& e,
439 ImpShapeEventMap::reverse_iterator& o_rHitShape )
441 // find hit shape in map
442 const basegfx::B2DPoint aPosition( e.X, e.Y );
444 // find matching shape (scan reversely, to coarsely match
445 // paint order)
446 ImpShapeEventMap::reverse_iterator aCurrShape(maShapeEventMap.rbegin());
447 const ImpShapeEventMap::reverse_iterator aEndShape( maShapeEventMap.rend() );
448 while( aCurrShape != aEndShape )
450 // TODO(F2): Get proper geometry polygon from the
451 // shape, to avoid having areas outside the shape
452 // react on the mouse
453 if( aCurrShape->first->getBounds().isInside( aPosition ) &&
454 aCurrShape->first->isVisible() )
456 // shape hit, and shape is visible - report a
457 // hit
458 o_rHitShape = aCurrShape;
459 return true;
462 ++aCurrShape;
465 return false; // nothing hit
468 bool sendEvent( ImpShapeEventMap::reverse_iterator& io_rHitShape )
470 // take next event from queue
471 const bool bRet( fireSingleEvent( io_rHitShape->second,
472 mrEventQueue ) );
474 // clear shape entry, if its queue is
475 // empty. This is important, since the shapes
476 // are held by shared ptr, and might otherwise
477 // not get released, even after their owning
478 // slide is long gone.
479 if( io_rHitShape->second.empty() )
481 // this looks funny, since ::std::map does
482 // provide an erase( iterator )
483 // method. Unfortunately, stlport does not
484 // declare the obvious erase(
485 // reverse_iterator ) needed here (missing
486 // orthogonality, eh?)
487 maShapeEventMap.erase( io_rHitShape->first );
490 return bRet;
493 bool processEvent( const awt::MouseEvent& e )
495 ImpShapeEventMap::reverse_iterator aCurrShape;
497 if( hitTest( e, aCurrShape ) )
498 return sendEvent( aCurrShape );
500 return false; // did not handle the event
503 private:
504 EventQueue& mrEventQueue;
505 ImpShapeEventMap maShapeEventMap;
508 class ShapeClickEventHandler : public MouseHandlerBase
510 public:
511 ShapeClickEventHandler( CursorManager& rCursorManager,
512 EventQueue& rEventQueue ) :
513 MouseHandlerBase( rEventQueue ),
514 mrCursorManager( rCursorManager )
517 virtual bool handleMouseReleased( const awt::MouseEvent& e )
519 if(e.Buttons != awt::MouseButton::LEFT)
520 return false;
521 return processEvent( e );
524 virtual bool handleMouseMoved( const awt::MouseEvent& e )
526 // TODO(P2): Maybe buffer last shape touched
528 // if we have a shape click event, and the mouse
529 // hovers over this shape, change cursor to hand
530 ImpShapeEventMap::reverse_iterator aDummy;
531 if( hitTest( e, aDummy ) )
532 mrCursorManager.requestCursor( awt::SystemPointer::REFHAND );
534 return false; // we don't /eat/ this event. Lower prio
535 // handler should see it, too.
538 private:
539 CursorManager& mrCursorManager;
542 class MouseEnterHandler : public MouseHandlerBase
544 public:
545 MouseEnterHandler( EventQueue& rEventQueue )
546 : MouseHandlerBase( rEventQueue ),
547 mpLastShape() {}
549 virtual bool handleMouseMoved( const awt::MouseEvent& e )
551 // TODO(P2): Maybe buffer last shape touched, and
552 // check against that _first_
554 ImpShapeEventMap::reverse_iterator aCurr;
555 if( hitTest( e, aCurr ) )
557 if( aCurr->first != mpLastShape )
559 // we actually hit a shape, and it's different
560 // from the previous one - thus we just
561 // entered it, raise event
562 sendEvent( aCurr );
563 mpLastShape = aCurr->first;
566 else
568 // don't hit no shape - thus, last shape is NULL
569 mpLastShape.reset();
572 return false; // we don't /eat/ this event. Lower prio
573 // handler should see it, too.
576 private:
577 ShapeSharedPtr mpLastShape;
580 class MouseLeaveHandler : public MouseHandlerBase
582 public:
583 MouseLeaveHandler( EventQueue& rEventQueue )
584 : MouseHandlerBase( rEventQueue ),
585 maLastIter() {}
587 virtual bool handleMouseMoved( const awt::MouseEvent& e )
589 // TODO(P2): Maybe buffer last shape touched, and
590 // check against that _first_
592 ImpShapeEventMap::reverse_iterator aCurr;
593 if( hitTest( e, aCurr ) )
595 maLastIter = aCurr;
597 else
599 if( maLastIter->first )
601 // last time, we were over a shape, now we're
602 // not - we thus just left that shape, raise
603 // event
604 sendEvent( maLastIter );
607 // in any case, when we hit this else-branch: no
608 // shape hit, thus have to clear maLastIter
609 maLastIter = ImpShapeEventMap::reverse_iterator();
612 return false; // we don't /eat/ this event. Lower prio
613 // handler should see it, too.
616 private:
617 ImpShapeEventMap::reverse_iterator maLastIter;
620 template< typename Handler, typename Functor >
621 void UserEventQueue::registerEvent(
622 boost::shared_ptr< Handler >& rHandler,
623 const EventSharedPtr& rEvent,
624 const Functor& rRegistrationFunctor )
626 ENSURE_OR_THROW( rEvent,
627 "UserEventQueue::registerEvent(): Invalid event" );
629 if( !rHandler ) {
630 // create handler
631 rHandler.reset( new Handler( mrEventQueue ) );
632 // register handler on EventMultiplexer
633 rRegistrationFunctor( rHandler );
636 rHandler->addEvent( rEvent );
639 template< typename Handler, typename Arg, typename Functor >
640 void UserEventQueue::registerEvent(
641 boost::shared_ptr< Handler >& rHandler,
642 const EventSharedPtr& rEvent,
643 const Arg& rArg,
644 const Functor& rRegistrationFunctor )
646 ENSURE_OR_THROW( rEvent,
647 "UserEventQueue::registerEvent(): Invalid event" );
649 if( !rHandler ) {
650 // create handler
651 rHandler.reset( new Handler( mrEventQueue ) );
653 // register handler on EventMultiplexer
654 rRegistrationFunctor( rHandler );
657 rHandler->addEvent( rEvent, rArg );
661 // Public methods
662 // =====================================================
664 UserEventQueue::UserEventQueue( EventMultiplexer& rMultiplexer,
665 EventQueue& rEventQueue,
666 CursorManager& rCursorManager )
667 : mrMultiplexer( rMultiplexer ),
668 mrEventQueue( rEventQueue ),
669 mrCursorManager( rCursorManager ),
670 mpStartEventHandler(),
671 mpEndEventHandler(),
672 mpAnimationStartEventHandler(),
673 mpAnimationEndEventHandler(),
674 mpAudioStoppedEventHandler(),
675 mpClickEventHandler(),
676 mpSkipEffectEventHandler(),
677 mpRewindEffectEventHandler(),
678 mpDoubleClickEventHandler(),
679 mpMouseEnterHandler(),
680 mpMouseLeaveHandler(),
681 mbAdvanceOnClick( true )
685 UserEventQueue::~UserEventQueue()
689 // unregister all handlers
690 clear();
692 catch (uno::Exception &) {
693 OSL_ENSURE( false, rtl::OUStringToOString(
694 comphelper::anyToString(
695 cppu::getCaughtException() ),
696 RTL_TEXTENCODING_UTF8 ).getStr() );
700 bool UserEventQueue::isEmpty() const
702 // TODO(T2): This is not thread safe, the handlers are all
703 // only separately synchronized. This poses the danger of
704 // generating false empty status on XSlideShow::update(), such
705 // that the last events of a slide are not triggered.
707 // we're empty iff all handler queues are empty
708 return
709 (mpStartEventHandler ? mpStartEventHandler->isEmpty() : true) &&
710 (mpEndEventHandler ? mpEndEventHandler->isEmpty() : true) &&
711 (mpAnimationStartEventHandler ? mpAnimationStartEventHandler->isEmpty() : true) &&
712 (mpAnimationEndEventHandler ? mpAnimationEndEventHandler->isEmpty() : true) &&
713 (mpAudioStoppedEventHandler ? mpAudioStoppedEventHandler->isEmpty() : true) &&
714 (mpShapeClickEventHandler ? mpShapeClickEventHandler->isEmpty() : true) &&
715 (mpClickEventHandler ? mpClickEventHandler->isEmpty() : true) &&
716 (mpSkipEffectEventHandler ? mpSkipEffectEventHandler->isEmpty() : true) &&
717 (mpRewindEffectEventHandler ? mpRewindEffectEventHandler->isEmpty() : true) &&
718 (mpShapeDoubleClickEventHandler ? mpShapeDoubleClickEventHandler->isEmpty() : true) &&
719 (mpDoubleClickEventHandler ? mpDoubleClickEventHandler->isEmpty() : true) &&
720 (mpMouseEnterHandler ? mpMouseEnterHandler->isEmpty() : true) &&
721 (mpMouseLeaveHandler ? mpMouseLeaveHandler->isEmpty() : true);
724 void UserEventQueue::clear()
726 // unregister and delete all handlers
727 if( mpStartEventHandler ) {
728 mrMultiplexer.removeSlideStartHandler( mpStartEventHandler );
729 mpStartEventHandler.reset();
731 if( mpEndEventHandler ) {
732 mrMultiplexer.removeSlideEndHandler( mpEndEventHandler );
733 mpEndEventHandler.reset();
735 if( mpAnimationStartEventHandler ) {
736 mrMultiplexer.removeAnimationStartHandler(
737 mpAnimationStartEventHandler );
738 mpAnimationStartEventHandler.reset();
740 if( mpAnimationEndEventHandler ) {
741 mrMultiplexer.removeAnimationEndHandler( mpAnimationEndEventHandler );
742 mpAnimationEndEventHandler.reset();
744 if( mpAudioStoppedEventHandler ) {
745 mrMultiplexer.removeAudioStoppedHandler( mpAudioStoppedEventHandler );
746 mpAudioStoppedEventHandler.reset();
748 if( mpShapeClickEventHandler ) {
749 mrMultiplexer.removeClickHandler( mpShapeClickEventHandler );
750 mrMultiplexer.removeMouseMoveHandler( mpShapeClickEventHandler );
751 mpShapeClickEventHandler.reset();
753 if( mpClickEventHandler ) {
754 mrMultiplexer.removeClickHandler( mpClickEventHandler );
755 mrMultiplexer.removeNextEffectHandler( mpClickEventHandler );
756 mpClickEventHandler.reset();
758 if(mpSkipEffectEventHandler) {
759 mrMultiplexer.removeClickHandler( mpSkipEffectEventHandler );
760 mrMultiplexer.removeNextEffectHandler( mpSkipEffectEventHandler );
761 mpSkipEffectEventHandler.reset();
763 if(mpRewindEffectEventHandler) {
764 mrMultiplexer.removeClickHandler( mpRewindEffectEventHandler );
765 mpRewindEffectEventHandler.reset();
767 if( mpShapeDoubleClickEventHandler ) {
768 mrMultiplexer.removeDoubleClickHandler( mpShapeDoubleClickEventHandler );
769 mrMultiplexer.removeMouseMoveHandler( mpShapeDoubleClickEventHandler );
770 mpShapeDoubleClickEventHandler.reset();
772 if( mpDoubleClickEventHandler ) {
773 mrMultiplexer.removeDoubleClickHandler( mpDoubleClickEventHandler );
774 mpDoubleClickEventHandler.reset();
776 if( mpMouseEnterHandler ) {
777 mrMultiplexer.removeMouseMoveHandler( mpMouseEnterHandler );
778 mpMouseEnterHandler.reset();
780 if( mpMouseLeaveHandler ) {
781 mrMultiplexer.removeMouseMoveHandler( mpMouseLeaveHandler );
782 mpMouseLeaveHandler.reset();
786 void UserEventQueue::setAdvanceOnClick( bool bAdvanceOnClick )
788 mbAdvanceOnClick = bAdvanceOnClick;
790 // forward to handler, if existing. Otherwise, the handler
791 // creation will do the forwarding.
792 if( mpClickEventHandler )
793 mpClickEventHandler->setAdvanceOnClick( bAdvanceOnClick );
796 void UserEventQueue::registerSlideStartEvent( const EventSharedPtr& rEvent )
798 registerEvent( mpStartEventHandler,
799 rEvent,
800 boost::bind( &EventMultiplexer::addSlideStartHandler,
801 boost::ref( mrMultiplexer ), _1 ) );
804 void UserEventQueue::registerSlideEndEvent( const EventSharedPtr& rEvent )
806 registerEvent( mpEndEventHandler,
807 rEvent,
808 boost::bind( &EventMultiplexer::addSlideEndHandler,
809 boost::ref( mrMultiplexer ), _1 ) );
812 void UserEventQueue::registerAnimationStartEvent(
813 const EventSharedPtr& rEvent,
814 const uno::Reference< animations::XAnimationNode>& xNode )
816 registerEvent( mpAnimationStartEventHandler,
817 rEvent,
818 xNode,
819 boost::bind( &EventMultiplexer::addAnimationStartHandler,
820 boost::ref( mrMultiplexer ), _1 ) );
823 void UserEventQueue::registerAnimationEndEvent(
824 const EventSharedPtr& rEvent,
825 const uno::Reference<animations::XAnimationNode>& xNode )
827 registerEvent( mpAnimationEndEventHandler,
828 rEvent,
829 xNode,
830 boost::bind( &EventMultiplexer::addAnimationEndHandler,
831 boost::ref( mrMultiplexer ), _1 ) );
834 void UserEventQueue::registerAudioStoppedEvent(
835 const EventSharedPtr& rEvent,
836 const uno::Reference<animations::XAnimationNode>& xNode )
838 registerEvent( mpAudioStoppedEventHandler,
839 rEvent,
840 xNode,
841 boost::bind( &EventMultiplexer::addAudioStoppedHandler,
842 boost::ref( mrMultiplexer ), _1 ) );
845 void UserEventQueue::registerShapeClickEvent( const EventSharedPtr& rEvent,
846 const ShapeSharedPtr& rShape )
848 ENSURE_OR_THROW(
849 rEvent,
850 "UserEventQueue::registerShapeClickEvent(): Invalid event" );
852 if( !mpShapeClickEventHandler )
854 // create handler
855 mpShapeClickEventHandler.reset(
856 new ShapeClickEventHandler(mrCursorManager,
857 mrEventQueue) );
859 // register handler on EventMultiplexer
860 mrMultiplexer.addClickHandler( mpShapeClickEventHandler, 1.0 );
861 mrMultiplexer.addMouseMoveHandler( mpShapeClickEventHandler, 1.0 );
864 mpShapeClickEventHandler->addEvent( rEvent, rShape );
867 namespace {
868 class ClickEventRegistrationFunctor
870 public:
871 ClickEventRegistrationFunctor( EventMultiplexer& rMultiplexer,
872 double nPrio,
873 bool bAdvanceOnClick )
874 : mrMultiplexer( rMultiplexer ),
875 mnPrio(nPrio),
876 mbAdvanceOnClick( bAdvanceOnClick ) {}
878 void operator()( const boost::shared_ptr<ClickEventHandler>& rHandler )const
880 // register the handler on _two_ sources: we want the
881 // nextEffect events, e.g. space bar, to trigger clicks, as well!
882 mrMultiplexer.addClickHandler( rHandler, mnPrio );
883 mrMultiplexer.addNextEffectHandler( rHandler, mnPrio );
885 // forward advance-on-click state to newly
886 // generated handler (that's the only reason why
887 // we're called here)
888 rHandler->setAdvanceOnClick( mbAdvanceOnClick );
891 private:
892 EventMultiplexer& mrMultiplexer;
893 double const mnPrio;
894 bool const mbAdvanceOnClick;
896 } // anon namespace
898 void UserEventQueue::registerNextEffectEvent( const EventSharedPtr& rEvent )
900 // TODO: better name may be mpNextEffectEventHandler? then we have
901 // next effect (=> waiting to be started)
902 // skip effect (skipping the currently running one)
903 // rewind effect (rewinding back running one and waiting (again)
904 // to be started)
905 registerEvent( mpClickEventHandler,
906 rEvent,
907 ClickEventRegistrationFunctor( mrMultiplexer,
908 0.0 /* default prio */,
909 mbAdvanceOnClick ) );
912 void UserEventQueue::registerSkipEffectEvent(
913 EventSharedPtr const & pEvent,
914 const bool bSkipTriggersNextEffect)
916 if(!mpSkipEffectEventHandler)
918 mpSkipEffectEventHandler.reset(
919 new SkipEffectEventHandler( mrEventQueue, mrMultiplexer ) );
920 // register the handler on _two_ sources: we want the
921 // nextEffect events, e.g. space bar, to trigger clicks, as well!
922 mrMultiplexer.addClickHandler( mpSkipEffectEventHandler,
923 -1.0 /* prio below default */ );
924 mrMultiplexer.addNextEffectHandler( mpSkipEffectEventHandler,
925 -1.0 /* prio below default */ );
926 // forward advance-on-click state to newly
927 // generated handler (that's the only reason why
928 // we're called here)
929 mpSkipEffectEventHandler->setAdvanceOnClick( mbAdvanceOnClick );
931 mpSkipEffectEventHandler->setSkipTriggersNextEffect(bSkipTriggersNextEffect);
932 mpSkipEffectEventHandler->addEvent( pEvent );
935 void UserEventQueue::registerRewindEffectEvent( EventSharedPtr const& pEvent )
937 registerEvent( mpRewindEffectEventHandler,
938 pEvent,
939 boost::bind( &EventMultiplexer::addClickHandler,
940 boost::ref(mrMultiplexer), _1,
941 -1.0 /* prio below default */ ) );
944 void UserEventQueue::registerShapeDoubleClickEvent(
945 const EventSharedPtr& rEvent,
946 const ShapeSharedPtr& rShape )
948 ENSURE_OR_THROW(
949 rEvent,
950 "UserEventQueue::registerShapeDoubleClickEvent(): Invalid event" );
952 if( !mpShapeDoubleClickEventHandler )
954 // create handler
955 mpShapeDoubleClickEventHandler.reset(
956 new ShapeClickEventHandler(mrCursorManager,
957 mrEventQueue) );
959 // register handler on EventMultiplexer
960 mrMultiplexer.addDoubleClickHandler( mpShapeDoubleClickEventHandler,
961 1.0 );
962 mrMultiplexer.addMouseMoveHandler( mpShapeDoubleClickEventHandler,
963 1.0 );
966 mpShapeDoubleClickEventHandler->addEvent( rEvent, rShape );
969 void UserEventQueue::registerDoubleClickEvent( const EventSharedPtr& rEvent )
971 registerEvent( mpDoubleClickEventHandler,
972 rEvent,
973 boost::bind( &EventMultiplexer::addDoubleClickHandler,
974 boost::ref( mrMultiplexer ), _1,
975 0.0 /* default prio */ ) );
978 void UserEventQueue::registerMouseEnterEvent( const EventSharedPtr& rEvent,
979 const ShapeSharedPtr& rShape )
981 registerEvent( mpMouseEnterHandler,
982 rEvent,
983 rShape,
984 boost::bind( &EventMultiplexer::addMouseMoveHandler,
985 boost::ref( mrMultiplexer ), _1,
986 0.0 /* default prio */ ) );
989 void UserEventQueue::registerMouseLeaveEvent( const EventSharedPtr& rEvent,
990 const ShapeSharedPtr& rShape )
992 registerEvent( mpMouseLeaveHandler,
993 rEvent,
994 rShape,
995 boost::bind( &EventMultiplexer::addMouseMoveHandler,
996 boost::ref( mrMultiplexer ), _1,
997 0.0 /* default prio */ ) );
1000 void UserEventQueue::callSkipEffectEventHandler (void)
1002 ::boost::shared_ptr<SkipEffectEventHandler> pHandler (
1003 ::boost::dynamic_pointer_cast<SkipEffectEventHandler>(mpSkipEffectEventHandler));
1004 if (pHandler)
1005 pHandler->skipEffect();
1008 } // namespace internal
1009 } // namespace presentation