| /************************************************************** |
| * |
| * 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" |
| |
| #include <canvas/debug.hxx> |
| #include <tools/diagnose_ex.h> |
| #include <com/sun/star/awt/MouseButton.hpp> |
| #include <com/sun/star/awt/SystemPointer.hpp> |
| #include <com/sun/star/presentation/XShapeEventListener.hpp> |
| #include <com/sun/star/presentation/XSlideShowListener.hpp> |
| #include <com/sun/star/awt/MouseButton.hpp> |
| |
| #include "shapemanagerimpl.hxx" |
| |
| #include <boost/bind.hpp> |
| |
| using namespace com::sun::star; |
| |
| namespace slideshow { |
| namespace internal { |
| |
| ShapeManagerImpl::ShapeManagerImpl( EventMultiplexer& rMultiplexer, |
| LayerManagerSharedPtr const& rLayerManager, |
| CursorManager& rCursorManager, |
| const ShapeEventListenerMap& rGlobalListenersMap, |
| const ShapeCursorMap& rGlobalCursorMap ): |
| mrMultiplexer(rMultiplexer), |
| mpLayerManager(rLayerManager), |
| mrCursorManager(rCursorManager), |
| mrGlobalListenersMap(rGlobalListenersMap), |
| mrGlobalCursorMap(rGlobalCursorMap), |
| maShapeListenerMap(), |
| maShapeCursorMap(), |
| maHyperlinkShapes(), |
| mbEnabled(false) |
| { |
| } |
| |
| void ShapeManagerImpl::activate( bool bSlideBackgoundPainted ) |
| { |
| if( !mbEnabled ) |
| { |
| mbEnabled = true; |
| |
| // register this handler on EventMultiplexer. |
| // Higher prio (overrides other engine handlers) |
| mrMultiplexer.addMouseMoveHandler( shared_from_this(), 2.0 ); |
| mrMultiplexer.addClickHandler( shared_from_this(), 2.0 ); |
| mrMultiplexer.addShapeListenerHandler( shared_from_this() ); |
| |
| // clone listener map |
| uno::Reference<presentation::XShapeEventListener> xDummyListener; |
| std::for_each( mrGlobalListenersMap.begin(), |
| mrGlobalListenersMap.end(), |
| boost::bind( &ShapeManagerImpl::listenerAdded, |
| this, |
| boost::cref(xDummyListener), |
| boost::bind( |
| std::select1st<ShapeEventListenerMap::value_type>(), |
| _1 ))); |
| |
| // clone cursor map |
| std::for_each( mrGlobalCursorMap.begin(), |
| mrGlobalCursorMap.end(), |
| boost::bind( &ShapeManagerImpl::cursorChanged, |
| this, |
| boost::bind( |
| std::select1st<ShapeCursorMap::value_type>(), |
| _1 ), |
| boost::bind( |
| std::select2nd<ShapeCursorMap::value_type>(), |
| _1 ))); |
| |
| if( mpLayerManager ) |
| mpLayerManager->activate( bSlideBackgoundPainted ); |
| } |
| } |
| |
| void ShapeManagerImpl::deactivate() |
| { |
| if( mbEnabled ) |
| { |
| mbEnabled = false; |
| |
| if( mpLayerManager ) |
| mpLayerManager->deactivate(); |
| |
| maShapeListenerMap.clear(); |
| maShapeCursorMap.clear(); |
| |
| mrMultiplexer.removeShapeListenerHandler( shared_from_this() ); |
| mrMultiplexer.removeMouseMoveHandler( shared_from_this() ); |
| mrMultiplexer.removeClickHandler( shared_from_this() ); |
| } |
| } |
| |
| void ShapeManagerImpl::dispose() |
| { |
| // remove listeners (EventMultiplexer holds shared_ptr on us) |
| deactivate(); |
| |
| maHyperlinkShapes.clear(); |
| maShapeCursorMap.clear(); |
| maShapeListenerMap.clear(); |
| mpLayerManager.reset(); |
| } |
| |
| bool ShapeManagerImpl::handleMousePressed( awt::MouseEvent const& ) |
| { |
| // not used here |
| return false; // did not handle the event |
| } |
| |
| bool ShapeManagerImpl::handleMouseReleased( awt::MouseEvent const& e ) |
| { |
| if( !mbEnabled || e.Buttons != awt::MouseButton::LEFT) |
| return false; |
| |
| basegfx::B2DPoint const aPosition( e.X, e.Y ); |
| |
| // first check for hyperlinks, because these have |
| // highest prio: |
| rtl::OUString const hyperlink( checkForHyperlink(aPosition) ); |
| if( hyperlink.getLength() > 0 ) |
| { |
| mrMultiplexer.notifyHyperlinkClicked(hyperlink); |
| return true; // event consumed |
| } |
| |
| // find matching shape (scan reversely, to coarsely match |
| // paint order) |
| ShapeToListenersMap::reverse_iterator aCurrBroadcaster( |
| maShapeListenerMap.rbegin() ); |
| ShapeToListenersMap::reverse_iterator const aEndBroadcasters( |
| maShapeListenerMap.rend() ); |
| while( aCurrBroadcaster != aEndBroadcasters ) |
| { |
| // TODO(F2): Get proper geometry polygon from the |
| // shape, to avoid having areas outside the shape |
| // react on the mouse |
| if( aCurrBroadcaster->first->getBounds().isInside( aPosition ) && |
| aCurrBroadcaster->first->isVisible() ) |
| { |
| // shape hit, and shape is visible. Raise |
| // event. |
| |
| boost::shared_ptr<cppu::OInterfaceContainerHelper> const pCont( |
| aCurrBroadcaster->second ); |
| uno::Reference<drawing::XShape> const xShape( |
| aCurrBroadcaster->first->getXShape() ); |
| |
| // DON'T do anything with /this/ after this point! |
| pCont->forEach<presentation::XShapeEventListener>( |
| boost::bind( &presentation::XShapeEventListener::click, |
| _1, |
| boost::cref(xShape), |
| boost::cref(e) )); |
| |
| return true; // handled this event |
| } |
| |
| ++aCurrBroadcaster; |
| } |
| |
| return false; // did not handle this event |
| } |
| |
| bool ShapeManagerImpl::handleMouseEntered( const awt::MouseEvent& ) |
| { |
| // not used here |
| return false; // did not handle the event |
| } |
| |
| bool ShapeManagerImpl::handleMouseExited( const awt::MouseEvent& ) |
| { |
| // not used here |
| return false; // did not handle the event |
| } |
| |
| bool ShapeManagerImpl::handleMouseDragged( const awt::MouseEvent& ) |
| { |
| // not used here |
| return false; // did not handle the event |
| } |
| |
| bool ShapeManagerImpl::handleMouseMoved( const awt::MouseEvent& e ) |
| { |
| if( !mbEnabled ) |
| return false; |
| |
| // find hit shape in map |
| const ::basegfx::B2DPoint aPosition( e.X, e.Y ); |
| sal_Int16 nNewCursor(-1); |
| |
| if( checkForHyperlink(aPosition).getLength() > 0 ) |
| { |
| nNewCursor = awt::SystemPointer::REFHAND; |
| } |
| else |
| { |
| // find matching shape (scan reversely, to coarsely match |
| // paint order) |
| ShapeToCursorMap::reverse_iterator aCurrCursor( |
| maShapeCursorMap.rbegin() ); |
| ShapeToCursorMap::reverse_iterator const aEndCursors( |
| maShapeCursorMap.rend() ); |
| while( aCurrCursor != aEndCursors ) |
| { |
| // TODO(F2): Get proper geometry polygon from the |
| // shape, to avoid having areas outside the shape |
| // react on the mouse |
| if( aCurrCursor->first->getBounds().isInside( aPosition ) && |
| aCurrCursor->first->isVisible() ) |
| { |
| // shape found, and it's visible. set |
| // requested cursor to shape's |
| nNewCursor = aCurrCursor->second; |
| break; |
| } |
| |
| ++aCurrCursor; |
| } |
| } |
| |
| if( nNewCursor == -1 ) |
| mrCursorManager.resetCursor(); |
| else |
| mrCursorManager.requestCursor( nNewCursor ); |
| |
| return false; // we don't /eat/ this event. Lower prio |
| // handler should see it, too. |
| } |
| |
| bool ShapeManagerImpl::update() |
| { |
| if( mbEnabled && mpLayerManager ) |
| return mpLayerManager->update(); |
| |
| return false; |
| } |
| |
| bool ShapeManagerImpl::update( ViewSharedPtr const& /*rView*/ ) |
| { |
| // am not doing view-specific updates here. |
| return false; |
| } |
| |
| bool ShapeManagerImpl::needsUpdate() const |
| { |
| if( mbEnabled && mpLayerManager ) |
| return mpLayerManager->isUpdatePending(); |
| |
| return false; |
| } |
| |
| void ShapeManagerImpl::enterAnimationMode( const AnimatableShapeSharedPtr& rShape ) |
| { |
| if( mbEnabled && mpLayerManager ) |
| mpLayerManager->enterAnimationMode(rShape); |
| } |
| |
| void ShapeManagerImpl::leaveAnimationMode( const AnimatableShapeSharedPtr& rShape ) |
| { |
| if( mbEnabled && mpLayerManager ) |
| mpLayerManager->leaveAnimationMode(rShape); |
| } |
| |
| void ShapeManagerImpl::notifyShapeUpdate( const ShapeSharedPtr& rShape ) |
| { |
| if( mbEnabled && mpLayerManager ) |
| mpLayerManager->notifyShapeUpdate(rShape); |
| } |
| |
| ShapeSharedPtr ShapeManagerImpl::lookupShape( uno::Reference< drawing::XShape > const & xShape ) const |
| { |
| if( mpLayerManager ) |
| return mpLayerManager->lookupShape(xShape); |
| |
| return ShapeSharedPtr(); |
| } |
| |
| void ShapeManagerImpl::addHyperlinkArea( const HyperlinkAreaSharedPtr& rArea ) |
| { |
| maHyperlinkShapes.insert(rArea); |
| } |
| |
| void ShapeManagerImpl::removeHyperlinkArea( const HyperlinkAreaSharedPtr& rArea ) |
| { |
| maHyperlinkShapes.erase(rArea); |
| } |
| |
| AttributableShapeSharedPtr ShapeManagerImpl::getSubsetShape( const AttributableShapeSharedPtr& rOrigShape, |
| const DocTreeNode& rTreeNode ) |
| { |
| if( mpLayerManager ) |
| return mpLayerManager->getSubsetShape(rOrigShape,rTreeNode); |
| |
| return AttributableShapeSharedPtr(); |
| } |
| |
| void ShapeManagerImpl::revokeSubset( const AttributableShapeSharedPtr& rOrigShape, |
| const AttributableShapeSharedPtr& rSubsetShape ) |
| { |
| if( mpLayerManager ) |
| mpLayerManager->revokeSubset(rOrigShape,rSubsetShape); |
| } |
| |
| bool ShapeManagerImpl::listenerAdded( |
| const uno::Reference<presentation::XShapeEventListener>& /*xListener*/, |
| const uno::Reference<drawing::XShape>& xShape ) |
| { |
| ShapeEventListenerMap::const_iterator aIter; |
| if( (aIter = mrGlobalListenersMap.find( xShape )) == |
| mrGlobalListenersMap.end() ) |
| { |
| ENSURE_OR_RETURN_FALSE(false, |
| "ShapeManagerImpl::listenerAdded(): global " |
| "shape listener map inconsistency!"); |
| } |
| |
| // is this one of our shapes? other shapes are ignored. |
| ShapeSharedPtr pShape( lookupShape(xShape) ); |
| if( pShape ) |
| { |
| maShapeListenerMap.insert( |
| ShapeToListenersMap::value_type( |
| pShape, |
| aIter->second)); |
| } |
| |
| return true; |
| } |
| |
| bool ShapeManagerImpl::listenerRemoved( |
| const uno::Reference<presentation::XShapeEventListener>& /*xListener*/, |
| const uno::Reference<drawing::XShape>& xShape ) |
| { |
| // shape really erased from map? maybe there are other listeners |
| // for the same shape pending... |
| if( mrGlobalListenersMap.find(xShape) == mrGlobalListenersMap.end() ) |
| { |
| // is this one of our shapes? other shapes are ignored. |
| ShapeSharedPtr pShape( lookupShape(xShape) ); |
| if( pShape ) |
| maShapeListenerMap.erase(pShape); |
| } |
| |
| return true; |
| } |
| |
| bool ShapeManagerImpl::cursorChanged( const uno::Reference<drawing::XShape>& xShape, |
| sal_Int16 nCursor ) |
| { |
| ShapeSharedPtr pShape( lookupShape(xShape) ); |
| |
| // is this one of our shapes? other shapes are ignored. |
| if( !pShape ) |
| return false; |
| |
| if( mrGlobalCursorMap.find(xShape) == mrGlobalCursorMap.end() ) |
| { |
| // erased from global map - erase locally, too |
| maShapeCursorMap.erase(pShape); |
| } |
| else |
| { |
| // included in global map - update local one |
| ShapeToCursorMap::iterator aIter; |
| if( (aIter = maShapeCursorMap.find(pShape)) |
| == maShapeCursorMap.end() ) |
| { |
| maShapeCursorMap.insert( |
| ShapeToCursorMap::value_type( |
| pShape, |
| nCursor )); |
| } |
| else |
| { |
| aIter->second = nCursor; |
| } |
| } |
| |
| return true; |
| } |
| |
| rtl::OUString ShapeManagerImpl::checkForHyperlink( basegfx::B2DPoint const& hitPos ) const |
| { |
| // find matching region (scan reversely, to coarsely match |
| // paint order): set is ordered by priority |
| AreaSet::const_reverse_iterator iPos( maHyperlinkShapes.rbegin() ); |
| AreaSet::const_reverse_iterator const iEnd( maHyperlinkShapes.rend() ); |
| for( ; iPos != iEnd; ++iPos ) |
| { |
| HyperlinkAreaSharedPtr const& pArea = *iPos; |
| |
| HyperlinkArea::HyperlinkRegions const linkRegions( |
| pArea->getHyperlinkRegions() ); |
| |
| for( std::size_t i = linkRegions.size(); i--; ) |
| { |
| basegfx::B2DRange const& region = linkRegions[i].first; |
| if( region.isInside(hitPos) ) |
| return linkRegions[i].second; |
| } |
| } |
| |
| return rtl::OUString(); |
| } |
| |
| void ShapeManagerImpl::addIntrinsicAnimationHandler( const IntrinsicAnimationEventHandlerSharedPtr& rHandler ) |
| { |
| maIntrinsicAnimationEventHandlers.add( rHandler ); |
| } |
| |
| void ShapeManagerImpl::removeIntrinsicAnimationHandler( const IntrinsicAnimationEventHandlerSharedPtr& rHandler ) |
| { |
| maIntrinsicAnimationEventHandlers.remove( rHandler ); |
| } |
| |
| bool ShapeManagerImpl::notifyIntrinsicAnimationsEnabled() |
| { |
| return maIntrinsicAnimationEventHandlers.applyAll( |
| boost::mem_fn(&IntrinsicAnimationEventHandler::enableAnimations)); |
| } |
| |
| bool ShapeManagerImpl::notifyIntrinsicAnimationsDisabled() |
| { |
| return maIntrinsicAnimationEventHandlers.applyAll( |
| boost::mem_fn(&IntrinsicAnimationEventHandler::disableAnimations)); |
| } |
| |
| |
| |
| } // namespace internal |
| } // namespace presentation |