1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_slideshow.hxx" 30 31 #include <canvas/debug.hxx> 32 #include <tools/diagnose_ex.h> 33 #include <com/sun/star/awt/MouseButton.hpp> 34 #include <com/sun/star/awt/SystemPointer.hpp> 35 #include <com/sun/star/presentation/XShapeEventListener.hpp> 36 #include <com/sun/star/presentation/XSlideShowListener.hpp> 37 #include <com/sun/star/awt/MouseButton.hpp> 38 39 #include "shapemanagerimpl.hxx" 40 41 #include <boost/bind.hpp> 42 43 using namespace com::sun::star; 44 45 namespace slideshow { 46 namespace internal { 47 48 ShapeManagerImpl::ShapeManagerImpl( EventMultiplexer& rMultiplexer, 49 LayerManagerSharedPtr const& rLayerManager, 50 CursorManager& rCursorManager, 51 const ShapeEventListenerMap& rGlobalListenersMap, 52 const ShapeCursorMap& rGlobalCursorMap ): 53 mrMultiplexer(rMultiplexer), 54 mpLayerManager(rLayerManager), 55 mrCursorManager(rCursorManager), 56 mrGlobalListenersMap(rGlobalListenersMap), 57 mrGlobalCursorMap(rGlobalCursorMap), 58 maShapeListenerMap(), 59 maShapeCursorMap(), 60 maHyperlinkShapes(), 61 mbEnabled(false) 62 { 63 } 64 65 void ShapeManagerImpl::activate( bool bSlideBackgoundPainted ) 66 { 67 if( !mbEnabled ) 68 { 69 mbEnabled = true; 70 71 // register this handler on EventMultiplexer. 72 // Higher prio (overrides other engine handlers) 73 mrMultiplexer.addMouseMoveHandler( shared_from_this(), 2.0 ); 74 mrMultiplexer.addClickHandler( shared_from_this(), 2.0 ); 75 mrMultiplexer.addShapeListenerHandler( shared_from_this() ); 76 77 // clone listener map 78 uno::Reference<presentation::XShapeEventListener> xDummyListener; 79 std::for_each( mrGlobalListenersMap.begin(), 80 mrGlobalListenersMap.end(), 81 boost::bind( &ShapeManagerImpl::listenerAdded, 82 this, 83 boost::cref(xDummyListener), 84 boost::bind( 85 std::select1st<ShapeEventListenerMap::value_type>(), 86 _1 ))); 87 88 // clone cursor map 89 std::for_each( mrGlobalCursorMap.begin(), 90 mrGlobalCursorMap.end(), 91 boost::bind( &ShapeManagerImpl::cursorChanged, 92 this, 93 boost::bind( 94 std::select1st<ShapeCursorMap::value_type>(), 95 _1 ), 96 boost::bind( 97 std::select2nd<ShapeCursorMap::value_type>(), 98 _1 ))); 99 100 if( mpLayerManager ) 101 mpLayerManager->activate( bSlideBackgoundPainted ); 102 } 103 } 104 105 void ShapeManagerImpl::deactivate() 106 { 107 if( mbEnabled ) 108 { 109 mbEnabled = false; 110 111 if( mpLayerManager ) 112 mpLayerManager->deactivate(); 113 114 maShapeListenerMap.clear(); 115 maShapeCursorMap.clear(); 116 117 mrMultiplexer.removeShapeListenerHandler( shared_from_this() ); 118 mrMultiplexer.removeMouseMoveHandler( shared_from_this() ); 119 mrMultiplexer.removeClickHandler( shared_from_this() ); 120 } 121 } 122 123 void ShapeManagerImpl::dispose() 124 { 125 // remove listeners (EventMultiplexer holds shared_ptr on us) 126 deactivate(); 127 128 maHyperlinkShapes.clear(); 129 maShapeCursorMap.clear(); 130 maShapeListenerMap.clear(); 131 mpLayerManager.reset(); 132 } 133 134 bool ShapeManagerImpl::handleMousePressed( awt::MouseEvent const& ) 135 { 136 // not used here 137 return false; // did not handle the event 138 } 139 140 bool ShapeManagerImpl::handleMouseReleased( awt::MouseEvent const& e ) 141 { 142 if( !mbEnabled || e.Buttons != awt::MouseButton::LEFT) 143 return false; 144 145 basegfx::B2DPoint const aPosition( e.X, e.Y ); 146 147 // first check for hyperlinks, because these have 148 // highest prio: 149 rtl::OUString const hyperlink( checkForHyperlink(aPosition) ); 150 if( hyperlink.getLength() > 0 ) 151 { 152 mrMultiplexer.notifyHyperlinkClicked(hyperlink); 153 return true; // event consumed 154 } 155 156 // find matching shape (scan reversely, to coarsely match 157 // paint order) 158 ShapeToListenersMap::reverse_iterator aCurrBroadcaster( 159 maShapeListenerMap.rbegin() ); 160 ShapeToListenersMap::reverse_iterator const aEndBroadcasters( 161 maShapeListenerMap.rend() ); 162 while( aCurrBroadcaster != aEndBroadcasters ) 163 { 164 // TODO(F2): Get proper geometry polygon from the 165 // shape, to avoid having areas outside the shape 166 // react on the mouse 167 if( aCurrBroadcaster->first->getBounds().isInside( aPosition ) && 168 aCurrBroadcaster->first->isVisible() ) 169 { 170 // shape hit, and shape is visible. Raise 171 // event. 172 173 boost::shared_ptr<cppu::OInterfaceContainerHelper> const pCont( 174 aCurrBroadcaster->second ); 175 uno::Reference<drawing::XShape> const xShape( 176 aCurrBroadcaster->first->getXShape() ); 177 178 // DON'T do anything with /this/ after this point! 179 pCont->forEach<presentation::XShapeEventListener>( 180 boost::bind( &presentation::XShapeEventListener::click, 181 _1, 182 boost::cref(xShape), 183 boost::cref(e) )); 184 185 return true; // handled this event 186 } 187 188 ++aCurrBroadcaster; 189 } 190 191 return false; // did not handle this event 192 } 193 194 bool ShapeManagerImpl::handleMouseEntered( const awt::MouseEvent& ) 195 { 196 // not used here 197 return false; // did not handle the event 198 } 199 200 bool ShapeManagerImpl::handleMouseExited( const awt::MouseEvent& ) 201 { 202 // not used here 203 return false; // did not handle the event 204 } 205 206 bool ShapeManagerImpl::handleMouseDragged( const awt::MouseEvent& ) 207 { 208 // not used here 209 return false; // did not handle the event 210 } 211 212 bool ShapeManagerImpl::handleMouseMoved( const awt::MouseEvent& e ) 213 { 214 if( !mbEnabled ) 215 return false; 216 217 // find hit shape in map 218 const ::basegfx::B2DPoint aPosition( e.X, e.Y ); 219 sal_Int16 nNewCursor(-1); 220 221 if( checkForHyperlink(aPosition).getLength() > 0 ) 222 { 223 nNewCursor = awt::SystemPointer::REFHAND; 224 } 225 else 226 { 227 // find matching shape (scan reversely, to coarsely match 228 // paint order) 229 ShapeToCursorMap::reverse_iterator aCurrCursor( 230 maShapeCursorMap.rbegin() ); 231 ShapeToCursorMap::reverse_iterator const aEndCursors( 232 maShapeCursorMap.rend() ); 233 while( aCurrCursor != aEndCursors ) 234 { 235 // TODO(F2): Get proper geometry polygon from the 236 // shape, to avoid having areas outside the shape 237 // react on the mouse 238 if( aCurrCursor->first->getBounds().isInside( aPosition ) && 239 aCurrCursor->first->isVisible() ) 240 { 241 // shape found, and it's visible. set 242 // requested cursor to shape's 243 nNewCursor = aCurrCursor->second; 244 break; 245 } 246 247 ++aCurrCursor; 248 } 249 } 250 251 if( nNewCursor == -1 ) 252 mrCursorManager.resetCursor(); 253 else 254 mrCursorManager.requestCursor( nNewCursor ); 255 256 return false; // we don't /eat/ this event. Lower prio 257 // handler should see it, too. 258 } 259 260 bool ShapeManagerImpl::update() 261 { 262 if( mbEnabled && mpLayerManager ) 263 return mpLayerManager->update(); 264 265 return false; 266 } 267 268 bool ShapeManagerImpl::update( ViewSharedPtr const& /*rView*/ ) 269 { 270 // am not doing view-specific updates here. 271 return false; 272 } 273 274 bool ShapeManagerImpl::needsUpdate() const 275 { 276 if( mbEnabled && mpLayerManager ) 277 return mpLayerManager->isUpdatePending(); 278 279 return false; 280 } 281 282 void ShapeManagerImpl::enterAnimationMode( const AnimatableShapeSharedPtr& rShape ) 283 { 284 if( mbEnabled && mpLayerManager ) 285 mpLayerManager->enterAnimationMode(rShape); 286 } 287 288 void ShapeManagerImpl::leaveAnimationMode( const AnimatableShapeSharedPtr& rShape ) 289 { 290 if( mbEnabled && mpLayerManager ) 291 mpLayerManager->leaveAnimationMode(rShape); 292 } 293 294 void ShapeManagerImpl::notifyShapeUpdate( const ShapeSharedPtr& rShape ) 295 { 296 if( mbEnabled && mpLayerManager ) 297 mpLayerManager->notifyShapeUpdate(rShape); 298 } 299 300 ShapeSharedPtr ShapeManagerImpl::lookupShape( uno::Reference< drawing::XShape > const & xShape ) const 301 { 302 if( mpLayerManager ) 303 return mpLayerManager->lookupShape(xShape); 304 305 return ShapeSharedPtr(); 306 } 307 308 void ShapeManagerImpl::addHyperlinkArea( const HyperlinkAreaSharedPtr& rArea ) 309 { 310 maHyperlinkShapes.insert(rArea); 311 } 312 313 void ShapeManagerImpl::removeHyperlinkArea( const HyperlinkAreaSharedPtr& rArea ) 314 { 315 maHyperlinkShapes.erase(rArea); 316 } 317 318 AttributableShapeSharedPtr ShapeManagerImpl::getSubsetShape( const AttributableShapeSharedPtr& rOrigShape, 319 const DocTreeNode& rTreeNode ) 320 { 321 if( mpLayerManager ) 322 return mpLayerManager->getSubsetShape(rOrigShape,rTreeNode); 323 324 return AttributableShapeSharedPtr(); 325 } 326 327 void ShapeManagerImpl::revokeSubset( const AttributableShapeSharedPtr& rOrigShape, 328 const AttributableShapeSharedPtr& rSubsetShape ) 329 { 330 if( mpLayerManager ) 331 mpLayerManager->revokeSubset(rOrigShape,rSubsetShape); 332 } 333 334 bool ShapeManagerImpl::listenerAdded( 335 const uno::Reference<presentation::XShapeEventListener>& /*xListener*/, 336 const uno::Reference<drawing::XShape>& xShape ) 337 { 338 ShapeEventListenerMap::const_iterator aIter; 339 if( (aIter = mrGlobalListenersMap.find( xShape )) == 340 mrGlobalListenersMap.end() ) 341 { 342 ENSURE_OR_RETURN_FALSE(false, 343 "ShapeManagerImpl::listenerAdded(): global " 344 "shape listener map inconsistency!"); 345 } 346 347 // is this one of our shapes? other shapes are ignored. 348 ShapeSharedPtr pShape( lookupShape(xShape) ); 349 if( pShape ) 350 { 351 maShapeListenerMap.insert( 352 ShapeToListenersMap::value_type( 353 pShape, 354 aIter->second)); 355 } 356 357 return true; 358 } 359 360 bool ShapeManagerImpl::listenerRemoved( 361 const uno::Reference<presentation::XShapeEventListener>& /*xListener*/, 362 const uno::Reference<drawing::XShape>& xShape ) 363 { 364 // shape really erased from map? maybe there are other listeners 365 // for the same shape pending... 366 if( mrGlobalListenersMap.find(xShape) == mrGlobalListenersMap.end() ) 367 { 368 // is this one of our shapes? other shapes are ignored. 369 ShapeSharedPtr pShape( lookupShape(xShape) ); 370 if( pShape ) 371 maShapeListenerMap.erase(pShape); 372 } 373 374 return true; 375 } 376 377 bool ShapeManagerImpl::cursorChanged( const uno::Reference<drawing::XShape>& xShape, 378 sal_Int16 nCursor ) 379 { 380 ShapeSharedPtr pShape( lookupShape(xShape) ); 381 382 // is this one of our shapes? other shapes are ignored. 383 if( !pShape ) 384 return false; 385 386 if( mrGlobalCursorMap.find(xShape) == mrGlobalCursorMap.end() ) 387 { 388 // erased from global map - erase locally, too 389 maShapeCursorMap.erase(pShape); 390 } 391 else 392 { 393 // included in global map - update local one 394 ShapeToCursorMap::iterator aIter; 395 if( (aIter = maShapeCursorMap.find(pShape)) 396 == maShapeCursorMap.end() ) 397 { 398 maShapeCursorMap.insert( 399 ShapeToCursorMap::value_type( 400 pShape, 401 nCursor )); 402 } 403 else 404 { 405 aIter->second = nCursor; 406 } 407 } 408 409 return true; 410 } 411 412 rtl::OUString ShapeManagerImpl::checkForHyperlink( basegfx::B2DPoint const& hitPos ) const 413 { 414 // find matching region (scan reversely, to coarsely match 415 // paint order): set is ordered by priority 416 AreaSet::const_reverse_iterator iPos( maHyperlinkShapes.rbegin() ); 417 AreaSet::const_reverse_iterator const iEnd( maHyperlinkShapes.rend() ); 418 for( ; iPos != iEnd; ++iPos ) 419 { 420 HyperlinkAreaSharedPtr const& pArea = *iPos; 421 422 HyperlinkArea::HyperlinkRegions const linkRegions( 423 pArea->getHyperlinkRegions() ); 424 425 for( std::size_t i = linkRegions.size(); i--; ) 426 { 427 basegfx::B2DRange const& region = linkRegions[i].first; 428 if( region.isInside(hitPos) ) 429 return linkRegions[i].second; 430 } 431 } 432 433 return rtl::OUString(); 434 } 435 436 void ShapeManagerImpl::addIntrinsicAnimationHandler( const IntrinsicAnimationEventHandlerSharedPtr& rHandler ) 437 { 438 maIntrinsicAnimationEventHandlers.add( rHandler ); 439 } 440 441 void ShapeManagerImpl::removeIntrinsicAnimationHandler( const IntrinsicAnimationEventHandlerSharedPtr& rHandler ) 442 { 443 maIntrinsicAnimationEventHandlers.remove( rHandler ); 444 } 445 446 bool ShapeManagerImpl::notifyIntrinsicAnimationsEnabled() 447 { 448 return maIntrinsicAnimationEventHandlers.applyAll( 449 boost::mem_fn(&IntrinsicAnimationEventHandler::enableAnimations)); 450 } 451 452 bool ShapeManagerImpl::notifyIntrinsicAnimationsDisabled() 453 { 454 return maIntrinsicAnimationEventHandlers.applyAll( 455 boost::mem_fn(&IntrinsicAnimationEventHandler::disableAnimations)); 456 } 457 458 459 460 } // namespace internal 461 } // namespace presentation 462