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 0 : class AllAnimationEventHandler : public AnimationEventHandler
131 : {
132 : public:
133 0 : AllAnimationEventHandler( EventQueue& rEventQueue ) :
134 : mrEventQueue( rEventQueue ),
135 0 : maAnimationEventMap()
136 0 : {}
137 :
138 0 : virtual void dispose()
139 : {
140 0 : maAnimationEventMap.clear();
141 0 : }
142 :
143 0 : virtual bool handleAnimationEvent( const AnimationNodeSharedPtr& rNode ) SAL_OVERRIDE
144 : {
145 0 : ENSURE_OR_RETURN_FALSE(
146 : rNode,
147 : "AllAnimationEventHandler::handleAnimationEvent(): Invalid node" );
148 :
149 0 : bool bRet( false );
150 :
151 0 : ImpAnimationEventMap::iterator aIter;
152 0 : if( (aIter=maAnimationEventMap.find(
153 0 : rNode->getXAnimationNode() )) != maAnimationEventMap.end() )
154 : {
155 0 : ImpEventVector& rVec( aIter->second );
156 :
157 0 : bRet = !rVec.empty();
158 :
159 : // registered node found -> fire all events in the vector
160 : std::for_each( rVec.begin(), rVec.end(),
161 : boost::bind( &EventQueue::addEvent,
162 0 : boost::ref( mrEventQueue ), _1 ) );
163 :
164 0 : rVec.clear();
165 : }
166 :
167 0 : return bRet;
168 : }
169 :
170 0 : void addEvent( const EventSharedPtr& rEvent,
171 : const uno::Reference< animations::XAnimationNode >& xNode )
172 : {
173 0 : ImpAnimationEventMap::iterator aIter;
174 0 : if( (aIter=maAnimationEventMap.find( xNode )) ==
175 0 : maAnimationEventMap.end() )
176 : {
177 : // no entry for this animation -> create one
178 : aIter = maAnimationEventMap.insert(
179 : ImpAnimationEventMap::value_type( xNode,
180 0 : ImpEventVector() ) ).first;
181 : }
182 :
183 : // add new event to queue
184 0 : aIter->second.push_back( rEvent );
185 0 : }
186 :
187 : private:
188 : EventQueue& mrEventQueue;
189 : ImpAnimationEventMap maAnimationEventMap;
190 : };
191 :
192 0 : class ClickEventHandler : public MouseEventHandler_,
193 : public EventHandler,
194 : public EventContainer
195 : {
196 : public:
197 0 : ClickEventHandler( EventQueue& rEventQueue ) :
198 : EventContainer(),
199 : mrEventQueue( rEventQueue ),
200 0 : mbAdvanceOnClick( true )
201 0 : {}
202 :
203 0 : void setAdvanceOnClick( bool bAdvanceOnClick )
204 : {
205 0 : mbAdvanceOnClick = bAdvanceOnClick;
206 0 : }
207 :
208 : private:
209 0 : virtual void dispose()
210 : {
211 0 : clearContainer();
212 0 : }
213 :
214 : // triggered by API calls, e.g. space bar
215 0 : virtual bool handleEvent() SAL_OVERRIDE
216 : {
217 0 : return handleEvent_impl();
218 : }
219 :
220 : // triggered by mouse release:
221 0 : virtual bool handleMouseReleased( const awt::MouseEvent& evt ) SAL_OVERRIDE
222 : {
223 0 : if(evt.Buttons != awt::MouseButton::LEFT)
224 0 : return false;
225 :
226 0 : if( mbAdvanceOnClick ) {
227 : // fire next event
228 0 : return handleEvent_impl();
229 : }
230 : else {
231 0 : return false; // advance-on-click disabled
232 : }
233 : }
234 :
235 : // triggered by both:
236 0 : virtual bool handleEvent_impl()
237 : {
238 : // fire next event:
239 0 : return fireSingleEvent( maEvents, mrEventQueue );
240 : }
241 :
242 : private:
243 : EventQueue& mrEventQueue;
244 : bool mbAdvanceOnClick;
245 : };
246 :
247 0 : class SkipEffectEventHandler : public ClickEventHandler
248 : {
249 : public:
250 0 : SkipEffectEventHandler( EventQueue & rEventQueue,
251 : EventMultiplexer & rEventMultiplexer )
252 : : ClickEventHandler(rEventQueue),
253 : mrEventQueue(rEventQueue),
254 : mrEventMultiplexer(rEventMultiplexer),
255 0 : mbSkipTriggersNextEffect(true) {}
256 :
257 : /** Remember to trigger (or not to trigger) the next effect after the
258 : current effect is skiped.
259 : */
260 0 : void setSkipTriggersNextEffect (const bool bSkipTriggersNextEffect)
261 0 : { mbSkipTriggersNextEffect = bSkipTriggersNextEffect; }
262 :
263 : /// Skip the current effect but do not triggere the next effect.
264 0 : void skipEffect (void) { handleEvent_impl(false); }
265 :
266 : private:
267 0 : virtual bool handleEvent_impl() SAL_OVERRIDE
268 : {
269 0 : return handleEvent_impl(true);
270 : }
271 :
272 0 : bool handleEvent_impl (bool bNotifyNextEffect)
273 : {
274 : // fire all events, so animation nodes can register their
275 : // next effect listeners:
276 0 : if(fireAllEvents( maEvents, mrEventQueue ))
277 : {
278 0 : if (mbSkipTriggersNextEffect && bNotifyNextEffect)
279 : {
280 : // then simulate a next effect event: this skip effect
281 : // handler is triggered upon next effect events (multiplexer
282 : // prio=-1)! Posting a notifyNextEffect() here is only safe
283 : // (we don't run into busy loop), because we assume that
284 : // someone has registerered above for next effects
285 : // (multiplexer prio=0) at the user event queue.
286 : return mrEventQueue.addEventWhenQueueIsEmpty(
287 0 : makeEvent( boost::bind( &EventMultiplexer::notifyNextEffect,
288 : boost::ref(mrEventMultiplexer) ),
289 0 : "EventMultiplexer::notifyNextEffect") );
290 : }
291 : else
292 0 : return true;
293 : }
294 0 : return false;
295 : }
296 :
297 : private:
298 : EventQueue & mrEventQueue;
299 : EventMultiplexer & mrEventMultiplexer;
300 : bool mbSkipTriggersNextEffect;
301 : };
302 :
303 0 : class RewindEffectEventHandler : public MouseEventHandler_,
304 : public EventContainer
305 : {
306 : public:
307 0 : RewindEffectEventHandler( EventQueue & rEventQueue )
308 0 : : EventContainer(), mrEventQueue(rEventQueue) {}
309 :
310 : private:
311 0 : virtual void dispose()
312 : {
313 0 : clearContainer();
314 0 : }
315 :
316 0 : virtual bool handleMouseReleased( awt::MouseEvent const& evt ) SAL_OVERRIDE
317 : {
318 0 : if(evt.Buttons != awt::MouseButton::RIGHT)
319 0 : return false;
320 :
321 0 : return fireAllEvents( maEvents, mrEventQueue );
322 : }
323 :
324 : private:
325 : EventQueue & mrEventQueue;
326 : };
327 :
328 : /** Base class to share some common code between
329 : ShapeClickEventHandler and MouseMoveHandler
330 :
331 : @derive override necessary MouseEventHandler interface methods,
332 : call sendEvent() method to actually process the event.
333 : */
334 0 : class MouseHandlerBase : public MouseEventHandler_
335 : {
336 : public:
337 0 : MouseHandlerBase( EventQueue& rEventQueue ) :
338 : mrEventQueue( rEventQueue ),
339 0 : maShapeEventMap()
340 0 : {}
341 :
342 0 : virtual void dispose()
343 : {
344 : // TODO(Q1): Check whether plain vector with swap idiom is
345 : // okay here
346 0 : maShapeEventMap = ImpShapeEventMap();
347 0 : }
348 :
349 0 : void addEvent( const EventSharedPtr& rEvent,
350 : const ShapeSharedPtr& rShape )
351 : {
352 0 : ImpShapeEventMap::iterator aIter;
353 0 : if( (aIter=maShapeEventMap.find( rShape )) == maShapeEventMap.end() )
354 : {
355 : // no entry for this shape -> create one
356 : aIter = maShapeEventMap.insert(
357 : ImpShapeEventMap::value_type( rShape,
358 0 : ImpEventQueue() ) ).first;
359 : }
360 :
361 : // add new event to queue
362 0 : aIter->second.push( rEvent );
363 0 : }
364 :
365 : protected:
366 0 : bool hitTest( const awt::MouseEvent& e,
367 : ImpShapeEventMap::reverse_iterator& o_rHitShape )
368 : {
369 : // find hit shape in map
370 0 : const basegfx::B2DPoint aPosition( e.X, e.Y );
371 :
372 : // find matching shape (scan reversely, to coarsely match
373 : // paint order)
374 0 : ImpShapeEventMap::reverse_iterator aCurrShape(maShapeEventMap.rbegin());
375 0 : const ImpShapeEventMap::reverse_iterator aEndShape( maShapeEventMap.rend() );
376 0 : while( aCurrShape != aEndShape )
377 : {
378 : // TODO(F2): Get proper geometry polygon from the
379 : // shape, to avoid having areas outside the shape
380 : // react on the mouse
381 0 : if( aCurrShape->first->getBounds().isInside( aPosition ) &&
382 0 : aCurrShape->first->isVisible() )
383 : {
384 : // shape hit, and shape is visible - report a
385 : // hit
386 0 : o_rHitShape = aCurrShape;
387 0 : return true;
388 : }
389 :
390 0 : ++aCurrShape;
391 : }
392 :
393 0 : return false; // nothing hit
394 : }
395 :
396 0 : bool sendEvent( ImpShapeEventMap::reverse_iterator& io_rHitShape )
397 : {
398 : // take next event from queue
399 0 : const bool bRet( fireSingleEvent( io_rHitShape->second,
400 0 : mrEventQueue ) );
401 :
402 : // clear shape entry, if its queue is
403 : // empty. This is important, since the shapes
404 : // are held by shared ptr, and might otherwise
405 : // not get released, even after their owning
406 : // slide is long gone.
407 0 : if( io_rHitShape->second.empty() )
408 : {
409 : // this looks funny, since ::std::map does
410 : // provide an erase( iterator )
411 : // method. Unfortunately, C++ does not
412 : // declare the obvious erase(
413 : // reverse_iterator ) needed here (missing
414 : // orthogonality, eh?)
415 0 : maShapeEventMap.erase( io_rHitShape->first );
416 : }
417 :
418 0 : return bRet;
419 : }
420 :
421 0 : bool processEvent( const awt::MouseEvent& e )
422 : {
423 0 : ImpShapeEventMap::reverse_iterator aCurrShape;
424 :
425 0 : if( hitTest( e, aCurrShape ) )
426 0 : return sendEvent( aCurrShape );
427 :
428 0 : return false; // did not handle the event
429 : }
430 :
431 : private:
432 : EventQueue& mrEventQueue;
433 : ImpShapeEventMap maShapeEventMap;
434 : };
435 :
436 0 : class ShapeClickEventHandler : public MouseHandlerBase
437 : {
438 : public:
439 0 : ShapeClickEventHandler( CursorManager& rCursorManager,
440 : EventQueue& rEventQueue ) :
441 : MouseHandlerBase( rEventQueue ),
442 0 : mrCursorManager( rCursorManager )
443 0 : {}
444 :
445 0 : virtual bool handleMouseReleased( const awt::MouseEvent& e ) SAL_OVERRIDE
446 : {
447 0 : if(e.Buttons != awt::MouseButton::LEFT)
448 0 : return false;
449 0 : return processEvent( e );
450 : }
451 :
452 0 : virtual bool handleMouseMoved( const awt::MouseEvent& e ) SAL_OVERRIDE
453 : {
454 : // TODO(P2): Maybe buffer last shape touched
455 :
456 : // if we have a shape click event, and the mouse
457 : // hovers over this shape, change cursor to hand
458 0 : ImpShapeEventMap::reverse_iterator aDummy;
459 0 : if( hitTest( e, aDummy ) )
460 0 : mrCursorManager.requestCursor( awt::SystemPointer::REFHAND );
461 :
462 0 : return false; // we don't /eat/ this event. Lower prio
463 : // handler should see it, too.
464 : }
465 :
466 : private:
467 : CursorManager& mrCursorManager;
468 : };
469 :
470 0 : class MouseEnterHandler : public MouseHandlerBase
471 : {
472 : public:
473 0 : MouseEnterHandler( EventQueue& rEventQueue )
474 : : MouseHandlerBase( rEventQueue ),
475 0 : mpLastShape() {}
476 :
477 0 : virtual bool handleMouseMoved( const awt::MouseEvent& e ) SAL_OVERRIDE
478 : {
479 : // TODO(P2): Maybe buffer last shape touched, and
480 : // check against that _first_
481 :
482 0 : ImpShapeEventMap::reverse_iterator aCurr;
483 0 : if( hitTest( e, aCurr ) )
484 : {
485 0 : if( aCurr->first != mpLastShape )
486 : {
487 : // we actually hit a shape, and it's different
488 : // from the previous one - thus we just
489 : // entered it, raise event
490 0 : sendEvent( aCurr );
491 0 : mpLastShape = aCurr->first;
492 : }
493 : }
494 : else
495 : {
496 : // don't hit no shape - thus, last shape is NULL
497 0 : mpLastShape.reset();
498 : }
499 :
500 0 : return false; // we don't /eat/ this event. Lower prio
501 : // handler should see it, too.
502 : }
503 :
504 : private:
505 : ShapeSharedPtr mpLastShape;
506 : };
507 :
508 0 : class MouseLeaveHandler : public MouseHandlerBase
509 : {
510 : public:
511 0 : MouseLeaveHandler( EventQueue& rEventQueue )
512 : : MouseHandlerBase( rEventQueue ),
513 0 : maLastIter() {}
514 :
515 0 : virtual bool handleMouseMoved( const awt::MouseEvent& e ) SAL_OVERRIDE
516 : {
517 : // TODO(P2): Maybe buffer last shape touched, and
518 : // check against that _first_
519 :
520 0 : ImpShapeEventMap::reverse_iterator aCurr;
521 0 : if( hitTest( e, aCurr ) )
522 : {
523 0 : maLastIter = aCurr;
524 : }
525 : else
526 : {
527 0 : if( maLastIter->first )
528 : {
529 : // last time, we were over a shape, now we're
530 : // not - we thus just left that shape, raise
531 : // event
532 0 : sendEvent( maLastIter );
533 : }
534 :
535 : // in any case, when we hit this else-branch: no
536 : // shape hit, thus have to clear maLastIter
537 0 : maLastIter = ImpShapeEventMap::reverse_iterator();
538 : }
539 :
540 0 : return false; // we don't /eat/ this event. Lower prio
541 : // handler should see it, too.
542 : }
543 :
544 : private:
545 : ImpShapeEventMap::reverse_iterator maLastIter;
546 : };
547 :
548 : template< typename Handler, typename Functor >
549 0 : void UserEventQueue::registerEvent(
550 : boost::shared_ptr< Handler >& rHandler,
551 : const EventSharedPtr& rEvent,
552 : const Functor& rRegistrationFunctor )
553 : {
554 0 : ENSURE_OR_THROW( rEvent,
555 : "UserEventQueue::registerEvent(): Invalid event" );
556 :
557 0 : if( !rHandler ) {
558 : // create handler
559 0 : rHandler.reset( new Handler( mrEventQueue ) );
560 : // register handler on EventMultiplexer
561 0 : rRegistrationFunctor( rHandler );
562 : }
563 :
564 0 : rHandler->addEvent( rEvent );
565 0 : }
566 :
567 : template< typename Handler, typename Arg, typename Functor >
568 0 : void UserEventQueue::registerEvent(
569 : boost::shared_ptr< Handler >& rHandler,
570 : const EventSharedPtr& rEvent,
571 : const Arg& rArg,
572 : const Functor& rRegistrationFunctor )
573 : {
574 0 : ENSURE_OR_THROW( rEvent,
575 : "UserEventQueue::registerEvent(): Invalid event" );
576 :
577 0 : if( !rHandler ) {
578 : // create handler
579 0 : rHandler.reset( new Handler( mrEventQueue ) );
580 :
581 : // register handler on EventMultiplexer
582 0 : rRegistrationFunctor( rHandler );
583 : }
584 :
585 0 : rHandler->addEvent( rEvent, rArg );
586 0 : }
587 :
588 :
589 :
590 2 : UserEventQueue::UserEventQueue( EventMultiplexer& rMultiplexer,
591 : EventQueue& rEventQueue,
592 : CursorManager& rCursorManager )
593 : : mrMultiplexer( rMultiplexer ),
594 : mrEventQueue( rEventQueue ),
595 : mrCursorManager( rCursorManager ),
596 : mpAnimationStartEventHandler(),
597 : mpAnimationEndEventHandler(),
598 : mpAudioStoppedEventHandler(),
599 : mpClickEventHandler(),
600 : mpSkipEffectEventHandler(),
601 : mpRewindEffectEventHandler(),
602 : mpDoubleClickEventHandler(),
603 : mpMouseEnterHandler(),
604 : mpMouseLeaveHandler(),
605 2 : mbAdvanceOnClick( true )
606 : {
607 2 : }
608 :
609 4 : UserEventQueue::~UserEventQueue()
610 : {
611 : try
612 : {
613 : // unregister all handlers
614 2 : clear();
615 : }
616 0 : catch (uno::Exception &) {
617 : OSL_FAIL( OUStringToOString(
618 : comphelper::anyToString(
619 : cppu::getCaughtException() ),
620 : RTL_TEXTENCODING_UTF8 ).getStr() );
621 : }
622 2 : }
623 :
624 4 : void UserEventQueue::clear()
625 : {
626 : // unregister and delete all handlers
627 4 : if( mpAnimationStartEventHandler ) {
628 : mrMultiplexer.removeAnimationStartHandler(
629 0 : mpAnimationStartEventHandler );
630 0 : mpAnimationStartEventHandler.reset();
631 : }
632 4 : if( mpAnimationEndEventHandler ) {
633 0 : mrMultiplexer.removeAnimationEndHandler( mpAnimationEndEventHandler );
634 0 : mpAnimationEndEventHandler.reset();
635 : }
636 4 : if( mpAudioStoppedEventHandler ) {
637 0 : mrMultiplexer.removeAudioStoppedHandler( mpAudioStoppedEventHandler );
638 0 : mpAudioStoppedEventHandler.reset();
639 : }
640 4 : if( mpShapeClickEventHandler ) {
641 0 : mrMultiplexer.removeClickHandler( mpShapeClickEventHandler );
642 0 : mrMultiplexer.removeMouseMoveHandler( mpShapeClickEventHandler );
643 0 : mpShapeClickEventHandler.reset();
644 : }
645 4 : if( mpClickEventHandler ) {
646 0 : mrMultiplexer.removeClickHandler( mpClickEventHandler );
647 0 : mrMultiplexer.removeNextEffectHandler( mpClickEventHandler );
648 0 : mpClickEventHandler.reset();
649 : }
650 4 : if(mpSkipEffectEventHandler) {
651 0 : mrMultiplexer.removeClickHandler( mpSkipEffectEventHandler );
652 0 : mrMultiplexer.removeNextEffectHandler( mpSkipEffectEventHandler );
653 0 : mpSkipEffectEventHandler.reset();
654 : }
655 4 : if(mpRewindEffectEventHandler) {
656 0 : mrMultiplexer.removeClickHandler( mpRewindEffectEventHandler );
657 0 : mpRewindEffectEventHandler.reset();
658 : }
659 4 : if( mpShapeDoubleClickEventHandler ) {
660 0 : mrMultiplexer.removeDoubleClickHandler( mpShapeDoubleClickEventHandler );
661 0 : mrMultiplexer.removeMouseMoveHandler( mpShapeDoubleClickEventHandler );
662 0 : mpShapeDoubleClickEventHandler.reset();
663 : }
664 4 : if( mpDoubleClickEventHandler ) {
665 0 : mrMultiplexer.removeDoubleClickHandler( mpDoubleClickEventHandler );
666 0 : mpDoubleClickEventHandler.reset();
667 : }
668 4 : if( mpMouseEnterHandler ) {
669 0 : mrMultiplexer.removeMouseMoveHandler( mpMouseEnterHandler );
670 0 : mpMouseEnterHandler.reset();
671 : }
672 4 : if( mpMouseLeaveHandler ) {
673 0 : mrMultiplexer.removeMouseMoveHandler( mpMouseLeaveHandler );
674 0 : mpMouseLeaveHandler.reset();
675 : }
676 4 : }
677 :
678 0 : void UserEventQueue::setAdvanceOnClick( bool bAdvanceOnClick )
679 : {
680 0 : mbAdvanceOnClick = bAdvanceOnClick;
681 :
682 : // forward to handler, if existing. Otherwise, the handler
683 : // creation will do the forwarding.
684 0 : if( mpClickEventHandler )
685 0 : mpClickEventHandler->setAdvanceOnClick( bAdvanceOnClick );
686 0 : }
687 :
688 0 : void UserEventQueue::registerAnimationStartEvent(
689 : const EventSharedPtr& rEvent,
690 : const uno::Reference< animations::XAnimationNode>& xNode )
691 : {
692 : registerEvent( mpAnimationStartEventHandler,
693 : rEvent,
694 : xNode,
695 : boost::bind( &EventMultiplexer::addAnimationStartHandler,
696 0 : boost::ref( mrMultiplexer ), _1 ) );
697 0 : }
698 :
699 0 : void UserEventQueue::registerAnimationEndEvent(
700 : const EventSharedPtr& rEvent,
701 : const uno::Reference<animations::XAnimationNode>& xNode )
702 : {
703 : registerEvent( mpAnimationEndEventHandler,
704 : rEvent,
705 : xNode,
706 : boost::bind( &EventMultiplexer::addAnimationEndHandler,
707 0 : boost::ref( mrMultiplexer ), _1 ) );
708 0 : }
709 :
710 0 : void UserEventQueue::registerAudioStoppedEvent(
711 : const EventSharedPtr& rEvent,
712 : const uno::Reference<animations::XAnimationNode>& xNode )
713 : {
714 : registerEvent( mpAudioStoppedEventHandler,
715 : rEvent,
716 : xNode,
717 : boost::bind( &EventMultiplexer::addAudioStoppedHandler,
718 0 : boost::ref( mrMultiplexer ), _1 ) );
719 0 : }
720 :
721 0 : void UserEventQueue::registerShapeClickEvent( const EventSharedPtr& rEvent,
722 : const ShapeSharedPtr& rShape )
723 : {
724 0 : ENSURE_OR_THROW(
725 : rEvent,
726 : "UserEventQueue::registerShapeClickEvent(): Invalid event" );
727 :
728 0 : if( !mpShapeClickEventHandler )
729 : {
730 : // create handler
731 : mpShapeClickEventHandler.reset(
732 : new ShapeClickEventHandler(mrCursorManager,
733 0 : mrEventQueue) );
734 :
735 : // register handler on EventMultiplexer
736 0 : mrMultiplexer.addClickHandler( mpShapeClickEventHandler, 1.0 );
737 0 : mrMultiplexer.addMouseMoveHandler( mpShapeClickEventHandler, 1.0 );
738 : }
739 :
740 0 : mpShapeClickEventHandler->addEvent( rEvent, rShape );
741 0 : }
742 :
743 : namespace {
744 : class ClickEventRegistrationFunctor
745 : {
746 : public:
747 0 : ClickEventRegistrationFunctor( EventMultiplexer& rMultiplexer,
748 : double nPrio,
749 : bool bAdvanceOnClick )
750 : : mrMultiplexer( rMultiplexer ),
751 : mnPrio(nPrio),
752 0 : mbAdvanceOnClick( bAdvanceOnClick ) {}
753 :
754 0 : void operator()( const boost::shared_ptr<ClickEventHandler>& rHandler )const
755 : {
756 : // register the handler on _two_ sources: we want the
757 : // nextEffect events, e.g. space bar, to trigger clicks, as well!
758 0 : mrMultiplexer.addClickHandler( rHandler, mnPrio );
759 0 : mrMultiplexer.addNextEffectHandler( rHandler, mnPrio );
760 :
761 : // forward advance-on-click state to newly
762 : // generated handler (that's the only reason why
763 : // we're called here)
764 0 : rHandler->setAdvanceOnClick( mbAdvanceOnClick );
765 0 : }
766 :
767 : private:
768 : EventMultiplexer& mrMultiplexer;
769 : double const mnPrio;
770 : bool const mbAdvanceOnClick;
771 : };
772 : } // anon namespace
773 :
774 0 : void UserEventQueue::registerNextEffectEvent( const EventSharedPtr& rEvent )
775 : {
776 : // TODO: better name may be mpNextEffectEventHandler? then we have
777 : // next effect (=> waiting to be started)
778 : // skip effect (skipping the currently running one)
779 : // rewind effect (rewinding back running one and waiting (again)
780 : // to be started)
781 : registerEvent( mpClickEventHandler,
782 : rEvent,
783 : ClickEventRegistrationFunctor( mrMultiplexer,
784 : 0.0 /* default prio */,
785 0 : mbAdvanceOnClick ) );
786 0 : }
787 :
788 0 : void UserEventQueue::registerSkipEffectEvent(
789 : EventSharedPtr const & pEvent,
790 : const bool bSkipTriggersNextEffect)
791 : {
792 0 : if(!mpSkipEffectEventHandler)
793 : {
794 : mpSkipEffectEventHandler.reset(
795 0 : new SkipEffectEventHandler( mrEventQueue, mrMultiplexer ) );
796 : // register the handler on _two_ sources: we want the
797 : // nextEffect events, e.g. space bar, to trigger clicks, as well!
798 : mrMultiplexer.addClickHandler( mpSkipEffectEventHandler,
799 0 : -1.0 /* prio below default */ );
800 : mrMultiplexer.addNextEffectHandler( mpSkipEffectEventHandler,
801 0 : -1.0 /* prio below default */ );
802 : // forward advance-on-click state to newly
803 : // generated handler (that's the only reason why
804 : // we're called here)
805 0 : mpSkipEffectEventHandler->setAdvanceOnClick( mbAdvanceOnClick );
806 : }
807 0 : mpSkipEffectEventHandler->setSkipTriggersNextEffect(bSkipTriggersNextEffect);
808 0 : mpSkipEffectEventHandler->addEvent( pEvent );
809 0 : }
810 :
811 0 : void UserEventQueue::registerRewindEffectEvent( EventSharedPtr const& pEvent )
812 : {
813 : registerEvent( mpRewindEffectEventHandler,
814 : pEvent,
815 : boost::bind( &EventMultiplexer::addClickHandler,
816 : boost::ref(mrMultiplexer), _1,
817 0 : -1.0 /* prio below default */ ) );
818 0 : }
819 :
820 0 : void UserEventQueue::registerShapeDoubleClickEvent(
821 : const EventSharedPtr& rEvent,
822 : const ShapeSharedPtr& rShape )
823 : {
824 0 : ENSURE_OR_THROW(
825 : rEvent,
826 : "UserEventQueue::registerShapeDoubleClickEvent(): Invalid event" );
827 :
828 0 : if( !mpShapeDoubleClickEventHandler )
829 : {
830 : // create handler
831 : mpShapeDoubleClickEventHandler.reset(
832 : new ShapeClickEventHandler(mrCursorManager,
833 0 : mrEventQueue) );
834 :
835 : // register handler on EventMultiplexer
836 : mrMultiplexer.addDoubleClickHandler( mpShapeDoubleClickEventHandler,
837 0 : 1.0 );
838 : mrMultiplexer.addMouseMoveHandler( mpShapeDoubleClickEventHandler,
839 0 : 1.0 );
840 : }
841 :
842 0 : mpShapeDoubleClickEventHandler->addEvent( rEvent, rShape );
843 0 : }
844 :
845 0 : void UserEventQueue::registerMouseEnterEvent( const EventSharedPtr& rEvent,
846 : const ShapeSharedPtr& rShape )
847 : {
848 : registerEvent( mpMouseEnterHandler,
849 : rEvent,
850 : rShape,
851 : boost::bind( &EventMultiplexer::addMouseMoveHandler,
852 : boost::ref( mrMultiplexer ), _1,
853 0 : 0.0 /* default prio */ ) );
854 0 : }
855 :
856 0 : void UserEventQueue::registerMouseLeaveEvent( const EventSharedPtr& rEvent,
857 : const ShapeSharedPtr& rShape )
858 : {
859 : registerEvent( mpMouseLeaveHandler,
860 : rEvent,
861 : rShape,
862 : boost::bind( &EventMultiplexer::addMouseMoveHandler,
863 : boost::ref( mrMultiplexer ), _1,
864 0 : 0.0 /* default prio */ ) );
865 0 : }
866 :
867 0 : void UserEventQueue::callSkipEffectEventHandler (void)
868 : {
869 : ::boost::shared_ptr<SkipEffectEventHandler> pHandler (
870 0 : ::boost::dynamic_pointer_cast<SkipEffectEventHandler>(mpSkipEffectEventHandler));
871 0 : if (pHandler)
872 0 : pHandler->skipEffect();
873 0 : }
874 :
875 : } // namespace internal
876 6 : } // namespace presentation
877 :
878 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|