blob: 205b7fa7a44a45d3c10ff6887eb99c945abb3202 [file] [log] [blame]
/**************************************************************
*
* 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