| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_slideshow.hxx" |
| |
| // must be first |
| #include <canvas/debug.hxx> |
| #include <tools/diagnose_ex.h> |
| |
| #include <rtl/ref.hxx> |
| #include <cppuhelper/compbase2.hxx> |
| #include <cppuhelper/basemutex.hxx> |
| |
| #include <com/sun/star/awt/XMouseListener.hpp> |
| #include <com/sun/star/awt/XMouseMotionListener.hpp> |
| #include <com/sun/star/awt/SystemPointer.hpp> |
| #include <com/sun/star/awt/XWindow.hpp> |
| #include <com/sun/star/awt/MouseButton.hpp> |
| #include <com/sun/star/presentation/XSlideShowView.hpp> |
| |
| #include <basegfx/matrix/b2dhommatrix.hxx> |
| #include <basegfx/numeric/ftools.hxx> |
| |
| #include "tools.hxx" |
| #include "eventqueue.hxx" |
| #include "eventmultiplexer.hxx" |
| #include "listenercontainer.hxx" |
| #include "delayevent.hxx" |
| #include "unoview.hxx" |
| #include "unoviewcontainer.hxx" |
| |
| #include <boost/shared_ptr.hpp> |
| #include <boost/weak_ptr.hpp> |
| #include <boost/function.hpp> |
| #include <boost/noncopyable.hpp> |
| #include <boost/bind.hpp> |
| |
| #include <vector> |
| #include <hash_map> |
| #include <algorithm> |
| |
| using namespace ::com::sun::star; |
| |
| namespace boost |
| { |
| // add operator== for weak_ptr |
| template<typename T> bool operator==( weak_ptr<T> const& rLHS, |
| weak_ptr<T> const& rRHS ) |
| { |
| return !(rLHS<rRHS) && !(rRHS<rLHS); |
| } |
| } |
| |
| namespace slideshow { |
| namespace internal { |
| |
| template <typename HandlerT> |
| class PrioritizedHandlerEntry |
| { |
| typedef boost::shared_ptr<HandlerT> HandlerSharedPtrT; |
| HandlerSharedPtrT mpHandler; |
| double mnPrio; |
| |
| public: |
| PrioritizedHandlerEntry( HandlerSharedPtrT const& pHandler, |
| double nPrio ) : |
| mpHandler(pHandler), |
| mnPrio(nPrio) |
| {} |
| |
| HandlerSharedPtrT const& getHandler() const { return mpHandler; } |
| |
| /// To sort according to priority |
| bool operator<( PrioritizedHandlerEntry const& rRHS ) const |
| { |
| // reversed order - high prioritized entries |
| // should be at the beginning of the queue |
| return mnPrio > rRHS.mnPrio; |
| } |
| |
| /// To permit std::remove in removeHandler template |
| bool operator==( PrioritizedHandlerEntry const& rRHS ) const |
| { |
| // ignore prio, for removal, only the handler ptr matters |
| return mpHandler == rRHS.mpHandler; |
| } |
| }; |
| |
| template<typename T> inline T* get_pointer(PrioritizedHandlerEntry<T> const& handler) |
| { |
| return handler.getHandler().get(); |
| } |
| |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| |
| |
| typedef cppu::WeakComponentImplHelper2< |
| awt::XMouseListener, |
| awt::XMouseMotionListener > Listener_UnoBase; |
| |
| /** Listener class, to decouple UNO lifetime from EventMultiplexer |
| |
| This class gets registered as the XMouse(Motion)Listener on the |
| XSlideViews, and passes on the events to the EventMultiplexer (via |
| EventQueue indirection, to force the events into the main thread) |
| */ |
| class EventMultiplexerListener : private cppu::BaseMutex, |
| public Listener_UnoBase, |
| private ::boost::noncopyable |
| { |
| public: |
| EventMultiplexerListener( EventQueue& rEventQueue, |
| EventMultiplexerImpl& rEventMultiplexer ) : |
| Listener_UnoBase( m_aMutex ), |
| mpEventQueue( &rEventQueue ), |
| mpEventMultiplexer( &rEventMultiplexer ) |
| { |
| } |
| |
| // WeakComponentImplHelperBase::disposing |
| virtual void SAL_CALL disposing(); |
| |
| private: |
| virtual void SAL_CALL disposing( const lang::EventObject& Source ) |
| throw (uno::RuntimeException); |
| |
| // XMouseListener implementation |
| virtual void SAL_CALL mousePressed( const awt::MouseEvent& e ) |
| throw (uno::RuntimeException); |
| virtual void SAL_CALL mouseReleased( const awt::MouseEvent& e ) |
| throw (uno::RuntimeException); |
| virtual void SAL_CALL mouseEntered( const awt::MouseEvent& e ) |
| throw (uno::RuntimeException); |
| virtual void SAL_CALL mouseExited( const awt::MouseEvent& e ) |
| throw (uno::RuntimeException); |
| |
| // XMouseMotionListener implementation |
| virtual void SAL_CALL mouseDragged( const awt::MouseEvent& e ) |
| throw (uno::RuntimeException); |
| virtual void SAL_CALL mouseMoved( const awt::MouseEvent& e ) |
| throw (uno::RuntimeException); |
| |
| |
| EventQueue* mpEventQueue; |
| EventMultiplexerImpl* mpEventMultiplexer; |
| }; |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| |
| |
| struct EventMultiplexerImpl |
| { |
| EventMultiplexerImpl( EventQueue& rEventQueue, |
| UnoViewContainer const& rViewContainer ) : |
| mrEventQueue(rEventQueue), |
| mrViewContainer(rViewContainer), |
| mxListener( new EventMultiplexerListener(rEventQueue, |
| *this) ), |
| maNextEffectHandlers(), |
| maSlideStartHandlers(), |
| maSlideEndHandlers(), |
| maAnimationStartHandlers(), |
| maAnimationEndHandlers(), |
| maSlideAnimationsEndHandlers(), |
| maAudioStoppedHandlers(), |
| maCommandStopAudioHandlers(), |
| maPauseHandlers(), |
| maViewHandlers(), |
| maViewRepaintHandlers(), |
| maShapeListenerHandlers(), |
| maUserPaintEventHandlers(), |
| maShapeCursorHandlers(), |
| maMouseClickHandlers(), |
| maMouseDoubleClickHandlers(), |
| maMouseMoveHandlers(), |
| maHyperlinkHandlers(), |
| mnTimeout(0.0), |
| mpTickEvent(), |
| mbIsAutoMode(false) |
| {} |
| |
| ~EventMultiplexerImpl() |
| { |
| if( mxListener.is() ) |
| mxListener->dispose(); |
| } |
| |
| /// Remove all handlers |
| void clear(); |
| |
| // actual handler callbacks (get called from the UNO interface |
| // listeners via event queue) |
| void mousePressed( const awt::MouseEvent& e ); |
| void mouseReleased( const awt::MouseEvent& e ); |
| void mouseDragged( const awt::MouseEvent& e ); |
| void mouseMoved( const awt::MouseEvent& e ); |
| |
| bool isMouseListenerRegistered() const; |
| |
| typedef ThreadUnsafeListenerContainer< |
| PrioritizedHandlerEntry<EventHandler>, |
| std::vector< |
| PrioritizedHandlerEntry<EventHandler> > > ImplNextEffectHandlers; |
| typedef PrioritizedHandlerEntry<MouseEventHandler> ImplMouseHandlerEntry; |
| typedef ThreadUnsafeListenerContainer< |
| ImplMouseHandlerEntry, |
| std::vector<ImplMouseHandlerEntry> > ImplMouseHandlers; |
| typedef ThreadUnsafeListenerContainer< |
| EventHandlerSharedPtr, |
| std::vector<EventHandlerSharedPtr> > ImplEventHandlers; |
| typedef ThreadUnsafeListenerContainer< |
| AnimationEventHandlerSharedPtr, |
| std::vector<AnimationEventHandlerSharedPtr> > ImplAnimationHandlers; |
| typedef ThreadUnsafeListenerContainer< |
| PauseEventHandlerSharedPtr, |
| std::vector<PauseEventHandlerSharedPtr> > ImplPauseHandlers; |
| typedef ThreadUnsafeListenerContainer< |
| ViewEventHandlerWeakPtr, |
| std::vector<ViewEventHandlerWeakPtr> > ImplViewHandlers; |
| typedef ThreadUnsafeListenerContainer< |
| ViewRepaintHandlerSharedPtr, |
| std::vector<ViewRepaintHandlerSharedPtr> > ImplRepaintHandlers; |
| typedef ThreadUnsafeListenerContainer< |
| ShapeListenerEventHandlerSharedPtr, |
| std::vector<ShapeListenerEventHandlerSharedPtr> > ImplShapeListenerHandlers; |
| typedef ThreadUnsafeListenerContainer< |
| UserPaintEventHandlerSharedPtr, |
| std::vector<UserPaintEventHandlerSharedPtr> > ImplUserPaintEventHandlers; |
| typedef ThreadUnsafeListenerContainer< |
| ShapeCursorEventHandlerSharedPtr, |
| std::vector<ShapeCursorEventHandlerSharedPtr> > ImplShapeCursorHandlers; |
| typedef ThreadUnsafeListenerContainer< |
| PrioritizedHandlerEntry<HyperlinkHandler>, |
| std::vector<PrioritizedHandlerEntry<HyperlinkHandler> > > ImplHyperLinkHandlers; |
| |
| template <typename XSlideShowViewFunc> |
| void forEachView( XSlideShowViewFunc pViewMethod ); |
| |
| UnoViewSharedPtr findUnoView(const uno::Reference< |
| presentation::XSlideShowView>& xView) const; |
| |
| template< typename RegisterFunction > |
| void addMouseHandler( ImplMouseHandlers& rHandlerContainer, |
| const MouseEventHandlerSharedPtr& rHandler, |
| double nPriority, |
| RegisterFunction pRegisterListener ); |
| |
| bool notifyAllAnimationHandlers( ImplAnimationHandlers const& rContainer, |
| AnimationNodeSharedPtr const& rNode ); |
| |
| bool notifyMouseHandlers( |
| const ImplMouseHandlers& rQueue, |
| bool (MouseEventHandler::*pHandlerMethod)( |
| const awt::MouseEvent& ), |
| const awt::MouseEvent& e ); |
| |
| bool notifyNextEffect(); |
| |
| /// Called for automatic nextEffect |
| void tick(); |
| |
| /// Schedules a tick event |
| void scheduleTick(); |
| |
| /// Schedules tick events, if mbIsAutoMode is true |
| void handleTicks(); |
| |
| |
| EventQueue& mrEventQueue; |
| UnoViewContainer const& mrViewContainer; |
| ::rtl::Reference< |
| EventMultiplexerListener> mxListener; |
| |
| ImplNextEffectHandlers maNextEffectHandlers; |
| ImplEventHandlers maSlideStartHandlers; |
| ImplEventHandlers maSlideEndHandlers; |
| ImplAnimationHandlers maAnimationStartHandlers; |
| ImplAnimationHandlers maAnimationEndHandlers; |
| ImplEventHandlers maSlideAnimationsEndHandlers; |
| ImplAnimationHandlers maAudioStoppedHandlers; |
| ImplAnimationHandlers maCommandStopAudioHandlers; |
| ImplPauseHandlers maPauseHandlers; |
| ImplViewHandlers maViewHandlers; |
| ImplRepaintHandlers maViewRepaintHandlers; |
| ImplShapeListenerHandlers maShapeListenerHandlers; |
| ImplUserPaintEventHandlers maUserPaintEventHandlers; |
| ImplShapeCursorHandlers maShapeCursorHandlers; |
| ImplMouseHandlers maMouseClickHandlers; |
| ImplMouseHandlers maMouseDoubleClickHandlers; |
| ImplMouseHandlers maMouseMoveHandlers; |
| ImplHyperLinkHandlers maHyperlinkHandlers; |
| |
| /// automatic next effect mode timeout |
| double mnTimeout; |
| |
| /** Holds ptr to optional tick event weakly |
| |
| When event queue is cleansed, the next |
| setAutomaticMode(true) call is then able to |
| regenerate the event. |
| */ |
| ::boost::weak_ptr< Event > mpTickEvent; |
| bool mbIsAutoMode; |
| }; |
| |
| |
| /////////////////////////////////////////////////////////////////////////// |
| |
| |
| void SAL_CALL EventMultiplexerListener::disposing() |
| { |
| osl::MutexGuard const guard( m_aMutex ); |
| mpEventQueue = NULL; |
| mpEventMultiplexer = NULL; |
| } |
| |
| void SAL_CALL EventMultiplexerListener::disposing( |
| const lang::EventObject& /*rSource*/ ) throw (uno::RuntimeException) |
| { |
| // there's no real point in acting on this message - after all, |
| // the event sources are the XSlideShowViews, which must be |
| // explicitely removed from the slideshow via |
| // XSlideShow::removeView(). thus, if a XSlideShowView has |
| // properly removed itself from the slideshow, it will not be |
| // found here. and if it hasn't, there'll be other references at |
| // other places within the slideshow, anyway... |
| } |
| |
| void SAL_CALL EventMultiplexerListener::mousePressed( |
| const awt::MouseEvent& e ) throw (uno::RuntimeException) |
| { |
| osl::MutexGuard const guard( m_aMutex ); |
| |
| // notify mouse press. Don't call handlers directly, this |
| // might not be the main thread! |
| if( mpEventQueue ) |
| mpEventQueue->addEvent( |
| makeEvent( boost::bind( &EventMultiplexerImpl::mousePressed, |
| mpEventMultiplexer, |
| e ), |
| "EventMultiplexerImpl::mousePressed") ); |
| } |
| |
| void SAL_CALL EventMultiplexerListener::mouseReleased( |
| const awt::MouseEvent& e ) throw (uno::RuntimeException) |
| { |
| osl::MutexGuard const guard( m_aMutex ); |
| |
| // notify mouse release. Don't call handlers directly, |
| // this might not be the main thread! |
| if( mpEventQueue ) |
| mpEventQueue->addEvent( |
| makeEvent( boost::bind( &EventMultiplexerImpl::mouseReleased, |
| mpEventMultiplexer, |
| e ), |
| "EventMultiplexerImpl::mouseReleased") ); |
| } |
| |
| void SAL_CALL EventMultiplexerListener::mouseEntered( |
| const awt::MouseEvent& /*e*/ ) throw (uno::RuntimeException) |
| { |
| // not used here |
| } |
| |
| void SAL_CALL EventMultiplexerListener::mouseExited( |
| const awt::MouseEvent& /*e*/ ) throw (uno::RuntimeException) |
| { |
| // not used here |
| } |
| |
| // XMouseMotionListener implementation |
| void SAL_CALL EventMultiplexerListener::mouseDragged( |
| const awt::MouseEvent& e ) throw (uno::RuntimeException) |
| { |
| osl::MutexGuard const guard( m_aMutex ); |
| |
| // notify mouse drag. Don't call handlers directly, this |
| // might not be the main thread! |
| if( mpEventQueue ) |
| mpEventQueue->addEvent( |
| makeEvent( boost::bind( &EventMultiplexerImpl::mouseDragged, |
| mpEventMultiplexer, |
| e ), |
| "EventMultiplexerImpl::mouseDragged") ); |
| } |
| |
| void SAL_CALL EventMultiplexerListener::mouseMoved( |
| const awt::MouseEvent& e ) throw (uno::RuntimeException) |
| { |
| osl::MutexGuard const guard( m_aMutex ); |
| |
| // notify mouse move. Don't call handlers directly, this |
| // might not be the main thread! |
| if( mpEventQueue ) |
| mpEventQueue->addEvent( |
| makeEvent( boost::bind( &EventMultiplexerImpl::mouseMoved, |
| mpEventMultiplexer, |
| e ), |
| "EventMultiplexerImpl::mouseMoved") ); |
| } |
| |
| |
| /////////////////////////////////////////////////////////////////////////// |
| |
| |
| bool EventMultiplexerImpl::notifyAllAnimationHandlers( ImplAnimationHandlers const& rContainer, |
| AnimationNodeSharedPtr const& rNode ) |
| { |
| return rContainer.applyAll( |
| boost::bind( &AnimationEventHandler::handleAnimationEvent, |
| _1, boost::cref(rNode) ) ); |
| } |
| |
| template <typename XSlideShowViewFunc> |
| void EventMultiplexerImpl::forEachView( XSlideShowViewFunc pViewMethod ) |
| { |
| if( pViewMethod ) |
| { |
| // (un)register mouse listener on all views |
| for( UnoViewVector::const_iterator aIter( mrViewContainer.begin() ), |
| aEnd( mrViewContainer.end() ); aIter != aEnd; ++aIter ) |
| { |
| uno::Reference<presentation::XSlideShowView> xView ((*aIter)->getUnoView()); |
| if (xView.is()) |
| { |
| (xView.get()->*pViewMethod)( mxListener.get() ); |
| } |
| else |
| { |
| OSL_ASSERT(xView.is()); |
| } |
| } |
| } |
| } |
| |
| UnoViewSharedPtr EventMultiplexerImpl::findUnoView( |
| const uno::Reference<presentation::XSlideShowView>& xView) const |
| { |
| // find view from which the change originated |
| UnoViewVector::const_iterator aIter; |
| const UnoViewVector::const_iterator aEnd ( mrViewContainer.end() ); |
| if( (aIter=std::find_if( mrViewContainer.begin(), |
| aEnd, |
| boost::bind( |
| std::equal_to<uno::Reference<presentation::XSlideShowView> >(), |
| boost::cref( xView ), |
| boost::bind( &UnoView::getUnoView, _1 )))) == aEnd ) |
| { |
| OSL_ENSURE(false, "EventMultiplexer::findUnoView(): unexpected message source" ); |
| return UnoViewSharedPtr(); |
| } |
| |
| return *aIter; |
| } |
| |
| template< typename RegisterFunction > |
| void EventMultiplexerImpl::addMouseHandler( |
| ImplMouseHandlers& rHandlerContainer, |
| const MouseEventHandlerSharedPtr& rHandler, |
| double nPriority, |
| RegisterFunction pRegisterListener ) |
| { |
| ENSURE_OR_THROW( |
| rHandler, |
| "EventMultiplexer::addMouseHandler(): Invalid handler" ); |
| |
| // register mouse listener on all views |
| forEachView( pRegisterListener ); |
| |
| // add into sorted container: |
| rHandlerContainer.addSorted( |
| typename ImplMouseHandlers::container_type::value_type( |
| rHandler, |
| nPriority )); |
| } |
| |
| bool EventMultiplexerImpl::isMouseListenerRegistered() const |
| { |
| return !(maMouseClickHandlers.isEmpty() && |
| maMouseDoubleClickHandlers.isEmpty()); |
| } |
| |
| void EventMultiplexerImpl::tick() |
| { |
| if( !mbIsAutoMode ) |
| return; // this event is just a left-over, ignore |
| |
| notifyNextEffect(); |
| |
| if( !maNextEffectHandlers.isEmpty() ) |
| { |
| // still handlers left, schedule next timeout |
| // event. Will also set mbIsTickEventOn back to true |
| scheduleTick(); |
| } |
| } |
| |
| void EventMultiplexerImpl::scheduleTick() |
| { |
| EventSharedPtr pEvent( |
| makeDelay( boost::bind( &EventMultiplexerImpl::tick, |
| this ), |
| mnTimeout, |
| "EventMultiplexerImpl::tick with delay")); |
| |
| // store weak reference to generated event, to notice when |
| // the event queue gets cleansed (we then have to |
| // regenerate the tick event!) |
| mpTickEvent = pEvent; |
| |
| // enabled auto mode: simply schedule a timeout event, |
| // which will eventually call our tick() method |
| mrEventQueue.addEventForNextRound( pEvent ); |
| } |
| |
| void EventMultiplexerImpl::handleTicks() |
| { |
| if( !mbIsAutoMode ) |
| return; // nothing to do, don't need no ticks |
| |
| EventSharedPtr pTickEvent( mpTickEvent.lock() ); |
| if( pTickEvent ) |
| return; // nothing to do, there's already a tick |
| // pending |
| |
| // schedule initial tick (which reschedules itself |
| // after that, all by itself) |
| scheduleTick(); |
| } |
| |
| |
| void EventMultiplexerImpl::clear() |
| { |
| // deregister from all views. |
| if( isMouseListenerRegistered() ) |
| { |
| for( UnoViewVector::const_iterator aIter=mrViewContainer.begin(), |
| aEnd=mrViewContainer.end(); |
| aIter!=aEnd; |
| ++aIter ) |
| { |
| if( (*aIter)->getUnoView().is() ) |
| (*aIter)->getUnoView()->removeMouseListener( mxListener.get() ); |
| } |
| } |
| |
| if( !maMouseMoveHandlers.isEmpty() ) |
| { |
| for( UnoViewVector::const_iterator aIter=mrViewContainer.begin(), |
| aEnd=mrViewContainer.end(); |
| aIter!=aEnd; |
| ++aIter ) |
| { |
| if( (*aIter)->getUnoView().is() ) |
| (*aIter)->getUnoView()->removeMouseMotionListener( mxListener.get() ); |
| } |
| } |
| |
| // clear all handlers (releases all references) |
| maNextEffectHandlers.clear(); |
| maSlideStartHandlers.clear(); |
| maSlideEndHandlers.clear(); |
| maAnimationStartHandlers.clear(); |
| maAnimationEndHandlers.clear(); |
| maSlideAnimationsEndHandlers.clear(); |
| maAudioStoppedHandlers.clear(); |
| maCommandStopAudioHandlers.clear(); |
| maPauseHandlers.clear(); |
| maViewHandlers.clear(); |
| maViewRepaintHandlers.clear(); |
| maMouseClickHandlers.clear(); |
| maMouseDoubleClickHandlers.clear(); |
| maMouseMoveHandlers.clear(); |
| maHyperlinkHandlers.clear(); |
| mpTickEvent.reset(); |
| } |
| |
| // XMouseListener implementation |
| bool EventMultiplexerImpl::notifyMouseHandlers( |
| const ImplMouseHandlers& rQueue, |
| bool (MouseEventHandler::*pHandlerMethod)( const awt::MouseEvent& ), |
| const awt::MouseEvent& e ) |
| { |
| uno::Reference<presentation::XSlideShowView> xView( |
| e.Source, uno::UNO_QUERY ); |
| |
| ENSURE_OR_RETURN_FALSE( xView.is(), "EventMultiplexer::notifyHandlers(): " |
| "event source is not an XSlideShowView" ); |
| |
| // find corresponding view (to map mouse position into user |
| // coordinate space) |
| UnoViewVector::const_iterator aIter; |
| const UnoViewVector::const_iterator aBegin( mrViewContainer.begin() ); |
| const UnoViewVector::const_iterator aEnd ( mrViewContainer.end() ); |
| if( (aIter=::std::find_if( |
| aBegin, aEnd, |
| boost::bind( std::equal_to< uno::Reference< |
| presentation::XSlideShowView > >(), |
| boost::cref( xView ), |
| boost::bind( &UnoView::getUnoView, _1 ) ) ) ) == aEnd) |
| { |
| ENSURE_OR_RETURN_FALSE( |
| false, "EventMultiplexer::notifyHandlers(): " |
| "event source not found under registered views" ); |
| } |
| |
| // convert mouse position to user coordinate space |
| ::basegfx::B2DPoint aPosition( e.X, e.Y ); |
| ::basegfx::B2DHomMatrix aMatrix( (*aIter)->getTransformation() ); |
| if( !aMatrix.invert() ) |
| ENSURE_OR_THROW( false, "EventMultiplexer::notifyHandlers():" |
| " view matrix singular" ); |
| aPosition *= aMatrix; |
| |
| awt::MouseEvent aEvent( e ); |
| aEvent.X = ::basegfx::fround( aPosition.getX() ); |
| aEvent.Y = ::basegfx::fround( aPosition.getY() ); |
| |
| // fire event on handlers, try in order of precedence. If |
| // one high-priority handler rejects the event |
| // (i.e. returns false), try next handler. |
| return rQueue.apply( |
| boost::bind( |
| pHandlerMethod, |
| boost::bind( |
| &ImplMouseHandlers::container_type::value_type::getHandler, |
| _1 ), |
| aEvent )); |
| } |
| |
| void EventMultiplexerImpl::mousePressed( const awt::MouseEvent& e ) |
| { |
| // fire double-click events for every second click |
| sal_Int32 nCurrClickCount = e.ClickCount; |
| while( nCurrClickCount > 1 && |
| notifyMouseHandlers( maMouseDoubleClickHandlers, |
| &MouseEventHandler::handleMousePressed, |
| e )) |
| { |
| nCurrClickCount -= 2; |
| } |
| |
| // fire single-click events for all remaining clicks |
| while( nCurrClickCount > 0 && |
| notifyMouseHandlers( maMouseClickHandlers, |
| &MouseEventHandler::handleMousePressed, |
| e )) |
| { |
| --nCurrClickCount; |
| } |
| } |
| |
| void EventMultiplexerImpl::mouseReleased( const awt::MouseEvent& e ) |
| { |
| // fire double-click events for every second click |
| sal_Int32 nCurrClickCount = e.ClickCount; |
| while( nCurrClickCount > 1 && |
| notifyMouseHandlers( maMouseDoubleClickHandlers, |
| &MouseEventHandler::handleMouseReleased, |
| e )) |
| { |
| nCurrClickCount -= 2; |
| } |
| |
| // fire single-click events for all remaining clicks |
| while( nCurrClickCount > 0 && |
| notifyMouseHandlers( maMouseClickHandlers, |
| &MouseEventHandler::handleMouseReleased, |
| e )) |
| { |
| --nCurrClickCount; |
| } |
| } |
| |
| void EventMultiplexerImpl::mouseDragged( const awt::MouseEvent& e ) |
| { |
| notifyMouseHandlers( maMouseMoveHandlers, |
| &MouseEventHandler::handleMouseDragged, |
| e ); |
| } |
| |
| void EventMultiplexerImpl::mouseMoved( const awt::MouseEvent& e ) |
| { |
| notifyMouseHandlers( maMouseMoveHandlers, |
| &MouseEventHandler::handleMouseMoved, |
| e ); |
| } |
| |
| bool EventMultiplexerImpl::notifyNextEffect() |
| { |
| // fire event on handlers, try in order of precedence. If one |
| // high-priority handler rejects the event (i.e. returns false), |
| // try next handler. |
| return maNextEffectHandlers.apply( |
| boost::bind( |
| &EventHandler::handleEvent, |
| boost::bind( |
| &ImplNextEffectHandlers::container_type::value_type::getHandler, |
| _1 )) ); |
| } |
| |
| ////////////////////////////////////////////////////////////////////////// |
| |
| |
| EventMultiplexer::EventMultiplexer( EventQueue& rEventQueue, |
| UnoViewContainer const& rViewContainer ) : |
| mpImpl( new EventMultiplexerImpl(rEventQueue, rViewContainer) ) |
| { |
| } |
| |
| EventMultiplexer::~EventMultiplexer() |
| { |
| // outline because of EventMultiplexerImpl's incomplete type |
| } |
| |
| void EventMultiplexer::clear() |
| { |
| mpImpl->clear(); |
| } |
| |
| void EventMultiplexer::setAutomaticMode( bool bIsAuto ) |
| { |
| if( bIsAuto == mpImpl->mbIsAutoMode ) |
| return; // no change, nothing to do |
| |
| mpImpl->mbIsAutoMode = bIsAuto; |
| |
| mpImpl->handleTicks(); |
| } |
| |
| bool EventMultiplexer::getAutomaticMode() const |
| { |
| return mpImpl->mbIsAutoMode; |
| } |
| |
| void EventMultiplexer::setAutomaticTimeout( double nTimeout ) |
| { |
| mpImpl->mnTimeout = nTimeout; |
| } |
| |
| double EventMultiplexer::getAutomaticTimeout() const |
| { |
| return mpImpl->mnTimeout; |
| } |
| |
| void EventMultiplexer::addNextEffectHandler( |
| EventHandlerSharedPtr const& rHandler, |
| double nPriority ) |
| { |
| mpImpl->maNextEffectHandlers.addSorted( |
| EventMultiplexerImpl::ImplNextEffectHandlers::container_type::value_type( |
| rHandler, |
| nPriority) ); |
| |
| // Enable tick events, if not done already |
| mpImpl->handleTicks(); |
| } |
| |
| void EventMultiplexer::removeNextEffectHandler( |
| const EventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maNextEffectHandlers.remove( |
| EventMultiplexerImpl::ImplNextEffectHandlers::container_type::value_type( |
| rHandler, |
| 0.0) ); |
| } |
| |
| void EventMultiplexer::addSlideStartHandler( |
| const EventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maSlideStartHandlers.add( rHandler ); |
| } |
| |
| void EventMultiplexer::removeSlideStartHandler( |
| const EventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maSlideStartHandlers.remove( rHandler ); |
| } |
| |
| void EventMultiplexer::addSlideEndHandler( |
| const EventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maSlideEndHandlers.add( rHandler ); |
| } |
| |
| void EventMultiplexer::removeSlideEndHandler( |
| const EventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maSlideEndHandlers.remove( rHandler ); |
| } |
| |
| void EventMultiplexer::addAnimationStartHandler( |
| const AnimationEventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maAnimationStartHandlers.add( rHandler ); |
| } |
| |
| void EventMultiplexer::removeAnimationStartHandler( |
| const AnimationEventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maAnimationStartHandlers.remove( rHandler ); |
| } |
| |
| void EventMultiplexer::addAnimationEndHandler( |
| const AnimationEventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maAnimationEndHandlers.add( rHandler ); |
| } |
| |
| void EventMultiplexer::removeAnimationEndHandler( |
| const AnimationEventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maAnimationEndHandlers.remove( rHandler ); |
| } |
| |
| void EventMultiplexer::addSlideAnimationsEndHandler( |
| const EventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maSlideAnimationsEndHandlers.add( rHandler ); |
| } |
| |
| void EventMultiplexer::removeSlideAnimationsEndHandler( |
| const EventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maSlideAnimationsEndHandlers.remove( rHandler ); |
| } |
| |
| void EventMultiplexer::addAudioStoppedHandler( |
| const AnimationEventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maAudioStoppedHandlers.add( rHandler ); |
| } |
| |
| void EventMultiplexer::removeAudioStoppedHandler( |
| const AnimationEventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maAudioStoppedHandlers.remove( rHandler ); |
| } |
| |
| void EventMultiplexer::addCommandStopAudioHandler( |
| const AnimationEventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maCommandStopAudioHandlers.add( rHandler ); |
| } |
| |
| void EventMultiplexer::removeCommandStopAudioHandler( |
| const AnimationEventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maCommandStopAudioHandlers.remove( rHandler ); |
| } |
| |
| void EventMultiplexer::addPauseHandler( |
| const PauseEventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maPauseHandlers.add( rHandler ); |
| } |
| |
| void EventMultiplexer::removePauseHandler( |
| const PauseEventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maPauseHandlers.remove( rHandler ); |
| } |
| |
| void EventMultiplexer::addViewHandler( |
| const ViewEventHandlerWeakPtr& rHandler ) |
| { |
| mpImpl->maViewHandlers.add( rHandler ); |
| } |
| |
| void EventMultiplexer::removeViewHandler( const ViewEventHandlerWeakPtr& rHandler ) |
| { |
| mpImpl->maViewHandlers.remove( rHandler ); |
| } |
| |
| void EventMultiplexer::addViewRepaintHandler( const ViewRepaintHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maViewRepaintHandlers.add( rHandler ); |
| } |
| |
| void EventMultiplexer::removeViewRepaintHandler( const ViewRepaintHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maViewRepaintHandlers.remove( rHandler ); |
| } |
| |
| void EventMultiplexer::addShapeListenerHandler( const ShapeListenerEventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maShapeListenerHandlers.add( rHandler ); |
| } |
| |
| void EventMultiplexer::removeShapeListenerHandler( const ShapeListenerEventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maShapeListenerHandlers.remove( rHandler ); |
| } |
| |
| void EventMultiplexer::addUserPaintHandler( const UserPaintEventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maUserPaintEventHandlers.add( rHandler ); |
| } |
| |
| void EventMultiplexer::removeUserPaintHandler( const UserPaintEventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maUserPaintEventHandlers.remove( rHandler ); |
| } |
| |
| void EventMultiplexer::addShapeCursorHandler( const ShapeCursorEventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maShapeCursorHandlers.add( rHandler ); |
| } |
| |
| void EventMultiplexer::removeShapeCursorHandler( const ShapeCursorEventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maShapeCursorHandlers.remove( rHandler ); |
| } |
| |
| void EventMultiplexer::addClickHandler( |
| const MouseEventHandlerSharedPtr& rHandler, |
| double nPriority ) |
| { |
| mpImpl->addMouseHandler( |
| mpImpl->maMouseClickHandlers, |
| rHandler, |
| nPriority, |
| mpImpl->isMouseListenerRegistered() |
| ? NULL |
| : &presentation::XSlideShowView::addMouseListener ); |
| } |
| |
| void EventMultiplexer::removeClickHandler( |
| const MouseEventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maMouseClickHandlers.remove( |
| EventMultiplexerImpl::ImplMouseHandlers::container_type::value_type( |
| rHandler, |
| 0.0) ); |
| |
| if( !mpImpl->isMouseListenerRegistered() ) |
| mpImpl->forEachView( &presentation::XSlideShowView::removeMouseListener ); |
| } |
| |
| void EventMultiplexer::addDoubleClickHandler( |
| const MouseEventHandlerSharedPtr& rHandler, |
| double nPriority ) |
| { |
| mpImpl->addMouseHandler( |
| mpImpl->maMouseDoubleClickHandlers, |
| rHandler, |
| nPriority, |
| mpImpl->isMouseListenerRegistered() |
| ? NULL |
| : &presentation::XSlideShowView::addMouseListener ); |
| } |
| |
| void EventMultiplexer::removeDoubleClickHandler( |
| const MouseEventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maMouseDoubleClickHandlers.remove( |
| EventMultiplexerImpl::ImplMouseHandlers::container_type::value_type( |
| rHandler, |
| 0.0) ); |
| |
| if( !mpImpl->isMouseListenerRegistered() ) |
| mpImpl->forEachView( &presentation::XSlideShowView::removeMouseListener ); |
| } |
| |
| void EventMultiplexer::addMouseMoveHandler( |
| const MouseEventHandlerSharedPtr& rHandler, |
| double nPriority ) |
| { |
| mpImpl->addMouseHandler( |
| mpImpl->maMouseMoveHandlers, |
| rHandler, |
| nPriority, |
| mpImpl->maMouseMoveHandlers.isEmpty() |
| ? &presentation::XSlideShowView::addMouseMotionListener |
| : NULL ); |
| } |
| |
| void EventMultiplexer::removeMouseMoveHandler( |
| const MouseEventHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maMouseMoveHandlers.remove( |
| EventMultiplexerImpl::ImplMouseHandlers::container_type::value_type( |
| rHandler, |
| 0.0) ); |
| |
| if( mpImpl->maMouseMoveHandlers.isEmpty() ) |
| mpImpl->forEachView( |
| &presentation::XSlideShowView::removeMouseMotionListener ); |
| } |
| |
| void EventMultiplexer::addHyperlinkHandler( const HyperlinkHandlerSharedPtr& rHandler, |
| double nPriority ) |
| { |
| mpImpl->maHyperlinkHandlers.addSorted( |
| EventMultiplexerImpl::ImplHyperLinkHandlers::container_type::value_type( |
| rHandler, |
| nPriority) ); |
| } |
| |
| void EventMultiplexer::removeHyperlinkHandler( const HyperlinkHandlerSharedPtr& rHandler ) |
| { |
| mpImpl->maHyperlinkHandlers.remove( |
| EventMultiplexerImpl::ImplHyperLinkHandlers::container_type::value_type( |
| rHandler, |
| 0.0) ); |
| } |
| |
| bool EventMultiplexer::notifyShapeListenerAdded( |
| const uno::Reference<presentation::XShapeEventListener>& xListener, |
| const uno::Reference<drawing::XShape>& xShape ) |
| { |
| return mpImpl->maShapeListenerHandlers.applyAll( |
| boost::bind(&ShapeListenerEventHandler::listenerAdded, |
| _1, |
| boost::cref(xListener), |
| boost::cref(xShape)) ); |
| } |
| |
| bool EventMultiplexer::notifyShapeListenerRemoved( |
| const uno::Reference<presentation::XShapeEventListener>& xListener, |
| const uno::Reference<drawing::XShape>& xShape ) |
| { |
| return mpImpl->maShapeListenerHandlers.applyAll( |
| boost::bind(&ShapeListenerEventHandler::listenerRemoved, |
| _1, |
| boost::cref(xListener), |
| boost::cref(xShape)) ); |
| } |
| |
| bool EventMultiplexer::notifyShapeCursorChange( |
| const uno::Reference<drawing::XShape>& xShape, |
| sal_Int16 nPointerShape ) |
| { |
| return mpImpl->maShapeCursorHandlers.applyAll( |
| boost::bind(&ShapeCursorEventHandler::cursorChanged, |
| _1, |
| boost::cref(xShape), |
| nPointerShape)); |
| } |
| |
| bool EventMultiplexer::notifyUserPaintColor( RGBColor const& rUserColor ) |
| { |
| return mpImpl->maUserPaintEventHandlers.applyAll( |
| boost::bind(&UserPaintEventHandler::colorChanged, |
| _1, |
| boost::cref(rUserColor))); |
| } |
| |
| bool EventMultiplexer::notifyUserPaintStrokeWidth( double rUserStrokeWidth ) |
| { |
| return mpImpl->maUserPaintEventHandlers.applyAll( |
| boost::bind(&UserPaintEventHandler::widthChanged, |
| _1, |
| rUserStrokeWidth)); |
| } |
| |
| bool EventMultiplexer::notifyUserPaintDisabled() |
| { |
| return mpImpl->maUserPaintEventHandlers.applyAll( |
| boost::mem_fn(&UserPaintEventHandler::disable)); |
| } |
| |
| bool EventMultiplexer::notifySwitchPenMode(){ |
| return mpImpl->maUserPaintEventHandlers.applyAll( |
| boost::mem_fn(&UserPaintEventHandler::switchPenMode)); |
| } |
| |
| bool EventMultiplexer::notifySwitchEraserMode(){ |
| return mpImpl->maUserPaintEventHandlers.applyAll( |
| boost::mem_fn(&UserPaintEventHandler::switchEraserMode)); |
| } |
| |
| //adding erasing all ink features with UserPaintOverlay |
| bool EventMultiplexer::notifyEraseAllInk( bool const& rEraseAllInk ) |
| { |
| return mpImpl->maUserPaintEventHandlers.applyAll( |
| boost::bind(&UserPaintEventHandler::eraseAllInkChanged, |
| _1, |
| boost::cref(rEraseAllInk))); |
| } |
| |
| //adding erasing features with UserPaintOverlay |
| bool EventMultiplexer::notifyEraseInkWidth( sal_Int32 rEraseInkSize ) |
| { |
| return mpImpl->maUserPaintEventHandlers.applyAll( |
| boost::bind(&UserPaintEventHandler::eraseInkWidthChanged, |
| _1, |
| boost::cref(rEraseInkSize))); |
| } |
| |
| bool EventMultiplexer::notifyNextEffect() |
| { |
| return mpImpl->notifyNextEffect(); |
| } |
| |
| bool EventMultiplexer::notifySlideStartEvent() |
| { |
| return mpImpl->maSlideStartHandlers.applyAll( |
| boost::mem_fn(&EventHandler::handleEvent) ); |
| } |
| |
| bool EventMultiplexer::notifySlideEndEvent() |
| { |
| return mpImpl->maSlideEndHandlers.applyAll( |
| boost::mem_fn(&EventHandler::handleEvent) ); |
| } |
| |
| bool EventMultiplexer::notifyAnimationStart( |
| const AnimationNodeSharedPtr& rNode ) |
| { |
| return mpImpl->notifyAllAnimationHandlers( mpImpl->maAnimationStartHandlers, |
| rNode ); |
| } |
| |
| bool EventMultiplexer::notifyAnimationEnd( |
| const AnimationNodeSharedPtr& rNode ) |
| { |
| return mpImpl->notifyAllAnimationHandlers( mpImpl->maAnimationEndHandlers, |
| rNode ); |
| } |
| |
| bool EventMultiplexer::notifySlideAnimationsEnd() |
| { |
| return mpImpl->maSlideAnimationsEndHandlers.applyAll( |
| boost::mem_fn(&EventHandler::handleEvent)); |
| } |
| |
| bool EventMultiplexer::notifyAudioStopped( |
| const AnimationNodeSharedPtr& rNode ) |
| { |
| return mpImpl->notifyAllAnimationHandlers( |
| mpImpl->maAudioStoppedHandlers, |
| rNode ); |
| } |
| |
| bool EventMultiplexer::notifyCommandStopAudio( |
| const AnimationNodeSharedPtr& rNode ) |
| { |
| return mpImpl->notifyAllAnimationHandlers( |
| mpImpl->maCommandStopAudioHandlers, |
| rNode ); |
| } |
| |
| bool EventMultiplexer::notifyPauseMode( bool bPauseShow ) |
| { |
| return mpImpl->maPauseHandlers.applyAll( |
| boost::bind( &PauseEventHandler::handlePause, |
| _1, bPauseShow )); |
| } |
| |
| bool EventMultiplexer::notifyViewAdded( const UnoViewSharedPtr& rView ) |
| { |
| ENSURE_OR_THROW( rView, "EventMultiplexer::notifyViewAdded(): Invalid view"); |
| |
| // register event listener |
| uno::Reference<presentation::XSlideShowView> const rUnoView( |
| rView->getUnoView() ); |
| |
| if( mpImpl->isMouseListenerRegistered() ) |
| rUnoView->addMouseListener( |
| mpImpl->mxListener.get() ); |
| |
| if( !mpImpl->maMouseMoveHandlers.isEmpty() ) |
| rUnoView->addMouseMotionListener( |
| mpImpl->mxListener.get() ); |
| |
| return mpImpl->maViewHandlers.applyAll( |
| boost::bind( &ViewEventHandler::viewAdded, |
| _1, |
| boost::cref(rView) )); |
| } |
| |
| bool EventMultiplexer::notifyViewRemoved( const UnoViewSharedPtr& rView ) |
| { |
| ENSURE_OR_THROW( rView, |
| "EventMultiplexer::removeView(): Invalid view" ); |
| |
| // revoke event listeners |
| uno::Reference<presentation::XSlideShowView> const rUnoView( |
| rView->getUnoView() ); |
| |
| if( mpImpl->isMouseListenerRegistered() ) |
| rUnoView->removeMouseListener( |
| mpImpl->mxListener.get() ); |
| |
| if( !mpImpl->maMouseMoveHandlers.isEmpty() ) |
| rUnoView->removeMouseMotionListener( |
| mpImpl->mxListener.get() ); |
| |
| return mpImpl->maViewHandlers.applyAll( |
| boost::bind( &ViewEventHandler::viewRemoved, |
| _1, |
| boost::cref(rView) )); |
| } |
| |
| bool EventMultiplexer::notifyViewChanged( const UnoViewSharedPtr& rView ) |
| { |
| return mpImpl->maViewHandlers.applyAll( |
| boost::bind( &ViewEventHandler::viewChanged, |
| _1, |
| boost::cref(rView) )); |
| } |
| |
| bool EventMultiplexer::notifyViewChanged( const uno::Reference<presentation::XSlideShowView>& xView ) |
| { |
| UnoViewSharedPtr pView( mpImpl->findUnoView(xView) ); |
| |
| if( !pView ) |
| return false; // view not registered here |
| |
| return notifyViewChanged( pView ); |
| } |
| |
| bool EventMultiplexer::notifyViewsChanged() |
| { |
| return mpImpl->maViewHandlers.applyAll( |
| boost::mem_fn( &ViewEventHandler::viewsChanged )); |
| } |
| |
| bool EventMultiplexer::notifyViewClobbered( |
| const uno::Reference<presentation::XSlideShowView>& xView ) |
| { |
| UnoViewSharedPtr pView( mpImpl->findUnoView(xView) ); |
| |
| if( !pView ) |
| return false; // view not registered here |
| |
| return mpImpl->maViewRepaintHandlers.applyAll( |
| boost::bind( &ViewRepaintHandler::viewClobbered, |
| _1, |
| boost::cref(pView) )); |
| } |
| |
| bool EventMultiplexer::notifyHyperlinkClicked( |
| rtl::OUString const& hyperLink ) |
| { |
| return mpImpl->maHyperlinkHandlers.apply( |
| boost::bind(&HyperlinkHandler::handleHyperlink, |
| _1, |
| boost::cref(hyperLink)) ); |
| } |
| |
| bool EventMultiplexer::notifySlideTransitionStarted() |
| { |
| return true; |
| } |
| |
| } // namespace internal |
| } // namespace presentation |
| |