LCOV - code coverage report
Current view: top level - slideshow/source/engine - usereventqueue.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 20 293 6.8 %
Date: 2014-11-03 Functions: 5 86 5.8 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10