fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / slideshow / source / engine / slideshowimpl.cxx
blob98d74146908f791209fba62fe678978e5619d337
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
88 #include "slide.hxx"
89 #include "shapemaps.hxx"
90 #include "slideview.hxx"
91 #include "tools.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>
103 #include <map>
104 #include <vector>
105 #include <iterator>
106 #include <string>
107 #include <algorithm>
108 #include <stdio.h>
109 #include <iostream>
111 using namespace com::sun::star;
112 using namespace ::slideshow::internal;
114 namespace {
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
120 steady.
122 class FrameSynchronization
124 public:
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
128 seconds.
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.
140 void Synchronize();
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.
146 void Activate();
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.
152 void Deactivate();
154 private:
155 /** The timer that is used for synchronization is independent from the
156 one used by SlideShowImpl: it is not paused or modified by
157 animations.
159 canvas::tools::ElapsedTime maTimer;
160 /** Time between the display of frames. Enforced only when mbIsActive
161 is <TRUE/>.
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.
171 bool mbIsActive;
174 /******************************************************************************
176 SlideShowImpl
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 -
203 deadlocked).
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
220 public:
221 explicit SlideShowImpl(
222 uno::Reference<uno::XComponentContext> const& xContext );
224 /** Notify that the transition phase of the current slide
225 has ended.
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.
236 @param bPaintSlide
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
244 has ended.
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
271 has been clicked.
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 );
280 private:
281 // XSlideShow:
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;
329 // CursorManager
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
338 transition.
340 void redisplayCurrentSlide();
342 protected:
343 // WeakComponentImplHelperBase
344 virtual void SAL_CALL disposing() SAL_OVERRIDE;
346 bool isDisposed() const
348 return (rBHelper.bDisposed || rBHelper.bInDispose);
351 private:
352 struct SeparateListenerImpl; friend struct SeparateListenerImpl;
353 class PrefetchPropertiesFunc; friend class PrefetchPropertiesFunc;
355 /// Stop currently running show.
356 void stopShow();
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
368 static bool matches(
369 SlideSharedPtr const& pSlide,
370 uno::Reference<drawing::XDrawPage> const& xSlide,
371 uno::Reference<animations::XAnimationNode> const& xNode )
373 if (pSlide)
374 return (pSlide->getXDrawPage() == xSlide &&
375 pSlide->getXAnimationNode() == xNode);
376 else
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(); }
412 ~WaitSymbolLock()
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;
448 //end changed
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;
469 uno::Reference<
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;
491 bool mbMouseVisible;
492 bool mbForceManualAdvance;
493 bool mbShowPaused;
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 ) :
520 mrShow( rShow ),
521 mrScreenUpdater( rScreenUpdater ),
522 mrEventQueue( rEventQueue )
525 // EventHandler
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(
537 makeEvent(
538 boost::bind( &SlideShowImpl::notifySlideAnimationsEnded, boost::ref(mrShow) ),
539 "SlideShowImpl::notifySlideAnimationsEnded"));
540 return true;
543 // ViewRepaintHandler
544 virtual void viewClobbered( const UnoViewSharedPtr& rView ) SAL_OVERRIDE
546 // given view needs repaint, request update
547 mrScreenUpdater.notifyUpdate(rView, true);
550 // HyperlinkHandler
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),
566 maViewContainer(),
567 maListenerContainer( m_aMutex ),
568 maShapeEventListeners(),
569 maShapeCursors(),
570 maUserPaintColor(),
571 maUserPaintStrokeWidth(4.0),
572 mpPresTimer( new canvas::tools::ElapsedTime ),
573 maScreenUpdater(maViewContainer),
574 maEventQueue( mpPresTimer ),
575 maEventMultiplexer( maEventQueue,
576 maViewContainer ),
577 maActivitiesQueue( mpPresTimer ),
578 maUserEventQueue( maEventMultiplexer,
579 maEventQueue,
580 *this ),
581 mpDummyPtr(),
582 mpListener(),
583 mpRehearseTimingsActivity(),
584 mpWaitSymbol(),
585 mpPointerSymbol(),
586 mpCurrentSlideTransitionSound(),
587 mxComponentContext( xContext ),
588 mxOptionalTransitionFactory(),
589 mpCurrentSlide(),
590 mpPrefetchSlide(),
591 mxPrefetchSlide(),
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() );
614 if( xFactory.is() )
618 // #i82460# try to retrieve special transition factory
619 mxOptionalTransitionFactory.set(
620 xFactory->createInstanceWithContext(
621 OUString("com.sun.star.presentation.TransitionFactory" ),
622 mxComponentContext ),
623 uno::UNO_QUERY );
625 catch (loader::CannotActivateFactoryException const&)
630 mpListener.reset( new SeparateListenerImpl(
631 *this,
632 maScreenUpdater,
633 maEventQueue ));
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();
668 if( mpListener )
670 maEventMultiplexer.removeSlideAnimationsEndHandler(mpListener);
671 maEventMultiplexer.removeViewRepaintHandler(mpListener);
672 maEventMultiplexer.removeHyperlinkHandler(mpListener);
673 maEventMultiplexer.removeAnimationStartHandler( mpListener );
674 maEventMultiplexer.removeAnimationEndHandler( mpListener );
676 mpListener.reset();
679 maUserEventQueue.clear();
680 maActivitiesQueue.clear();
681 maEventMultiplexer.clear();
682 maEventQueue.clear();
683 mpPresTimer.reset();
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();
693 // release slides:
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;
715 OUString url;
717 if( !(rSound >>= bStopSound) )
718 bStopSound = false;
719 rSound >>= url;
721 if( !bStopSound && url.isEmpty() )
722 return SoundPlayerSharedPtr();
724 stopSlideTransitionSound();
726 if (!url.isEmpty())
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
739 // shown).
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
757 // are disabled.
758 if (mbNoSlideTransitions)
759 return ActivitySharedPtr();
761 // retrieve slide change parameters from XDrawPage
762 uno::Reference< beans::XPropertySet > xPropSet( xDrawPage,
763 uno::UNO_QUERY );
765 if( !xPropSet.is() )
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,
774 xPropSet,
775 "TransitionType") )
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,
784 xPropSet,
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,
794 xPropSet,
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,
803 xPropSet,
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 ));
812 uno::Any aSound;
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(
823 rLeavingSlide,
824 rEnteringSlide,
825 maViewContainer,
826 maScreenUpdater,
827 maEventMultiplexer,
828 mxOptionalTransitionFactory,
829 nTransitionType,
830 nTransitionSubType,
831 bTransitionDirection,
832 aTransitionFadeColor,
833 resetSlideTransitionSound( aSound, bLoopSound ) ));
835 if( !pTransition )
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,
843 xPropSet,
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,
853 xPropSet,
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(
864 makeEvent(
865 boost::bind(
866 &::slideshow::internal::Animation::prefetch,
867 pTransition,
868 AnimatableShapeSharedPtr(),
869 ShapeAttributeLayerSharedPtr()),
870 "Animation::prefetch"));
872 return ActivitySharedPtr(
873 ActivitiesFactory::createSimpleActivity(
874 ActivitiesFactory::CommonParameters(
875 rTransitionEndEvent,
876 maEventQueue,
877 maActivitiesQueue,
878 nTransitionDuration,
879 nMinFrames,
880 false,
881 boost::optional<double>(1.0),
882 0.0,
883 0.0,
884 ShapeSharedPtr(),
885 basegfx::B2DSize( rEnteringSlide->getSlideSize() ) ),
886 pTransition,
887 true ));
890 PolygonMap::iterator SlideShowImpl::findPolygons( uno::Reference<drawing::XDrawPage> const& xDrawPage)
892 // TODO(P2) : Optimze research in the map.
893 bool bFound = false;
894 PolygonMap::iterator aIter=maPolygons.begin();
896 while(aIter!=maPolygons.end() && !bFound)
898 if(aIter->first == xDrawPage)
899 bFound = true;
900 else
901 ++aIter;
904 return aIter;
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,
920 xDrawPages,
921 xRootNode,
922 maEventQueue,
923 maEventMultiplexer,
924 maScreenUpdater,
925 maActivitiesQueue,
926 maUserEventQueue,
927 *this,
928 maViewContainer,
929 mxComponentContext,
930 maShapeEventListeners,
931 maShapeCursors,
932 (aIter != maPolygons.end()) ? aIter->second : PolyPolygonVector(),
933 maUserPaintColor ? *maUserPaintColor : RGBColor(),
934 maUserPaintStrokeWidth,
935 !!maUserPaintColor,
936 mbImageAnimationsAllowed,
937 mbDisableAnimationZOrder) );
939 // prefetch show content (reducing latency for slide
940 // bitmap and effect start later on)
941 pSlide->prefetch();
943 return pSlide;
946 void SlideShowImpl::requestWaitSymbol()
948 ++mnWaitSymbolRequestCount;
949 OSL_ASSERT(mnWaitSymbolRequestCount>0);
951 if (mnWaitSymbolRequestCount == 1)
953 if( !mpWaitSymbol )
955 // fall back to cursor
956 requestCursor(calcActiveCursor(mnCurrentCursor));
958 else
959 mpWaitSymbol->show();
963 void SlideShowImpl::releaseWaitSymbol()
965 --mnWaitSymbolRequestCount;
966 OSL_ASSERT(mnWaitSymbolRequestCount>=0);
968 if (mnWaitSymbolRequestCount == 0)
970 if( !mpWaitSymbol )
972 // fall back to cursor
973 requestCursor(calcActiveCursor(mnCurrentCursor));
975 else
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;
990 return nCursorShape;
993 void SlideShowImpl::stopShow()
995 // Force-end running animation
996 // ===========================
997 if (mpCurrentSlide)
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()));
1007 // clear all queues
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
1034 public:
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;
1061 else
1063 OSL_FAIL( OUStringToOString(
1064 rProperty.Name, RTL_TEXTENCODING_UTF8 ).getStr() );
1067 private:
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 );
1082 if (isDisposed())
1083 return;
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()
1096 // relies on that
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())
1109 return;
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;
1123 else
1124 mpCurrentSlide = makeSlide( xSlide, xDrawPages, xRootNode );
1126 OSL_ASSERT( mpCurrentSlide );
1127 if (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(),
1156 mpPreviousSlide,
1157 mpCurrentSlide,
1158 makeEvent(
1159 boost::bind(
1160 &SlideShowImpl::notifySlideTransitionEnded,
1161 this,
1162 false ),
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
1170 // anymore.
1171 pSlideChangeActivity.reset();
1174 if (pSlideChangeActivity)
1176 // factory generated a slide transition - activate it!
1177 maActivitiesQueue.addActivity( pSlideChangeActivity );
1179 else
1181 // no transition effect on this slide - schedule slide
1182 // effect start event right away.
1183 maEventQueue.addEvent(
1184 makeEvent(
1185 boost::bind(
1186 &SlideShowImpl::notifySlideTransitionEnded,
1187 this,
1188 true ),
1189 "SlideShowImpl::notifySlideTransitionEnded"));
1192 } // finally
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 );
1208 if (isDisposed())
1209 return;
1211 // precondition: must only be called from the main thread!
1212 DBG_TESTSOLARMUTEX();
1213 stopShow();
1215 OSL_ENSURE( !maViewContainer.empty(), "### no views!" );
1216 if (maViewContainer.empty())
1217 return;
1219 // No transition effect on this slide - schedule slide
1220 // effect start event right away.
1221 maEventQueue.addEvent(
1222 makeEvent(
1223 boost::bind(
1224 &SlideShowImpl::notifySlideTransitionEnded,
1225 this,
1226 true ),
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 );
1237 if (isDisposed())
1238 return false;
1240 // precondition: must only be called from the main thread!
1241 DBG_TESTSOLARMUTEX();
1243 if (mbShowPaused)
1244 return true;
1245 else
1246 return maEventMultiplexer.notifyNextEffect();
1249 sal_Bool SlideShowImpl::previousEffect() throw (uno::RuntimeException, std::exception)
1251 osl::MutexGuard const guard( m_aMutex );
1253 if (isDisposed())
1254 return false;
1256 // precondition: must only be called from the main thread!
1257 DBG_TESTSOLARMUTEX();
1259 if (mbShowPaused)
1260 return true;
1261 else
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
1283 // necessary.
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();
1301 // TODO(F3): NYI
1302 OSL_FAIL( "not yet implemented!" );
1303 return false;
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();
1315 // TODO(F3): NYI
1316 OSL_FAIL( "not yet implemented!" );
1317 return false;
1320 sal_Bool SlideShowImpl::pause( sal_Bool bPauseShow )
1321 throw (uno::RuntimeException, std::exception)
1323 osl::MutexGuard const guard( m_aMutex );
1325 if (isDisposed())
1326 return false;
1328 // precondition: must only be called from the main thread!
1329 DBG_TESTSOLARMUTEX();
1331 if (bPauseShow)
1332 mpPresTimer->pauseTimer();
1333 else
1334 mpPresTimer->continueTimer();
1336 maEventMultiplexer.notifyPauseMode(bPauseShow);
1338 mbShowPaused = bPauseShow;
1339 return true;
1342 uno::Reference<drawing::XDrawPage> SlideShowImpl::getCurrentSlide()
1343 throw (uno::RuntimeException, std::exception)
1345 osl::MutexGuard const guard( m_aMutex );
1347 if (isDisposed())
1348 return uno::Reference<drawing::XDrawPage>();
1350 // precondition: must only be called from the main thread!
1351 DBG_TESTSOLARMUTEX();
1353 if (mpCurrentSlide)
1354 return mpCurrentSlide->getXDrawPage();
1355 else
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 );
1365 if (isDisposed())
1366 return false;
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(
1377 xView,
1378 maEventQueue,
1379 maEventMultiplexer ));
1380 if (!maViewContainer.addView( pView ))
1381 return false; // view already added
1383 // initialize view content
1384 // =======================
1386 if (mpCurrentSlide)
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)
1396 pView->clearAll();
1398 // broadcast newly added view
1399 maEventMultiplexer.notifyViewAdded( pView );
1401 // set current mouse ptr
1402 pView->setCursorShape( calcActiveCursor(mnCurrentCursor) );
1404 return true;
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 ) );
1419 if( !pView )
1420 return false; // view was not added in the first place
1422 // remove view from EventMultiplexer (mouse events etc.)
1423 maEventMultiplexer.notifyViewRemoved( pView );
1425 pView->_dispose();
1427 return true;
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
1433 if (mpCurrentSlide)
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();
1490 if( nPoints > 1)
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.
1522 uno::Any aParam;
1523 aParam <<= aRetval;
1524 aXPropSet->setPropertyValue("PolyPolygon", aParam );
1526 //LineStyle : SOLID by default
1527 uno::Any aAny;
1528 drawing::LineStyle eLS;
1529 eLS = drawing::LineStyle_SOLID;
1530 aAny <<= eLS;
1531 aXPropSet->setPropertyValue("LineStyle", aAny );
1533 //LineColor
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 );
1540 //LineWidth
1541 double fLineWidth;
1542 fLineWidth = pPolyPoly->getStrokeWidth();
1543 aAny <<= (sal_Int32)fLineWidth;
1544 aXPropSet->setPropertyValue("LineWidth", aAny );
1546 // make polygons special
1547 xLayerManager->attachShapeToLayer(rPolyShape, xDrawnInSlideshow);
1551 ++aIter;
1555 sal_Bool SlideShowImpl::setProperty( beans::PropertyValue const& rProperty )
1556 throw (uno::RuntimeException, std::exception)
1558 osl::MutexGuard const guard( m_aMutex );
1560 if (isDisposed())
1561 return false;
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 );
1575 return true;
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 );
1593 else
1595 // disable user paint
1596 maUserPaintColor.reset();
1597 maEventMultiplexer.notifyUserPaintDisabled();
1598 if( mpCurrentSlide )
1599 mpCurrentSlide->disablePaintOverlay();
1602 resetCursor();
1604 return true;
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 );
1621 return true;
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" );
1632 if(nSwitchPenMode){
1633 // Switch to Pen Mode
1634 maSwitchPenMode.reset( nSwitchPenMode );
1635 maEventMultiplexer.notifySwitchPenMode();
1638 return true;
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();
1655 return true;
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 );
1671 return true;
1674 // new Property for pen's width
1675 if ( rProperty.Name == "UserPaintStrokeWidth" )
1677 double nWidth(4.0);
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 );
1686 return true;
1689 if ( rProperty.Name == "AdvanceOnClick" )
1691 bool bAdvanceOnClick = false;
1692 if (! (rProperty.Value >>= bAdvanceOnClick))
1693 return false;
1694 maUserEventQueue.setAdvanceOnClick( bAdvanceOnClick );
1695 return true;
1698 if ( rProperty.Name == "DisableAnimationZOrder" )
1700 bool bDisableAnimationZOrder = false;
1701 if (! (rProperty.Value >>= bDisableAnimationZOrder))
1702 return false;
1703 mbDisableAnimationZOrder = bDisableAnimationZOrder;
1704 return true;
1707 if ( rProperty.Name == "ImageAnimationsAllowed" )
1709 if (! (rProperty.Value >>= mbImageAnimationsAllowed))
1710 return false;
1712 // TODO(F3): Forward to slides!
1713 return true;
1716 if ( rProperty.Name == "MouseVisible" )
1718 if (! (rProperty.Value >>= mbMouseVisible))
1719 return false;
1721 requestCursor(mnCurrentCursor);
1723 return true;
1726 if ( rProperty.Name == "ForceManualAdvance" )
1728 return (rProperty.Value >>= mbForceManualAdvance);
1731 if ( rProperty.Name == "RehearseTimings" )
1733 bool bRehearseTimings = false;
1734 if (! (rProperty.Value >>= bRehearseTimings))
1735 return false;
1737 if (bRehearseTimings)
1739 // TODO(Q3): Move to slide
1740 mpRehearseTimingsActivity = RehearseTimingsActivity::create(
1741 SlideShowContext(
1742 mpDummyPtr,
1743 maEventQueue,
1744 maEventMultiplexer,
1745 maScreenUpdater,
1746 maActivitiesQueue,
1747 maUserEventQueue,
1748 *this,
1749 maViewContainer,
1750 mxComponentContext) );
1752 else if (mpRehearseTimingsActivity)
1754 // removes timer from all views:
1755 mpRehearseTimingsActivity->dispose();
1756 mpRehearseTimingsActivity.reset();
1758 return true;
1761 if ( rProperty.Name == "WaitSymbolBitmap" )
1763 uno::Reference<rendering::XBitmap> xBitmap;
1764 if (! (rProperty.Value >>= xBitmap))
1765 return false;
1767 mpWaitSymbol = WaitSymbol::create( xBitmap,
1768 maScreenUpdater,
1769 maEventMultiplexer,
1770 maViewContainer );
1772 return true;
1775 if ( rProperty.Name == "PointerSymbolBitmap" )
1777 uno::Reference<rendering::XBitmap> xBitmap;
1778 if (! (rProperty.Value >>= xBitmap))
1779 return false;
1781 mpPointerSymbol = PointerSymbol::create( xBitmap,
1782 maScreenUpdater,
1783 maEventMultiplexer,
1784 maViewContainer );
1786 return true;
1789 if ( rProperty.Name == "PointerVisible" )
1791 bool visible;
1792 if (!(rProperty.Value >>= visible))
1793 return false;
1795 mpPointerSymbol->setVisible(visible);
1796 return true;
1799 if ( rProperty.Name == "PointerPosition")
1801 ::com::sun::star::geometry::RealPoint2D pos;
1802 if (! (rProperty.Value >>= pos))
1803 return false;
1805 mpPointerSymbol->viewsChanged(pos);
1806 return true;
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());
1828 iView!=iEnd;
1829 ++iView)
1831 if (*iView && (*iView)->getUnoView()==xView)
1833 // Store the flag at the view so that media shapes have
1834 // access to it.
1835 (*iView)->setIsSoundEnabled(bValue);
1836 return true;
1842 return false;
1845 void SlideShowImpl::addSlideShowListener(
1846 uno::Reference<presentation::XSlideShowListener> const& xListener )
1847 throw (uno::RuntimeException, std::exception)
1849 osl::MutexGuard const guard( m_aMutex );
1851 if (isDisposed())
1852 return;
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 );
1875 if (isDisposed())
1876 return;
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(
1888 xShape,
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,
1898 xShape);
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
1916 // helper object
1917 ENSURE_OR_THROW(
1918 aIter->second.get(),
1919 "SlideShowImpl::removeShapeEventListener(): "
1920 "listener map contains NULL broadcast helper" );
1922 aIter->second->removeInterface( xListener );
1925 maEventMultiplexer.notifyShapeListenerRemoved(xListener,
1926 xShape);
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 );
1935 if (isDisposed())
1936 return;
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
1949 // case
1950 maShapeCursors.insert(
1951 ShapeCursorMap::value_type(xShape,
1952 nPointerShape) );
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 );
1961 else
1963 // existing entry found, update with new cursor ID
1964 aIter->second = nPointerShape;
1967 maEventMultiplexer.notifyShapeCursorChange(xShape,
1968 nPointerShape);
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,
1982 nActualCursor ));
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 );
2004 if (isDisposed())
2005 return false;
2007 // precondition: update() must only be called from the
2008 // main thread!
2009 DBG_TESTSOLARMUTEX();
2011 if( mbShowPaused )
2013 // commit frame (might be repaints pending)
2014 maScreenUpdater.commitUpdates();
2016 return false;
2018 else
2020 // TODO(F2): re-evaluate whether that timer lagging makes
2021 // sense.
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();
2039 // process queues
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.
2047 if (isDisposed())
2049 scopeGuard.dismiss();
2050 return false;
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);
2093 if (bRet)
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.
2105 nNextTimeout = 0;
2106 maFrameSynchronization.Activate();
2108 else
2110 // timer events left:
2111 // difference from current time (nota bene:
2112 // time no longer held here!) to the next event in
2113 // the event queue.
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
2133 // implementations
2134 if( !mbSlideShowIdle &&
2135 (!bRet ||
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& )
2152 throw;
2154 catch( uno::Exception& )
2156 OSL_FAIL( OUStringToOString(
2157 comphelper::anyToString( cppu::getCaughtException() ),
2158 RTL_TEXTENCODING_UTF8 ).getStr() );
2161 ++aCurr;
2164 mbSlideShowIdle = true;
2166 #endif
2168 return bRet;
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" );
2179 if (mpCurrentSlide)
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,
2199 uno::UNO_QUERY );
2201 sal_Int32 nChange(0);
2202 if( !xPropSet.is() ||
2203 !getPropertyValue( nChange,
2204 xPropSet,
2205 OUString(
2206 "Change")) )
2208 OSL_TRACE(
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,
2217 xPropSet,
2218 OUString(
2219 "HighResDuration")) )
2221 OSL_TRACE(
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
2247 // delay
2248 aNotificationEvents = makeInterruptableDelay(
2249 boost::bind<void>( boost::mem_fn(&SlideShowImpl::notifySlideEnded), this, false ),
2250 maEventMultiplexer.getAutomaticTimeout() );
2252 else
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()
2280 else
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() );
2329 } // finally
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() );
2350 if (xPropSet.is())
2352 xPropSet->setPropertyValue(
2353 "Change",
2354 uno::Any( static_cast<sal_Int32>(1) ) );
2355 xPropSet->setPropertyValue(
2356 "Duration",
2357 uno::Any( static_cast<sal_Int32>(time) ) );
2362 if (bReverse)
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()
2369 // relies on that
2370 // unconditionally. Otherwise, genuine
2371 // shape animations (drawing layer and
2372 // GIF) will not be stopped.
2374 maListenerContainer.forEach<presentation::XSlideShowListener>(
2375 boost::bind<void>(
2376 ::boost::mem_fn(&presentation::XSlideShowListener::slideEnded),
2378 bReverse));
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) ));
2389 return true;
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) ));
2408 break;
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();
2418 break;
2419 default:
2420 break;
2423 return true;
2426 //===== FrameSynchronization ==================================================
2428 FrameSynchronization::FrameSynchronization (const double nFrameDuration)
2429 : maTimer(),
2430 mnFrameDuration(nFrameDuration),
2431 mnNextFrameTargetTime(0),
2432 mbIsActive(false)
2434 MarkCurrentFrame();
2437 void FrameSynchronization::MarkCurrentFrame()
2439 mnNextFrameTargetTime = maTimer.getElapsedTime() + mnFrameDuration;
2442 void FrameSynchronization::Synchronize()
2444 if (mbIsActive)
2446 // Do busy waiting for now.
2447 while (maTimer.getElapsedTime() < mnNextFrameTargetTime)
2451 MarkCurrentFrame();
2454 void FrameSynchronization::Activate()
2456 mbIsActive = true;
2459 void FrameSynchronization::Deactivate()
2461 mbIsActive = false;
2464 } // anon namespace
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: */