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