LCOV - code coverage report
Current view: top level - libreoffice/slideshow/source/engine - usereventqueue.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 305 0.0 %
Date: 2012-12-27 Functions: 0 90 0.0 %
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*/ ) { return false;}
      67           0 :     virtual bool handleMouseReleased( awt::MouseEvent const& /*e*/) { return false;}
      68           0 :     virtual bool handleMouseEntered( awt::MouseEvent const& /*e*/ ) { return false;}
      69           0 :     virtual bool handleMouseExited( awt::MouseEvent const& /*e*/ ) { return false; }
      70           0 :     virtual bool handleMouseDragged( awt::MouseEvent const& /*e*/ ) { return false;}
      71           0 :     virtual bool handleMouseMoved( awt::MouseEvent const& /*e*/ ) { 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             :     bool isEmpty()
     125             :     {
     126             :         return maEvents.empty();
     127             :     }
     128             : 
     129             : protected:
     130             :     ImpEventQueue maEvents;
     131             : };
     132             : 
     133             : } // anon namespace
     134             : 
     135           0 : class PlainEventHandler : public EventHandler,
     136             :                           public EventContainer
     137             : {
     138             : public:
     139             :     PlainEventHandler( EventQueue & rEventQueue )
     140             :         : EventContainer(), mrEventQueue(rEventQueue) {}
     141             : 
     142           0 :     virtual void dispose()
     143             :     {
     144           0 :         clearContainer();
     145           0 :     }
     146             : 
     147           0 :     virtual bool handleEvent()
     148             :     {
     149           0 :         return fireAllEvents( maEvents, mrEventQueue );
     150             :     }
     151             : 
     152             : private:
     153             :     EventQueue & mrEventQueue;
     154             : };
     155             : 
     156           0 : class AllAnimationEventHandler : public AnimationEventHandler
     157             : {
     158             : public:
     159           0 :     AllAnimationEventHandler( EventQueue& rEventQueue ) :
     160             :         mrEventQueue( rEventQueue ),
     161           0 :         maAnimationEventMap()
     162           0 :     {}
     163             : 
     164           0 :     virtual void dispose()
     165             :     {
     166           0 :         maAnimationEventMap.clear();
     167           0 :     }
     168             : 
     169           0 :     virtual bool handleAnimationEvent( const AnimationNodeSharedPtr& rNode )
     170             :     {
     171           0 :         ENSURE_OR_RETURN_FALSE(
     172             :             rNode,
     173             :             "AllAnimationEventHandler::handleAnimationEvent(): Invalid node" );
     174             : 
     175           0 :         bool bRet( false );
     176             : 
     177           0 :         ImpAnimationEventMap::iterator aIter;
     178           0 :         if( (aIter=maAnimationEventMap.find(
     179           0 :                  rNode->getXAnimationNode() )) != maAnimationEventMap.end() )
     180             :         {
     181           0 :             ImpEventVector& rVec( aIter->second );
     182             : 
     183           0 :             bRet = !rVec.empty();
     184             : 
     185             :             // registered node found -> fire all events in the vector
     186             :             std::for_each( rVec.begin(), rVec.end(),
     187             :                            boost::bind( &EventQueue::addEvent,
     188           0 :                                         boost::ref( mrEventQueue ), _1 ) );
     189             : 
     190           0 :             rVec.clear();
     191             :         }
     192             : 
     193           0 :         return bRet;
     194             :     }
     195             : 
     196           0 :     void addEvent( const EventSharedPtr&                                rEvent,
     197             :                    const uno::Reference< animations::XAnimationNode >&  xNode )
     198             :     {
     199           0 :         ImpAnimationEventMap::iterator aIter;
     200           0 :         if( (aIter=maAnimationEventMap.find( xNode )) ==
     201           0 :             maAnimationEventMap.end() )
     202             :         {
     203             :             // no entry for this animation -> create one
     204             :             aIter = maAnimationEventMap.insert(
     205             :                 ImpAnimationEventMap::value_type( xNode,
     206           0 :                                                   ImpEventVector() ) ).first;
     207             :         }
     208             : 
     209             :         // add new event to queue
     210           0 :         aIter->second.push_back( rEvent );
     211           0 :     }
     212             : 
     213             :     bool isEmpty()
     214             :     {
     215             :         // find at least one animation with a non-empty vector
     216             :         ImpAnimationEventMap::const_iterator aCurr( maAnimationEventMap.begin() );
     217             :         const ImpAnimationEventMap::const_iterator aEnd( maAnimationEventMap.end() );
     218             :         while( aCurr != aEnd )
     219             :         {
     220             :             if( !aCurr->second.empty() )
     221             :                 return false; // at least one non-empty entry found
     222             : 
     223             :             ++aCurr;
     224             :         }
     225             : 
     226             :         return true; // not a single non-empty entry found
     227             :     }
     228             : 
     229             : private:
     230             :     EventQueue&             mrEventQueue;
     231             :     ImpAnimationEventMap    maAnimationEventMap;
     232             : };
     233             : 
     234           0 : class ClickEventHandler : public MouseEventHandler_,
     235             :                           public EventHandler,
     236             :                           public EventContainer
     237             : {
     238             : public:
     239           0 :     ClickEventHandler( EventQueue& rEventQueue ) :
     240             :         EventContainer(),
     241             :         mrEventQueue( rEventQueue ),
     242           0 :         mbAdvanceOnClick( true )
     243           0 :     {}
     244             : 
     245           0 :     void setAdvanceOnClick( bool bAdvanceOnClick )
     246             :     {
     247           0 :         mbAdvanceOnClick = bAdvanceOnClick;
     248           0 :     }
     249             : 
     250             : private:
     251           0 :     virtual void dispose()
     252             :     {
     253           0 :         clearContainer();
     254           0 :     }
     255             : 
     256             :     // triggered by API calls, e.g. space bar
     257           0 :     virtual bool handleEvent()
     258             :     {
     259           0 :         return handleEvent_impl();
     260             :     }
     261             : 
     262             :     // triggered by mouse release:
     263           0 :     virtual bool handleMouseReleased( const awt::MouseEvent& evt )
     264             :     {
     265           0 :         if(evt.Buttons != awt::MouseButton::LEFT)
     266           0 :             return false;
     267             : 
     268           0 :         if( mbAdvanceOnClick ) {
     269             :             // fire next event
     270           0 :             return handleEvent_impl();
     271             :         }
     272             :         else {
     273           0 :             return false; // advance-on-click disabled
     274             :         }
     275             :     }
     276             : 
     277             :     // triggered by both:
     278           0 :     virtual bool handleEvent_impl()
     279             :     {
     280             :         // fire next event:
     281           0 :         return fireSingleEvent( maEvents, mrEventQueue );
     282             :     }
     283             : 
     284             : private:
     285             :     EventQueue& mrEventQueue;
     286             :     bool        mbAdvanceOnClick;
     287             : };
     288             : 
     289           0 : class SkipEffectEventHandler : public ClickEventHandler
     290             : {
     291             : public:
     292           0 :     SkipEffectEventHandler( EventQueue & rEventQueue,
     293             :                             EventMultiplexer & rEventMultiplexer )
     294             :         : ClickEventHandler(rEventQueue),
     295             :           mrEventQueue(rEventQueue),
     296             :           mrEventMultiplexer(rEventMultiplexer),
     297           0 :           mbSkipTriggersNextEffect(true) {}
     298             : 
     299             :     /** Remember to trigger (or not to trigger) the next effect after the
     300             :         current effect is skiped.
     301             :     */
     302           0 :     void setSkipTriggersNextEffect (const bool bSkipTriggersNextEffect)
     303           0 :     { mbSkipTriggersNextEffect = bSkipTriggersNextEffect; }
     304             : 
     305             :     ///  Skip the current effect but do not triggere the next effect.
     306           0 :     void skipEffect (void) { handleEvent_impl(false); }
     307             : 
     308             : private:
     309           0 :     virtual bool handleEvent_impl()
     310             :     {
     311           0 :         return handleEvent_impl(true);
     312             :     }
     313             : 
     314           0 :     bool handleEvent_impl (bool bNotifyNextEffect)
     315             :     {
     316             :         // fire all events, so animation nodes can register their
     317             :         // next effect listeners:
     318           0 :         if(fireAllEvents( maEvents, mrEventQueue ))
     319             :         {
     320           0 :             if (mbSkipTriggersNextEffect && bNotifyNextEffect)
     321             :             {
     322             :                 // then simulate a next effect event: this skip effect
     323             :                 // handler is triggered upon next effect events (multiplexer
     324             :                 // prio=-1)!  Posting a notifyNextEffect() here is only safe
     325             :                 // (we don't run into busy loop), because we assume that
     326             :                 // someone has registerered above for next effects
     327             :                 // (multiplexer prio=0) at the user event queue.
     328             :                 return mrEventQueue.addEventWhenQueueIsEmpty(
     329           0 :                     makeEvent( boost::bind( &EventMultiplexer::notifyNextEffect,
     330             :                                             boost::ref(mrEventMultiplexer) ),
     331           0 :                                "EventMultiplexer::notifyNextEffect") );
     332             :             }
     333             :             else
     334           0 :                 return true;
     335             :         }
     336           0 :         return false;
     337             :     }
     338             : 
     339             : private:
     340             :     EventQueue & mrEventQueue;
     341             :     EventMultiplexer & mrEventMultiplexer;
     342             :     bool mbSkipTriggersNextEffect;
     343             : };
     344             : 
     345           0 : class RewindEffectEventHandler : public MouseEventHandler_,
     346             :                                  public EventContainer
     347             : {
     348             : public:
     349           0 :     RewindEffectEventHandler( EventQueue & rEventQueue )
     350           0 :         : EventContainer(), mrEventQueue(rEventQueue) {}
     351             : 
     352             : private:
     353           0 :     virtual void dispose()
     354             :     {
     355           0 :         clearContainer();
     356           0 :     }
     357             : 
     358           0 :     virtual bool handleMouseReleased( awt::MouseEvent const& evt )
     359             :     {
     360           0 :         if(evt.Buttons != awt::MouseButton::RIGHT)
     361           0 :             return false;
     362             : 
     363           0 :         return fireAllEvents( maEvents, mrEventQueue );
     364             :     }
     365             : 
     366             : private:
     367             :     EventQueue & mrEventQueue;
     368             : };
     369             : 
     370             : /** Base class to share some common code between
     371             :     ShapeClickEventHandler and MouseMoveHandler
     372             : 
     373             :     @derive override necessary MouseEventHandler interface methods,
     374             :     call sendEvent() method to actually process the event.
     375             : */
     376           0 : class MouseHandlerBase : public MouseEventHandler_
     377             : {
     378             : public:
     379           0 :     MouseHandlerBase( EventQueue& rEventQueue ) :
     380             :         mrEventQueue( rEventQueue ),
     381           0 :         maShapeEventMap()
     382           0 :     {}
     383             : 
     384           0 :     virtual void dispose()
     385             :     {
     386             :         // TODO(Q1): Check whether plain vector with swap idiom is
     387             :         // okay here
     388           0 :         maShapeEventMap = ImpShapeEventMap();
     389           0 :     }
     390             : 
     391           0 :     void addEvent( const EventSharedPtr& rEvent,
     392             :                    const ShapeSharedPtr& rShape )
     393             :     {
     394           0 :         ImpShapeEventMap::iterator aIter;
     395           0 :         if( (aIter=maShapeEventMap.find( rShape )) == maShapeEventMap.end() )
     396             :         {
     397             :             // no entry for this shape -> create one
     398             :             aIter = maShapeEventMap.insert(
     399             :                 ImpShapeEventMap::value_type( rShape,
     400           0 :                                               ImpEventQueue() ) ).first;
     401             :         }
     402             : 
     403             :         // add new event to queue
     404           0 :         aIter->second.push( rEvent );
     405           0 :     }
     406             : 
     407             :     bool isEmpty()
     408             :     {
     409             :         // find at least one shape with a non-empty queue
     410             :         ImpShapeEventMap::reverse_iterator aCurrShape( maShapeEventMap.begin());
     411             :         ImpShapeEventMap::reverse_iterator aEndShape( maShapeEventMap.end() );
     412             :         while( aCurrShape != aEndShape )
     413             :         {
     414             :             if( !aCurrShape->second.empty() )
     415             :                 return false; // at least one non-empty entry found
     416             : 
     417             :             ++aCurrShape;
     418             :         }
     419             : 
     420             :         return true; // not a single non-empty entry found
     421             :     }
     422             : 
     423             : protected:
     424           0 :     bool hitTest( const awt::MouseEvent&                e,
     425             :                   ImpShapeEventMap::reverse_iterator&   o_rHitShape )
     426             :     {
     427             :         // find hit shape in map
     428           0 :         const basegfx::B2DPoint aPosition( e.X, e.Y );
     429             : 
     430             :         // find matching shape (scan reversely, to coarsely match
     431             :         // paint order)
     432           0 :         ImpShapeEventMap::reverse_iterator       aCurrShape(maShapeEventMap.rbegin());
     433           0 :         const ImpShapeEventMap::reverse_iterator aEndShape( maShapeEventMap.rend() );
     434           0 :         while( aCurrShape != aEndShape )
     435             :         {
     436             :             // TODO(F2): Get proper geometry polygon from the
     437             :             // shape, to avoid having areas outside the shape
     438             :             // react on the mouse
     439           0 :             if( aCurrShape->first->getBounds().isInside( aPosition ) &&
     440           0 :                 aCurrShape->first->isVisible() )
     441             :             {
     442             :                 // shape hit, and shape is visible - report a
     443             :                 // hit
     444           0 :                 o_rHitShape = aCurrShape;
     445           0 :                 return true;
     446             :             }
     447             : 
     448           0 :             ++aCurrShape;
     449             :         }
     450             : 
     451           0 :         return false; // nothing hit
     452             :     }
     453             : 
     454           0 :     bool sendEvent( ImpShapeEventMap::reverse_iterator& io_rHitShape )
     455             :     {
     456             :         // take next event from queue
     457           0 :         const bool bRet( fireSingleEvent( io_rHitShape->second,
     458           0 :                                           mrEventQueue ) );
     459             : 
     460             :         // clear shape entry, if its queue is
     461             :         // empty. This is important, since the shapes
     462             :         // are held by shared ptr, and might otherwise
     463             :         // not get released, even after their owning
     464             :         // slide is long gone.
     465           0 :         if( io_rHitShape->second.empty() )
     466             :         {
     467             :             // this looks funny, since ::std::map does
     468             :             // provide an erase( iterator )
     469             :             // method. Unfortunately, C++ does not
     470             :             // declare the obvious erase(
     471             :             // reverse_iterator ) needed here (missing
     472             :             // orthogonality, eh?)
     473           0 :             maShapeEventMap.erase( io_rHitShape->first );
     474             :         }
     475             : 
     476           0 :         return bRet;
     477             :     }
     478             : 
     479           0 :     bool processEvent( const awt::MouseEvent& e )
     480             :     {
     481           0 :         ImpShapeEventMap::reverse_iterator aCurrShape;
     482             : 
     483           0 :         if( hitTest( e, aCurrShape ) )
     484           0 :             return sendEvent( aCurrShape );
     485             : 
     486           0 :         return false; // did not handle the event
     487             :     }
     488             : 
     489             : private:
     490             :     EventQueue&         mrEventQueue;
     491             :     ImpShapeEventMap    maShapeEventMap;
     492             : };
     493             : 
     494           0 : class ShapeClickEventHandler : public MouseHandlerBase
     495             : {
     496             : public:
     497           0 :     ShapeClickEventHandler( CursorManager& rCursorManager,
     498             :                             EventQueue&    rEventQueue ) :
     499             :         MouseHandlerBase( rEventQueue ),
     500           0 :         mrCursorManager( rCursorManager )
     501           0 :     {}
     502             : 
     503           0 :     virtual bool handleMouseReleased( const awt::MouseEvent& e )
     504             :     {
     505           0 :         if(e.Buttons != awt::MouseButton::LEFT)
     506           0 :             return false;
     507           0 :         return processEvent( e );
     508             :     }
     509             : 
     510           0 :     virtual bool handleMouseMoved( const awt::MouseEvent& e )
     511             :     {
     512             :         // TODO(P2): Maybe buffer last shape touched
     513             : 
     514             :         // if we have a shape click event, and the mouse
     515             :         // hovers over this shape, change cursor to hand
     516           0 :         ImpShapeEventMap::reverse_iterator aDummy;
     517           0 :         if( hitTest( e, aDummy ) )
     518           0 :             mrCursorManager.requestCursor( awt::SystemPointer::REFHAND );
     519             : 
     520           0 :         return false; // we don't /eat/ this event. Lower prio
     521             :         // handler should see it, too.
     522             :     }
     523             : 
     524             : private:
     525             :     CursorManager& mrCursorManager;
     526             : };
     527             : 
     528           0 : class MouseEnterHandler : public MouseHandlerBase
     529             : {
     530             : public:
     531           0 :     MouseEnterHandler( EventQueue& rEventQueue )
     532             :         : MouseHandlerBase( rEventQueue ),
     533           0 :           mpLastShape() {}
     534             : 
     535           0 :     virtual bool handleMouseMoved( const awt::MouseEvent& e )
     536             :     {
     537             :         // TODO(P2): Maybe buffer last shape touched, and
     538             :         // check against that _first_
     539             : 
     540           0 :         ImpShapeEventMap::reverse_iterator aCurr;
     541           0 :         if( hitTest( e, aCurr ) )
     542             :         {
     543           0 :             if( aCurr->first != mpLastShape )
     544             :             {
     545             :                 // we actually hit a shape, and it's different
     546             :                 // from the previous one - thus we just
     547             :                 // entered it, raise event
     548           0 :                 sendEvent( aCurr );
     549           0 :                 mpLastShape = aCurr->first;
     550             :             }
     551             :         }
     552             :         else
     553             :         {
     554             :             // don't hit no shape - thus, last shape is NULL
     555           0 :             mpLastShape.reset();
     556             :         }
     557             : 
     558           0 :         return false; // we don't /eat/ this event. Lower prio
     559             :         // handler should see it, too.
     560             :     }
     561             : 
     562             : private:
     563             :     ShapeSharedPtr mpLastShape;
     564             : };
     565             : 
     566           0 : class MouseLeaveHandler : public MouseHandlerBase
     567             : {
     568             : public:
     569           0 :     MouseLeaveHandler( EventQueue& rEventQueue )
     570             :         : MouseHandlerBase( rEventQueue ),
     571           0 :           maLastIter() {}
     572             : 
     573           0 :     virtual bool handleMouseMoved( const awt::MouseEvent& e )
     574             :     {
     575             :         // TODO(P2): Maybe buffer last shape touched, and
     576             :         // check against that _first_
     577             : 
     578           0 :         ImpShapeEventMap::reverse_iterator aCurr;
     579           0 :         if( hitTest( e, aCurr ) )
     580             :         {
     581           0 :             maLastIter = aCurr;
     582             :         }
     583             :         else
     584             :         {
     585           0 :             if( maLastIter->first )
     586             :             {
     587             :                 // last time, we were over a shape, now we're
     588             :                 // not - we thus just left that shape, raise
     589             :                 // event
     590           0 :                 sendEvent( maLastIter );
     591             :             }
     592             : 
     593             :             // in any case, when we hit this else-branch: no
     594             :             // shape hit, thus have to clear maLastIter
     595           0 :             maLastIter = ImpShapeEventMap::reverse_iterator();
     596             :         }
     597             : 
     598           0 :         return false; // we don't /eat/ this event. Lower prio
     599             :         // handler should see it, too.
     600             :     }
     601             : 
     602             : private:
     603             :     ImpShapeEventMap::reverse_iterator maLastIter;
     604             : };
     605             : 
     606             : template< typename Handler, typename Functor >
     607           0 : void UserEventQueue::registerEvent(
     608             :     boost::shared_ptr< Handler >& rHandler,
     609             :     const EventSharedPtr&         rEvent,
     610             :     const Functor&                rRegistrationFunctor )
     611             : {
     612           0 :     ENSURE_OR_THROW( rEvent,
     613             :                       "UserEventQueue::registerEvent(): Invalid event" );
     614             : 
     615           0 :     if( !rHandler ) {
     616             :         // create handler
     617           0 :         rHandler.reset( new Handler( mrEventQueue ) );
     618             :         // register handler on EventMultiplexer
     619           0 :         rRegistrationFunctor( rHandler );
     620             :     }
     621             : 
     622           0 :     rHandler->addEvent( rEvent );
     623           0 : }
     624             : 
     625             : template< typename Handler, typename Arg, typename Functor >
     626           0 : void UserEventQueue::registerEvent(
     627             :     boost::shared_ptr< Handler >& rHandler,
     628             :     const EventSharedPtr&         rEvent,
     629             :     const Arg&                    rArg,
     630             :     const Functor&                rRegistrationFunctor )
     631             : {
     632           0 :     ENSURE_OR_THROW( rEvent,
     633             :                       "UserEventQueue::registerEvent(): Invalid event" );
     634             : 
     635           0 :     if( !rHandler ) {
     636             :         // create handler
     637           0 :         rHandler.reset( new Handler( mrEventQueue ) );
     638             : 
     639             :         // register handler on EventMultiplexer
     640           0 :         rRegistrationFunctor( rHandler );
     641             :     }
     642             : 
     643           0 :     rHandler->addEvent( rEvent, rArg );
     644           0 : }
     645             : 
     646             : 
     647             : // Public methods
     648             : // =====================================================
     649             : 
     650           0 : UserEventQueue::UserEventQueue( EventMultiplexer&   rMultiplexer,
     651             :                                 EventQueue&         rEventQueue,
     652             :                                 CursorManager&      rCursorManager )
     653             :     : mrMultiplexer( rMultiplexer ),
     654             :       mrEventQueue( rEventQueue ),
     655             :       mrCursorManager( rCursorManager ),
     656             :       mpStartEventHandler(),
     657             :       mpEndEventHandler(),
     658             :       mpAnimationStartEventHandler(),
     659             :       mpAnimationEndEventHandler(),
     660             :       mpAudioStoppedEventHandler(),
     661             :       mpClickEventHandler(),
     662             :       mpSkipEffectEventHandler(),
     663             :       mpRewindEffectEventHandler(),
     664             :       mpDoubleClickEventHandler(),
     665             :       mpMouseEnterHandler(),
     666             :       mpMouseLeaveHandler(),
     667           0 :       mbAdvanceOnClick( true )
     668             : {
     669           0 : }
     670             : 
     671           0 : UserEventQueue::~UserEventQueue()
     672             : {
     673             :     try
     674             :     {
     675             :         // unregister all handlers
     676           0 :         clear();
     677             :     }
     678           0 :     catch (uno::Exception &) {
     679             :         OSL_FAIL( rtl::OUStringToOString(
     680             :                         comphelper::anyToString(
     681             :                             cppu::getCaughtException() ),
     682             :                         RTL_TEXTENCODING_UTF8 ).getStr() );
     683             :     }
     684           0 : }
     685             : 
     686           0 : void UserEventQueue::clear()
     687             : {
     688             :     // unregister and delete all handlers
     689           0 :     if( mpStartEventHandler ) {
     690           0 :         mrMultiplexer.removeSlideStartHandler( mpStartEventHandler );
     691           0 :         mpStartEventHandler.reset();
     692             :     }
     693           0 :     if( mpEndEventHandler ) {
     694           0 :         mrMultiplexer.removeSlideEndHandler( mpEndEventHandler );
     695           0 :         mpEndEventHandler.reset();
     696             :     }
     697           0 :     if( mpAnimationStartEventHandler ) {
     698             :         mrMultiplexer.removeAnimationStartHandler(
     699           0 :             mpAnimationStartEventHandler );
     700           0 :         mpAnimationStartEventHandler.reset();
     701             :     }
     702           0 :     if( mpAnimationEndEventHandler ) {
     703           0 :         mrMultiplexer.removeAnimationEndHandler( mpAnimationEndEventHandler );
     704           0 :         mpAnimationEndEventHandler.reset();
     705             :     }
     706           0 :     if( mpAudioStoppedEventHandler ) {
     707           0 :         mrMultiplexer.removeAudioStoppedHandler( mpAudioStoppedEventHandler );
     708           0 :         mpAudioStoppedEventHandler.reset();
     709             :     }
     710           0 :     if( mpShapeClickEventHandler ) {
     711           0 :         mrMultiplexer.removeClickHandler( mpShapeClickEventHandler );
     712           0 :         mrMultiplexer.removeMouseMoveHandler( mpShapeClickEventHandler );
     713           0 :         mpShapeClickEventHandler.reset();
     714             :     }
     715           0 :     if( mpClickEventHandler ) {
     716           0 :         mrMultiplexer.removeClickHandler( mpClickEventHandler );
     717           0 :         mrMultiplexer.removeNextEffectHandler( mpClickEventHandler );
     718           0 :         mpClickEventHandler.reset();
     719             :     }
     720           0 :     if(mpSkipEffectEventHandler) {
     721           0 :         mrMultiplexer.removeClickHandler( mpSkipEffectEventHandler );
     722           0 :         mrMultiplexer.removeNextEffectHandler( mpSkipEffectEventHandler );
     723           0 :         mpSkipEffectEventHandler.reset();
     724             :     }
     725           0 :     if(mpRewindEffectEventHandler) {
     726           0 :         mrMultiplexer.removeClickHandler( mpRewindEffectEventHandler );
     727           0 :         mpRewindEffectEventHandler.reset();
     728             :     }
     729           0 :     if( mpShapeDoubleClickEventHandler ) {
     730           0 :         mrMultiplexer.removeDoubleClickHandler( mpShapeDoubleClickEventHandler );
     731           0 :         mrMultiplexer.removeMouseMoveHandler( mpShapeDoubleClickEventHandler );
     732           0 :         mpShapeDoubleClickEventHandler.reset();
     733             :     }
     734           0 :     if( mpDoubleClickEventHandler ) {
     735           0 :         mrMultiplexer.removeDoubleClickHandler( mpDoubleClickEventHandler );
     736           0 :         mpDoubleClickEventHandler.reset();
     737             :     }
     738           0 :     if( mpMouseEnterHandler ) {
     739           0 :         mrMultiplexer.removeMouseMoveHandler( mpMouseEnterHandler );
     740           0 :         mpMouseEnterHandler.reset();
     741             :     }
     742           0 :     if( mpMouseLeaveHandler ) {
     743           0 :         mrMultiplexer.removeMouseMoveHandler( mpMouseLeaveHandler );
     744           0 :         mpMouseLeaveHandler.reset();
     745             :     }
     746           0 : }
     747             : 
     748           0 : void UserEventQueue::setAdvanceOnClick( bool bAdvanceOnClick )
     749             : {
     750           0 :     mbAdvanceOnClick = bAdvanceOnClick;
     751             : 
     752             :     // forward to handler, if existing. Otherwise, the handler
     753             :     // creation will do the forwarding.
     754           0 :     if( mpClickEventHandler )
     755           0 :         mpClickEventHandler->setAdvanceOnClick( bAdvanceOnClick );
     756           0 : }
     757             : 
     758           0 : void UserEventQueue::registerAnimationStartEvent(
     759             :     const EventSharedPtr&                                 rEvent,
     760             :     const uno::Reference< animations::XAnimationNode>&    xNode )
     761             : {
     762             :     registerEvent( mpAnimationStartEventHandler,
     763             :                    rEvent,
     764             :                    xNode,
     765             :                    boost::bind( &EventMultiplexer::addAnimationStartHandler,
     766           0 :                                 boost::ref( mrMultiplexer ), _1 ) );
     767           0 : }
     768             : 
     769           0 : void UserEventQueue::registerAnimationEndEvent(
     770             :     const EventSharedPtr&                               rEvent,
     771             :     const uno::Reference<animations::XAnimationNode>&   xNode )
     772             : {
     773             :     registerEvent( mpAnimationEndEventHandler,
     774             :                    rEvent,
     775             :                    xNode,
     776             :                    boost::bind( &EventMultiplexer::addAnimationEndHandler,
     777           0 :                                 boost::ref( mrMultiplexer ), _1 ) );
     778           0 : }
     779             : 
     780           0 : void UserEventQueue::registerAudioStoppedEvent(
     781             :     const EventSharedPtr&                               rEvent,
     782             :     const uno::Reference<animations::XAnimationNode>&   xNode )
     783             : {
     784             :     registerEvent( mpAudioStoppedEventHandler,
     785             :                    rEvent,
     786             :                    xNode,
     787             :                    boost::bind( &EventMultiplexer::addAudioStoppedHandler,
     788           0 :                                 boost::ref( mrMultiplexer ), _1 ) );
     789           0 : }
     790             : 
     791           0 : void UserEventQueue::registerShapeClickEvent( const EventSharedPtr& rEvent,
     792             :                                               const ShapeSharedPtr& rShape )
     793             : {
     794           0 :     ENSURE_OR_THROW(
     795             :         rEvent,
     796             :         "UserEventQueue::registerShapeClickEvent(): Invalid event" );
     797             : 
     798           0 :     if( !mpShapeClickEventHandler )
     799             :     {
     800             :         // create handler
     801             :         mpShapeClickEventHandler.reset(
     802             :             new ShapeClickEventHandler(mrCursorManager,
     803           0 :                                        mrEventQueue) );
     804             : 
     805             :         // register handler on EventMultiplexer
     806           0 :         mrMultiplexer.addClickHandler( mpShapeClickEventHandler, 1.0 );
     807           0 :         mrMultiplexer.addMouseMoveHandler( mpShapeClickEventHandler, 1.0 );
     808             :     }
     809             : 
     810           0 :     mpShapeClickEventHandler->addEvent( rEvent, rShape );
     811           0 : }
     812             : 
     813             : namespace {
     814             : class ClickEventRegistrationFunctor
     815             : {
     816             : public:
     817           0 :     ClickEventRegistrationFunctor( EventMultiplexer& rMultiplexer,
     818             :                                    double            nPrio,
     819             :                                    bool              bAdvanceOnClick )
     820             :         : mrMultiplexer( rMultiplexer ),
     821             :           mnPrio(nPrio),
     822           0 :           mbAdvanceOnClick( bAdvanceOnClick ) {}
     823             : 
     824           0 :     void operator()( const boost::shared_ptr<ClickEventHandler>& rHandler )const
     825             :     {
     826             :         // register the handler on _two_ sources: we want the
     827             :         // nextEffect events, e.g. space bar, to trigger clicks, as well!
     828           0 :         mrMultiplexer.addClickHandler( rHandler, mnPrio );
     829           0 :         mrMultiplexer.addNextEffectHandler( rHandler, mnPrio );
     830             : 
     831             :         // forward advance-on-click state to newly
     832             :         // generated handler (that's the only reason why
     833             :         // we're called here)
     834           0 :         rHandler->setAdvanceOnClick( mbAdvanceOnClick );
     835           0 :     }
     836             : 
     837             : private:
     838             :     EventMultiplexer&   mrMultiplexer;
     839             :     double const        mnPrio;
     840             :     bool const          mbAdvanceOnClick;
     841             : };
     842             : } // anon namespace
     843             : 
     844           0 : void UserEventQueue::registerNextEffectEvent( const EventSharedPtr& rEvent )
     845             : {
     846             :     // TODO: better name may be mpNextEffectEventHandler?  then we have
     847             :     //       next effect (=> waiting to be started)
     848             :     //       skip effect (skipping the currently running one)
     849             :     //       rewind effect (rewinding back running one and waiting (again)
     850             :     //                      to be started)
     851             :     registerEvent( mpClickEventHandler,
     852             :                    rEvent,
     853             :                    ClickEventRegistrationFunctor( mrMultiplexer,
     854             :                                                   0.0 /* default prio */,
     855           0 :                                                   mbAdvanceOnClick ) );
     856           0 : }
     857             : 
     858           0 : void UserEventQueue::registerSkipEffectEvent(
     859             :     EventSharedPtr const & pEvent,
     860             :     const bool bSkipTriggersNextEffect)
     861             : {
     862           0 :     if(!mpSkipEffectEventHandler)
     863             :     {
     864             :         mpSkipEffectEventHandler.reset(
     865           0 :             new SkipEffectEventHandler( mrEventQueue, mrMultiplexer ) );
     866             :         // register the handler on _two_ sources: we want the
     867             :         // nextEffect events, e.g. space bar, to trigger clicks, as well!
     868             :         mrMultiplexer.addClickHandler( mpSkipEffectEventHandler,
     869           0 :                                        -1.0 /* prio below default */ );
     870             :         mrMultiplexer.addNextEffectHandler( mpSkipEffectEventHandler,
     871           0 :                                             -1.0 /* prio below default */ );
     872             :         // forward advance-on-click state to newly
     873             :         // generated handler (that's the only reason why
     874             :         // we're called here)
     875           0 :         mpSkipEffectEventHandler->setAdvanceOnClick( mbAdvanceOnClick );
     876             :     }
     877           0 :     mpSkipEffectEventHandler->setSkipTriggersNextEffect(bSkipTriggersNextEffect);
     878           0 :     mpSkipEffectEventHandler->addEvent( pEvent );
     879           0 : }
     880             : 
     881           0 : void UserEventQueue::registerRewindEffectEvent( EventSharedPtr const& pEvent )
     882             : {
     883             :     registerEvent( mpRewindEffectEventHandler,
     884             :                    pEvent,
     885             :                    boost::bind( &EventMultiplexer::addClickHandler,
     886             :                                 boost::ref(mrMultiplexer), _1,
     887           0 :                                 -1.0 /* prio below default */ ) );
     888           0 : }
     889             : 
     890           0 : void UserEventQueue::registerShapeDoubleClickEvent(
     891             :     const EventSharedPtr& rEvent,
     892             :     const ShapeSharedPtr& rShape )
     893             : {
     894           0 :     ENSURE_OR_THROW(
     895             :         rEvent,
     896             :         "UserEventQueue::registerShapeDoubleClickEvent(): Invalid event" );
     897             : 
     898           0 :     if( !mpShapeDoubleClickEventHandler )
     899             :     {
     900             :         // create handler
     901             :         mpShapeDoubleClickEventHandler.reset(
     902             :             new ShapeClickEventHandler(mrCursorManager,
     903           0 :                                        mrEventQueue) );
     904             : 
     905             :         // register handler on EventMultiplexer
     906             :         mrMultiplexer.addDoubleClickHandler( mpShapeDoubleClickEventHandler,
     907           0 :                                              1.0 );
     908             :         mrMultiplexer.addMouseMoveHandler( mpShapeDoubleClickEventHandler,
     909           0 :                                            1.0 );
     910             :     }
     911             : 
     912           0 :     mpShapeDoubleClickEventHandler->addEvent( rEvent, rShape );
     913           0 : }
     914             : 
     915           0 : void UserEventQueue::registerMouseEnterEvent( const EventSharedPtr& rEvent,
     916             :                                               const ShapeSharedPtr& rShape )
     917             : {
     918             :     registerEvent( mpMouseEnterHandler,
     919             :                    rEvent,
     920             :                    rShape,
     921             :                    boost::bind( &EventMultiplexer::addMouseMoveHandler,
     922             :                                 boost::ref( mrMultiplexer ), _1,
     923           0 :                                 0.0 /* default prio */ ) );
     924           0 : }
     925             : 
     926           0 : void UserEventQueue::registerMouseLeaveEvent( const EventSharedPtr& rEvent,
     927             :                                               const ShapeSharedPtr& rShape )
     928             : {
     929             :     registerEvent( mpMouseLeaveHandler,
     930             :                    rEvent,
     931             :                    rShape,
     932             :                    boost::bind( &EventMultiplexer::addMouseMoveHandler,
     933             :                                 boost::ref( mrMultiplexer ), _1,
     934           0 :                                 0.0 /* default prio */ ) );
     935           0 : }
     936             : 
     937           0 : void UserEventQueue::callSkipEffectEventHandler (void)
     938             : {
     939             :     ::boost::shared_ptr<SkipEffectEventHandler> pHandler (
     940           0 :         ::boost::dynamic_pointer_cast<SkipEffectEventHandler>(mpSkipEffectEventHandler));
     941           0 :     if (pHandler)
     942           0 :         pHandler->skipEffect();
     943           0 : }
     944             : 
     945             : } // namespace internal
     946           0 : } // namespace presentation
     947             : 
     948             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10