LCOV - code coverage report
Current view: top level - slideshow/source/engine - usereventqueue.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 305 0.0 %
Date: 2012-08-25 Functions: 0 90 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

           Branch data     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, stlport 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