/************************************************************** * * 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 #include #include #include #include #include #include #include "shapemanagerimpl.hxx" #include 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 xDummyListener; std::for_each( mrGlobalListenersMap.begin(), mrGlobalListenersMap.end(), boost::bind( &ShapeManagerImpl::listenerAdded, this, boost::cref(xDummyListener), boost::bind( std::select1st(), _1 ))); // clone cursor map std::for_each( mrGlobalCursorMap.begin(), mrGlobalCursorMap.end(), boost::bind( &ShapeManagerImpl::cursorChanged, this, boost::bind( std::select1st(), _1 ), boost::bind( std::select2nd(), _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 const pCont( aCurrBroadcaster->second ); uno::Reference const xShape( aCurrBroadcaster->first->getXShape() ); // DON'T do anything with /this/ after this point! pCont->forEach( 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& /*xListener*/, const uno::Reference& 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& /*xListener*/, const uno::Reference& 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& 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