1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <canvas/debug.hxx>
22 #include <tools/diagnose_ex.h>
24 #include <cppuhelper/basemutex.hxx>
25 #include <cppuhelper/compbase1.hxx>
26 #include <cppuhelper/factory.hxx>
27 #include <cppuhelper/implementationentry.hxx>
28 #include <cppuhelper/compbase2.hxx>
29 #include <cppuhelper/interfacecontainer.h>
30 #include <cppuhelper/exc_hlp.hxx>
32 #include <comphelper/anytostring.hxx>
33 #include <comphelper/make_shared_from_uno.hxx>
34 #include <comphelper/scopeguard.hxx>
35 #include <comphelper/optional.hxx>
36 #include <comphelper/servicedecl.hxx>
37 #include <comphelper/namecontainer.hxx>
39 #include <cppcanvas/spritecanvas.hxx>
40 #include <cppcanvas/vclfactory.hxx>
41 #include <cppcanvas/basegfxfactory.hxx>
43 #include <tools/debug.hxx>
45 #include <basegfx/point/b2dpoint.hxx>
46 #include <basegfx/polygon/b2dpolygon.hxx>
47 #include <basegfx/matrix/b2dhommatrix.hxx>
48 #include <basegfx/polygon/b2dpolygontools.hxx>
49 #include <basegfx/polygon/b2dpolypolygontools.hxx>
50 #include <basegfx/tools/canvastools.hxx>
52 #include <vcl/font.hxx>
53 #include "rtl/ref.hxx"
55 #include <com/sun/star/beans/XPropertySet.hpp>
56 #include <com/sun/star/util/XModifyListener.hpp>
57 #include <com/sun/star/util/XUpdatable.hpp>
58 #include <com/sun/star/awt/XPaintListener.hpp>
59 #include <com/sun/star/awt/SystemPointer.hpp>
60 #include <com/sun/star/animations/TransitionType.hpp>
61 #include <com/sun/star/animations/TransitionSubType.hpp>
62 #include <com/sun/star/presentation/XSlideShow.hpp>
63 #include <com/sun/star/presentation/XSlideShowListener.hpp>
64 #include <com/sun/star/lang/XServiceInfo.hpp>
65 #include <com/sun/star/lang/XServiceName.hpp>
66 #include <com/sun/star/lang/XComponent.hpp>
67 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
68 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
69 #include <com/sun/star/drawing/PointSequence.hpp>
70 #include <com/sun/star/drawing/XLayer.hpp>
71 #include <com/sun/star/drawing/XLayerSupplier.hpp>
72 #include <com/sun/star/drawing/XLayerManager.hpp>
73 #include <com/sun/star/container/XNameAccess.hpp>
75 #include "com/sun/star/uno/Reference.hxx"
76 #include <com/sun/star/loader/CannotActivateFactoryException.hpp>
78 #include "unoviewcontainer.hxx"
79 #include "transitionfactory.hxx"
80 #include "eventmultiplexer.hxx"
81 #include "usereventqueue.hxx"
82 #include "eventqueue.hxx"
83 #include "cursormanager.hxx"
84 #include "slideshowcontext.hxx"
85 #include "activitiesqueue.hxx"
86 #include "activitiesfactory.hxx"
87 #include "interruptabledelayevent.hxx"
89 #include "shapemaps.hxx"
90 #include "slideview.hxx"
92 #include "unoview.hxx"
93 #include "slidebitmap.hxx"
94 #include "rehearsetimingsactivity.hxx"
95 #include "waitsymbol.hxx"
96 #include "effectrewinder.hxx"
97 #include "framerate.hxx"
98 #include "pointersymbol.hxx"
100 #include <boost/noncopyable.hpp>
101 #include <boost/bind.hpp>
111 using namespace com::sun::star
;
112 using namespace ::slideshow::internal
;
116 /** During animations the update() method tells its caller to call it as
117 soon as possible. This gives us more time to render the next frame and
118 still maintain a steady frame rate. This class is responsible for
119 synchronizing the display of new frames and thus keeping the frame rate
122 class FrameSynchronization
125 /** Create new object with a predefined duration between two frames.
126 @param nFrameDuration
127 The preferred duration between the display of two frames in
130 FrameSynchronization (const double nFrameDuration
);
132 /** Set the current time as the time at which the current frame is
133 displayed. From this the target time of the next frame is derived.
135 void MarkCurrentFrame();
137 /** When there is time left until the next frame is due then wait.
138 Otherwise return without delay.
142 /** Activate frame synchronization when an animation is active and
143 frames are to be displayed in a steady rate. While active
144 Synchronize() will wait until the frame duration time has passed.
148 /** Deactivate frame sychronization when no animation is active and the
149 time between frames depends on user actions and other external
150 sources. While deactivated Synchronize() will return without delay.
155 /** The timer that is used for synchronization is independent from the
156 one used by SlideShowImpl: it is not paused or modified by
159 canvas::tools::ElapsedTime maTimer
;
160 /** Time between the display of frames. Enforced only when mbIsActive
163 const double mnFrameDuration
;
164 /** Time (of maTimer) when the next frame shall be displayed.
165 Synchronize() will wait until this time.
167 double mnNextFrameTargetTime
;
168 /** Synchronize() will wait only when this flag is <TRUE/>. Otherwise
169 it returns immediately.
174 /******************************************************************************
178 This class encapsulates the slideshow presentation viewer.
180 With an instance of this class, it is possible to statically
181 and dynamically show a presentation, as defined by the
182 constructor-provided draw model (represented by a sequence
183 of ::com::sun::star::drawing::XDrawPage objects).
185 It is possible to show the presentation on multiple views
186 simultaneously (e.g. for a multi-monitor setup). Since this
187 class also relies on user interaction, the corresponding
188 XSlideShowView interface provides means to register some UI
189 event listeners (mostly borrowed from awt::XWindow interface).
191 Since currently (mid 2004), OOo isn't very well suited to
192 multi-threaded rendering, this class relies on <em>very
193 frequent</em> external update() calls, which will render the
194 next frame of animations. This works as follows: after the
195 displaySlide() has been successfully called (which setup and
196 starts an actual slide show), the update() method must be
197 called until it returns false.
198 Effectively, this puts the burden of providing
199 concurrency to the clients of this class, which, as noted
200 above, is currently unavoidable with the current state of
201 affairs (I've actually tried threading here, but failed
202 miserably when using the VCL canvas as the render backend -
205 ******************************************************************************/
207 typedef cppu::WeakComponentImplHelper1
<presentation::XSlideShow
> SlideShowImplBase
;
209 typedef ::std::vector
< ::cppcanvas::PolyPolygonSharedPtr
> PolyPolygonVector
;
211 /// Maps XDrawPage for annotations persistence
212 typedef ::std::map
< ::com::sun::star::uno::Reference
<
213 ::com::sun::star::drawing::XDrawPage
>,
214 PolyPolygonVector
> PolygonMap
;
216 class SlideShowImpl
: private cppu::BaseMutex
,
217 public CursorManager
,
218 public SlideShowImplBase
221 explicit SlideShowImpl(
222 uno::Reference
<uno::XComponentContext
> const& xContext
);
224 /** Notify that the transition phase of the current slide
227 The life of a slide has three phases: the transition
228 phase, when the previous slide vanishes, and the
229 current slide becomes visible, the shape animation
230 phase, when shape effects are running, and the phase
231 after the last shape animation has ended, but before
232 the next slide transition starts.
234 This method notifies the end of the first phase.
237 When true, Slide::show() is passed a true as well, denoting
238 explicit paint of slide content. Pass false here, if e.g. a
239 slide transition has already rendered the initial slide image.
241 void notifySlideTransitionEnded( bool bPaintSlide
);
243 /** Notify that the shape animation phase of the current slide
246 The life of a slide has three phases: the transition
247 phase, when the previous slide vanishes, and the
248 current slide becomes visible, the shape animation
249 phase, when shape effects are running, and the phase
250 after the last shape animation has ended, but before
251 the next slide transition starts.
253 This method notifies the end of the second phase.
255 void notifySlideAnimationsEnded();
257 /** Notify that the slide has ended.
259 The life of a slide has three phases: the transition
260 phase, when the previous slide vanishes, and the
261 current slide becomes visible, the shape animation
262 phase, when shape effects are running, and the phase
263 after the last shape animation has ended, but before
264 the next slide transition starts.
266 This method notifies the end of the third phase.
268 void notifySlideEnded (const bool bReverse
);
270 /** Notification from eventmultiplexer that a hyperlink
273 bool notifyHyperLinkClicked( OUString
const& hyperLink
);
275 /** Notification from eventmultiplexer that an animation event has occoured.
276 This will be forewarded to all registered XSlideShowListener
278 bool handleAnimationEvent( const AnimationNodeSharedPtr
& rNode
);
282 virtual sal_Bool SAL_CALL
nextEffect() throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
283 virtual sal_Bool SAL_CALL
previousEffect() throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
284 virtual sal_Bool SAL_CALL
startShapeActivity(
285 uno::Reference
<drawing::XShape
> const& xShape
)
286 throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
287 virtual sal_Bool SAL_CALL
stopShapeActivity(
288 uno::Reference
<drawing::XShape
> const& xShape
)
289 throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
290 virtual sal_Bool SAL_CALL
pause( sal_Bool bPauseShow
)
291 throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
292 virtual uno::Reference
<drawing::XDrawPage
> SAL_CALL
getCurrentSlide()
293 throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
294 virtual void SAL_CALL
displaySlide(
295 uno::Reference
<drawing::XDrawPage
> const& xSlide
,
296 uno::Reference
<drawing::XDrawPagesSupplier
> const& xDrawPages
,
297 uno::Reference
<animations::XAnimationNode
> const& xRootNode
,
298 uno::Sequence
<beans::PropertyValue
> const& rProperties
)
299 throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
300 virtual void SAL_CALL
registerUserPaintPolygons( const ::com::sun::star::uno::Reference
< ::com::sun::star::lang::XMultiServiceFactory
>& xDocFactory
) throw (::com::sun::star::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
301 virtual sal_Bool SAL_CALL
setProperty(
302 beans::PropertyValue
const& rProperty
) throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
303 virtual sal_Bool SAL_CALL
addView(
304 uno::Reference
<presentation::XSlideShowView
> const& xView
)
305 throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
306 virtual sal_Bool SAL_CALL
removeView(
307 uno::Reference
<presentation::XSlideShowView
> const& xView
)
308 throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
309 virtual sal_Bool SAL_CALL
update( double & nNextTimeout
)
310 throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
311 virtual void SAL_CALL
addSlideShowListener(
312 uno::Reference
<presentation::XSlideShowListener
> const& xListener
)
313 throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
314 virtual void SAL_CALL
removeSlideShowListener(
315 uno::Reference
<presentation::XSlideShowListener
> const& xListener
)
316 throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
317 virtual void SAL_CALL
addShapeEventListener(
318 uno::Reference
<presentation::XShapeEventListener
> const& xListener
,
319 uno::Reference
<drawing::XShape
> const& xShape
)
320 throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
321 virtual void SAL_CALL
removeShapeEventListener(
322 uno::Reference
<presentation::XShapeEventListener
> const& xListener
,
323 uno::Reference
<drawing::XShape
> const& xShape
)
324 throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
325 virtual void SAL_CALL
setShapeCursor(
326 uno::Reference
<drawing::XShape
> const& xShape
, sal_Int16 nPointerShape
)
327 throw (uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
332 virtual bool requestCursor( sal_Int16 nCursorShape
) SAL_OVERRIDE
;
333 virtual void resetCursor() SAL_OVERRIDE
;
335 /** This is somewhat similar to displaySlide when called for the current
336 slide. It has been simplified to take advantage of that no slide
337 change takes place. Furthermore it does not show the slide
340 void redisplayCurrentSlide();
343 // WeakComponentImplHelperBase
344 virtual void SAL_CALL
disposing() SAL_OVERRIDE
;
346 bool isDisposed() const
348 return (rBHelper
.bDisposed
|| rBHelper
.bInDispose
);
352 struct SeparateListenerImpl
; friend struct SeparateListenerImpl
;
353 class PrefetchPropertiesFunc
; friend class PrefetchPropertiesFunc
;
355 /// Stop currently running show.
358 ///Find a polygons vector in maPolygons (map)
359 PolygonMap::iterator
findPolygons( uno::Reference
<drawing::XDrawPage
> const& xDrawPage
);
361 /// Creates a new slide.
362 SlideSharedPtr
makeSlide(
363 uno::Reference
<drawing::XDrawPage
> const& xDrawPage
,
364 uno::Reference
<drawing::XDrawPagesSupplier
> const& xDrawPages
,
365 uno::Reference
<animations::XAnimationNode
> const& xRootNode
);
367 /// Checks whether the given slide/animation node matches mpPrefetchSlide
369 SlideSharedPtr
const& pSlide
,
370 uno::Reference
<drawing::XDrawPage
> const& xSlide
,
371 uno::Reference
<animations::XAnimationNode
> const& xNode
)
374 return (pSlide
->getXDrawPage() == xSlide
&&
375 pSlide
->getXAnimationNode() == xNode
);
377 return (!xSlide
.is() && !xNode
.is());
380 /// Resets the current slide transition sound object with a new one:
381 SoundPlayerSharedPtr
resetSlideTransitionSound(
382 uno::Any
const& url
= uno::Any(), bool bLoopSound
= false );
384 /// stops the current slide transition sound
385 void stopSlideTransitionSound();
387 /** Prepare a slide transition
389 This method registers all necessary events and
390 activities for a slide transition.
392 @return the slide change activity, or NULL for no transition effect
394 ActivitySharedPtr
createSlideTransition(
395 const uno::Reference
< drawing::XDrawPage
>& xDrawPage
,
396 const SlideSharedPtr
& rLeavingSlide
,
397 const SlideSharedPtr
& rEnteringSlide
,
398 const EventSharedPtr
& rTransitionEndEvent
);
400 /** Request/release the wait symbol. The wait symbol is displayed when
401 there are more requests then releases. Locking the wait symbol
402 helps to avoid intermediate repaints.
404 Do not call this method directly. Use WaitSymbolLock instead.
406 void requestWaitSymbol();
407 void releaseWaitSymbol();
409 class WaitSymbolLock
{public:
410 WaitSymbolLock(SlideShowImpl
& rSlideShowImpl
) : mrSlideShowImpl(rSlideShowImpl
)
411 { mrSlideShowImpl
.requestWaitSymbol(); }
413 { mrSlideShowImpl
.releaseWaitSymbol(); }
414 private: SlideShowImpl
& mrSlideShowImpl
;
417 /// Filter requested cursor shape against hard slideshow cursors (wait, etc.)
418 sal_Int16
calcActiveCursor( sal_Int16 nCursorShape
) const;
420 /** This method is called asynchronously to finish the rewinding of an
421 effect to the previous slide that was initiated earlier.
423 void rewindEffectToPreviousSlide();
425 /// all registered views
426 UnoViewContainer maViewContainer
;
428 /// all registered slide show listeners
429 cppu::OInterfaceContainerHelper maListenerContainer
;
431 /// map of vectors, containing all registered listeners for a shape
432 ShapeEventListenerMap maShapeEventListeners
;
433 /// map of sal_Int16 values, specifying the mouse cursor for every shape
434 ShapeCursorMap maShapeCursors
;
436 //map of vector of Polygons, containing polygons drawn on each slide.
437 PolygonMap maPolygons
;
439 boost::optional
<RGBColor
> maUserPaintColor
;
441 double maUserPaintStrokeWidth
;
443 //changed for the eraser project
444 boost::optional
<bool> maEraseAllInk
;
445 boost::optional
<bool> maSwitchPenMode
;
446 boost::optional
<bool> maSwitchEraserMode
;
447 boost::optional
<sal_Int32
> maEraseInk
;
450 boost::shared_ptr
<canvas::tools::ElapsedTime
> mpPresTimer
;
451 ScreenUpdater maScreenUpdater
;
452 EventQueue maEventQueue
;
453 EventMultiplexer maEventMultiplexer
;
454 ActivitiesQueue maActivitiesQueue
;
455 UserEventQueue maUserEventQueue
;
456 SubsettableShapeManagerSharedPtr mpDummyPtr
;
458 boost::shared_ptr
<SeparateListenerImpl
> mpListener
;
460 boost::shared_ptr
<RehearseTimingsActivity
> mpRehearseTimingsActivity
;
461 boost::shared_ptr
<WaitSymbol
> mpWaitSymbol
;
463 boost::shared_ptr
<PointerSymbol
> mpPointerSymbol
;
465 /// the current slide transition sound object:
466 SoundPlayerSharedPtr mpCurrentSlideTransitionSound
;
468 uno::Reference
<uno::XComponentContext
> mxComponentContext
;
470 presentation::XTransitionFactory
> mxOptionalTransitionFactory
;
472 /// the previously running slide
473 SlideSharedPtr mpPreviousSlide
;
474 /// the currently running slide
475 SlideSharedPtr mpCurrentSlide
;
476 /// the already prefetched slide: best candidate for upcoming slide
477 SlideSharedPtr mpPrefetchSlide
;
478 /// slide to be prefetched: best candidate for upcoming slide
479 uno::Reference
<drawing::XDrawPage
> mxPrefetchSlide
;
480 /// save the XDrawPagesSupplier to retieve polygons
481 uno::Reference
<drawing::XDrawPagesSupplier
> mxDrawPagesSupplier
;
482 /// slide animation to be prefetched:
483 uno::Reference
<animations::XAnimationNode
> mxPrefetchAnimationNode
;
485 sal_Int16 mnCurrentCursor
;
487 sal_Int32 mnWaitSymbolRequestCount
;
488 bool mbAutomaticAdvancementMode
;
489 bool mbImageAnimationsAllowed
;
490 bool mbNoSlideTransitions
;
492 bool mbForceManualAdvance
;
494 bool mbSlideShowIdle
;
495 bool mbDisableAnimationZOrder
;
497 EffectRewinder maEffectRewinder
;
498 FrameSynchronization maFrameSynchronization
;
501 /** Separate event listener for animation, view and hyperlink events.
503 This handler is registered for slide animation end, view and
504 hyperlink events at the global EventMultiplexer, and forwards
505 notifications to the SlideShowImpl
507 struct SlideShowImpl::SeparateListenerImpl
: public EventHandler
,
508 public ViewRepaintHandler
,
509 public HyperlinkHandler
,
510 public AnimationEventHandler
,
511 private boost::noncopyable
513 SlideShowImpl
& mrShow
;
514 ScreenUpdater
& mrScreenUpdater
;
515 EventQueue
& mrEventQueue
;
517 SeparateListenerImpl( SlideShowImpl
& rShow
,
518 ScreenUpdater
& rScreenUpdater
,
519 EventQueue
& rEventQueue
) :
521 mrScreenUpdater( rScreenUpdater
),
522 mrEventQueue( rEventQueue
)
526 virtual bool handleEvent() SAL_OVERRIDE
528 // DON't call notifySlideAnimationsEnded()
529 // directly, but queue an event. handleEvent()
530 // might be called from e.g.
531 // showNext(), and notifySlideAnimationsEnded() must not be called
532 // in recursion. Note that the event is scheduled for the next
533 // frame so that its expensive execution does not come in between
534 // sprite hiding and shape redraw (at the end of the animation of a
535 // shape), which would cause a flicker.
536 mrEventQueue
.addEventForNextRound(
538 boost::bind( &SlideShowImpl::notifySlideAnimationsEnded
, boost::ref(mrShow
) ),
539 "SlideShowImpl::notifySlideAnimationsEnded"));
543 // ViewRepaintHandler
544 virtual void viewClobbered( const UnoViewSharedPtr
& rView
) SAL_OVERRIDE
546 // given view needs repaint, request update
547 mrScreenUpdater
.notifyUpdate(rView
, true);
551 virtual bool handleHyperlink( OUString
const& rLink
) SAL_OVERRIDE
553 return mrShow
.notifyHyperLinkClicked(rLink
);
556 // AnimationEventHandler
557 virtual bool handleAnimationEvent( const AnimationNodeSharedPtr
& rNode
) SAL_OVERRIDE
559 return mrShow
.handleAnimationEvent(rNode
);
563 SlideShowImpl::SlideShowImpl(
564 uno::Reference
<uno::XComponentContext
> const& xContext
)
565 : SlideShowImplBase(m_aMutex
),
567 maListenerContainer( m_aMutex
),
568 maShapeEventListeners(),
571 maUserPaintStrokeWidth(4.0),
572 mpPresTimer( new canvas::tools::ElapsedTime
),
573 maScreenUpdater(maViewContainer
),
574 maEventQueue( mpPresTimer
),
575 maEventMultiplexer( maEventQueue
,
577 maActivitiesQueue( mpPresTimer
),
578 maUserEventQueue( maEventMultiplexer
,
583 mpRehearseTimingsActivity(),
586 mpCurrentSlideTransitionSound(),
587 mxComponentContext( xContext
),
588 mxOptionalTransitionFactory(),
592 mxDrawPagesSupplier(),
593 mxPrefetchAnimationNode(),
594 mnCurrentCursor(awt::SystemPointer::ARROW
),
595 mnWaitSymbolRequestCount(0),
596 mbAutomaticAdvancementMode(false),
597 mbImageAnimationsAllowed( true ),
598 mbNoSlideTransitions( false ),
599 mbMouseVisible( true ),
600 mbForceManualAdvance( false ),
601 mbShowPaused( false ),
602 mbSlideShowIdle( true ),
603 mbDisableAnimationZOrder( false ),
604 maEffectRewinder(maEventMultiplexer
, maEventQueue
, maUserEventQueue
),
605 maFrameSynchronization(1.0 / FrameRate::PreferredFramesPerSecond
)
608 // keep care not constructing any UNO references to this inside ctor,
609 // shift that code to create()!
611 uno::Reference
<lang::XMultiComponentFactory
> xFactory(
612 mxComponentContext
->getServiceManager() );
618 // #i82460# try to retrieve special transition factory
619 mxOptionalTransitionFactory
.set(
620 xFactory
->createInstanceWithContext(
621 OUString("com.sun.star.presentation.TransitionFactory" ),
622 mxComponentContext
),
625 catch (loader::CannotActivateFactoryException
const&)
630 mpListener
.reset( new SeparateListenerImpl(
634 maEventMultiplexer
.addSlideAnimationsEndHandler( mpListener
);
635 maEventMultiplexer
.addViewRepaintHandler( mpListener
);
636 maEventMultiplexer
.addHyperlinkHandler( mpListener
, 0.0 );
637 maEventMultiplexer
.addAnimationStartHandler( mpListener
);
638 maEventMultiplexer
.addAnimationEndHandler( mpListener
);
641 // we are about to be disposed (someone call dispose() on us)
642 void SlideShowImpl::disposing()
644 osl::MutexGuard
const guard( m_aMutex
);
646 maEffectRewinder
.dispose();
648 // stop slide transition sound, if any:
649 stopSlideTransitionSound();
651 mxComponentContext
.clear();
653 if( mpCurrentSlideTransitionSound
)
655 mpCurrentSlideTransitionSound
->dispose();
656 mpCurrentSlideTransitionSound
.reset();
659 mpWaitSymbol
.reset();
660 mpPointerSymbol
.reset();
662 if( mpRehearseTimingsActivity
)
664 mpRehearseTimingsActivity
->dispose();
665 mpRehearseTimingsActivity
.reset();
670 maEventMultiplexer
.removeSlideAnimationsEndHandler(mpListener
);
671 maEventMultiplexer
.removeViewRepaintHandler(mpListener
);
672 maEventMultiplexer
.removeHyperlinkHandler(mpListener
);
673 maEventMultiplexer
.removeAnimationStartHandler( mpListener
);
674 maEventMultiplexer
.removeAnimationEndHandler( mpListener
);
679 maUserEventQueue
.clear();
680 maActivitiesQueue
.clear();
681 maEventMultiplexer
.clear();
682 maEventQueue
.clear();
684 maShapeCursors
.clear();
685 maShapeEventListeners
.clear();
687 // send all listeners a disposing() that we are going down:
688 maListenerContainer
.disposeAndClear(
689 lang::EventObject( static_cast<cppu::OWeakObject
*>(this) ) );
691 maViewContainer
.dispose();
694 mxPrefetchAnimationNode
.clear();
695 mxPrefetchSlide
.clear();
696 mpPrefetchSlide
.reset();
697 mpCurrentSlide
.reset();
698 mpPreviousSlide
.reset();
701 /// stops the current slide transition sound
702 void SlideShowImpl::stopSlideTransitionSound()
704 if (mpCurrentSlideTransitionSound
)
706 mpCurrentSlideTransitionSound
->stopPlayback();
707 mpCurrentSlideTransitionSound
->dispose();
708 mpCurrentSlideTransitionSound
.reset();
712 SoundPlayerSharedPtr
SlideShowImpl::resetSlideTransitionSound( const uno::Any
& rSound
, bool bLoopSound
)
714 bool bStopSound
= false;
717 if( !(rSound
>>= bStopSound
) )
721 if( !bStopSound
&& url
.isEmpty() )
722 return SoundPlayerSharedPtr();
724 stopSlideTransitionSound();
730 mpCurrentSlideTransitionSound
= SoundPlayer::create(
731 maEventMultiplexer
, url
, mxComponentContext
);
732 mpCurrentSlideTransitionSound
->setPlaybackLoop( bLoopSound
);
734 catch (lang::NoSupportException
const&)
736 // catch possible exceptions from SoundPlayer, since
737 // being not able to playback the sound is not a hard
738 // error here (still, the slide transition should be
742 return mpCurrentSlideTransitionSound
;
745 ActivitySharedPtr
SlideShowImpl::createSlideTransition(
746 const uno::Reference
< drawing::XDrawPage
>& xDrawPage
,
747 const SlideSharedPtr
& rLeavingSlide
,
748 const SlideSharedPtr
& rEnteringSlide
,
749 const EventSharedPtr
& rTransitionEndEvent
)
751 ENSURE_OR_THROW( !maViewContainer
.empty(),
752 "createSlideTransition(): No views" );
753 ENSURE_OR_THROW( rEnteringSlide
,
754 "createSlideTransition(): No entering slide" );
756 // return empty transition, if slide transitions
758 if (mbNoSlideTransitions
)
759 return ActivitySharedPtr();
761 // retrieve slide change parameters from XDrawPage
762 uno::Reference
< beans::XPropertySet
> xPropSet( xDrawPage
,
767 OSL_TRACE( "createSlideTransition(): "
768 "Slide has no PropertySet - assuming no transition\n" );
769 return ActivitySharedPtr();
772 sal_Int16
nTransitionType(0);
773 if( !getPropertyValue( nTransitionType
,
777 OSL_TRACE( "createSlideTransition(): "
778 "Could not extract slide transition type from XDrawPage - assuming no transition\n" );
779 return ActivitySharedPtr();
782 sal_Int16
nTransitionSubType(0);
783 if( !getPropertyValue( nTransitionSubType
,
785 "TransitionSubtype") )
787 OSL_TRACE( "createSlideTransition(): "
788 "Could not extract slide transition subtype from XDrawPage - assuming no transition\n" );
789 return ActivitySharedPtr();
792 bool bTransitionDirection(false);
793 if( !getPropertyValue( bTransitionDirection
,
795 "TransitionDirection") )
797 OSL_TRACE( "createSlideTransition(): "
798 "Could not extract slide transition direction from XDrawPage - assuming default direction\n" );
801 sal_Int32
aUnoColor(0);
802 if( !getPropertyValue( aUnoColor
,
804 "TransitionFadeColor") )
806 OSL_TRACE( "createSlideTransition(): "
807 "Could not extract slide transition fade color from XDrawPage - assuming black\n" );
810 const RGBColor
aTransitionFadeColor( unoColor2RGBColor( aUnoColor
));
813 bool bLoopSound
= false;
815 if( !getPropertyValue( aSound
, xPropSet
, "Sound") )
816 OSL_TRACE( "createSlideTransition(): Could not determine transition sound effect URL from XDrawPage - using no sound" );
818 if( !getPropertyValue( bLoopSound
, xPropSet
, "LoopSound" ) )
819 OSL_TRACE( "createSlideTransition(): Could not get slide property 'LoopSound' - using no sound" );
821 NumberAnimationSharedPtr
pTransition(
822 TransitionFactory::createSlideTransition(
828 mxOptionalTransitionFactory
,
831 bTransitionDirection
,
832 aTransitionFadeColor
,
833 resetSlideTransitionSound( aSound
, bLoopSound
) ));
836 return ActivitySharedPtr(); // no transition effect has been
837 // generated. Normally, that means
838 // that simply no transition is
839 // set on this slide.
841 double nTransitionDuration(0.0);
842 if( !getPropertyValue( nTransitionDuration
,
844 "TransitionDuration") )
846 OSL_TRACE( "createSlideTransition(): "
847 "Could not extract slide transition duration from XDrawPage - assuming no transition\n" );
848 return ActivitySharedPtr();
851 sal_Int32
nMinFrames(5);
852 if( !getPropertyValue( nMinFrames
,
854 "MinimalFrameNumber") )
856 OSL_TRACE( "createSlideTransition(): "
857 "No minimal number of frames given - assuming 5\n" );
860 // prefetch slide transition bitmaps, but postpone it after
861 // displaySlide() has finished - sometimes, view size has not yet
862 // reached final size
863 maEventQueue
.addEvent(
866 &::slideshow::internal::Animation::prefetch
,
868 AnimatableShapeSharedPtr(),
869 ShapeAttributeLayerSharedPtr()),
870 "Animation::prefetch"));
872 return ActivitySharedPtr(
873 ActivitiesFactory::createSimpleActivity(
874 ActivitiesFactory::CommonParameters(
881 boost::optional
<double>(1.0),
885 basegfx::B2DSize( rEnteringSlide
->getSlideSize() ) ),
890 PolygonMap::iterator
SlideShowImpl::findPolygons( uno::Reference
<drawing::XDrawPage
> const& xDrawPage
)
892 // TODO(P2) : Optimze research in the map.
894 PolygonMap::iterator aIter
=maPolygons
.begin();
896 while(aIter
!=maPolygons
.end() && !bFound
)
898 if(aIter
->first
== xDrawPage
)
907 SlideSharedPtr
SlideShowImpl::makeSlide(
908 uno::Reference
<drawing::XDrawPage
> const& xDrawPage
,
909 uno::Reference
<drawing::XDrawPagesSupplier
> const& xDrawPages
,
910 uno::Reference
<animations::XAnimationNode
> const& xRootNode
)
912 if( !xDrawPage
.is() )
913 return SlideSharedPtr();
915 //Retrieve polygons for the current slide
916 PolygonMap::iterator aIter
;
917 aIter
= findPolygons(xDrawPage
);
919 const SlideSharedPtr
pSlide( createSlide(xDrawPage
,
930 maShapeEventListeners
,
932 (aIter
!= maPolygons
.end()) ? aIter
->second
: PolyPolygonVector(),
933 maUserPaintColor
? *maUserPaintColor
: RGBColor(),
934 maUserPaintStrokeWidth
,
936 mbImageAnimationsAllowed
,
937 mbDisableAnimationZOrder
) );
939 // prefetch show content (reducing latency for slide
940 // bitmap and effect start later on)
946 void SlideShowImpl::requestWaitSymbol()
948 ++mnWaitSymbolRequestCount
;
949 OSL_ASSERT(mnWaitSymbolRequestCount
>0);
951 if (mnWaitSymbolRequestCount
== 1)
955 // fall back to cursor
956 requestCursor(calcActiveCursor(mnCurrentCursor
));
959 mpWaitSymbol
->show();
963 void SlideShowImpl::releaseWaitSymbol()
965 --mnWaitSymbolRequestCount
;
966 OSL_ASSERT(mnWaitSymbolRequestCount
>=0);
968 if (mnWaitSymbolRequestCount
== 0)
972 // fall back to cursor
973 requestCursor(calcActiveCursor(mnCurrentCursor
));
976 mpWaitSymbol
->hide();
980 sal_Int16
SlideShowImpl::calcActiveCursor( sal_Int16 nCursorShape
) const
982 if( mnWaitSymbolRequestCount
>0 && !mpWaitSymbol
) // enforce wait cursor
983 nCursorShape
= awt::SystemPointer::WAIT
;
984 else if( !mbMouseVisible
) // enforce INVISIBLE
985 nCursorShape
= awt::SystemPointer::INVISIBLE
;
986 else if( maUserPaintColor
&&
987 nCursorShape
== awt::SystemPointer::ARROW
)
988 nCursorShape
= awt::SystemPointer::PEN
;
993 void SlideShowImpl::stopShow()
995 // Force-end running animation
996 // ===========================
999 mpCurrentSlide
->hide();
1000 //Register polygons in the map
1001 if(findPolygons(mpCurrentSlide
->getXDrawPage()) != maPolygons
.end())
1002 maPolygons
.erase(mpCurrentSlide
->getXDrawPage());
1004 maPolygons
.insert(make_pair(mpCurrentSlide
->getXDrawPage(),mpCurrentSlide
->getPolygons()));
1008 maEventQueue
.clear();
1009 maActivitiesQueue
.clear();
1011 // Attention: we MUST clear the user event queue here,
1012 // this is because the current slide might have registered
1013 // shape events (click or enter/leave), which might
1014 // otherwise dangle forever in the queue (because of the
1015 // shared ptr nature). If someone needs to change this:
1016 // somehow unregister those shapes at the user event queue
1017 // on notifySlideEnded().
1018 maUserEventQueue
.clear();
1020 // re-enable automatic effect advancement
1021 // (maEventQueue.clear() above might have killed
1022 // maEventMultiplexer's tick events)
1023 if (mbAutomaticAdvancementMode
)
1025 // toggle automatic mode (enabling just again is
1026 // ignored by EventMultiplexer)
1027 maEventMultiplexer
.setAutomaticMode( false );
1028 maEventMultiplexer
.setAutomaticMode( true );
1032 class SlideShowImpl::PrefetchPropertiesFunc
1035 PrefetchPropertiesFunc( SlideShowImpl
* that_
,
1036 bool& rbSkipAllMainSequenceEffects
,
1037 bool& rbSkipSlideTransition
)
1038 : mpSlideShowImpl(that_
),
1039 mrbSkipAllMainSequenceEffects(rbSkipAllMainSequenceEffects
),
1040 mrbSkipSlideTransition(rbSkipSlideTransition
)
1043 void operator()( beans::PropertyValue
const& rProperty
) const {
1044 if (rProperty
.Name
== "Prefetch" )
1046 uno::Sequence
<uno::Any
> seq
;
1047 if ((rProperty
.Value
>>= seq
) && seq
.getLength() == 2)
1049 seq
[0] >>= mpSlideShowImpl
->mxPrefetchSlide
;
1050 seq
[1] >>= mpSlideShowImpl
->mxPrefetchAnimationNode
;
1053 else if ( rProperty
.Name
== "SkipAllMainSequenceEffects" )
1055 rProperty
.Value
>>= mrbSkipAllMainSequenceEffects
;
1057 else if ( rProperty
.Name
== "SkipSlideTransition" )
1059 rProperty
.Value
>>= mrbSkipSlideTransition
;
1063 OSL_FAIL( OUStringToOString(
1064 rProperty
.Name
, RTL_TEXTENCODING_UTF8
).getStr() );
1068 SlideShowImpl
*const mpSlideShowImpl
;
1069 bool& mrbSkipAllMainSequenceEffects
;
1070 bool& mrbSkipSlideTransition
;
1073 void SlideShowImpl::displaySlide(
1074 uno::Reference
<drawing::XDrawPage
> const& xSlide
,
1075 uno::Reference
<drawing::XDrawPagesSupplier
> const& xDrawPages
,
1076 uno::Reference
<animations::XAnimationNode
> const& xRootNode
,
1077 uno::Sequence
<beans::PropertyValue
> const& rProperties
)
1078 throw (uno::RuntimeException
, std::exception
)
1080 osl::MutexGuard
const guard( m_aMutex
);
1085 maEffectRewinder
.setRootAnimationNode(xRootNode
);
1087 // precondition: must only be called from the main thread!
1088 DBG_TESTSOLARMUTEX();
1090 mxDrawPagesSupplier
= xDrawPages
;
1092 stopShow(); // MUST call that: results in
1093 // maUserEventQueue.clear(). What's more,
1094 // stopShow()'s currSlide->hide() call is
1095 // now also required, notifySlideEnded()
1097 // unconditionally. Otherwise, genuine
1098 // shape animations (drawing layer and
1099 // GIF) will not be stopped.
1101 bool bSkipAllMainSequenceEffects (false);
1102 bool bSkipSlideTransition (false);
1103 std::for_each( rProperties
.getConstArray(),
1104 rProperties
.getConstArray() + rProperties
.getLength(),
1105 PrefetchPropertiesFunc(this, bSkipAllMainSequenceEffects
, bSkipSlideTransition
) );
1107 OSL_ENSURE( !maViewContainer
.empty(), "### no views!" );
1108 if (maViewContainer
.empty())
1111 // this here might take some time
1113 WaitSymbolLock
aLock (*this);
1115 mpPreviousSlide
= mpCurrentSlide
;
1116 mpCurrentSlide
.reset();
1118 if (matches( mpPrefetchSlide
, xSlide
, xRootNode
))
1120 // prefetched slide matches:
1121 mpCurrentSlide
= mpPrefetchSlide
;
1124 mpCurrentSlide
= makeSlide( xSlide
, xDrawPages
, xRootNode
);
1126 OSL_ASSERT( mpCurrentSlide
);
1129 basegfx::B2DSize oldSlideSize
;
1130 if( mpPreviousSlide
)
1131 oldSlideSize
= basegfx::B2DSize( mpPreviousSlide
->getSlideSize() );
1133 basegfx::B2DSize
const slideSize( mpCurrentSlide
->getSlideSize() );
1135 // push new transformation to all views, if size changed
1136 if( !mpPreviousSlide
|| oldSlideSize
!= slideSize
)
1138 std::for_each( maViewContainer
.begin(),
1139 maViewContainer
.end(),
1140 boost::bind( &View::setViewSize
, _1
,
1141 boost::cref(slideSize
) ));
1143 // explicitly notify view change here,
1144 // because transformation might have changed:
1145 // optimization, this->notifyViewChange() would
1146 // repaint slide which is not necessary.
1147 maEventMultiplexer
.notifyViewsChanged();
1150 // create slide transition, and add proper end event
1151 // (which then starts the slide effects
1152 // via CURRENT_SLIDE.show())
1153 ActivitySharedPtr
pSlideChangeActivity (
1154 createSlideTransition(
1155 mpCurrentSlide
->getXDrawPage(),
1160 &SlideShowImpl::notifySlideTransitionEnded
,
1163 "SlideShowImpl::notifySlideTransitionEnded")));
1165 if (bSkipSlideTransition
)
1167 // The transition activity was created for the side effects
1168 // (like sound transitions). Because we want to skip the
1169 // acutual transition animation we do not need the activity
1171 pSlideChangeActivity
.reset();
1174 if (pSlideChangeActivity
)
1176 // factory generated a slide transition - activate it!
1177 maActivitiesQueue
.addActivity( pSlideChangeActivity
);
1181 // no transition effect on this slide - schedule slide
1182 // effect start event right away.
1183 maEventQueue
.addEvent(
1186 &SlideShowImpl::notifySlideTransitionEnded
,
1189 "SlideShowImpl::notifySlideTransitionEnded"));
1194 maListenerContainer
.forEach
<presentation::XSlideShowListener
>(
1195 boost::mem_fn( &presentation::XSlideShowListener::slideTransitionStarted
) );
1197 // We are currently rewinding an effect. This lead us from the next
1198 // slide to this one. To complete this we have to play back all main
1199 // sequence effects on this slide.
1200 if (bSkipAllMainSequenceEffects
)
1201 maEffectRewinder
.skipAllMainSequenceEffects();
1204 void SlideShowImpl::redisplayCurrentSlide()
1206 osl::MutexGuard
const guard( m_aMutex
);
1211 // precondition: must only be called from the main thread!
1212 DBG_TESTSOLARMUTEX();
1215 OSL_ENSURE( !maViewContainer
.empty(), "### no views!" );
1216 if (maViewContainer
.empty())
1219 // No transition effect on this slide - schedule slide
1220 // effect start event right away.
1221 maEventQueue
.addEvent(
1224 &SlideShowImpl::notifySlideTransitionEnded
,
1227 "SlideShowImpl::notifySlideTransitionEnded"));
1229 maListenerContainer
.forEach
<presentation::XSlideShowListener
>(
1230 boost::mem_fn( &presentation::XSlideShowListener::slideTransitionStarted
) );
1233 sal_Bool
SlideShowImpl::nextEffect() throw (uno::RuntimeException
, std::exception
)
1235 osl::MutexGuard
const guard( m_aMutex
);
1240 // precondition: must only be called from the main thread!
1241 DBG_TESTSOLARMUTEX();
1246 return maEventMultiplexer
.notifyNextEffect();
1249 sal_Bool
SlideShowImpl::previousEffect() throw (uno::RuntimeException
, std::exception
)
1251 osl::MutexGuard
const guard( m_aMutex
);
1256 // precondition: must only be called from the main thread!
1257 DBG_TESTSOLARMUTEX();
1263 return maEffectRewinder
.rewind(
1264 maScreenUpdater
.createLock(false),
1265 ::boost::bind
<void>(::boost::mem_fn(&SlideShowImpl::redisplayCurrentSlide
), this),
1266 ::boost::bind
<void>(::boost::mem_fn(&SlideShowImpl::rewindEffectToPreviousSlide
), this));
1270 void SlideShowImpl::rewindEffectToPreviousSlide()
1272 // Show the wait symbol now and prevent it from showing temporary slide
1273 // content while effects are played back.
1274 WaitSymbolLock
aLock (*this);
1276 // A previous call to EffectRewinder::Rewind could not rewind the current
1277 // effect because there are no effects on the current slide or none has
1278 // yet been displayed. Go to the previous slide.
1279 notifySlideEnded(true);
1281 // Process pending events once more in order to have the following
1282 // screen update show the last effect. Not sure whether this should be
1284 maEventQueue
.forceEmpty();
1286 // We have to call the screen updater before the wait symbol is turned
1287 // off. Otherwise the wait symbol would force the display of an
1288 // intermediate state of the slide (before the effects are replayed.)
1289 maScreenUpdater
.commitUpdates();
1292 sal_Bool
SlideShowImpl::startShapeActivity(
1293 uno::Reference
<drawing::XShape
> const& /*xShape*/ )
1294 throw (uno::RuntimeException
, std::exception
)
1296 osl::MutexGuard
const guard( m_aMutex
);
1298 // precondition: must only be called from the main thread!
1299 DBG_TESTSOLARMUTEX();
1302 OSL_FAIL( "not yet implemented!" );
1306 sal_Bool
SlideShowImpl::stopShapeActivity(
1307 uno::Reference
<drawing::XShape
> const& /*xShape*/ )
1308 throw (uno::RuntimeException
, std::exception
)
1310 osl::MutexGuard
const guard( m_aMutex
);
1312 // precondition: must only be called from the main thread!
1313 DBG_TESTSOLARMUTEX();
1316 OSL_FAIL( "not yet implemented!" );
1320 sal_Bool
SlideShowImpl::pause( sal_Bool bPauseShow
)
1321 throw (uno::RuntimeException
, std::exception
)
1323 osl::MutexGuard
const guard( m_aMutex
);
1328 // precondition: must only be called from the main thread!
1329 DBG_TESTSOLARMUTEX();
1332 mpPresTimer
->pauseTimer();
1334 mpPresTimer
->continueTimer();
1336 maEventMultiplexer
.notifyPauseMode(bPauseShow
);
1338 mbShowPaused
= bPauseShow
;
1342 uno::Reference
<drawing::XDrawPage
> SlideShowImpl::getCurrentSlide()
1343 throw (uno::RuntimeException
, std::exception
)
1345 osl::MutexGuard
const guard( m_aMutex
);
1348 return uno::Reference
<drawing::XDrawPage
>();
1350 // precondition: must only be called from the main thread!
1351 DBG_TESTSOLARMUTEX();
1354 return mpCurrentSlide
->getXDrawPage();
1356 return uno::Reference
<drawing::XDrawPage
>();
1359 sal_Bool
SlideShowImpl::addView(
1360 uno::Reference
<presentation::XSlideShowView
> const& xView
)
1361 throw (uno::RuntimeException
, std::exception
)
1363 osl::MutexGuard
const guard( m_aMutex
);
1368 // precondition: must only be called from the main thread!
1369 DBG_TESTSOLARMUTEX();
1371 // first of all, check if view has a valid canvas
1372 ENSURE_OR_RETURN_FALSE( xView
.is(), "addView(): Invalid view" );
1373 ENSURE_OR_RETURN_FALSE( xView
->getCanvas().is(),
1374 "addView(): View does not provide a valid canvas" );
1376 UnoViewSharedPtr
const pView( createSlideView(
1379 maEventMultiplexer
));
1380 if (!maViewContainer
.addView( pView
))
1381 return false; // view already added
1383 // initialize view content
1384 // =======================
1388 // set view transformation
1389 const basegfx::B2ISize slideSize
= mpCurrentSlide
->getSlideSize();
1390 pView
->setViewSize( basegfx::B2DSize( slideSize
.getX(),
1391 slideSize
.getY() ) );
1394 // clear view area (since its newly added,
1395 // we need a clean slate)
1398 // broadcast newly added view
1399 maEventMultiplexer
.notifyViewAdded( pView
);
1401 // set current mouse ptr
1402 pView
->setCursorShape( calcActiveCursor(mnCurrentCursor
) );
1407 sal_Bool
SlideShowImpl::removeView(
1408 uno::Reference
<presentation::XSlideShowView
> const& xView
)
1409 throw (uno::RuntimeException
, std::exception
)
1411 osl::MutexGuard
const guard( m_aMutex
);
1413 // precondition: must only be called from the main thread!
1414 DBG_TESTSOLARMUTEX();
1416 ENSURE_OR_RETURN_FALSE( xView
.is(), "removeView(): Invalid view" );
1418 UnoViewSharedPtr
const pView( maViewContainer
.removeView( xView
) );
1420 return false; // view was not added in the first place
1422 // remove view from EventMultiplexer (mouse events etc.)
1423 maEventMultiplexer
.notifyViewRemoved( pView
);
1430 void SlideShowImpl::registerUserPaintPolygons( const uno::Reference
< lang::XMultiServiceFactory
>& xDocFactory
) throw (uno::RuntimeException
, std::exception
)
1432 //Retrieve Polygons if user ends presentation by context menu
1435 if(findPolygons(mpCurrentSlide
->getXDrawPage()) != maPolygons
.end())
1436 maPolygons
.erase(mpCurrentSlide
->getXDrawPage());
1438 maPolygons
.insert(make_pair(mpCurrentSlide
->getXDrawPage(),mpCurrentSlide
->getPolygons()));
1441 //Creating the layer for shapes
1442 // query for the XLayerManager
1443 uno::Reference
< drawing::XLayerSupplier
> xLayerSupplier(xDocFactory
, uno::UNO_QUERY
);
1444 uno::Reference
< container::XNameAccess
> xNameAccess
= xLayerSupplier
->getLayerManager();
1446 uno::Reference
< drawing::XLayerManager
> xLayerManager(xNameAccess
, uno::UNO_QUERY
);
1447 // create a layer and set its properties
1448 uno::Reference
< drawing::XLayer
> xDrawnInSlideshow
= xLayerManager
->insertNewByIndex(xLayerManager
->getCount());
1449 uno::Reference
< beans::XPropertySet
> xLayerPropSet(xDrawnInSlideshow
, uno::UNO_QUERY
);
1451 //Layer Name which enables to catch annotations
1452 OUString layerName
= "DrawnInSlideshow";
1453 uno::Any aPropLayer
;
1455 aPropLayer
<<= layerName
;
1456 xLayerPropSet
->setPropertyValue("Name", aPropLayer
);
1458 aPropLayer
<<= true;
1459 xLayerPropSet
->setPropertyValue("IsVisible", aPropLayer
);
1461 aPropLayer
<<= false;
1462 xLayerPropSet
->setPropertyValue("IsLocked", aPropLayer
);
1464 PolygonMap::iterator aIter
=maPolygons
.begin();
1466 PolyPolygonVector aPolygons
;
1467 ::cppcanvas::PolyPolygonSharedPtr pPolyPoly
;
1468 ::basegfx::B2DPolyPolygon b2DPolyPoly
;
1470 //Register polygons for each slide
1471 while(aIter
!=maPolygons
.end())
1473 aPolygons
= aIter
->second
;
1474 //Get shapes for the slide
1475 ::com::sun::star::uno::Reference
< ::com::sun::star::drawing::XShapes
> Shapes(aIter
->first
, ::com::sun::star::uno::UNO_QUERY
);
1476 //Retrieve polygons for one slide
1477 for( PolyPolygonVector::iterator aIterPoly
=aPolygons
.begin(),
1478 aEnd
=aPolygons
.end();
1479 aIterPoly
!=aEnd
; ++aIterPoly
)
1481 pPolyPoly
= (*aIterPoly
);
1482 b2DPolyPoly
= ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(pPolyPoly
->getUNOPolyPolygon());
1484 //Normally there is only one polygon
1485 for(sal_uInt32 i
=0; i
< b2DPolyPoly
.count();i
++)
1487 const ::basegfx::B2DPolygon
& aPoly
= b2DPolyPoly
.getB2DPolygon(i
);
1488 sal_uInt32 nPoints
= aPoly
.count();
1492 //create the PolyLineShape
1493 uno::Reference
< uno::XInterface
> polyshape(xDocFactory
->createInstance(
1494 OUString("com.sun.star.drawing.PolyLineShape") ) );
1495 uno::Reference
< drawing::XShape
> rPolyShape(polyshape
, uno::UNO_QUERY
);
1497 //Add the shape to the slide
1498 Shapes
->add(rPolyShape
);
1500 //Retrieve shape properties
1501 uno::Reference
< beans::XPropertySet
> aXPropSet
= uno::Reference
< beans::XPropertySet
>( rPolyShape
, uno::UNO_QUERY
);
1502 //Construct a sequence of points sequence
1503 drawing::PointSequenceSequence aRetval
;
1504 //Create only one sequence for one polygon
1505 aRetval
.realloc( 1 );
1506 // Retrieve the sequence of points from aRetval
1507 drawing::PointSequence
* pOuterSequence
= aRetval
.getArray();
1508 // Create 2 points in this sequence
1509 pOuterSequence
->realloc(nPoints
);
1510 // Get these points which are in an array
1511 awt::Point
* pInnerSequence
= pOuterSequence
->getArray();
1512 for( sal_uInt32 n
= 0; n
< nPoints
; n
++ )
1514 //Create a point from the polygon
1515 *pInnerSequence
++ = awt::Point(
1516 basegfx::fround(aPoly
.getB2DPoint(n
).getX()),
1517 basegfx::fround(aPoly
.getB2DPoint(n
).getY()));
1520 //Fill the properties
1521 //Give the built PointSequenceSequence.
1524 aXPropSet
->setPropertyValue("PolyPolygon", aParam
);
1526 //LineStyle : SOLID by default
1528 drawing::LineStyle eLS
;
1529 eLS
= drawing::LineStyle_SOLID
;
1531 aXPropSet
->setPropertyValue("LineStyle", aAny
);
1534 sal_uInt32 nLineColor
;
1535 nLineColor
= pPolyPoly
->getRGBALineColor();
1536 //Transform polygon color from RRGGBBAA to AARRGGBB
1537 aAny
<<= RGBAColor2UnoColor(nLineColor
);
1538 aXPropSet
->setPropertyValue("LineColor", aAny
);
1542 fLineWidth
= pPolyPoly
->getStrokeWidth();
1543 aAny
<<= (sal_Int32
)fLineWidth
;
1544 aXPropSet
->setPropertyValue("LineWidth", aAny
);
1546 // make polygons special
1547 xLayerManager
->attachShapeToLayer(rPolyShape
, xDrawnInSlideshow
);
1555 sal_Bool
SlideShowImpl::setProperty( beans::PropertyValue
const& rProperty
)
1556 throw (uno::RuntimeException
, std::exception
)
1558 osl::MutexGuard
const guard( m_aMutex
);
1563 // precondition: must only be called from the main thread!
1564 DBG_TESTSOLARMUTEX();
1566 if ( rProperty
.Name
== "AutomaticAdvancement" )
1568 double nTimeout(0.0);
1569 mbAutomaticAdvancementMode
= (rProperty
.Value
>>= nTimeout
);
1570 if (mbAutomaticAdvancementMode
)
1572 maEventMultiplexer
.setAutomaticTimeout( nTimeout
);
1574 maEventMultiplexer
.setAutomaticMode( mbAutomaticAdvancementMode
);
1578 if ( rProperty
.Name
== "UserPaintColor" )
1580 sal_Int32
nColor(0);
1581 if (rProperty
.Value
>>= nColor
)
1583 OSL_ENSURE( mbMouseVisible
,
1584 "setProperty(): User paint overrides invisible mouse" );
1586 // enable user paint
1587 maUserPaintColor
.reset( unoColor2RGBColor( nColor
) );
1588 if( mpCurrentSlide
&& !mpCurrentSlide
->isPaintOverlayActive() )
1589 mpCurrentSlide
->enablePaintOverlay();
1591 maEventMultiplexer
.notifyUserPaintColor( *maUserPaintColor
);
1595 // disable user paint
1596 maUserPaintColor
.reset();
1597 maEventMultiplexer
.notifyUserPaintDisabled();
1598 if( mpCurrentSlide
)
1599 mpCurrentSlide
->disablePaintOverlay();
1607 //adding support for erasing features in UserPaintOverlay
1608 if ( rProperty
.Name
== "EraseAllInk" )
1610 bool nEraseAllInk(false);
1611 if (rProperty
.Value
>>= nEraseAllInk
)
1613 OSL_ENSURE( mbMouseVisible
,
1614 "setProperty(): User paint overrides invisible mouse" );
1616 // enable user paint
1617 maEraseAllInk
.reset( nEraseAllInk
);
1618 maEventMultiplexer
.notifyEraseAllInk( *maEraseAllInk
);
1624 if ( rProperty
.Name
== "SwitchPenMode" )
1626 bool nSwitchPenMode(false);
1627 if (rProperty
.Value
>>= nSwitchPenMode
)
1629 OSL_ENSURE( mbMouseVisible
,
1630 "setProperty(): User paint overrides invisible mouse" );
1633 // Switch to Pen Mode
1634 maSwitchPenMode
.reset( nSwitchPenMode
);
1635 maEventMultiplexer
.notifySwitchPenMode();
1641 if ( rProperty
.Name
== "SwitchEraserMode" )
1643 bool nSwitchEraserMode(false);
1644 if (rProperty
.Value
>>= nSwitchEraserMode
)
1646 OSL_ENSURE( mbMouseVisible
,
1647 "setProperty(): User paint overrides invisible mouse" );
1648 if(nSwitchEraserMode
){
1649 // switch to Eraser mode
1650 maSwitchEraserMode
.reset( nSwitchEraserMode
);
1651 maEventMultiplexer
.notifySwitchEraserMode();
1658 if ( rProperty
.Name
== "EraseInk" )
1660 sal_Int32
nEraseInk(100);
1661 if (rProperty
.Value
>>= nEraseInk
)
1663 OSL_ENSURE( mbMouseVisible
,
1664 "setProperty(): User paint overrides invisible mouse" );
1666 // enable user paint
1667 maEraseInk
.reset( nEraseInk
);
1668 maEventMultiplexer
.notifyEraseInkWidth( *maEraseInk
);
1674 // new Property for pen's width
1675 if ( rProperty
.Name
== "UserPaintStrokeWidth" )
1678 if (rProperty
.Value
>>= nWidth
)
1680 OSL_ENSURE( mbMouseVisible
,"setProperty(): User paint overrides invisible mouse" );
1681 // enable user paint stroke width
1682 maUserPaintStrokeWidth
= nWidth
;
1683 maEventMultiplexer
.notifyUserPaintStrokeWidth( maUserPaintStrokeWidth
);
1689 if ( rProperty
.Name
== "AdvanceOnClick" )
1691 bool bAdvanceOnClick
= false;
1692 if (! (rProperty
.Value
>>= bAdvanceOnClick
))
1694 maUserEventQueue
.setAdvanceOnClick( bAdvanceOnClick
);
1698 if ( rProperty
.Name
== "DisableAnimationZOrder" )
1700 bool bDisableAnimationZOrder
= false;
1701 if (! (rProperty
.Value
>>= bDisableAnimationZOrder
))
1703 mbDisableAnimationZOrder
= bDisableAnimationZOrder
;
1707 if ( rProperty
.Name
== "ImageAnimationsAllowed" )
1709 if (! (rProperty
.Value
>>= mbImageAnimationsAllowed
))
1712 // TODO(F3): Forward to slides!
1716 if ( rProperty
.Name
== "MouseVisible" )
1718 if (! (rProperty
.Value
>>= mbMouseVisible
))
1721 requestCursor(mnCurrentCursor
);
1726 if ( rProperty
.Name
== "ForceManualAdvance" )
1728 return (rProperty
.Value
>>= mbForceManualAdvance
);
1731 if ( rProperty
.Name
== "RehearseTimings" )
1733 bool bRehearseTimings
= false;
1734 if (! (rProperty
.Value
>>= bRehearseTimings
))
1737 if (bRehearseTimings
)
1739 // TODO(Q3): Move to slide
1740 mpRehearseTimingsActivity
= RehearseTimingsActivity::create(
1750 mxComponentContext
) );
1752 else if (mpRehearseTimingsActivity
)
1754 // removes timer from all views:
1755 mpRehearseTimingsActivity
->dispose();
1756 mpRehearseTimingsActivity
.reset();
1761 if ( rProperty
.Name
== "WaitSymbolBitmap" )
1763 uno::Reference
<rendering::XBitmap
> xBitmap
;
1764 if (! (rProperty
.Value
>>= xBitmap
))
1767 mpWaitSymbol
= WaitSymbol::create( xBitmap
,
1775 if ( rProperty
.Name
== "PointerSymbolBitmap" )
1777 uno::Reference
<rendering::XBitmap
> xBitmap
;
1778 if (! (rProperty
.Value
>>= xBitmap
))
1781 mpPointerSymbol
= PointerSymbol::create( xBitmap
,
1789 if ( rProperty
.Name
== "PointerVisible" )
1792 if (!(rProperty
.Value
>>= visible
))
1795 mpPointerSymbol
->setVisible(visible
);
1799 if ( rProperty
.Name
== "PointerPosition")
1801 ::com::sun::star::geometry::RealPoint2D pos
;
1802 if (! (rProperty
.Value
>>= pos
))
1805 mpPointerSymbol
->viewsChanged(pos
);
1809 if (rProperty
.Name
== "NoSlideTransitions" )
1811 return (rProperty
.Value
>>= mbNoSlideTransitions
);
1814 if ( rProperty
.Name
== "IsSoundEnabled" )
1816 uno::Sequence
<uno::Any
> aValues
;
1817 uno::Reference
<presentation::XSlideShowView
> xView
;
1818 bool bValue (false);
1819 if ((rProperty
.Value
>>= aValues
)
1820 && aValues
.getLength()==2
1821 && (aValues
[0] >>= xView
)
1822 && (aValues
[1] >>= bValue
))
1824 // Look up the view.
1825 for (UnoViewVector::const_iterator
1826 iView (maViewContainer
.begin()),
1827 iEnd (maViewContainer
.end());
1831 if (*iView
&& (*iView
)->getUnoView()==xView
)
1833 // Store the flag at the view so that media shapes have
1835 (*iView
)->setIsSoundEnabled(bValue
);
1845 void SlideShowImpl::addSlideShowListener(
1846 uno::Reference
<presentation::XSlideShowListener
> const& xListener
)
1847 throw (uno::RuntimeException
, std::exception
)
1849 osl::MutexGuard
const guard( m_aMutex
);
1854 // container syncs with passed mutex ref
1855 maListenerContainer
.addInterface(xListener
);
1858 void SlideShowImpl::removeSlideShowListener(
1859 uno::Reference
<presentation::XSlideShowListener
> const& xListener
)
1860 throw (uno::RuntimeException
, std::exception
)
1862 osl::MutexGuard
const guard( m_aMutex
);
1864 // container syncs with passed mutex ref
1865 maListenerContainer
.removeInterface(xListener
);
1868 void SlideShowImpl::addShapeEventListener(
1869 uno::Reference
<presentation::XShapeEventListener
> const& xListener
,
1870 uno::Reference
<drawing::XShape
> const& xShape
)
1871 throw (uno::RuntimeException
, std::exception
)
1873 osl::MutexGuard
const guard( m_aMutex
);
1878 // precondition: must only be called from the main thread!
1879 DBG_TESTSOLARMUTEX();
1881 ShapeEventListenerMap::iterator aIter
;
1882 if( (aIter
=maShapeEventListeners
.find( xShape
)) ==
1883 maShapeEventListeners
.end() )
1885 // no entry for this shape -> create one
1886 aIter
= maShapeEventListeners
.insert(
1887 ShapeEventListenerMap::value_type(
1889 boost::shared_ptr
<cppu::OInterfaceContainerHelper
>(
1890 new cppu::OInterfaceContainerHelper(m_aMutex
)))).first
;
1893 // add new listener to broadcaster
1894 if( aIter
->second
.get() )
1895 aIter
->second
->addInterface( xListener
);
1897 maEventMultiplexer
.notifyShapeListenerAdded(xListener
,
1901 void SlideShowImpl::removeShapeEventListener(
1902 uno::Reference
<presentation::XShapeEventListener
> const& xListener
,
1903 uno::Reference
<drawing::XShape
> const& xShape
)
1904 throw (uno::RuntimeException
, std::exception
)
1906 osl::MutexGuard
const guard( m_aMutex
);
1908 // precondition: must only be called from the main thread!
1909 DBG_TESTSOLARMUTEX();
1911 ShapeEventListenerMap::iterator aIter
;
1912 if( (aIter
= maShapeEventListeners
.find( xShape
)) !=
1913 maShapeEventListeners
.end() )
1915 // entry for this shape found -> remove listener from
1918 aIter
->second
.get(),
1919 "SlideShowImpl::removeShapeEventListener(): "
1920 "listener map contains NULL broadcast helper" );
1922 aIter
->second
->removeInterface( xListener
);
1925 maEventMultiplexer
.notifyShapeListenerRemoved(xListener
,
1929 void SlideShowImpl::setShapeCursor(
1930 uno::Reference
<drawing::XShape
> const& xShape
, sal_Int16 nPointerShape
)
1931 throw (uno::RuntimeException
, std::exception
)
1933 osl::MutexGuard
const guard( m_aMutex
);
1938 // precondition: must only be called from the main thread!
1939 DBG_TESTSOLARMUTEX();
1941 ShapeCursorMap::iterator aIter
;
1942 if( (aIter
=maShapeCursors
.find( xShape
)) == maShapeCursors
.end() )
1944 // no entry for this shape -> create one
1945 if( nPointerShape
!= awt::SystemPointer::ARROW
)
1947 // add new entry, unless shape shall display
1948 // normal pointer arrow -> no need to handle that
1950 maShapeCursors
.insert(
1951 ShapeCursorMap::value_type(xShape
,
1955 else if( nPointerShape
== awt::SystemPointer::ARROW
)
1957 // shape shall display normal cursor -> can disable
1958 // the cursor and clear the entry
1959 maShapeCursors
.erase( xShape
);
1963 // existing entry found, update with new cursor ID
1964 aIter
->second
= nPointerShape
;
1967 maEventMultiplexer
.notifyShapeCursorChange(xShape
,
1971 bool SlideShowImpl::requestCursor( sal_Int16 nCursorShape
)
1973 mnCurrentCursor
= nCursorShape
;
1975 const sal_Int16 nActualCursor
= calcActiveCursor(mnCurrentCursor
);
1977 // change all views to the requested cursor ID
1978 std::for_each( maViewContainer
.begin(),
1979 maViewContainer
.end(),
1980 boost::bind( &View::setCursorShape
,
1984 return nActualCursor
==nCursorShape
;
1987 void SlideShowImpl::resetCursor()
1989 mnCurrentCursor
= awt::SystemPointer::ARROW
;
1991 // change all views to the default cursor ID
1992 std::for_each( maViewContainer
.begin(),
1993 maViewContainer
.end(),
1994 boost::bind( &View::setCursorShape
,
1996 calcActiveCursor(mnCurrentCursor
) ));
1999 sal_Bool
SlideShowImpl::update( double & nNextTimeout
)
2000 throw (uno::RuntimeException
, std::exception
)
2002 osl::MutexGuard
const guard( m_aMutex
);
2007 // precondition: update() must only be called from the
2009 DBG_TESTSOLARMUTEX();
2013 // commit frame (might be repaints pending)
2014 maScreenUpdater
.commitUpdates();
2020 // TODO(F2): re-evaluate whether that timer lagging makes
2023 // hold timer, while processing the queues:
2024 // 1. when there is more than one active activity this ensures the
2025 // same time for all activities and events
2026 // 2. processing of events may lead to creation of further events
2027 // that have zero delay. While the timer is stopped these events
2028 // are processed in the same run.
2030 //Get a shared-ptr that outlives the scope-guard which will
2031 //ensure that the pointed-to-item exists in the case of a
2032 //::dispose clearing mpPresTimer
2033 boost::shared_ptr
<canvas::tools::ElapsedTime
> xTimer(mpPresTimer
);
2034 comphelper::ScopeGuard
scopeGuard(
2035 boost::bind( &canvas::tools::ElapsedTime::releaseTimer
,
2036 boost::cref(xTimer
) ) );
2037 xTimer
->holdTimer();
2040 maEventQueue
.process();
2042 // #i118671# the call above may execute a macro bound to an object. In
2043 // that case this macro may have destroyed this local sliseshow so that it
2044 // is disposed (see bugdoc at task). In that case, detect this and exit
2045 // gently from this slideshow. Do not forget to disable the scoped
2046 // call to mpPresTimer, this will be deleted if we are disposed.
2049 scopeGuard
.dismiss();
2053 maActivitiesQueue
.process();
2055 // commit frame to screen
2056 maFrameSynchronization
.Synchronize();
2057 maScreenUpdater
.commitUpdates();
2059 // TODO(Q3): remove need to call dequeued() from
2060 // activities. feels like a wart.
2062 // Rationale for ActivitiesQueue::processDequeued(): when
2063 // an activity ends, it usually pushed the end state to
2064 // the animated shape in question, and ends the animation
2065 // (which, in turn, will usually disable shape sprite
2066 // mode). Disabling shape sprite mode causes shape
2067 // repaint, which, depending on slide content, takes
2068 // considerably more time than sprite updates. Thus, the
2069 // last animation step tends to look delayed. To
2070 // camouflage this, reaching end position and disabling
2071 // sprite mode is split into two (normal Activity::end(),
2072 // and Activity::dequeued()). Now, the reason to call
2073 // commitUpdates() twice here is caused by the unrelated
2074 // fact that during wait cursor display/hide, the screen
2075 // is updated, and shows hidden sprites, but, in case of
2076 // leaving the second commitUpdates() call out and punting
2077 // that to the next round, no updated static slide
2078 // content. In short, the last shape animation of a slide
2079 // tends to blink at its end.
2081 // process dequeued activities _after_ commit to screen
2082 maActivitiesQueue
.processDequeued();
2084 // commit frame to screen
2085 maScreenUpdater
.commitUpdates();
2087 // Time held until here
2089 const bool bActivitiesLeft
= (! maActivitiesQueue
.isEmpty());
2090 const bool bTimerEventsLeft
= (! maEventQueue
.isEmpty());
2091 const bool bRet
= (bActivitiesLeft
|| bTimerEventsLeft
);
2095 // calc nNextTimeout value:
2096 if (bActivitiesLeft
)
2098 // Activity queue is not empty. Tell caller that we would
2099 // like to render another frame.
2101 // Return a zero time-out to signal our caller to call us
2102 // back as soon as possible. The actual timing, waiting the
2103 // appropriate amount of time between frames, is then done
2104 // by the maFrameSynchronization object.
2106 maFrameSynchronization
.Activate();
2110 // timer events left:
2111 // difference from current time (nota bene:
2112 // time no longer held here!) to the next event in
2115 // #i61190# Retrieve next timeout only _after_
2116 // processing activity queue
2118 // ensure positive value:
2119 nNextTimeout
= std::max( 0.0, maEventQueue
.nextTimeout() );
2121 // There is no active animation so the frame rate does not
2122 // need to be synchronized.
2123 maFrameSynchronization
.Deactivate();
2126 mbSlideShowIdle
= false;
2129 #if OSL_DEBUG_LEVEL >= 2 && defined(DBG_UTIL)
2130 // when slideshow is idle, issue an XUpdatable::update() call
2131 // exactly once after a previous animation sequence finished -
2132 // this might trigger screen dumps on some canvas
2134 if( !mbSlideShowIdle
&&
2136 nNextTimeout
> 1.0) )
2138 UnoViewVector::const_iterator
aCurr(maViewContainer
.begin());
2139 const UnoViewVector::const_iterator
aEnd(maViewContainer
.end());
2140 while( aCurr
!= aEnd
)
2144 uno::Reference
< presentation::XSlideShowView
> xView( (*aCurr
)->getUnoView(),
2145 uno::UNO_QUERY_THROW
);
2146 uno::Reference
< util::XUpdatable
> xUpdatable( xView
->getCanvas(),
2147 uno::UNO_QUERY_THROW
);
2148 xUpdatable
->update();
2150 catch( uno::RuntimeException
& )
2154 catch( uno::Exception
& )
2156 OSL_FAIL( OUStringToOString(
2157 comphelper::anyToString( cppu::getCaughtException() ),
2158 RTL_TEXTENCODING_UTF8
).getStr() );
2164 mbSlideShowIdle
= true;
2172 void SlideShowImpl::notifySlideTransitionEnded( bool bPaintSlide
)
2174 osl::MutexGuard
const guard( m_aMutex
);
2176 OSL_ENSURE( !isDisposed(), "### already disposed!" );
2177 OSL_ENSURE( mpCurrentSlide
,
2178 "notifySlideTransitionEnded(): Invalid current slide" );
2181 mpCurrentSlide
->update_settings( !!maUserPaintColor
, maUserPaintColor
? *maUserPaintColor
: RGBColor(), maUserPaintStrokeWidth
);
2183 // first init show, to give the animations
2184 // the chance to register SlideStartEvents
2185 const bool bBackgroundLayerRendered( !bPaintSlide
);
2186 mpCurrentSlide
->show( bBackgroundLayerRendered
);
2187 maEventMultiplexer
.notifySlideStartEvent();
2191 void queryAutomaticSlideTransition( uno::Reference
<drawing::XDrawPage
> const& xDrawPage
,
2192 double& nAutomaticNextSlideTimeout
,
2193 bool& bHasAutomaticNextSlide
)
2195 // retrieve slide change parameters from XDrawPage
2196 // ===============================================
2198 uno::Reference
< beans::XPropertySet
> xPropSet( xDrawPage
,
2201 sal_Int32
nChange(0);
2202 if( !xPropSet
.is() ||
2203 !getPropertyValue( nChange
,
2209 "queryAutomaticSlideTransition(): "
2210 "Could not extract slide change mode from XDrawPage - assuming <none>\n" );
2213 bHasAutomaticNextSlide
= nChange
== 1;
2215 if( !xPropSet
.is() ||
2216 !getPropertyValue( nAutomaticNextSlideTimeout
,
2219 "HighResDuration")) )
2222 "queryAutomaticSlideTransition(): "
2223 "Could not extract slide transition timeout from "
2224 "XDrawPage - assuming 1 sec\n" );
2228 void SlideShowImpl::notifySlideAnimationsEnded()
2230 osl::MutexGuard
const guard( m_aMutex
);
2232 //Draw polygons above animations
2233 mpCurrentSlide
->drawPolygons();
2235 OSL_ENSURE( !isDisposed(), "### already disposed!" );
2237 // This struct will receive the (interruptable) event,
2238 // that triggers the notifySlideEnded() method.
2239 InterruptableEventPair aNotificationEvents
;
2241 if( maEventMultiplexer
.getAutomaticMode() )
2243 OSL_ENSURE( ! mpRehearseTimingsActivity
,
2244 "unexpected: RehearseTimings mode!" );
2246 // schedule a slide end event, with automatic mode's
2248 aNotificationEvents
= makeInterruptableDelay(
2249 boost::bind
<void>( boost::mem_fn(&SlideShowImpl::notifySlideEnded
), this, false ),
2250 maEventMultiplexer
.getAutomaticTimeout() );
2254 OSL_ENSURE( mpCurrentSlide
,
2255 "notifySlideAnimationsEnded(): Invalid current slide!" );
2257 bool bHasAutomaticNextSlide
=false;
2258 double nAutomaticNextSlideTimeout
=0.0;
2259 queryAutomaticSlideTransition(mpCurrentSlide
->getXDrawPage(),
2260 nAutomaticNextSlideTimeout
,
2261 bHasAutomaticNextSlide
);
2263 // check whether slide transition should happen
2264 // 'automatically'. If yes, simply schedule the
2265 // specified timeout.
2266 // NOTE: mbForceManualAdvance and mpRehearseTimingsActivity
2267 // override any individual slide setting, to always
2268 // step slides manually.
2269 if( !mbForceManualAdvance
&&
2270 !mpRehearseTimingsActivity
&&
2271 bHasAutomaticNextSlide
)
2273 aNotificationEvents
= makeInterruptableDelay(
2274 boost::bind
<void>( boost::mem_fn(&SlideShowImpl::notifySlideEnded
), this, false ),
2275 nAutomaticNextSlideTimeout
);
2277 // TODO(F2): Provide a mechanism to let the user override
2278 // this automatic timeout via next()
2282 if (mpRehearseTimingsActivity
)
2283 mpRehearseTimingsActivity
->start();
2285 // generate click event. Thus, the user must
2286 // trigger the actual end of a slide. No need to
2287 // generate interruptable event here, there's no
2288 // timeout involved.
2289 aNotificationEvents
.mpImmediateEvent
=
2290 makeEvent( boost::bind
<void>(
2291 boost::mem_fn(&SlideShowImpl::notifySlideEnded
), this, false ),
2292 "SlideShowImpl::notifySlideEnded");
2296 // register events on the queues. To make automatic slide
2297 // changes interruptable, register the interruption event
2298 // as a nextEffectEvent target. Note that the timeout
2299 // event is optional (e.g. manual slide changes don't
2300 // generate a timeout)
2301 maUserEventQueue
.registerNextEffectEvent(
2302 aNotificationEvents
.mpImmediateEvent
);
2304 if( aNotificationEvents
.mpTimeoutEvent
)
2305 maEventQueue
.addEvent( aNotificationEvents
.mpTimeoutEvent
);
2307 // current slide's main sequence is over. Now should be
2308 // the time to prefetch the next slide (if any), and
2309 // prepare the initial slide bitmap (speeds up slide
2310 // change setup time a lot). Show the wait cursor, this
2311 // indeed might take some seconds.
2313 WaitSymbolLock
aLock (*this);
2315 if (! matches( mpPrefetchSlide
,
2316 mxPrefetchSlide
, mxPrefetchAnimationNode
))
2318 mpPrefetchSlide
= makeSlide( mxPrefetchSlide
, mxDrawPagesSupplier
,
2319 mxPrefetchAnimationNode
);
2321 if (mpPrefetchSlide
)
2323 // ignore return value, this is just to populate
2324 // Slide's internal bitmap buffer, such that the time
2325 // needed to generate the slide bitmap is not spent
2326 // when the slide change is requested.
2327 mpPrefetchSlide
->getCurrentSlideBitmap( *maViewContainer
.begin() );
2331 maListenerContainer
.forEach
<presentation::XSlideShowListener
>(
2332 boost::mem_fn( &presentation::XSlideShowListener::slideAnimationsEnded
) );
2335 void SlideShowImpl::notifySlideEnded (const bool bReverse
)
2337 osl::MutexGuard
const guard( m_aMutex
);
2339 OSL_ENSURE( !isDisposed(), "### already disposed!" );
2341 if (mpRehearseTimingsActivity
&& !bReverse
)
2343 const double time
= mpRehearseTimingsActivity
->stop();
2344 if (mpRehearseTimingsActivity
->hasBeenClicked())
2346 // save time at current drawpage:
2347 uno::Reference
<beans::XPropertySet
> xPropSet(
2348 mpCurrentSlide
->getXDrawPage(), uno::UNO_QUERY
);
2349 OSL_ASSERT( xPropSet
.is() );
2352 xPropSet
->setPropertyValue(
2354 uno::Any( static_cast<sal_Int32
>(1) ) );
2355 xPropSet
->setPropertyValue(
2357 uno::Any( static_cast<sal_Int32
>(time
) ) );
2363 maEventMultiplexer
.notifySlideEndEvent();
2365 stopShow(); // MUST call that: results in
2366 // maUserEventQueue.clear(). What's more,
2367 // stopShow()'s currSlide->hide() call is
2368 // now also required, notifySlideEnded()
2370 // unconditionally. Otherwise, genuine
2371 // shape animations (drawing layer and
2372 // GIF) will not be stopped.
2374 maListenerContainer
.forEach
<presentation::XSlideShowListener
>(
2376 ::boost::mem_fn(&presentation::XSlideShowListener::slideEnded
),
2381 bool SlideShowImpl::notifyHyperLinkClicked( OUString
const& hyperLink
)
2383 osl::MutexGuard
const guard( m_aMutex
);
2385 maListenerContainer
.forEach
<presentation::XSlideShowListener
>(
2386 boost::bind( &presentation::XSlideShowListener::hyperLinkClicked
,
2388 boost::cref(hyperLink
) ));
2392 /** Notification from eventmultiplexer that an animation event has occoured.
2393 This will be forewarded to all registered XSlideShoeListener
2395 bool SlideShowImpl::handleAnimationEvent( const AnimationNodeSharedPtr
& rNode
)
2397 osl::MutexGuard
const guard( m_aMutex
);
2399 uno::Reference
<animations::XAnimationNode
> xNode( rNode
->getXAnimationNode() );
2401 switch( rNode
->getState() )
2403 case AnimationNode::ACTIVE
:
2404 maListenerContainer
.forEach
<presentation::XSlideShowListener
>(
2405 boost::bind( &animations::XAnimationListener::beginEvent
,
2407 boost::cref(xNode
) ));
2410 case AnimationNode::FROZEN
:
2411 case AnimationNode::ENDED
:
2412 maListenerContainer
.forEach
<presentation::XSlideShowListener
>(
2413 boost::bind( &animations::XAnimationListener::endEvent
,
2415 boost::cref(xNode
) ));
2416 if(mpCurrentSlide
->isPaintOverlayActive())
2417 mpCurrentSlide
->drawPolygons();
2426 //===== FrameSynchronization ==================================================
2428 FrameSynchronization::FrameSynchronization (const double nFrameDuration
)
2430 mnFrameDuration(nFrameDuration
),
2431 mnNextFrameTargetTime(0),
2437 void FrameSynchronization::MarkCurrentFrame()
2439 mnNextFrameTargetTime
= maTimer
.getElapsedTime() + mnFrameDuration
;
2442 void FrameSynchronization::Synchronize()
2446 // Do busy waiting for now.
2447 while (maTimer
.getElapsedTime() < mnNextFrameTargetTime
)
2454 void FrameSynchronization::Activate()
2459 void FrameSynchronization::Deactivate()
2466 namespace sdecl
= comphelper::service_decl
;
2467 const sdecl::ServiceDecl
slideShowDecl(
2468 sdecl::class_
<SlideShowImpl
>(),
2469 "com.sun.star.comp.presentation.SlideShow",
2470 "com.sun.star.presentation.SlideShow" );
2472 // The C shared lib entry points
2473 COMPHELPER_SERVICEDECL_EXPORTS1(slideshow
, slideShowDecl
)
2475 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */