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 // must be first 28 #include <canvas/debug.hxx> 29 #include <tools/diagnose_ex.h> 30 31 #include <comphelper/anytostring.hxx> 32 #include <cppuhelper/exc_hlp.hxx> 33 34 #include <com/sun/star/awt/SystemPointer.hpp> 35 #include <com/sun/star/awt/MouseButton.hpp> 36 #include <com/sun/star/awt/MouseEvent.hpp> 37 38 #include <boost/bind.hpp> 39 40 #include "delayevent.hxx" 41 #include "usereventqueue.hxx" 42 #include "cursormanager.hxx" 43 #include "slideshowexceptions.hxx" 44 45 #include <vector> 46 #include <queue> 47 #include <map> 48 #include <functional> 49 #include <algorithm> 50 51 52 using namespace com::sun::star; 53 54 /* Implementation of UserEventQueue class */ 55 56 namespace slideshow { 57 namespace internal { 58 59 namespace { 60 61 typedef std::vector<EventSharedPtr> ImpEventVector; 62 typedef std::queue<EventSharedPtr> ImpEventQueue; 63 typedef std::map<uno::Reference<animations::XAnimationNode>, 64 ImpEventVector> ImpAnimationEventMap; 65 typedef std::map<ShapeSharedPtr, ImpEventQueue, 66 Shape::lessThanShape> ImpShapeEventMap; 67 68 // MouseEventHandler base class, not consuming any event: 69 class MouseEventHandler_ : public MouseEventHandler 70 { 71 public: 72 virtual bool handleMousePressed( awt::MouseEvent const& /*e*/ ) { return false;} 73 virtual bool handleMouseReleased( awt::MouseEvent const& /*e*/) { return false;} 74 virtual bool handleMouseEntered( awt::MouseEvent const& /*e*/ ) { return false;} 75 virtual bool handleMouseExited( awt::MouseEvent const& /*e*/ ) { return false; } 76 virtual bool handleMouseDragged( awt::MouseEvent const& /*e*/ ) { return false;} 77 virtual bool handleMouseMoved( awt::MouseEvent const& /*e*/ ) { return false; } 78 }; 79 80 /** @return one event has been posted 81 */ 82 template <typename ContainerT> 83 bool fireSingleEvent( ContainerT & rQueue, EventQueue & rEventQueue ) 84 { 85 // post next event in given queue: 86 while (! rQueue.empty()) 87 { 88 EventSharedPtr const pEvent(rQueue.front()); 89 rQueue.pop(); 90 91 // skip all inactive events (as the purpose of 92 // nextEventFromQueue() is to activate the next 93 // event, and events which return false on 94 // isCharged() will never be activated by the 95 // EventQueue) 96 if(pEvent->isCharged()) 97 return rEventQueue.addEvent( pEvent ); 98 } 99 return false; // no more (active) events in queue 100 } 101 102 /** @return at least one event has been posted 103 */ 104 template <typename ContainerT> 105 bool fireAllEvents( ContainerT & rQueue, EventQueue & rEventQueue ) 106 { 107 bool bFiredAny = false; 108 while (fireSingleEvent( rQueue, rEventQueue )) 109 bFiredAny = true; 110 return bFiredAny; 111 } 112 113 class EventContainer 114 { 115 public: 116 EventContainer() : 117 maEvents() 118 {} 119 120 void clearContainer() 121 { 122 maEvents = ImpEventQueue(); 123 } 124 125 void addEvent( const EventSharedPtr& rEvent ) 126 { 127 maEvents.push( rEvent ); 128 } 129 130 bool isEmpty() 131 { 132 return maEvents.empty(); 133 } 134 135 protected: 136 ImpEventQueue maEvents; 137 }; 138 139 } // anon namespace 140 141 class PlainEventHandler : public EventHandler, 142 public EventContainer 143 { 144 public: 145 PlainEventHandler( EventQueue & rEventQueue ) 146 : EventContainer(), mrEventQueue(rEventQueue) {} 147 148 virtual void dispose() 149 { 150 clearContainer(); 151 } 152 153 virtual bool handleEvent() 154 { 155 return fireAllEvents( maEvents, mrEventQueue ); 156 } 157 158 private: 159 EventQueue & mrEventQueue; 160 }; 161 162 class AllAnimationEventHandler : public AnimationEventHandler 163 { 164 public: 165 AllAnimationEventHandler( EventQueue& rEventQueue ) : 166 mrEventQueue( rEventQueue ), 167 maAnimationEventMap() 168 {} 169 170 virtual void dispose() 171 { 172 maAnimationEventMap.clear(); 173 } 174 175 virtual bool handleAnimationEvent( const AnimationNodeSharedPtr& rNode ) 176 { 177 ENSURE_OR_RETURN_FALSE( 178 rNode, 179 "AllAnimationEventHandler::handleAnimationEvent(): Invalid node" ); 180 181 bool bRet( false ); 182 183 ImpAnimationEventMap::iterator aIter; 184 if( (aIter=maAnimationEventMap.find( 185 rNode->getXAnimationNode() )) != maAnimationEventMap.end() ) 186 { 187 ImpEventVector& rVec( aIter->second ); 188 189 bRet = !rVec.empty(); 190 191 // registered node found -> fire all events in the vector 192 std::for_each( rVec.begin(), rVec.end(), 193 boost::bind( &EventQueue::addEvent, 194 boost::ref( mrEventQueue ), _1 ) ); 195 196 rVec.clear(); 197 } 198 199 return bRet; 200 } 201 202 void addEvent( const EventSharedPtr& rEvent, 203 const uno::Reference< animations::XAnimationNode >& xNode ) 204 { 205 ImpAnimationEventMap::iterator aIter; 206 if( (aIter=maAnimationEventMap.find( xNode )) == 207 maAnimationEventMap.end() ) 208 { 209 // no entry for this animation -> create one 210 aIter = maAnimationEventMap.insert( 211 ImpAnimationEventMap::value_type( xNode, 212 ImpEventVector() ) ).first; 213 } 214 215 // add new event to queue 216 aIter->second.push_back( rEvent ); 217 } 218 219 bool isEmpty() 220 { 221 // find at least one animation with a non-empty vector 222 ImpAnimationEventMap::const_iterator aCurr( maAnimationEventMap.begin() ); 223 const ImpAnimationEventMap::const_iterator aEnd( maAnimationEventMap.end() ); 224 while( aCurr != aEnd ) 225 { 226 if( !aCurr->second.empty() ) 227 return false; // at least one non-empty entry found 228 229 ++aCurr; 230 } 231 232 return true; // not a single non-empty entry found 233 } 234 235 private: 236 EventQueue& mrEventQueue; 237 ImpAnimationEventMap maAnimationEventMap; 238 }; 239 240 class ClickEventHandler : public MouseEventHandler_, 241 public EventHandler, 242 public EventContainer 243 { 244 public: 245 ClickEventHandler( EventQueue& rEventQueue ) : 246 EventContainer(), 247 mrEventQueue( rEventQueue ), 248 mbAdvanceOnClick( true ) 249 {} 250 251 void setAdvanceOnClick( bool bAdvanceOnClick ) 252 { 253 mbAdvanceOnClick = bAdvanceOnClick; 254 } 255 256 private: 257 virtual void dispose() 258 { 259 clearContainer(); 260 } 261 262 // triggered by API calls, e.g. space bar 263 virtual bool handleEvent() 264 { 265 return handleEvent_impl(); 266 } 267 268 // triggered by mouse release: 269 virtual bool handleMouseReleased( const awt::MouseEvent& evt ) 270 { 271 if(evt.Buttons != awt::MouseButton::LEFT) 272 return false; 273 274 if( mbAdvanceOnClick ) { 275 // fire next event 276 return handleEvent_impl(); 277 } 278 else { 279 return false; // advance-on-click disabled 280 } 281 } 282 283 // triggered by both: 284 virtual bool handleEvent_impl() 285 { 286 // fire next event: 287 return fireSingleEvent( maEvents, mrEventQueue ); 288 } 289 290 private: 291 EventQueue& mrEventQueue; 292 bool mbAdvanceOnClick; 293 }; 294 295 class SkipEffectEventHandler : public ClickEventHandler 296 { 297 public: 298 SkipEffectEventHandler( EventQueue & rEventQueue, 299 EventMultiplexer & rEventMultiplexer ) 300 : ClickEventHandler(rEventQueue), 301 mrEventQueue(rEventQueue), 302 mrEventMultiplexer(rEventMultiplexer), 303 mbSkipTriggersNextEffect(true) {} 304 305 /** Remember to trigger (or not to trigger) the next effect after the 306 current effect is skiped. 307 */ 308 void setSkipTriggersNextEffect (const bool bSkipTriggersNextEffect) 309 { mbSkipTriggersNextEffect = bSkipTriggersNextEffect; } 310 311 /// Skip the current effect but do not triggere the next effect. 312 void skipEffect (void) { handleEvent_impl(false); } 313 314 private: 315 virtual bool handleEvent_impl() 316 { 317 return handleEvent_impl(true); 318 } 319 320 bool handleEvent_impl (bool bNotifyNextEffect) 321 { 322 // fire all events, so animation nodes can register their 323 // next effect listeners: 324 if(fireAllEvents( maEvents, mrEventQueue )) 325 { 326 if (mbSkipTriggersNextEffect && bNotifyNextEffect) 327 { 328 // then simulate a next effect event: this skip effect 329 // handler is triggered upon next effect events (multiplexer 330 // prio=-1)! Posting a notifyNextEffect() here is only safe 331 // (we don't run into busy loop), because we assume that 332 // someone has registerered above for next effects 333 // (multiplexer prio=0) at the user event queue. 334 return mrEventQueue.addEventWhenQueueIsEmpty( 335 makeEvent( boost::bind( &EventMultiplexer::notifyNextEffect, 336 boost::ref(mrEventMultiplexer) ), 337 "EventMultiplexer::notifyNextEffect") ); 338 } 339 else 340 return true; 341 } 342 return false; 343 } 344 345 private: 346 EventQueue & mrEventQueue; 347 EventMultiplexer & mrEventMultiplexer; 348 bool mbSkipTriggersNextEffect; 349 }; 350 351 class RewindEffectEventHandler : public MouseEventHandler_, 352 public EventContainer 353 { 354 public: 355 RewindEffectEventHandler( EventQueue & rEventQueue ) 356 : EventContainer(), mrEventQueue(rEventQueue) {} 357 358 private: 359 virtual void dispose() 360 { 361 clearContainer(); 362 } 363 364 virtual bool handleMouseReleased( awt::MouseEvent const& evt ) 365 { 366 if(evt.Buttons != awt::MouseButton::RIGHT) 367 return false; 368 369 return fireAllEvents( maEvents, mrEventQueue ); 370 } 371 372 private: 373 EventQueue & mrEventQueue; 374 }; 375 376 /** Base class to share some common code between 377 ShapeClickEventHandler and MouseMoveHandler 378 379 @derive override necessary MouseEventHandler interface methods, 380 call sendEvent() method to actually process the event. 381 */ 382 class MouseHandlerBase : public MouseEventHandler_ 383 { 384 public: 385 MouseHandlerBase( EventQueue& rEventQueue ) : 386 mrEventQueue( rEventQueue ), 387 maShapeEventMap() 388 {} 389 390 virtual void dispose() 391 { 392 // TODO(Q1): Check whether plain vector with swap idiom is 393 // okay here 394 maShapeEventMap = ImpShapeEventMap(); 395 } 396 397 void addEvent( const EventSharedPtr& rEvent, 398 const ShapeSharedPtr& rShape ) 399 { 400 ImpShapeEventMap::iterator aIter; 401 if( (aIter=maShapeEventMap.find( rShape )) == maShapeEventMap.end() ) 402 { 403 // no entry for this shape -> create one 404 aIter = maShapeEventMap.insert( 405 ImpShapeEventMap::value_type( rShape, 406 ImpEventQueue() ) ).first; 407 } 408 409 // add new event to queue 410 aIter->second.push( rEvent ); 411 } 412 413 bool isEmpty() 414 { 415 // find at least one shape with a non-empty queue 416 ImpShapeEventMap::reverse_iterator aCurrShape( maShapeEventMap.begin()); 417 ImpShapeEventMap::reverse_iterator aEndShape( maShapeEventMap.end() ); 418 while( aCurrShape != aEndShape ) 419 { 420 if( !aCurrShape->second.empty() ) 421 return false; // at least one non-empty entry found 422 423 ++aCurrShape; 424 } 425 426 return true; // not a single non-empty entry found 427 } 428 429 protected: 430 bool hitTest( const awt::MouseEvent& e, 431 ImpShapeEventMap::reverse_iterator& o_rHitShape ) 432 { 433 // find hit shape in map 434 const basegfx::B2DPoint aPosition( e.X, e.Y ); 435 436 // find matching shape (scan reversely, to coarsely match 437 // paint order) 438 ImpShapeEventMap::reverse_iterator aCurrShape(maShapeEventMap.rbegin()); 439 const ImpShapeEventMap::reverse_iterator aEndShape( maShapeEventMap.rend() ); 440 while( aCurrShape != aEndShape ) 441 { 442 // TODO(F2): Get proper geometry polygon from the 443 // shape, to avoid having areas outside the shape 444 // react on the mouse 445 if( aCurrShape->first->getBounds().isInside( aPosition ) && 446 aCurrShape->first->isVisible() ) 447 { 448 // shape hit, and shape is visible - report a 449 // hit 450 o_rHitShape = aCurrShape; 451 return true; 452 } 453 454 ++aCurrShape; 455 } 456 457 return false; // nothing hit 458 } 459 460 bool sendEvent( ImpShapeEventMap::reverse_iterator& io_rHitShape ) 461 { 462 // take next event from queue 463 const bool bRet( fireSingleEvent( io_rHitShape->second, 464 mrEventQueue ) ); 465 466 // clear shape entry, if its queue is 467 // empty. This is important, since the shapes 468 // are held by shared ptr, and might otherwise 469 // not get released, even after their owning 470 // slide is long gone. 471 if( io_rHitShape->second.empty() ) 472 { 473 // this looks funny, since ::std::map does 474 // provide an erase( iterator ) 475 // method. Unfortunately, stlport does not 476 // declare the obvious erase( 477 // reverse_iterator ) needed here (missing 478 // orthogonality, eh?) 479 maShapeEventMap.erase( io_rHitShape->first ); 480 } 481 482 return bRet; 483 } 484 485 bool processEvent( const awt::MouseEvent& e ) 486 { 487 ImpShapeEventMap::reverse_iterator aCurrShape; 488 489 if( hitTest( e, aCurrShape ) ) 490 return sendEvent( aCurrShape ); 491 492 return false; // did not handle the event 493 } 494 495 private: 496 EventQueue& mrEventQueue; 497 ImpShapeEventMap maShapeEventMap; 498 }; 499 500 class ShapeClickEventHandler : public MouseHandlerBase 501 { 502 public: 503 ShapeClickEventHandler( CursorManager& rCursorManager, 504 EventQueue& rEventQueue ) : 505 MouseHandlerBase( rEventQueue ), 506 mrCursorManager( rCursorManager ) 507 {} 508 509 virtual bool handleMouseReleased( const awt::MouseEvent& e ) 510 { 511 if(e.Buttons != awt::MouseButton::LEFT) 512 return false; 513 return processEvent( e ); 514 } 515 516 virtual bool handleMouseMoved( const awt::MouseEvent& e ) 517 { 518 // TODO(P2): Maybe buffer last shape touched 519 520 // if we have a shape click event, and the mouse 521 // hovers over this shape, change cursor to hand 522 ImpShapeEventMap::reverse_iterator aDummy; 523 if( hitTest( e, aDummy ) ) 524 mrCursorManager.requestCursor( awt::SystemPointer::REFHAND ); 525 526 return false; // we don't /eat/ this event. Lower prio 527 // handler should see it, too. 528 } 529 530 private: 531 CursorManager& mrCursorManager; 532 }; 533 534 class MouseEnterHandler : public MouseHandlerBase 535 { 536 public: 537 MouseEnterHandler( EventQueue& rEventQueue ) 538 : MouseHandlerBase( rEventQueue ), 539 mpLastShape() {} 540 541 virtual bool handleMouseMoved( const awt::MouseEvent& e ) 542 { 543 // TODO(P2): Maybe buffer last shape touched, and 544 // check against that _first_ 545 546 ImpShapeEventMap::reverse_iterator aCurr; 547 if( hitTest( e, aCurr ) ) 548 { 549 if( aCurr->first != mpLastShape ) 550 { 551 // we actually hit a shape, and it's different 552 // from the previous one - thus we just 553 // entered it, raise event 554 sendEvent( aCurr ); 555 mpLastShape = aCurr->first; 556 } 557 } 558 else 559 { 560 // don't hit no shape - thus, last shape is NULL 561 mpLastShape.reset(); 562 } 563 564 return false; // we don't /eat/ this event. Lower prio 565 // handler should see it, too. 566 } 567 568 private: 569 ShapeSharedPtr mpLastShape; 570 }; 571 572 class MouseLeaveHandler : public MouseHandlerBase 573 { 574 public: 575 MouseLeaveHandler( EventQueue& rEventQueue ) 576 : MouseHandlerBase( rEventQueue ), 577 maLastIter() {} 578 579 virtual bool handleMouseMoved( const awt::MouseEvent& e ) 580 { 581 // TODO(P2): Maybe buffer last shape touched, and 582 // check against that _first_ 583 584 ImpShapeEventMap::reverse_iterator aCurr; 585 if( hitTest( e, aCurr ) ) 586 { 587 maLastIter = aCurr; 588 } 589 else 590 { 591 if( maLastIter->first ) 592 { 593 // last time, we were over a shape, now we're 594 // not - we thus just left that shape, raise 595 // event 596 sendEvent( maLastIter ); 597 } 598 599 // in any case, when we hit this else-branch: no 600 // shape hit, thus have to clear maLastIter 601 maLastIter = ImpShapeEventMap::reverse_iterator(); 602 } 603 604 return false; // we don't /eat/ this event. Lower prio 605 // handler should see it, too. 606 } 607 608 private: 609 ImpShapeEventMap::reverse_iterator maLastIter; 610 }; 611 612 template< typename Handler, typename Functor > 613 void UserEventQueue::registerEvent( 614 boost::shared_ptr< Handler >& rHandler, 615 const EventSharedPtr& rEvent, 616 const Functor& rRegistrationFunctor ) 617 { 618 ENSURE_OR_THROW( rEvent, 619 "UserEventQueue::registerEvent(): Invalid event" ); 620 621 if( !rHandler ) { 622 // create handler 623 rHandler.reset( new Handler( mrEventQueue ) ); 624 // register handler on EventMultiplexer 625 rRegistrationFunctor( rHandler ); 626 } 627 628 rHandler->addEvent( rEvent ); 629 } 630 631 template< typename Handler, typename Arg, typename Functor > 632 void UserEventQueue::registerEvent( 633 boost::shared_ptr< Handler >& rHandler, 634 const EventSharedPtr& rEvent, 635 const Arg& rArg, 636 const Functor& rRegistrationFunctor ) 637 { 638 ENSURE_OR_THROW( rEvent, 639 "UserEventQueue::registerEvent(): Invalid event" ); 640 641 if( !rHandler ) { 642 // create handler 643 rHandler.reset( new Handler( mrEventQueue ) ); 644 645 // register handler on EventMultiplexer 646 rRegistrationFunctor( rHandler ); 647 } 648 649 rHandler->addEvent( rEvent, rArg ); 650 } 651 652 653 // Public methods 654 // ===================================================== 655 656 UserEventQueue::UserEventQueue( EventMultiplexer& rMultiplexer, 657 EventQueue& rEventQueue, 658 CursorManager& rCursorManager ) 659 : mrMultiplexer( rMultiplexer ), 660 mrEventQueue( rEventQueue ), 661 mrCursorManager( rCursorManager ), 662 mpStartEventHandler(), 663 mpEndEventHandler(), 664 mpAnimationStartEventHandler(), 665 mpAnimationEndEventHandler(), 666 mpAudioStoppedEventHandler(), 667 mpClickEventHandler(), 668 mpSkipEffectEventHandler(), 669 mpRewindEffectEventHandler(), 670 mpDoubleClickEventHandler(), 671 mpMouseEnterHandler(), 672 mpMouseLeaveHandler(), 673 mbAdvanceOnClick( true ) 674 { 675 } 676 677 UserEventQueue::~UserEventQueue() 678 { 679 try 680 { 681 // unregister all handlers 682 clear(); 683 } 684 catch (uno::Exception &) { 685 OSL_ENSURE( false, rtl::OUStringToOString( 686 comphelper::anyToString( 687 cppu::getCaughtException() ), 688 RTL_TEXTENCODING_UTF8 ).getStr() ); 689 } 690 } 691 692 bool UserEventQueue::isEmpty() const 693 { 694 // TODO(T2): This is not thread safe, the handlers are all 695 // only separately synchronized. This poses the danger of 696 // generating false empty status on XSlideShow::update(), such 697 // that the last events of a slide are not triggered. 698 699 // we're empty iff all handler queues are empty 700 return 701 (mpStartEventHandler ? mpStartEventHandler->isEmpty() : true) && 702 (mpEndEventHandler ? mpEndEventHandler->isEmpty() : true) && 703 (mpAnimationStartEventHandler ? mpAnimationStartEventHandler->isEmpty() : true) && 704 (mpAnimationEndEventHandler ? mpAnimationEndEventHandler->isEmpty() : true) && 705 (mpAudioStoppedEventHandler ? mpAudioStoppedEventHandler->isEmpty() : true) && 706 (mpShapeClickEventHandler ? mpShapeClickEventHandler->isEmpty() : true) && 707 (mpClickEventHandler ? mpClickEventHandler->isEmpty() : true) && 708 (mpSkipEffectEventHandler ? mpSkipEffectEventHandler->isEmpty() : true) && 709 (mpRewindEffectEventHandler ? mpRewindEffectEventHandler->isEmpty() : true) && 710 (mpShapeDoubleClickEventHandler ? mpShapeDoubleClickEventHandler->isEmpty() : true) && 711 (mpDoubleClickEventHandler ? mpDoubleClickEventHandler->isEmpty() : true) && 712 (mpMouseEnterHandler ? mpMouseEnterHandler->isEmpty() : true) && 713 (mpMouseLeaveHandler ? mpMouseLeaveHandler->isEmpty() : true); 714 } 715 716 void UserEventQueue::clear() 717 { 718 // unregister and delete all handlers 719 if( mpStartEventHandler ) { 720 mrMultiplexer.removeSlideStartHandler( mpStartEventHandler ); 721 mpStartEventHandler.reset(); 722 } 723 if( mpEndEventHandler ) { 724 mrMultiplexer.removeSlideEndHandler( mpEndEventHandler ); 725 mpEndEventHandler.reset(); 726 } 727 if( mpAnimationStartEventHandler ) { 728 mrMultiplexer.removeAnimationStartHandler( 729 mpAnimationStartEventHandler ); 730 mpAnimationStartEventHandler.reset(); 731 } 732 if( mpAnimationEndEventHandler ) { 733 mrMultiplexer.removeAnimationEndHandler( mpAnimationEndEventHandler ); 734 mpAnimationEndEventHandler.reset(); 735 } 736 if( mpAudioStoppedEventHandler ) { 737 mrMultiplexer.removeAudioStoppedHandler( mpAudioStoppedEventHandler ); 738 mpAudioStoppedEventHandler.reset(); 739 } 740 if( mpShapeClickEventHandler ) { 741 mrMultiplexer.removeClickHandler( mpShapeClickEventHandler ); 742 mrMultiplexer.removeMouseMoveHandler( mpShapeClickEventHandler ); 743 mpShapeClickEventHandler.reset(); 744 } 745 if( mpClickEventHandler ) { 746 mrMultiplexer.removeClickHandler( mpClickEventHandler ); 747 mrMultiplexer.removeNextEffectHandler( mpClickEventHandler ); 748 mpClickEventHandler.reset(); 749 } 750 if(mpSkipEffectEventHandler) { 751 mrMultiplexer.removeClickHandler( mpSkipEffectEventHandler ); 752 mrMultiplexer.removeNextEffectHandler( mpSkipEffectEventHandler ); 753 mpSkipEffectEventHandler.reset(); 754 } 755 if(mpRewindEffectEventHandler) { 756 mrMultiplexer.removeClickHandler( mpRewindEffectEventHandler ); 757 mpRewindEffectEventHandler.reset(); 758 } 759 if( mpShapeDoubleClickEventHandler ) { 760 mrMultiplexer.removeDoubleClickHandler( mpShapeDoubleClickEventHandler ); 761 mrMultiplexer.removeMouseMoveHandler( mpShapeDoubleClickEventHandler ); 762 mpShapeDoubleClickEventHandler.reset(); 763 } 764 if( mpDoubleClickEventHandler ) { 765 mrMultiplexer.removeDoubleClickHandler( mpDoubleClickEventHandler ); 766 mpDoubleClickEventHandler.reset(); 767 } 768 if( mpMouseEnterHandler ) { 769 mrMultiplexer.removeMouseMoveHandler( mpMouseEnterHandler ); 770 mpMouseEnterHandler.reset(); 771 } 772 if( mpMouseLeaveHandler ) { 773 mrMultiplexer.removeMouseMoveHandler( mpMouseLeaveHandler ); 774 mpMouseLeaveHandler.reset(); 775 } 776 } 777 778 void UserEventQueue::setAdvanceOnClick( bool bAdvanceOnClick ) 779 { 780 mbAdvanceOnClick = bAdvanceOnClick; 781 782 // forward to handler, if existing. Otherwise, the handler 783 // creation will do the forwarding. 784 if( mpClickEventHandler ) 785 mpClickEventHandler->setAdvanceOnClick( bAdvanceOnClick ); 786 } 787 788 789 void UserEventQueue::registerSlideStartEvent( const EventSharedPtr& rEvent ) 790 { 791 registerEvent( mpStartEventHandler, 792 rEvent, 793 boost::bind( &EventMultiplexer::addSlideStartHandler, 794 boost::ref( mrMultiplexer ), _1 ) ); 795 } 796 797 void UserEventQueue::registerSlideEndEvent( const EventSharedPtr& rEvent ) 798 { 799 registerEvent( mpEndEventHandler, 800 rEvent, 801 boost::bind( &EventMultiplexer::addSlideEndHandler, 802 boost::ref( mrMultiplexer ), _1 ) ); 803 } 804 805 void UserEventQueue::registerAnimationStartEvent( 806 const EventSharedPtr& rEvent, 807 const uno::Reference< animations::XAnimationNode>& xNode ) 808 { 809 registerEvent( mpAnimationStartEventHandler, 810 rEvent, 811 xNode, 812 boost::bind( &EventMultiplexer::addAnimationStartHandler, 813 boost::ref( mrMultiplexer ), _1 ) ); 814 } 815 816 void UserEventQueue::registerAnimationEndEvent( 817 const EventSharedPtr& rEvent, 818 const uno::Reference<animations::XAnimationNode>& xNode ) 819 { 820 registerEvent( mpAnimationEndEventHandler, 821 rEvent, 822 xNode, 823 boost::bind( &EventMultiplexer::addAnimationEndHandler, 824 boost::ref( mrMultiplexer ), _1 ) ); 825 } 826 827 void UserEventQueue::registerAudioStoppedEvent( 828 const EventSharedPtr& rEvent, 829 const uno::Reference<animations::XAnimationNode>& xNode ) 830 { 831 registerEvent( mpAudioStoppedEventHandler, 832 rEvent, 833 xNode, 834 boost::bind( &EventMultiplexer::addAudioStoppedHandler, 835 boost::ref( mrMultiplexer ), _1 ) ); 836 } 837 838 void UserEventQueue::registerShapeClickEvent( const EventSharedPtr& rEvent, 839 const ShapeSharedPtr& rShape ) 840 { 841 ENSURE_OR_THROW( 842 rEvent, 843 "UserEventQueue::registerShapeClickEvent(): Invalid event" ); 844 845 if( !mpShapeClickEventHandler ) 846 { 847 // create handler 848 mpShapeClickEventHandler.reset( 849 new ShapeClickEventHandler(mrCursorManager, 850 mrEventQueue) ); 851 852 // register handler on EventMultiplexer 853 mrMultiplexer.addClickHandler( mpShapeClickEventHandler, 1.0 ); 854 mrMultiplexer.addMouseMoveHandler( mpShapeClickEventHandler, 1.0 ); 855 } 856 857 mpShapeClickEventHandler->addEvent( rEvent, rShape ); 858 } 859 860 namespace { 861 class ClickEventRegistrationFunctor 862 { 863 public: 864 ClickEventRegistrationFunctor( EventMultiplexer& rMultiplexer, 865 double nPrio, 866 bool bAdvanceOnClick ) 867 : mrMultiplexer( rMultiplexer ), 868 mnPrio(nPrio), 869 mbAdvanceOnClick( bAdvanceOnClick ) {} 870 871 void operator()( const boost::shared_ptr<ClickEventHandler>& rHandler )const 872 { 873 // register the handler on _two_ sources: we want the 874 // nextEffect events, e.g. space bar, to trigger clicks, as well! 875 mrMultiplexer.addClickHandler( rHandler, mnPrio ); 876 mrMultiplexer.addNextEffectHandler( rHandler, mnPrio ); 877 878 // forward advance-on-click state to newly 879 // generated handler (that's the only reason why 880 // we're called here) 881 rHandler->setAdvanceOnClick( mbAdvanceOnClick ); 882 } 883 884 private: 885 EventMultiplexer& mrMultiplexer; 886 double const mnPrio; 887 bool const mbAdvanceOnClick; 888 }; 889 } // anon namespace 890 891 void UserEventQueue::registerNextEffectEvent( const EventSharedPtr& rEvent ) 892 { 893 // TODO: better name may be mpNextEffectEventHandler? then we have 894 // next effect (=> waiting to be started) 895 // skip effect (skipping the currently running one) 896 // rewind effect (rewinding back running one and waiting (again) 897 // to be started) 898 registerEvent( mpClickEventHandler, 899 rEvent, 900 ClickEventRegistrationFunctor( mrMultiplexer, 901 0.0 /* default prio */, 902 mbAdvanceOnClick ) ); 903 } 904 905 void UserEventQueue::registerSkipEffectEvent( 906 EventSharedPtr const & pEvent, 907 const bool bSkipTriggersNextEffect) 908 { 909 if(!mpSkipEffectEventHandler) 910 { 911 mpSkipEffectEventHandler.reset( 912 new SkipEffectEventHandler( mrEventQueue, mrMultiplexer ) ); 913 // register the handler on _two_ sources: we want the 914 // nextEffect events, e.g. space bar, to trigger clicks, as well! 915 mrMultiplexer.addClickHandler( mpSkipEffectEventHandler, 916 -1.0 /* prio below default */ ); 917 mrMultiplexer.addNextEffectHandler( mpSkipEffectEventHandler, 918 -1.0 /* prio below default */ ); 919 // forward advance-on-click state to newly 920 // generated handler (that's the only reason why 921 // we're called here) 922 mpSkipEffectEventHandler->setAdvanceOnClick( mbAdvanceOnClick ); 923 } 924 mpSkipEffectEventHandler->setSkipTriggersNextEffect(bSkipTriggersNextEffect); 925 mpSkipEffectEventHandler->addEvent( pEvent ); 926 } 927 928 void UserEventQueue::registerRewindEffectEvent( EventSharedPtr const& pEvent ) 929 { 930 registerEvent( mpRewindEffectEventHandler, 931 pEvent, 932 boost::bind( &EventMultiplexer::addClickHandler, 933 boost::ref(mrMultiplexer), _1, 934 -1.0 /* prio below default */ ) ); 935 } 936 937 void UserEventQueue::registerShapeDoubleClickEvent( 938 const EventSharedPtr& rEvent, 939 const ShapeSharedPtr& rShape ) 940 { 941 ENSURE_OR_THROW( 942 rEvent, 943 "UserEventQueue::registerShapeDoubleClickEvent(): Invalid event" ); 944 945 if( !mpShapeDoubleClickEventHandler ) 946 { 947 // create handler 948 mpShapeDoubleClickEventHandler.reset( 949 new ShapeClickEventHandler(mrCursorManager, 950 mrEventQueue) ); 951 952 // register handler on EventMultiplexer 953 mrMultiplexer.addDoubleClickHandler( mpShapeDoubleClickEventHandler, 954 1.0 ); 955 mrMultiplexer.addMouseMoveHandler( mpShapeDoubleClickEventHandler, 956 1.0 ); 957 } 958 959 mpShapeDoubleClickEventHandler->addEvent( rEvent, rShape ); 960 } 961 962 void UserEventQueue::registerDoubleClickEvent( const EventSharedPtr& rEvent ) 963 { 964 registerEvent( mpDoubleClickEventHandler, 965 rEvent, 966 boost::bind( &EventMultiplexer::addDoubleClickHandler, 967 boost::ref( mrMultiplexer ), _1, 968 0.0 /* default prio */ ) ); 969 } 970 971 void UserEventQueue::registerMouseEnterEvent( const EventSharedPtr& rEvent, 972 const ShapeSharedPtr& rShape ) 973 { 974 registerEvent( mpMouseEnterHandler, 975 rEvent, 976 rShape, 977 boost::bind( &EventMultiplexer::addMouseMoveHandler, 978 boost::ref( mrMultiplexer ), _1, 979 0.0 /* default prio */ ) ); 980 } 981 982 void UserEventQueue::registerMouseLeaveEvent( const EventSharedPtr& rEvent, 983 const ShapeSharedPtr& rShape ) 984 { 985 registerEvent( mpMouseLeaveHandler, 986 rEvent, 987 rShape, 988 boost::bind( &EventMultiplexer::addMouseMoveHandler, 989 boost::ref( mrMultiplexer ), _1, 990 0.0 /* default prio */ ) ); 991 } 992 993 void UserEventQueue::callSkipEffectEventHandler (void) 994 { 995 ::boost::shared_ptr<SkipEffectEventHandler> pHandler ( 996 ::boost::dynamic_pointer_cast<SkipEffectEventHandler>(mpSkipEffectEventHandler)); 997 if (pHandler) 998 pHandler->skipEffect(); 999 } 1000 1001 } // namespace internal 1002 } // namespace presentation 1003 1004