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