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