/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; namespace { // add operator== for weak_ptr, so we can use std::find over lists of them struct ViewEventHandlerWeakPtrWrapper final { slideshow::internal::ViewEventHandlerWeakPtr ptr; ViewEventHandlerWeakPtrWrapper(slideshow::internal::ViewEventHandlerWeakPtr thePtr): ptr(std::move(thePtr)) {} bool operator ==(ViewEventHandlerWeakPtrWrapper const & other) const { return ptr.lock().get() == other.ptr.lock().get(); } }; } // Needed by ImplViewHandlers; see the ListenerOperations> partial // specialization in slideshow/source/inc/listenercontainer.hxx: template<> struct slideshow::internal::ListenerOperations { template< typename ContainerT, typename FuncT > static bool notifySingleListener( ContainerT& rContainer, FuncT func ) { for( const auto& rCurr : rContainer ) { std::shared_ptr pListener( rCurr.ptr.lock() ); if( pListener && func(pListener) ) return true; } return false; } template< typename ContainerT, typename FuncT > static bool notifyAllListeners( ContainerT& rContainer, FuncT func ) { bool bRet(false); for( const auto& rCurr : rContainer ) { std::shared_ptr pListener( rCurr.ptr.lock() ); if( pListener.get() && FunctionApply const&>::type, std::shared_ptr >::apply(func,pListener) ) { bRet = true; } } return bRet; } template< typename ContainerT > static void pruneListeners( ContainerT& rContainer, size_t nSizeThreshold ) { if( rContainer.size() <= nSizeThreshold ) return; ContainerT aAliveListeners; aAliveListeners.reserve(rContainer.size()); for( const auto& rCurr : rContainer ) { if( !rCurr.ptr.expired() ) aAliveListeners.push_back( rCurr ); } std::swap( rContainer, aAliveListeners ); } }; namespace slideshow::internal { namespace { template class PrioritizedHandlerEntry { typedef std::shared_ptr HandlerSharedPtrT; HandlerSharedPtrT mpHandler; double mnPrio; public: PrioritizedHandlerEntry( HandlerSharedPtrT pHandler, double nPrio ) : mpHandler(std::move(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; } }; } typedef comphelper::WeakComponentImplHelper< awt::XMouseListener, awt::XMouseMotionListener > Listener_UnoBase; namespace { /** 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 : public Listener_UnoBase { public: EventMultiplexerListener( EventQueue& rEventQueue, EventMultiplexerImpl& rEventMultiplexer ) : mpEventQueue( &rEventQueue ), mpEventMultiplexer( &rEventMultiplexer ) { } EventMultiplexerListener( const EventMultiplexerListener& ) = delete; EventMultiplexerListener& operator=( const EventMultiplexerListener& ) = delete; // WeakComponentImplHelperBase::disposing virtual void disposing(std::unique_lock& rGuard) override; private: virtual void SAL_CALL disposing( const lang::EventObject& Source ) override; // XMouseListener implementation virtual void SAL_CALL mousePressed( const awt::MouseEvent& e ) override; virtual void SAL_CALL mouseReleased( const awt::MouseEvent& e ) override; virtual void SAL_CALL mouseEntered( const awt::MouseEvent& e ) override; virtual void SAL_CALL mouseExited( const awt::MouseEvent& e ) override; // XMouseMotionListener implementation virtual void SAL_CALL mouseDragged( const awt::MouseEvent& e ) override; virtual void SAL_CALL mouseMoved( const awt::MouseEvent& e ) override; 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(), 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, std::vector< PrioritizedHandlerEntry > > ImplNextEffectHandlers; typedef PrioritizedHandlerEntry ImplMouseHandlerEntry; typedef ThreadUnsafeListenerContainer< ImplMouseHandlerEntry, std::vector > ImplMouseHandlers; typedef ThreadUnsafeListenerContainer< EventHandlerSharedPtr, std::vector > ImplEventHandlers; typedef ThreadUnsafeListenerContainer< AnimationEventHandlerSharedPtr, std::vector > ImplAnimationHandlers; typedef ThreadUnsafeListenerContainer< PauseEventHandlerSharedPtr, std::vector > ImplPauseHandlers; typedef ThreadUnsafeListenerContainer< ViewEventHandlerWeakPtrWrapper, std::vector > ImplViewHandlers; typedef ThreadUnsafeListenerContainer< ViewRepaintHandlerSharedPtr, std::vector > ImplRepaintHandlers; typedef ThreadUnsafeListenerContainer< ShapeListenerEventHandlerSharedPtr, std::vector > ImplShapeListenerHandlers; typedef ThreadUnsafeListenerContainer< UserPaintEventHandlerSharedPtr, std::vector > ImplUserPaintEventHandlers; typedef ThreadUnsafeListenerContainer< PrioritizedHandlerEntry, std::vector > > ImplHyperLinkHandlers; template 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 ); static 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(); basegfx::B2DPoint toMatrixPoint(const uno::Reference& xView, const basegfx::B2DPoint& pnt); basegfx::B2DPoint toNormalPoint(const uno::Reference& xView, const basegfx::B2DPoint& pnt); 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; 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. */ ::std::weak_ptr< Event > mpTickEvent; bool mbIsAutoMode; }; void EventMultiplexerListener::disposing(std::unique_lock& /*rGuard*/) { mpEventQueue = nullptr; mpEventMultiplexer = nullptr; } void SAL_CALL EventMultiplexerListener::disposing( const lang::EventObject& /*rSource*/ ) { // there's no real point in acting on this message - after all, // the event sources are the XSlideShowViews, which must be // explicitly 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 ) { std::unique_lock const guard( m_aMutex ); // notify mouse press. Don't call handlers directly, this // might not be the main thread! if( mpEventQueue ) mpEventQueue->addEvent( makeEvent( std::bind( &EventMultiplexerImpl::mousePressed, mpEventMultiplexer, e ), u"EventMultiplexerImpl::mousePressed"_ustr) ); } void SAL_CALL EventMultiplexerListener::mouseReleased( const awt::MouseEvent& e ) { std::unique_lock const guard( m_aMutex ); // notify mouse release. Don't call handlers directly, // this might not be the main thread! if( mpEventQueue ) mpEventQueue->addEvent( makeEvent( std::bind( &EventMultiplexerImpl::mouseReleased, mpEventMultiplexer, e ), u"EventMultiplexerImpl::mouseReleased"_ustr) ); } void SAL_CALL EventMultiplexerListener::mouseEntered( const awt::MouseEvent& /*e*/ ) { // not used here } void SAL_CALL EventMultiplexerListener::mouseExited( const awt::MouseEvent& /*e*/ ) { // not used here } // XMouseMotionListener implementation void SAL_CALL EventMultiplexerListener::mouseDragged( const awt::MouseEvent& e ) { std::unique_lock const guard( m_aMutex ); // notify mouse drag. Don't call handlers directly, this // might not be the main thread! if( mpEventQueue ) mpEventQueue->addEvent( makeEvent( std::bind( &EventMultiplexerImpl::mouseDragged, mpEventMultiplexer, e ), u"EventMultiplexerImpl::mouseDragged"_ustr) ); } void SAL_CALL EventMultiplexerListener::mouseMoved( const awt::MouseEvent& e ) { std::unique_lock const guard( m_aMutex ); // notify mouse move. Don't call handlers directly, this // might not be the main thread! if( mpEventQueue ) mpEventQueue->addEvent( makeEvent( std::bind( &EventMultiplexerImpl::mouseMoved, mpEventMultiplexer, e ), u"EventMultiplexerImpl::mouseMoved"_ustr) ); } bool EventMultiplexerImpl::notifyAllAnimationHandlers( ImplAnimationHandlers const& rContainer, AnimationNodeSharedPtr const& rNode ) { return rContainer.applyAll( [&rNode]( const AnimationEventHandlerSharedPtr& pEventHandler ) { return pEventHandler->handleAnimationEvent( rNode ); } ); } template void EventMultiplexerImpl::forEachView( XSlideShowViewFunc pViewMethod ) { if( !pViewMethod ) return; // (un)register mouse listener on all views for( UnoViewVector::const_iterator aIter( mrViewContainer.begin() ), aEnd( mrViewContainer.end() ); aIter != aEnd; ++aIter ) { uno::Reference xView ((*aIter)->getUnoView()); if (xView.is()) { (xView.get()->*pViewMethod)( mxListener.get() ); } else { OSL_ASSERT(xView.is()); } } } UnoViewSharedPtr EventMultiplexerImpl::findUnoView( const uno::Reference& 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, [&xView]( const UnoViewSharedPtr& pView ) { return xView == pView->getUnoView(); } )) == aEnd ) { OSL_FAIL("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( [this] () { this->tick(); }, mnTimeout, u"EventMultiplexerImpl::tick with delay"_ustr)); // 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(); } basegfx::B2DPoint EventMultiplexerImpl::toNormalPoint(const uno::Reference& xView, const basegfx::B2DPoint& pnt) { UnoViewVector::const_iterator aIter; const UnoViewVector::const_iterator aEnd(mrViewContainer.end()); if ((aIter = std::find_if( mrViewContainer.begin(), aEnd, [&xView](const UnoViewSharedPtr& pView) { return xView == pView->getUnoView(); })) == aEnd) { return pnt; } basegfx::B2DPoint aPosition(pnt.getX(), pnt.getY()); basegfx::B2DHomMatrix aMatrix((*aIter)->getTransformation()); aPosition *= aMatrix; aPosition.setX(std::round(aPosition.getX())); aPosition.setY(std::round(aPosition.getY())); return aPosition; } basegfx::B2DPoint EventMultiplexerImpl::toMatrixPoint(const uno::Reference& xView, const basegfx::B2DPoint& pnt) { UnoViewVector::const_iterator aIter; const UnoViewVector::const_iterator aEnd(mrViewContainer.end()); if ((aIter = std::find_if( mrViewContainer.begin(), aEnd, [&xView](const UnoViewSharedPtr& pView) { return xView == pView->getUnoView(); })) == aEnd) { return pnt; } basegfx::B2DPoint aPosition(pnt.getX(), pnt.getY()); basegfx::B2DHomMatrix aMatrix((*aIter)->getTransformation()); if (!aMatrix.invert()) ENSURE_OR_THROW(false, "EventMultiplexer::notifyHandlers():" " view matrix singular"); aPosition *= aMatrix; aPosition.setX(std::round(aPosition.getX())); aPosition.setY(std::round(aPosition.getY())); return aPosition; } 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 ); } } if( !maMouseMoveHandlers.isEmpty() ) { for( UnoViewVector::const_iterator aIter=mrViewContainer.begin(), aEnd=mrViewContainer.end(); aIter!=aEnd; ++aIter ) { if( (*aIter)->getUnoView().is() ) (*aIter)->getUnoView()->removeMouseMotionListener( mxListener ); } } // 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 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 aEnd ( mrViewContainer.end() ); if( (aIter=::std::find_if( mrViewContainer.begin(), aEnd, [&xView]( const UnoViewSharedPtr& pView ) { return xView == pView->getUnoView(); } )) == 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( [&pHandlerMethod, &aEvent]( const ImplMouseHandlerEntry& rMouseHandler ) { return ( ( *rMouseHandler.getHandler() ).*pHandlerMethod )( 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( []( const PrioritizedHandlerEntry< EventHandler >& pHandler ) { return pHandler.getHandler()->handleEvent(); } ); } 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::addClickHandler( const MouseEventHandlerSharedPtr& rHandler, double nPriority ) { mpImpl->addMouseHandler( mpImpl->maMouseClickHandlers, rHandler, nPriority, mpImpl->isMouseListenerRegistered() ? nullptr : &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() ? nullptr : &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 : nullptr ); } 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) ); } void EventMultiplexer::notifyShapeListenerAdded( const uno::Reference& xShape ) { mpImpl->maShapeListenerHandlers.applyAll( [&xShape]( const ShapeListenerEventHandlerSharedPtr& pHandler ) { return pHandler->listenerAdded( xShape ); } ); } void EventMultiplexer::notifyShapeListenerRemoved( const uno::Reference& xShape ) { mpImpl->maShapeListenerHandlers.applyAll( [&xShape]( const ShapeListenerEventHandlerSharedPtr& pHandler ) { return pHandler->listenerRemoved( xShape ); } ); } void EventMultiplexer::notifyUserPaintColor( RGBColor const& rUserColor ) { mpImpl->maUserPaintEventHandlers.applyAll( [&rUserColor]( const UserPaintEventHandlerSharedPtr& pHandler ) { return pHandler->colorChanged( rUserColor ); } ); } void EventMultiplexer::notifyUserPaintStrokeWidth( double rUserStrokeWidth ) { mpImpl->maUserPaintEventHandlers.applyAll( [&rUserStrokeWidth]( const UserPaintEventHandlerSharedPtr& pHandler ) { return pHandler->widthChanged( rUserStrokeWidth ); } ); } void EventMultiplexer::notifyUserPaintDisabled() { mpImpl->maUserPaintEventHandlers.applyAll( std::mem_fn(&UserPaintEventHandler::disable)); } void EventMultiplexer::notifySwitchPenMode(){ mpImpl->maUserPaintEventHandlers.applyAll( std::mem_fn(&UserPaintEventHandler::switchPenMode)); } void EventMultiplexer::notifySwitchEraserMode(){ mpImpl->maUserPaintEventHandlers.applyAll( std::mem_fn(&UserPaintEventHandler::switchEraserMode)); } //adding erasing all ink features with UserPaintOverlay void EventMultiplexer::notifyEraseAllInk( bool bEraseAllInk ) { mpImpl->maUserPaintEventHandlers.applyAll( [&bEraseAllInk]( const UserPaintEventHandlerSharedPtr& pHandler ) { return pHandler->eraseAllInkChanged( bEraseAllInk ); } ); } //adding erasing features with UserPaintOverlay void EventMultiplexer::notifyEraseInkWidth( sal_Int32 rEraseInkSize ) { mpImpl->maUserPaintEventHandlers.applyAll( [&rEraseInkSize]( const UserPaintEventHandlerSharedPtr& pHandler ) { return pHandler->eraseInkWidthChanged( rEraseInkSize ); } ); } bool EventMultiplexer::notifyNextEffect() { return mpImpl->notifyNextEffect(); } void EventMultiplexer::notifySlideStartEvent() { mpImpl->maSlideStartHandlers.applyAll( std::mem_fn(&EventHandler::handleEvent) ); } bool EventMultiplexer::notifySlideEndEvent() { return mpImpl->maSlideEndHandlers.applyAll( std::mem_fn(&EventHandler::handleEvent) ); } bool EventMultiplexer::notifyAnimationStart( const AnimationNodeSharedPtr& rNode ) { return EventMultiplexerImpl::notifyAllAnimationHandlers( mpImpl->maAnimationStartHandlers, rNode ); } bool EventMultiplexer::notifyAnimationEnd( const AnimationNodeSharedPtr& rNode ) { return EventMultiplexerImpl::notifyAllAnimationHandlers( mpImpl->maAnimationEndHandlers, rNode ); } bool EventMultiplexer::notifySlideAnimationsEnd() { return mpImpl->maSlideAnimationsEndHandlers.applyAll( std::mem_fn(&EventHandler::handleEvent)); } bool EventMultiplexer::notifyAudioStopped( const AnimationNodeSharedPtr& rNode ) { return EventMultiplexerImpl::notifyAllAnimationHandlers( mpImpl->maAudioStoppedHandlers, rNode ); } bool EventMultiplexer::notifyCommandStopAudio( const AnimationNodeSharedPtr& rNode ) { return EventMultiplexerImpl::notifyAllAnimationHandlers( mpImpl->maCommandStopAudioHandlers, rNode ); } void EventMultiplexer::notifyPauseMode( bool bPauseShow ) { mpImpl->maPauseHandlers.applyAll( [&bPauseShow]( const PauseEventHandlerSharedPtr& pHandler ) { return pHandler->handlePause( bPauseShow ); } ); } void EventMultiplexer::notifyViewAdded( const UnoViewSharedPtr& rView ) { ENSURE_OR_THROW( rView, "EventMultiplexer::notifyViewAdded(): Invalid view"); // register event listener uno::Reference const rUnoView( rView->getUnoView() ); if( mpImpl->isMouseListenerRegistered() ) rUnoView->addMouseListener( mpImpl->mxListener ); if( !mpImpl->maMouseMoveHandlers.isEmpty() ) rUnoView->addMouseMotionListener( mpImpl->mxListener ); mpImpl->maViewHandlers.applyAll( [&rView]( const ViewEventHandlerWeakPtr& pHandler ) { return pHandler.lock()->viewAdded( rView ); } ); } void EventMultiplexer::notifyViewRemoved( const UnoViewSharedPtr& rView ) { ENSURE_OR_THROW( rView, "EventMultiplexer::removeView(): Invalid view" ); // revoke event listeners uno::Reference const rUnoView( rView->getUnoView() ); if( mpImpl->isMouseListenerRegistered() ) rUnoView->removeMouseListener( mpImpl->mxListener ); if( !mpImpl->maMouseMoveHandlers.isEmpty() ) rUnoView->removeMouseMotionListener( mpImpl->mxListener ); mpImpl->maViewHandlers.applyAll( [&rView]( const ViewEventHandlerWeakPtr& pHandler ) { return pHandler.lock()->viewRemoved( rView ); } ); } void EventMultiplexer::notifyViewChanged( const UnoViewSharedPtr& rView ) { mpImpl->maViewHandlers.applyAll( [&rView]( const ViewEventHandlerWeakPtr& pHandler ) { return pHandler.lock()->viewChanged( rView ); } ); } void EventMultiplexer::notifyViewChanged( const uno::Reference& xView ) { UnoViewSharedPtr pView( mpImpl->findUnoView(xView) ); if( !pView ) return; // view not registered here notifyViewChanged( pView ); } void EventMultiplexer::notifyViewsChanged() { mpImpl->maViewHandlers.applyAll( std::mem_fn( &ViewEventHandler::viewsChanged )); } void EventMultiplexer::notifyViewClobbered( const uno::Reference& xView ) { UnoViewSharedPtr pView( mpImpl->findUnoView(xView) ); if( !pView ) return; // view not registered here mpImpl->maViewRepaintHandlers.applyAll( [&pView]( const ViewRepaintHandlerSharedPtr& pHandler ) { return pHandler->viewClobbered( pView ); } ); } void EventMultiplexer::notifyHyperlinkClicked( OUString const& hyperLink ) { mpImpl->maHyperlinkHandlers.apply( [&hyperLink]( const PrioritizedHandlerEntry< HyperlinkHandler >& pHandler ) { return pHandler.getHandler()->handleHyperlink( hyperLink ); } ); } basegfx::B2DPoint EventMultiplexer::toMatrixPoint(const uno::Reference& xInterface, const basegfx::B2DPoint& pnt) { uno::Reference xView(xInterface, uno::UNO_QUERY_THROW); return mpImpl->toMatrixPoint(xView, pnt); } basegfx::B2DPoint EventMultiplexer::toNormalPoint(const uno::Reference& xInterface, const basegfx::B2DPoint& pnt) { uno::Reference xView(xInterface, uno::UNO_QUERY_THROW); return mpImpl->toNormalPoint(xView, pnt); } } // namespace presentation /* vim:set shiftwidth=4 softtabstop=4 expandtab: */