Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <canvas/debug.hxx>
22 : #include <tools/diagnose_ex.h>
23 :
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>
31 :
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>
38 :
39 : #include <cppcanvas/spritecanvas.hxx>
40 : #include <cppcanvas/vclfactory.hxx>
41 : #include <cppcanvas/basegfxfactory.hxx>
42 :
43 : #include <tools/debug.hxx>
44 :
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>
51 :
52 : #include <vcl/font.hxx>
53 : #include "rtl/ref.hxx"
54 :
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>
74 :
75 : #include "com/sun/star/uno/Reference.hxx"
76 : #include <com/sun/star/loader/CannotActivateFactoryException.hpp>
77 :
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 :
99 : #include <boost/noncopyable.hpp>
100 : #include <boost/bind.hpp>
101 :
102 : #include <map>
103 : #include <vector>
104 : #include <iterator>
105 : #include <string>
106 : #include <algorithm>
107 : #include <stdio.h>
108 : #include <iostream>
109 :
110 : using namespace com::sun::star;
111 : using namespace ::slideshow::internal;
112 :
113 : namespace {
114 :
115 : /** During animations the update() method tells its caller to call it as
116 : soon as possible. This gives us more time to render the next frame and
117 : still maintain a steady frame rate. This class is responsible for
118 : synchronizing the display of new frames and thus keeping the frame rate
119 : steady.
120 : */
121 0 : class FrameSynchronization
122 : {
123 : public:
124 : /** Create new object with a predefined duration between two frames.
125 : @param nFrameDuration
126 : The preferred duration between the display of two frames in
127 : seconds.
128 : */
129 : FrameSynchronization (const double nFrameDuration);
130 :
131 : /** Set the current time as the time at which the current frame is
132 : displayed. From this the target time of the next frame is derived.
133 : */
134 : void MarkCurrentFrame (void);
135 :
136 : /** When there is time left until the next frame is due then wait.
137 : Otherwise return without delay.
138 : */
139 : void Synchronize (void);
140 :
141 : /** Activate frame synchronization when an animation is active and
142 : frames are to be displayed in a steady rate. While active
143 : Synchronize() will wait until the frame duration time has passed.
144 : */
145 : void Activate (void);
146 :
147 : /** Deactivate frame sychronization when no animation is active and the
148 : time between frames depends on user actions and other external
149 : sources. While deactivated Synchronize() will return without delay.
150 : */
151 : void Deactivate (void);
152 :
153 : private:
154 : /** The timer that is used for synchronization is independent from the
155 : one used by SlideShowImpl: it is not paused or modified by
156 : animations.
157 : */
158 : canvas::tools::ElapsedTime maTimer;
159 : /** Time between the display of frames. Enforced only when mbIsActive
160 : is <TRUE/>.
161 : */
162 : const double mnFrameDuration;
163 : /** Time (of maTimer) when the next frame shall be displayed.
164 : Synchronize() will wait until this time.
165 : */
166 : double mnNextFrameTargetTime;
167 : /** Synchronize() will wait only when this flag is <TRUE/>. Otherwise
168 : it returns immediately.
169 : */
170 : bool mbIsActive;
171 : };
172 :
173 : /******************************************************************************
174 :
175 : SlideShowImpl
176 :
177 : This class encapsulates the slideshow presentation viewer.
178 :
179 : With an instance of this class, it is possible to statically
180 : and dynamically show a presentation, as defined by the
181 : constructor-provided draw model (represented by a sequence
182 : of ::com::sun::star::drawing::XDrawPage objects).
183 :
184 : It is possible to show the presentation on multiple views
185 : simultaneously (e.g. for a multi-monitor setup). Since this
186 : class also relies on user interaction, the corresponding
187 : XSlideShowView interface provides means to register some UI
188 : event listeners (mostly borrowed from awt::XWindow interface).
189 :
190 : Since currently (mid 2004), OOo isn't very well suited to
191 : multi-threaded rendering, this class relies on <em>very
192 : frequent</em> external update() calls, which will render the
193 : next frame of animations. This works as follows: after the
194 : displaySlide() has been successfully called (which setup and
195 : starts an actual slide show), the update() method must be
196 : called until it returns false.
197 : Effectively, this puts the burden of providing
198 : concurrency to the clients of this class, which, as noted
199 : above, is currently unavoidable with the current state of
200 : affairs (I've actually tried threading here, but failed
201 : miserably when using the VCL canvas as the render backend -
202 : deadlocked).
203 :
204 : ******************************************************************************/
205 :
206 : typedef cppu::WeakComponentImplHelper1<presentation::XSlideShow> SlideShowImplBase;
207 :
208 : typedef ::std::vector< ::cppcanvas::PolyPolygonSharedPtr> PolyPolygonVector;
209 :
210 : /// Maps XDrawPage for annotations persistence
211 : typedef ::std::map< ::com::sun::star::uno::Reference<
212 : ::com::sun::star::drawing::XDrawPage>,
213 : PolyPolygonVector> PolygonMap;
214 :
215 0 : class SlideShowImpl : private cppu::BaseMutex,
216 : public CursorManager,
217 : public SlideShowImplBase
218 : {
219 : public:
220 : explicit SlideShowImpl(
221 : uno::Reference<uno::XComponentContext> const& xContext );
222 :
223 : /** Notify that the transition phase of the current slide
224 : has ended.
225 :
226 : The life of a slide has three phases: the transition
227 : phase, when the previous slide vanishes, and the
228 : current slide becomes visible, the shape animation
229 : phase, when shape effects are running, and the phase
230 : after the last shape animation has ended, but before
231 : the next slide transition starts.
232 :
233 : This method notifies the end of the first phase.
234 :
235 : @param bPaintSlide
236 : When true, Slide::show() is passed a true as well, denoting
237 : explicit paint of slide content. Pass false here, if e.g. a
238 : slide transition has already rendered the initial slide image.
239 : */
240 : void notifySlideTransitionEnded( bool bPaintSlide );
241 :
242 : /** Notify that the shape animation phase of the current slide
243 : has ended.
244 :
245 : The life of a slide has three phases: the transition
246 : phase, when the previous slide vanishes, and the
247 : current slide becomes visible, the shape animation
248 : phase, when shape effects are running, and the phase
249 : after the last shape animation has ended, but before
250 : the next slide transition starts.
251 :
252 : This method notifies the end of the second phase.
253 : */
254 : void notifySlideAnimationsEnded();
255 :
256 : /** Notify that the slide has ended.
257 :
258 : The life of a slide has three phases: the transition
259 : phase, when the previous slide vanishes, and the
260 : current slide becomes visible, the shape animation
261 : phase, when shape effects are running, and the phase
262 : after the last shape animation has ended, but before
263 : the next slide transition starts.
264 :
265 : This method notifies the end of the third phase.
266 : */
267 : void notifySlideEnded (const bool bReverse);
268 :
269 : /** Notification from eventmultiplexer that a hyperlink
270 : has been clicked.
271 : */
272 : bool notifyHyperLinkClicked( rtl::OUString const& hyperLink );
273 :
274 : /** Notification from eventmultiplexer that an animation event has occoured.
275 : This will be forewarded to all registered XSlideShowListener
276 : */
277 : bool handleAnimationEvent( const AnimationNodeSharedPtr& rNode );
278 :
279 : private:
280 : // XSlideShow:
281 : virtual sal_Bool SAL_CALL nextEffect() throw (uno::RuntimeException);
282 : virtual sal_Bool SAL_CALL previousEffect() throw (uno::RuntimeException);
283 : virtual sal_Bool SAL_CALL startShapeActivity(
284 : uno::Reference<drawing::XShape> const& xShape )
285 : throw (uno::RuntimeException);
286 : virtual sal_Bool SAL_CALL stopShapeActivity(
287 : uno::Reference<drawing::XShape> const& xShape )
288 : throw (uno::RuntimeException);
289 : virtual sal_Bool SAL_CALL pause( sal_Bool bPauseShow )
290 : throw (uno::RuntimeException);
291 : virtual uno::Reference<drawing::XDrawPage> SAL_CALL getCurrentSlide()
292 : throw (uno::RuntimeException);
293 : virtual void SAL_CALL displaySlide(
294 : uno::Reference<drawing::XDrawPage> const& xSlide,
295 : uno::Reference<drawing::XDrawPagesSupplier> const& xDrawPages,
296 : uno::Reference<animations::XAnimationNode> const& xRootNode,
297 : uno::Sequence<beans::PropertyValue> const& rProperties )
298 : throw (uno::RuntimeException);
299 : virtual void SAL_CALL registerUserPaintPolygons( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xDocFactory ) throw (::com::sun::star::uno::RuntimeException);
300 : virtual sal_Bool SAL_CALL setProperty(
301 : beans::PropertyValue const& rProperty ) throw (uno::RuntimeException);
302 : virtual sal_Bool SAL_CALL addView(
303 : uno::Reference<presentation::XSlideShowView> const& xView )
304 : throw (uno::RuntimeException);
305 : virtual sal_Bool SAL_CALL removeView(
306 : uno::Reference<presentation::XSlideShowView> const& xView )
307 : throw (uno::RuntimeException);
308 : virtual sal_Bool SAL_CALL update( double & nNextTimeout )
309 : throw (uno::RuntimeException);
310 : virtual void SAL_CALL addSlideShowListener(
311 : uno::Reference<presentation::XSlideShowListener> const& xListener )
312 : throw (uno::RuntimeException);
313 : virtual void SAL_CALL removeSlideShowListener(
314 : uno::Reference<presentation::XSlideShowListener> const& xListener )
315 : throw (uno::RuntimeException);
316 : virtual void SAL_CALL addShapeEventListener(
317 : uno::Reference<presentation::XShapeEventListener> const& xListener,
318 : uno::Reference<drawing::XShape> const& xShape )
319 : throw (uno::RuntimeException);
320 : virtual void SAL_CALL removeShapeEventListener(
321 : uno::Reference<presentation::XShapeEventListener> const& xListener,
322 : uno::Reference<drawing::XShape> const& xShape )
323 : throw (uno::RuntimeException);
324 : virtual void SAL_CALL setShapeCursor(
325 : uno::Reference<drawing::XShape> const& xShape, sal_Int16 nPointerShape )
326 : throw (uno::RuntimeException);
327 :
328 : // CursorManager
329 : // -----------------------------------------------------------
330 :
331 : virtual bool requestCursor( sal_Int16 nCursorShape );
332 : virtual void resetCursor();
333 :
334 : /** This is somewhat similar to displaySlide when called for the current
335 : slide. It has been simplified to take advantage of that no slide
336 : change takes place. Furthermore it does not show the slide
337 : transition.
338 : */
339 : void redisplayCurrentSlide (void);
340 :
341 : protected:
342 : // WeakComponentImplHelperBase
343 : virtual void SAL_CALL disposing();
344 :
345 0 : bool isDisposed() const
346 : {
347 0 : return (rBHelper.bDisposed || rBHelper.bInDispose);
348 : }
349 :
350 : private:
351 : struct SeparateListenerImpl; friend struct SeparateListenerImpl;
352 : class PrefetchPropertiesFunc; friend class PrefetchPropertiesFunc;
353 :
354 : /// Stop currently running show.
355 : void stopShow();
356 :
357 : ///Find a polygons vector in maPolygons (map)
358 : PolygonMap::iterator findPolygons( uno::Reference<drawing::XDrawPage> const& xDrawPage);
359 :
360 : /// Creates a new slide.
361 : SlideSharedPtr makeSlide(
362 : uno::Reference<drawing::XDrawPage> const& xDrawPage,
363 : uno::Reference<drawing::XDrawPagesSupplier> const& xDrawPages,
364 : uno::Reference<animations::XAnimationNode> const& xRootNode );
365 :
366 : /// Checks whether the given slide/animation node matches mpPrefetchSlide
367 0 : static bool matches(
368 : SlideSharedPtr const& pSlide,
369 : uno::Reference<drawing::XDrawPage> const& xSlide,
370 : uno::Reference<animations::XAnimationNode> const& xNode )
371 : {
372 0 : if (pSlide)
373 0 : return (pSlide->getXDrawPage() == xSlide &&
374 0 : pSlide->getXAnimationNode() == xNode);
375 : else
376 0 : return (!xSlide.is() && !xNode.is());
377 : }
378 :
379 : /// Resets the current slide transition sound object with a new one:
380 : SoundPlayerSharedPtr resetSlideTransitionSound(
381 : uno::Any const& url = uno::Any(), bool bLoopSound = false );
382 :
383 : /// stops the current slide transition sound
384 : void stopSlideTransitionSound();
385 :
386 : /** Prepare a slide transition
387 :
388 : This method registers all necessary events and
389 : activities for a slide transition.
390 :
391 : @return the slide change activity, or NULL for no transition effect
392 : */
393 : ActivitySharedPtr createSlideTransition(
394 : const uno::Reference< drawing::XDrawPage >& xDrawPage,
395 : const SlideSharedPtr& rLeavingSlide,
396 : const SlideSharedPtr& rEnteringSlide,
397 : const EventSharedPtr& rTransitionEndEvent );
398 :
399 : /** Request/release the wait symbol. The wait symbol is displayed when
400 : there are more requests then releases. Locking the wait symbol
401 : helps to avoid intermediate repaints.
402 :
403 : Do not call this method directly. Use WaitSymbolLock instead.
404 : */
405 : void requestWaitSymbol (void);
406 : void releaseWaitSymbol (void);
407 :
408 : class WaitSymbolLock {public:
409 0 : WaitSymbolLock(SlideShowImpl& rSlideShowImpl) : mrSlideShowImpl(rSlideShowImpl)
410 0 : { mrSlideShowImpl.requestWaitSymbol(); }
411 0 : ~WaitSymbolLock(void)
412 0 : { mrSlideShowImpl.releaseWaitSymbol(); }
413 : private: SlideShowImpl& mrSlideShowImpl;
414 : };
415 :
416 : /// Filter requested cursor shape against hard slideshow cursors (wait, etc.)
417 : sal_Int16 calcActiveCursor( sal_Int16 nCursorShape ) const;
418 :
419 : /** This method is called asynchronously to finish the rewinding of an
420 : effect to the previous slide that was initiated earlier.
421 : */
422 : void rewindEffectToPreviousSlide (void);
423 :
424 : /// all registered views
425 : UnoViewContainer maViewContainer;
426 :
427 : /// all registered slide show listeners
428 : cppu::OInterfaceContainerHelper maListenerContainer;
429 :
430 : /// map of vectors, containing all registered listeners for a shape
431 : ShapeEventListenerMap maShapeEventListeners;
432 : /// map of sal_Int16 values, specifying the mouse cursor for every shape
433 : ShapeCursorMap maShapeCursors;
434 :
435 : //map of vector of Polygons, containing polygons drawn on each slide.
436 : PolygonMap maPolygons;
437 :
438 : boost::optional<RGBColor> maUserPaintColor;
439 :
440 : double maUserPaintStrokeWidth;
441 :
442 : //changed for the eraser project
443 : boost::optional<bool> maEraseAllInk;
444 : boost::optional<bool> maSwitchPenMode;
445 : boost::optional<bool> maSwitchEraserMode;
446 : boost::optional<sal_Int32> maEraseInk;
447 : //end changed
448 :
449 : boost::shared_ptr<canvas::tools::ElapsedTime> mpPresTimer;
450 : ScreenUpdater maScreenUpdater;
451 : EventQueue maEventQueue;
452 : EventMultiplexer maEventMultiplexer;
453 : ActivitiesQueue maActivitiesQueue;
454 : UserEventQueue maUserEventQueue;
455 : SubsettableShapeManagerSharedPtr mpDummyPtr;
456 :
457 : boost::shared_ptr<SeparateListenerImpl> mpListener;
458 :
459 : boost::shared_ptr<RehearseTimingsActivity> mpRehearseTimingsActivity;
460 : boost::shared_ptr<WaitSymbol> mpWaitSymbol;
461 :
462 : /// the current slide transition sound object:
463 : SoundPlayerSharedPtr mpCurrentSlideTransitionSound;
464 :
465 : uno::Reference<uno::XComponentContext> mxComponentContext;
466 : uno::Reference<
467 : presentation::XTransitionFactory> mxOptionalTransitionFactory;
468 :
469 : /// the previously running slide
470 : SlideSharedPtr mpPreviousSlide;
471 : /// the currently running slide
472 : SlideSharedPtr mpCurrentSlide;
473 : /// the already prefetched slide: best candidate for upcoming slide
474 : SlideSharedPtr mpPrefetchSlide;
475 : /// slide to be prefetched: best candidate for upcoming slide
476 : uno::Reference<drawing::XDrawPage> mxPrefetchSlide;
477 : /// save the XDrawPagesSupplier to retieve polygons
478 : uno::Reference<drawing::XDrawPagesSupplier> mxDrawPagesSupplier;
479 : /// slide animation to be prefetched:
480 : uno::Reference<animations::XAnimationNode> mxPrefetchAnimationNode;
481 :
482 : sal_Int16 mnCurrentCursor;
483 :
484 : sal_Int32 mnWaitSymbolRequestCount;
485 : bool mbAutomaticAdvancementMode;
486 : bool mbImageAnimationsAllowed;
487 : bool mbNoSlideTransitions;
488 : bool mbMouseVisible;
489 : bool mbForceManualAdvance;
490 : bool mbShowPaused;
491 : bool mbSlideShowIdle;
492 : bool mbDisableAnimationZOrder;
493 :
494 : EffectRewinder maEffectRewinder;
495 : FrameSynchronization maFrameSynchronization;
496 : };
497 :
498 : /** Separate event listener for animation, view and hyperlink events.
499 :
500 : This handler is registered for slide animation end, view and
501 : hyperlink events at the global EventMultiplexer, and forwards
502 : notifications to the SlideShowImpl
503 : */
504 0 : struct SlideShowImpl::SeparateListenerImpl : public EventHandler,
505 : public ViewRepaintHandler,
506 : public HyperlinkHandler,
507 : public AnimationEventHandler,
508 : private boost::noncopyable
509 : {
510 : SlideShowImpl& mrShow;
511 : ScreenUpdater& mrScreenUpdater;
512 : EventQueue& mrEventQueue;
513 :
514 0 : SeparateListenerImpl( SlideShowImpl& rShow,
515 : ScreenUpdater& rScreenUpdater,
516 : EventQueue& rEventQueue ) :
517 : mrShow( rShow ),
518 : mrScreenUpdater( rScreenUpdater ),
519 0 : mrEventQueue( rEventQueue )
520 0 : {}
521 :
522 : // EventHandler
523 0 : virtual bool handleEvent()
524 : {
525 : // DON't call notifySlideAnimationsEnded()
526 : // directly, but queue an event. handleEvent()
527 : // might be called from e.g.
528 : // showNext(), and notifySlideAnimationsEnded() must not be called
529 : // in recursion. Note that the event is scheduled for the next
530 : // frame so that its expensive execution does not come in between
531 : // sprite hiding and shape redraw (at the end of the animation of a
532 : // shape), which would cause a flicker.
533 : mrEventQueue.addEventForNextRound(
534 0 : makeEvent(
535 : boost::bind( &SlideShowImpl::notifySlideAnimationsEnded, boost::ref(mrShow) ),
536 0 : "SlideShowImpl::notifySlideAnimationsEnded"));
537 0 : return true;
538 : }
539 :
540 : // ViewRepaintHandler
541 0 : virtual void viewClobbered( const UnoViewSharedPtr& rView )
542 : {
543 : // given view needs repaint, request update
544 0 : mrScreenUpdater.notifyUpdate(rView, true);
545 0 : }
546 :
547 : // HyperlinkHandler
548 0 : virtual bool handleHyperlink( ::rtl::OUString const& rLink )
549 : {
550 0 : return mrShow.notifyHyperLinkClicked(rLink);
551 : }
552 :
553 : // AnimationEventHandler
554 0 : virtual bool handleAnimationEvent( const AnimationNodeSharedPtr& rNode )
555 : {
556 0 : return mrShow.handleAnimationEvent(rNode);
557 : }
558 : };
559 :
560 0 : SlideShowImpl::SlideShowImpl(
561 : uno::Reference<uno::XComponentContext> const& xContext )
562 : : SlideShowImplBase(m_aMutex),
563 : maViewContainer(),
564 : maListenerContainer( m_aMutex ),
565 : maShapeEventListeners(),
566 : maShapeCursors(),
567 : maUserPaintColor(),
568 : maUserPaintStrokeWidth(4.0),
569 0 : mpPresTimer( new canvas::tools::ElapsedTime ),
570 : maScreenUpdater(maViewContainer),
571 : maEventQueue( mpPresTimer ),
572 : maEventMultiplexer( maEventQueue,
573 : maViewContainer ),
574 : maActivitiesQueue( mpPresTimer ),
575 : maUserEventQueue( maEventMultiplexer,
576 : maEventQueue,
577 : *this ),
578 : mpDummyPtr(),
579 : mpListener(),
580 : mpRehearseTimingsActivity(),
581 : mpWaitSymbol(),
582 : mpCurrentSlideTransitionSound(),
583 : mxComponentContext( xContext ),
584 : mxOptionalTransitionFactory(),
585 : mpCurrentSlide(),
586 : mpPrefetchSlide(),
587 : mxPrefetchSlide(),
588 : mxDrawPagesSupplier(),
589 : mxPrefetchAnimationNode(),
590 : mnCurrentCursor(awt::SystemPointer::ARROW),
591 : mnWaitSymbolRequestCount(0),
592 : mbAutomaticAdvancementMode(false),
593 : mbImageAnimationsAllowed( true ),
594 : mbNoSlideTransitions( false ),
595 : mbMouseVisible( true ),
596 : mbForceManualAdvance( false ),
597 : mbShowPaused( false ),
598 : mbSlideShowIdle( true ),
599 : mbDisableAnimationZOrder( false ),
600 : maEffectRewinder(maEventMultiplexer, maEventQueue, maUserEventQueue),
601 0 : maFrameSynchronization(1.0 / FrameRate::PreferredFramesPerSecond)
602 :
603 : {
604 : // keep care not constructing any UNO references to this inside ctor,
605 : // shift that code to create()!
606 :
607 : uno::Reference<lang::XMultiComponentFactory> xFactory(
608 0 : mxComponentContext->getServiceManager() );
609 :
610 0 : if( xFactory.is() )
611 : {
612 : try
613 : {
614 : // #i82460# try to retrieve special transition factory
615 : mxOptionalTransitionFactory.set(
616 0 : xFactory->createInstanceWithContext(
617 : ::rtl::OUString("com.sun.star.presentation.TransitionFactory" ),
618 0 : mxComponentContext ),
619 0 : uno::UNO_QUERY );
620 : }
621 0 : catch (loader::CannotActivateFactoryException const&)
622 : {
623 : }
624 : }
625 :
626 : mpListener.reset( new SeparateListenerImpl(
627 : *this,
628 : maScreenUpdater,
629 0 : maEventQueue ));
630 0 : maEventMultiplexer.addSlideAnimationsEndHandler( mpListener );
631 0 : maEventMultiplexer.addViewRepaintHandler( mpListener );
632 0 : maEventMultiplexer.addHyperlinkHandler( mpListener, 0.0 );
633 0 : maEventMultiplexer.addAnimationStartHandler( mpListener );
634 0 : maEventMultiplexer.addAnimationEndHandler( mpListener );
635 0 : }
636 :
637 : // we are about to be disposed (someone call dispose() on us)
638 0 : void SlideShowImpl::disposing()
639 : {
640 0 : osl::MutexGuard const guard( m_aMutex );
641 :
642 0 : maEffectRewinder.dispose();
643 :
644 : // stop slide transition sound, if any:
645 0 : stopSlideTransitionSound();
646 :
647 0 : mxComponentContext.clear();
648 :
649 0 : if( mpCurrentSlideTransitionSound )
650 : {
651 0 : mpCurrentSlideTransitionSound->dispose();
652 0 : mpCurrentSlideTransitionSound.reset();
653 : }
654 :
655 0 : mpWaitSymbol.reset();
656 :
657 0 : if( mpRehearseTimingsActivity )
658 : {
659 0 : mpRehearseTimingsActivity->dispose();
660 0 : mpRehearseTimingsActivity.reset();
661 : }
662 :
663 0 : if( mpListener )
664 : {
665 0 : maEventMultiplexer.removeSlideAnimationsEndHandler(mpListener);
666 0 : maEventMultiplexer.removeViewRepaintHandler(mpListener);
667 0 : maEventMultiplexer.removeHyperlinkHandler(mpListener);
668 0 : maEventMultiplexer.removeAnimationStartHandler( mpListener );
669 0 : maEventMultiplexer.removeAnimationEndHandler( mpListener );
670 :
671 0 : mpListener.reset();
672 : }
673 :
674 0 : maUserEventQueue.clear();
675 0 : maActivitiesQueue.clear();
676 0 : maEventMultiplexer.clear();
677 0 : maEventQueue.clear();
678 0 : mpPresTimer.reset();
679 0 : maShapeCursors.clear();
680 0 : maShapeEventListeners.clear();
681 :
682 : // send all listeners a disposing() that we are going down:
683 : maListenerContainer.disposeAndClear(
684 0 : lang::EventObject( static_cast<cppu::OWeakObject *>(this) ) );
685 :
686 0 : maViewContainer.dispose();
687 :
688 : // release slides:
689 0 : mxPrefetchAnimationNode.clear();
690 0 : mxPrefetchSlide.clear();
691 0 : mpPrefetchSlide.reset();
692 0 : mpCurrentSlide.reset();
693 0 : mpPreviousSlide.reset();
694 0 : }
695 :
696 : /// stops the current slide transition sound
697 0 : void SlideShowImpl::stopSlideTransitionSound()
698 : {
699 0 : if (mpCurrentSlideTransitionSound)
700 : {
701 0 : mpCurrentSlideTransitionSound->stopPlayback();
702 0 : mpCurrentSlideTransitionSound->dispose();
703 0 : mpCurrentSlideTransitionSound.reset();
704 : }
705 0 : }
706 :
707 0 : SoundPlayerSharedPtr SlideShowImpl::resetSlideTransitionSound( const uno::Any& rSound, bool bLoopSound )
708 : {
709 0 : sal_Bool bStopSound = sal_False;
710 0 : rtl::OUString url;
711 :
712 0 : if( !(rSound >>= bStopSound) )
713 0 : bStopSound = sal_False;
714 0 : rSound >>= url;
715 :
716 0 : if( !bStopSound && url.isEmpty() )
717 0 : return SoundPlayerSharedPtr();
718 :
719 0 : stopSlideTransitionSound();
720 :
721 0 : if (!url.isEmpty())
722 : {
723 : try
724 : {
725 : mpCurrentSlideTransitionSound = SoundPlayer::create(
726 0 : maEventMultiplexer, url, mxComponentContext );
727 0 : mpCurrentSlideTransitionSound->setPlaybackLoop( bLoopSound );
728 : }
729 0 : catch (lang::NoSupportException const&)
730 : {
731 : // catch possible exceptions from SoundPlayer, since
732 : // being not able to playback the sound is not a hard
733 : // error here (still, the slide transition should be
734 : // shown).
735 : }
736 : }
737 0 : return mpCurrentSlideTransitionSound;
738 : }
739 :
740 0 : ActivitySharedPtr SlideShowImpl::createSlideTransition(
741 : const uno::Reference< drawing::XDrawPage >& xDrawPage,
742 : const SlideSharedPtr& rLeavingSlide,
743 : const SlideSharedPtr& rEnteringSlide,
744 : const EventSharedPtr& rTransitionEndEvent)
745 : {
746 0 : ENSURE_OR_THROW( !maViewContainer.empty(),
747 : "createSlideTransition(): No views" );
748 0 : ENSURE_OR_THROW( rEnteringSlide,
749 : "createSlideTransition(): No entering slide" );
750 :
751 : // return empty transition, if slide transitions
752 : // are disabled.
753 0 : if (mbNoSlideTransitions)
754 0 : return ActivitySharedPtr();
755 :
756 : // retrieve slide change parameters from XDrawPage
757 : uno::Reference< beans::XPropertySet > xPropSet( xDrawPage,
758 0 : uno::UNO_QUERY );
759 :
760 0 : if( !xPropSet.is() )
761 : {
762 : OSL_TRACE( "createSlideTransition(): "
763 : "Slide has no PropertySet - assuming no transition\n" );
764 0 : return ActivitySharedPtr();
765 : }
766 :
767 0 : sal_Int16 nTransitionType(0);
768 0 : if( !getPropertyValue( nTransitionType,
769 : xPropSet,
770 0 : OUSTR("TransitionType" )) )
771 : {
772 : OSL_TRACE( "createSlideTransition(): "
773 : "Could not extract slide transition type from XDrawPage - assuming no transition\n" );
774 0 : return ActivitySharedPtr();
775 : }
776 :
777 0 : sal_Int16 nTransitionSubType(0);
778 0 : if( !getPropertyValue( nTransitionSubType,
779 : xPropSet,
780 0 : OUSTR("TransitionSubtype" )) )
781 : {
782 : OSL_TRACE( "createSlideTransition(): "
783 : "Could not extract slide transition subtype from XDrawPage - assuming no transition\n" );
784 0 : return ActivitySharedPtr();
785 : }
786 :
787 0 : bool bTransitionDirection(false);
788 0 : if( !getPropertyValue( bTransitionDirection,
789 : xPropSet,
790 0 : OUSTR("TransitionDirection")) )
791 : {
792 : OSL_TRACE( "createSlideTransition(): "
793 : "Could not extract slide transition direction from XDrawPage - assuming default direction\n" );
794 : }
795 :
796 0 : sal_Int32 aUnoColor(0);
797 0 : if( !getPropertyValue( aUnoColor,
798 : xPropSet,
799 0 : OUSTR("TransitionFadeColor")) )
800 : {
801 : OSL_TRACE( "createSlideTransition(): "
802 : "Could not extract slide transition fade color from XDrawPage - assuming black\n" );
803 : }
804 :
805 0 : const RGBColor aTransitionFadeColor( unoColor2RGBColor( aUnoColor ));
806 :
807 0 : uno::Any aSound;
808 0 : sal_Bool bLoopSound = sal_False;
809 :
810 0 : if( !getPropertyValue( aSound, xPropSet, OUSTR("Sound")) )
811 : OSL_TRACE( "createSlideTransition(): Could not determine transition sound effect URL from XDrawPage - using no sound" );
812 :
813 0 : if( !getPropertyValue( bLoopSound, xPropSet, OUSTR("LoopSound") ) )
814 : OSL_TRACE( "createSlideTransition(): Could not get slide property 'LoopSound' - using no sound" );
815 :
816 : NumberAnimationSharedPtr pTransition(
817 : TransitionFactory::createSlideTransition(
818 : rLeavingSlide,
819 : rEnteringSlide,
820 : maViewContainer,
821 : maScreenUpdater,
822 : maEventMultiplexer,
823 : mxOptionalTransitionFactory,
824 : nTransitionType,
825 : nTransitionSubType,
826 : bTransitionDirection,
827 : aTransitionFadeColor,
828 0 : resetSlideTransitionSound( aSound, bLoopSound ) ));
829 :
830 0 : if( !pTransition )
831 0 : return ActivitySharedPtr(); // no transition effect has been
832 : // generated. Normally, that means
833 : // that simply no transition is
834 : // set on this slide.
835 :
836 0 : double nTransitionDuration(0.0);
837 0 : if( !getPropertyValue( nTransitionDuration,
838 : xPropSet,
839 0 : OUSTR("TransitionDuration")) )
840 : {
841 : OSL_TRACE( "createSlideTransition(): "
842 : "Could not extract slide transition duration from XDrawPage - assuming no transition\n" );
843 0 : return ActivitySharedPtr();
844 : }
845 :
846 0 : sal_Int32 nMinFrames(5);
847 0 : if( !getPropertyValue( nMinFrames,
848 : xPropSet,
849 0 : OUSTR("MinimalFrameNumber")) )
850 : {
851 : OSL_TRACE( "createSlideTransition(): "
852 : "No minimal number of frames given - assuming 5\n" );
853 : }
854 :
855 : // prefetch slide transition bitmaps, but postpone it after
856 : // displaySlide() has finished - sometimes, view size has not yet
857 : // reached final size
858 : maEventQueue.addEvent(
859 : makeEvent(
860 : boost::bind(
861 : &::slideshow::internal::Animation::prefetch,
862 : pTransition,
863 : AnimatableShapeSharedPtr(),
864 : ShapeAttributeLayerSharedPtr()),
865 0 : "Animation::prefetch"));
866 :
867 : return ActivitySharedPtr(
868 : ActivitiesFactory::createSimpleActivity(
869 : ActivitiesFactory::CommonParameters(
870 : rTransitionEndEvent,
871 : maEventQueue,
872 : maActivitiesQueue,
873 : nTransitionDuration,
874 : nMinFrames,
875 : false,
876 : boost::optional<double>(1.0),
877 : 0.0,
878 : 0.0,
879 : ShapeSharedPtr(),
880 0 : basegfx::B2DSize( rEnteringSlide->getSlideSize() ) ),
881 : pTransition,
882 0 : true ));
883 : }
884 :
885 0 : PolygonMap::iterator SlideShowImpl::findPolygons( uno::Reference<drawing::XDrawPage> const& xDrawPage)
886 : {
887 : // TODO(P2) : Optimze research in the map.
888 0 : bool bFound = false;
889 0 : PolygonMap::iterator aIter=maPolygons.begin();
890 :
891 0 : while(aIter!=maPolygons.end() && !bFound)
892 : {
893 0 : if(aIter->first == xDrawPage)
894 0 : bFound = true;
895 : else
896 0 : ++aIter;
897 : }
898 :
899 0 : return aIter;
900 : }
901 :
902 0 : SlideSharedPtr SlideShowImpl::makeSlide(
903 : uno::Reference<drawing::XDrawPage> const& xDrawPage,
904 : uno::Reference<drawing::XDrawPagesSupplier> const& xDrawPages,
905 : uno::Reference<animations::XAnimationNode> const& xRootNode )
906 : {
907 0 : if( !xDrawPage.is() )
908 0 : return SlideSharedPtr();
909 :
910 : //Retrieve polygons for the current slide
911 0 : PolygonMap::iterator aIter;
912 0 : aIter = findPolygons(xDrawPage);
913 :
914 : const SlideSharedPtr pSlide( createSlide(xDrawPage,
915 : xDrawPages,
916 : xRootNode,
917 : maEventQueue,
918 : maEventMultiplexer,
919 : maScreenUpdater,
920 : maActivitiesQueue,
921 : maUserEventQueue,
922 : *this,
923 : maViewContainer,
924 : mxComponentContext,
925 : maShapeEventListeners,
926 : maShapeCursors,
927 0 : (aIter != maPolygons.end()) ? aIter->second : PolyPolygonVector(),
928 0 : maUserPaintColor ? *maUserPaintColor : RGBColor(),
929 : maUserPaintStrokeWidth,
930 0 : !!maUserPaintColor,
931 : mbImageAnimationsAllowed,
932 0 : mbDisableAnimationZOrder) );
933 :
934 : // prefetch show content (reducing latency for slide
935 : // bitmap and effect start later on)
936 0 : pSlide->prefetch();
937 :
938 0 : return pSlide;
939 : }
940 :
941 0 : void SlideShowImpl::requestWaitSymbol (void)
942 : {
943 0 : ++mnWaitSymbolRequestCount;
944 : OSL_ASSERT(mnWaitSymbolRequestCount>0);
945 :
946 0 : if (mnWaitSymbolRequestCount == 1)
947 : {
948 0 : if( !mpWaitSymbol )
949 : {
950 : // fall back to cursor
951 0 : requestCursor(calcActiveCursor(mnCurrentCursor));
952 : }
953 : else
954 0 : mpWaitSymbol->show();
955 : }
956 0 : }
957 :
958 0 : void SlideShowImpl::releaseWaitSymbol (void)
959 : {
960 0 : --mnWaitSymbolRequestCount;
961 : OSL_ASSERT(mnWaitSymbolRequestCount>=0);
962 :
963 0 : if (mnWaitSymbolRequestCount == 0)
964 : {
965 0 : if( !mpWaitSymbol )
966 : {
967 : // fall back to cursor
968 0 : requestCursor(calcActiveCursor(mnCurrentCursor));
969 : }
970 : else
971 0 : mpWaitSymbol->hide();
972 : }
973 0 : }
974 :
975 0 : sal_Int16 SlideShowImpl::calcActiveCursor( sal_Int16 nCursorShape ) const
976 : {
977 0 : if( mnWaitSymbolRequestCount>0 && !mpWaitSymbol ) // enforce wait cursor
978 0 : nCursorShape = awt::SystemPointer::WAIT;
979 0 : else if( !mbMouseVisible ) // enforce INVISIBLE
980 0 : nCursorShape = awt::SystemPointer::INVISIBLE;
981 0 : else if( maUserPaintColor &&
982 0 : nCursorShape == awt::SystemPointer::ARROW )
983 0 : nCursorShape = awt::SystemPointer::PEN;
984 :
985 0 : return nCursorShape;
986 : }
987 :
988 0 : void SlideShowImpl::stopShow()
989 : {
990 : // Force-end running animation
991 : // ===========================
992 0 : if (mpCurrentSlide)
993 : {
994 0 : mpCurrentSlide->hide();
995 : //Register polygons in the map
996 0 : if(findPolygons(mpCurrentSlide->getXDrawPage()) != maPolygons.end())
997 0 : maPolygons.erase(mpCurrentSlide->getXDrawPage());
998 :
999 0 : maPolygons.insert(make_pair(mpCurrentSlide->getXDrawPage(),mpCurrentSlide->getPolygons()));
1000 : }
1001 :
1002 : // clear all queues
1003 0 : maEventQueue.clear();
1004 0 : maActivitiesQueue.clear();
1005 :
1006 : // Attention: we MUST clear the user event queue here,
1007 : // this is because the current slide might have registered
1008 : // shape events (click or enter/leave), which might
1009 : // otherwise dangle forever in the queue (because of the
1010 : // shared ptr nature). If someone needs to change this:
1011 : // somehow unregister those shapes at the user event queue
1012 : // on notifySlideEnded().
1013 0 : maUserEventQueue.clear();
1014 :
1015 : // re-enable automatic effect advancement
1016 : // (maEventQueue.clear() above might have killed
1017 : // maEventMultiplexer's tick events)
1018 0 : if (mbAutomaticAdvancementMode)
1019 : {
1020 : // toggle automatic mode (enabling just again is
1021 : // ignored by EventMultiplexer)
1022 0 : maEventMultiplexer.setAutomaticMode( false );
1023 0 : maEventMultiplexer.setAutomaticMode( true );
1024 : }
1025 0 : }
1026 :
1027 : class SlideShowImpl::PrefetchPropertiesFunc
1028 : {
1029 : public:
1030 0 : PrefetchPropertiesFunc( SlideShowImpl * that_,
1031 : bool& rbSkipAllMainSequenceEffects,
1032 : bool& rbSkipSlideTransition)
1033 : : mpSlideShowImpl(that_),
1034 : mrbSkipAllMainSequenceEffects(rbSkipAllMainSequenceEffects),
1035 0 : mrbSkipSlideTransition(rbSkipSlideTransition)
1036 0 : {}
1037 :
1038 0 : void operator()( beans::PropertyValue const& rProperty ) const {
1039 0 : if (rProperty.Name == "Prefetch" )
1040 : {
1041 0 : uno::Sequence<uno::Any> seq;
1042 0 : if ((rProperty.Value >>= seq) && seq.getLength() == 2)
1043 : {
1044 0 : seq[0] >>= mpSlideShowImpl->mxPrefetchSlide;
1045 0 : seq[1] >>= mpSlideShowImpl->mxPrefetchAnimationNode;
1046 0 : }
1047 : }
1048 0 : else if ( rProperty.Name == "SkipAllMainSequenceEffects" )
1049 : {
1050 0 : rProperty.Value >>= mrbSkipAllMainSequenceEffects;
1051 : }
1052 0 : else if ( rProperty.Name == "SkipSlideTransition" )
1053 : {
1054 0 : rProperty.Value >>= mrbSkipSlideTransition;
1055 : }
1056 : else
1057 : {
1058 : OSL_FAIL( rtl::OUStringToOString(
1059 : rProperty.Name, RTL_TEXTENCODING_UTF8 ).getStr() );
1060 : }
1061 0 : }
1062 : private:
1063 : SlideShowImpl *const mpSlideShowImpl;
1064 : bool& mrbSkipAllMainSequenceEffects;
1065 : bool& mrbSkipSlideTransition;
1066 : };
1067 :
1068 0 : void SlideShowImpl::displaySlide(
1069 : uno::Reference<drawing::XDrawPage> const& xSlide,
1070 : uno::Reference<drawing::XDrawPagesSupplier> const& xDrawPages,
1071 : uno::Reference<animations::XAnimationNode> const& xRootNode,
1072 : uno::Sequence<beans::PropertyValue> const& rProperties )
1073 : throw (uno::RuntimeException)
1074 : {
1075 0 : osl::MutexGuard const guard( m_aMutex );
1076 :
1077 0 : if (isDisposed())
1078 : return;
1079 :
1080 0 : maEffectRewinder.setRootAnimationNode(xRootNode);
1081 :
1082 : // precondition: must only be called from the main thread!
1083 : DBG_TESTSOLARMUTEX();
1084 :
1085 0 : mxDrawPagesSupplier = xDrawPages;
1086 :
1087 0 : stopShow(); // MUST call that: results in
1088 : // maUserEventQueue.clear(). What's more,
1089 : // stopShow()'s currSlide->hide() call is
1090 : // now also required, notifySlideEnded()
1091 : // relies on that
1092 : // unconditionally. Otherwise, genuine
1093 : // shape animations (drawing layer and
1094 : // GIF) will not be stopped.
1095 :
1096 0 : bool bSkipAllMainSequenceEffects (false);
1097 0 : bool bSkipSlideTransition (false);
1098 : std::for_each( rProperties.getConstArray(),
1099 0 : rProperties.getConstArray() + rProperties.getLength(),
1100 0 : PrefetchPropertiesFunc(this, bSkipAllMainSequenceEffects, bSkipSlideTransition) );
1101 :
1102 : OSL_ENSURE( !maViewContainer.empty(), "### no views!" );
1103 0 : if (maViewContainer.empty())
1104 : return;
1105 :
1106 : // this here might take some time
1107 : {
1108 0 : WaitSymbolLock aLock (*this);
1109 :
1110 0 : mpPreviousSlide = mpCurrentSlide;
1111 0 : mpCurrentSlide.reset();
1112 :
1113 0 : if (matches( mpPrefetchSlide, xSlide, xRootNode ))
1114 : {
1115 : // prefetched slide matches:
1116 0 : mpCurrentSlide = mpPrefetchSlide;
1117 : }
1118 : else
1119 0 : mpCurrentSlide = makeSlide( xSlide, xDrawPages, xRootNode );
1120 :
1121 : OSL_ASSERT( mpCurrentSlide );
1122 0 : if (mpCurrentSlide)
1123 : {
1124 0 : basegfx::B2DSize oldSlideSize;
1125 0 : if( mpPreviousSlide )
1126 0 : oldSlideSize = basegfx::B2DSize( mpPreviousSlide->getSlideSize() );
1127 :
1128 0 : basegfx::B2DSize const slideSize( mpCurrentSlide->getSlideSize() );
1129 :
1130 : // push new transformation to all views, if size changed
1131 0 : if( !mpPreviousSlide || oldSlideSize != slideSize )
1132 : {
1133 : std::for_each( maViewContainer.begin(),
1134 : maViewContainer.end(),
1135 : boost::bind( &View::setViewSize, _1,
1136 0 : boost::cref(slideSize) ));
1137 :
1138 : // explicitly notify view change here,
1139 : // because transformation might have changed:
1140 : // optimization, this->notifyViewChange() would
1141 : // repaint slide which is not necessary.
1142 0 : maEventMultiplexer.notifyViewsChanged();
1143 : }
1144 :
1145 : // create slide transition, and add proper end event
1146 : // (which then starts the slide effects
1147 : // via CURRENT_SLIDE.show())
1148 : ActivitySharedPtr pSlideChangeActivity (
1149 : createSlideTransition(
1150 0 : mpCurrentSlide->getXDrawPage(),
1151 : mpPreviousSlide,
1152 : mpCurrentSlide,
1153 0 : makeEvent(
1154 : boost::bind(
1155 : &SlideShowImpl::notifySlideTransitionEnded,
1156 : this,
1157 : false ),
1158 0 : "SlideShowImpl::notifySlideTransitionEnded")));
1159 :
1160 0 : if (bSkipSlideTransition)
1161 : {
1162 : // The transition activity was created for the side effects
1163 : // (like sound transitions). Because we want to skip the
1164 : // acutual transition animation we do not need the activity
1165 : // anymore.
1166 0 : pSlideChangeActivity.reset();
1167 : }
1168 :
1169 0 : if (pSlideChangeActivity)
1170 : {
1171 : // factory generated a slide transition - activate it!
1172 0 : maActivitiesQueue.addActivity( pSlideChangeActivity );
1173 : }
1174 : else
1175 : {
1176 : // no transition effect on this slide - schedule slide
1177 : // effect start event right away.
1178 : maEventQueue.addEvent(
1179 0 : makeEvent(
1180 : boost::bind(
1181 : &SlideShowImpl::notifySlideTransitionEnded,
1182 : this,
1183 : true ),
1184 0 : "SlideShowImpl::notifySlideTransitionEnded"));
1185 0 : }
1186 0 : }
1187 : } // finally
1188 :
1189 0 : maEventMultiplexer.notifySlideTransitionStarted();
1190 : maListenerContainer.forEach<presentation::XSlideShowListener>(
1191 0 : boost::mem_fn( &presentation::XSlideShowListener::slideTransitionStarted ) );
1192 :
1193 : // We are currently rewinding an effect. This lead us from the next
1194 : // slide to this one. To complete this we have to play back all main
1195 : // sequence effects on this slide.
1196 0 : if (bSkipAllMainSequenceEffects)
1197 0 : maEffectRewinder.skipAllMainSequenceEffects();
1198 : }
1199 :
1200 0 : void SlideShowImpl::redisplayCurrentSlide (void)
1201 : {
1202 0 : osl::MutexGuard const guard( m_aMutex );
1203 :
1204 0 : if (isDisposed())
1205 : return;
1206 :
1207 : // precondition: must only be called from the main thread!
1208 : DBG_TESTSOLARMUTEX();
1209 0 : stopShow();
1210 :
1211 : OSL_ENSURE( !maViewContainer.empty(), "### no views!" );
1212 0 : if (maViewContainer.empty())
1213 : return;
1214 :
1215 : // No transition effect on this slide - schedule slide
1216 : // effect start event right away.
1217 : maEventQueue.addEvent(
1218 0 : makeEvent(
1219 : boost::bind(
1220 : &SlideShowImpl::notifySlideTransitionEnded,
1221 : this,
1222 : true ),
1223 0 : "SlideShowImpl::notifySlideTransitionEnded"));
1224 :
1225 0 : maEventMultiplexer.notifySlideTransitionStarted();
1226 : maListenerContainer.forEach<presentation::XSlideShowListener>(
1227 0 : boost::mem_fn( &presentation::XSlideShowListener::slideTransitionStarted ) );
1228 : }
1229 :
1230 0 : sal_Bool SlideShowImpl::nextEffect() throw (uno::RuntimeException)
1231 : {
1232 0 : osl::MutexGuard const guard( m_aMutex );
1233 :
1234 0 : if (isDisposed())
1235 0 : return false;
1236 :
1237 : // precondition: must only be called from the main thread!
1238 : DBG_TESTSOLARMUTEX();
1239 :
1240 0 : if (mbShowPaused)
1241 0 : return true;
1242 : else
1243 0 : return maEventMultiplexer.notifyNextEffect();
1244 : }
1245 :
1246 0 : sal_Bool SlideShowImpl::previousEffect() throw (uno::RuntimeException)
1247 : {
1248 0 : osl::MutexGuard const guard( m_aMutex );
1249 :
1250 0 : if (isDisposed())
1251 0 : return false;
1252 :
1253 : // precondition: must only be called from the main thread!
1254 : DBG_TESTSOLARMUTEX();
1255 :
1256 0 : if (mbShowPaused)
1257 0 : return true;
1258 : else
1259 : {
1260 : return maEffectRewinder.rewind(
1261 : maScreenUpdater.createLock(false),
1262 : ::boost::bind<void>(::boost::mem_fn(&SlideShowImpl::redisplayCurrentSlide), this),
1263 0 : ::boost::bind<void>(::boost::mem_fn(&SlideShowImpl::rewindEffectToPreviousSlide), this));
1264 0 : }
1265 : }
1266 :
1267 0 : void SlideShowImpl::rewindEffectToPreviousSlide (void)
1268 : {
1269 : // Show the wait symbol now and prevent it from showing temporary slide
1270 : // content while effects are played back.
1271 0 : WaitSymbolLock aLock (*this);
1272 :
1273 : // A previous call to EffectRewinder::Rewind could not rewind the current
1274 : // effect because there are no effects on the current slide or none has
1275 : // yet been displayed. Go to the previous slide.
1276 0 : notifySlideEnded(true);
1277 :
1278 : // Process pending events once more in order to have the following
1279 : // screen update show the last effect. Not sure whether this should be
1280 : // necessary.
1281 0 : maEventQueue.forceEmpty();
1282 :
1283 : // We have to call the screen updater before the wait symbol is turned
1284 : // off. Otherwise the wait symbol would force the display of an
1285 : // intermediate state of the slide (before the effects are replayed.)
1286 0 : maScreenUpdater.commitUpdates();
1287 0 : }
1288 :
1289 0 : sal_Bool SlideShowImpl::startShapeActivity(
1290 : uno::Reference<drawing::XShape> const& /*xShape*/ )
1291 : throw (uno::RuntimeException)
1292 : {
1293 0 : osl::MutexGuard const guard( m_aMutex );
1294 :
1295 : // precondition: must only be called from the main thread!
1296 : DBG_TESTSOLARMUTEX();
1297 :
1298 : // TODO(F3): NYI
1299 : OSL_FAIL( "not yet implemented!" );
1300 0 : return false;
1301 : }
1302 :
1303 0 : sal_Bool SlideShowImpl::stopShapeActivity(
1304 : uno::Reference<drawing::XShape> const& /*xShape*/ )
1305 : throw (uno::RuntimeException)
1306 : {
1307 0 : osl::MutexGuard const guard( m_aMutex );
1308 :
1309 : // precondition: must only be called from the main thread!
1310 : DBG_TESTSOLARMUTEX();
1311 :
1312 : // TODO(F3): NYI
1313 : OSL_FAIL( "not yet implemented!" );
1314 0 : return false;
1315 : }
1316 :
1317 0 : sal_Bool SlideShowImpl::pause( sal_Bool bPauseShow )
1318 : throw (uno::RuntimeException)
1319 : {
1320 0 : osl::MutexGuard const guard( m_aMutex );
1321 :
1322 0 : if (isDisposed())
1323 0 : return false;
1324 :
1325 : // precondition: must only be called from the main thread!
1326 : DBG_TESTSOLARMUTEX();
1327 :
1328 0 : if (bPauseShow)
1329 0 : mpPresTimer->pauseTimer();
1330 : else
1331 0 : mpPresTimer->continueTimer();
1332 :
1333 0 : maEventMultiplexer.notifyPauseMode(bPauseShow);
1334 :
1335 0 : mbShowPaused = bPauseShow;
1336 0 : return true;
1337 : }
1338 :
1339 0 : uno::Reference<drawing::XDrawPage> SlideShowImpl::getCurrentSlide()
1340 : throw (uno::RuntimeException)
1341 : {
1342 0 : osl::MutexGuard const guard( m_aMutex );
1343 :
1344 0 : if (isDisposed())
1345 0 : return uno::Reference<drawing::XDrawPage>();
1346 :
1347 : // precondition: must only be called from the main thread!
1348 : DBG_TESTSOLARMUTEX();
1349 :
1350 0 : if (mpCurrentSlide)
1351 0 : return mpCurrentSlide->getXDrawPage();
1352 : else
1353 0 : return uno::Reference<drawing::XDrawPage>();
1354 : }
1355 :
1356 0 : sal_Bool SlideShowImpl::addView(
1357 : uno::Reference<presentation::XSlideShowView> const& xView )
1358 : throw (uno::RuntimeException)
1359 : {
1360 0 : osl::MutexGuard const guard( m_aMutex );
1361 :
1362 0 : if (isDisposed())
1363 0 : return false;
1364 :
1365 : // precondition: must only be called from the main thread!
1366 : DBG_TESTSOLARMUTEX();
1367 :
1368 : // first of all, check if view has a valid canvas
1369 0 : ENSURE_OR_RETURN_FALSE( xView.is(), "addView(): Invalid view" );
1370 0 : ENSURE_OR_RETURN_FALSE( xView->getCanvas().is(),
1371 : "addView(): View does not provide a valid canvas" );
1372 :
1373 : UnoViewSharedPtr const pView( createSlideView(
1374 : xView,
1375 : maEventQueue,
1376 0 : maEventMultiplexer ));
1377 0 : if (!maViewContainer.addView( pView ))
1378 0 : return false; // view already added
1379 :
1380 : // initialize view content
1381 : // =======================
1382 :
1383 0 : if (mpCurrentSlide)
1384 : {
1385 : // set view transformation
1386 0 : const basegfx::B2ISize slideSize = mpCurrentSlide->getSlideSize();
1387 0 : pView->setViewSize( basegfx::B2DSize( slideSize.getX(),
1388 0 : slideSize.getY() ) );
1389 : }
1390 :
1391 : // clear view area (since its newly added,
1392 : // we need a clean slate)
1393 0 : pView->clearAll();
1394 :
1395 : // broadcast newly added view
1396 0 : maEventMultiplexer.notifyViewAdded( pView );
1397 :
1398 : // set current mouse ptr
1399 0 : pView->setCursorShape( calcActiveCursor(mnCurrentCursor) );
1400 :
1401 0 : return true;
1402 : }
1403 :
1404 0 : sal_Bool SlideShowImpl::removeView(
1405 : uno::Reference<presentation::XSlideShowView> const& xView )
1406 : throw (uno::RuntimeException)
1407 : {
1408 0 : osl::MutexGuard const guard( m_aMutex );
1409 :
1410 : // precondition: must only be called from the main thread!
1411 : DBG_TESTSOLARMUTEX();
1412 :
1413 0 : ENSURE_OR_RETURN_FALSE( xView.is(), "removeView(): Invalid view" );
1414 :
1415 0 : UnoViewSharedPtr const pView( maViewContainer.removeView( xView ) );
1416 0 : if( !pView )
1417 0 : return false; // view was not added in the first place
1418 :
1419 : // remove view from EventMultiplexer (mouse events etc.)
1420 0 : maEventMultiplexer.notifyViewRemoved( pView );
1421 :
1422 0 : pView->_dispose();
1423 :
1424 0 : return true;
1425 : }
1426 :
1427 0 : void SlideShowImpl::registerUserPaintPolygons( const uno::Reference< lang::XMultiServiceFactory >& xDocFactory ) throw (uno::RuntimeException)
1428 : {
1429 : //Retrieve Polygons if user ends presentation by context menu
1430 0 : if (mpCurrentSlide)
1431 : {
1432 0 : if(findPolygons(mpCurrentSlide->getXDrawPage()) != maPolygons.end())
1433 0 : maPolygons.erase(mpCurrentSlide->getXDrawPage());
1434 :
1435 0 : maPolygons.insert(make_pair(mpCurrentSlide->getXDrawPage(),mpCurrentSlide->getPolygons()));
1436 : }
1437 :
1438 : //Creating the layer for shapes
1439 : // query for the XLayerManager
1440 0 : uno::Reference< drawing::XLayerSupplier > xLayerSupplier(xDocFactory, uno::UNO_QUERY);
1441 0 : uno::Reference< container::XNameAccess > xNameAccess = xLayerSupplier->getLayerManager();
1442 :
1443 0 : uno::Reference< drawing::XLayerManager > xLayerManager(xNameAccess, uno::UNO_QUERY);
1444 : // create a layer and set its properties
1445 0 : uno::Reference< drawing::XLayer > xDrawnInSlideshow = xLayerManager->insertNewByIndex(xLayerManager->getCount());
1446 0 : uno::Reference< beans::XPropertySet > xLayerPropSet(xDrawnInSlideshow, uno::UNO_QUERY);
1447 :
1448 : //Layer Name which enables to catch annotations
1449 0 : rtl::OUString layerName = rtl::OUString("DrawnInSlideshow");
1450 0 : uno::Any aPropLayer;
1451 :
1452 0 : aPropLayer <<= layerName;
1453 0 : xLayerPropSet->setPropertyValue(rtl::OUString("Name"), aPropLayer);
1454 :
1455 0 : aPropLayer <<= true;
1456 0 : xLayerPropSet->setPropertyValue(rtl::OUString("IsVisible"), aPropLayer);
1457 :
1458 0 : aPropLayer <<= false;
1459 0 : xLayerPropSet->setPropertyValue(rtl::OUString("IsLocked"), aPropLayer);
1460 :
1461 0 : PolygonMap::iterator aIter=maPolygons.begin();
1462 :
1463 0 : PolyPolygonVector aPolygons;
1464 0 : ::cppcanvas::PolyPolygonSharedPtr pPolyPoly;
1465 0 : ::basegfx::B2DPolyPolygon b2DPolyPoly;
1466 :
1467 : //Register polygons for each slide
1468 0 : while(aIter!=maPolygons.end())
1469 : {
1470 0 : aPolygons = aIter->second;
1471 : //Get shapes for the slide
1472 0 : ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > Shapes(aIter->first, ::com::sun::star::uno::UNO_QUERY);
1473 : //Retrieve polygons for one slide
1474 0 : for( PolyPolygonVector::iterator aIterPoly=aPolygons.begin(),
1475 0 : aEnd=aPolygons.end();
1476 : aIterPoly!=aEnd; ++aIterPoly )
1477 : {
1478 0 : pPolyPoly = (*aIterPoly);
1479 0 : b2DPolyPoly = ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(pPolyPoly->getUNOPolyPolygon());
1480 :
1481 : //Normally there is only one polygon
1482 0 : for(sal_uInt32 i=0; i< b2DPolyPoly.count();i++)
1483 : {
1484 0 : const ::basegfx::B2DPolygon& aPoly = b2DPolyPoly.getB2DPolygon(i);
1485 0 : sal_uInt32 nPoints = aPoly.count();
1486 :
1487 0 : if( nPoints > 1)
1488 : {
1489 : //create the PolyLineShape
1490 0 : uno::Reference< uno::XInterface > polyshape(xDocFactory->createInstance(
1491 0 : rtl::OUString("com.sun.star.drawing.PolyLineShape") ) );
1492 0 : uno::Reference< drawing::XShape > rPolyShape(polyshape, uno::UNO_QUERY);
1493 :
1494 : //Add the shape to the slide
1495 0 : Shapes->add(rPolyShape);
1496 :
1497 : //Retrieve shape properties
1498 0 : uno::Reference< beans::XPropertySet > aXPropSet = uno::Reference< beans::XPropertySet >( rPolyShape, uno::UNO_QUERY );
1499 : //Construct a sequence of points sequence
1500 0 : drawing::PointSequenceSequence aRetval;
1501 : //Create only one sequence for one polygon
1502 0 : aRetval.realloc( 1 );
1503 : // Retrieve the sequence of points from aRetval
1504 0 : drawing::PointSequence* pOuterSequence = aRetval.getArray();
1505 : // Create 2 points in this sequence
1506 0 : pOuterSequence->realloc(nPoints);
1507 : // Get these points which are in an array
1508 0 : awt::Point* pInnerSequence = pOuterSequence->getArray();
1509 0 : for( sal_uInt32 n = 0; n < nPoints; n++ )
1510 : {
1511 : //Create a point from the polygon
1512 : *pInnerSequence++ = awt::Point(
1513 0 : basegfx::fround(aPoly.getB2DPoint(n).getX()),
1514 0 : basegfx::fround(aPoly.getB2DPoint(n).getY()));
1515 : }
1516 :
1517 : //Fill the properties
1518 : //Give the built PointSequenceSequence.
1519 0 : uno::Any aParam;
1520 0 : aParam <<= aRetval;
1521 0 : aXPropSet->setPropertyValue( rtl::OUString("PolyPolygon"), aParam );
1522 :
1523 : //LineStyle : SOLID by default
1524 0 : uno::Any aAny;
1525 : drawing::LineStyle eLS;
1526 0 : eLS = drawing::LineStyle_SOLID;
1527 0 : aAny <<= eLS;
1528 0 : aXPropSet->setPropertyValue( rtl::OUString("LineStyle"), aAny );
1529 :
1530 : //LineColor
1531 : sal_uInt32 nLineColor;
1532 0 : nLineColor = pPolyPoly->getRGBALineColor();
1533 : //Transform polygon color from RRGGBBAA to AARRGGBB
1534 0 : aAny <<= RGBAColor2UnoColor(nLineColor);
1535 0 : aXPropSet->setPropertyValue( rtl::OUString("LineColor"), aAny );
1536 :
1537 : //LineWidth
1538 : double fLineWidth;
1539 0 : fLineWidth = pPolyPoly->getStrokeWidth();
1540 0 : aAny <<= (sal_Int32)fLineWidth;
1541 0 : aXPropSet->setPropertyValue( rtl::OUString("LineWidth"), aAny );
1542 :
1543 : // make polygons special
1544 0 : xLayerManager->attachShapeToLayer(rPolyShape, xDrawnInSlideshow);
1545 : }
1546 0 : }
1547 : }
1548 0 : ++aIter;
1549 0 : }
1550 0 : }
1551 :
1552 0 : sal_Bool SlideShowImpl::setProperty( beans::PropertyValue const& rProperty )
1553 : throw (uno::RuntimeException)
1554 : {
1555 0 : osl::MutexGuard const guard( m_aMutex );
1556 :
1557 0 : if (isDisposed())
1558 0 : return false;
1559 :
1560 : // precondition: must only be called from the main thread!
1561 : DBG_TESTSOLARMUTEX();
1562 :
1563 0 : if ( rProperty.Name == "AutomaticAdvancement" )
1564 : {
1565 0 : double nTimeout(0.0);
1566 0 : mbAutomaticAdvancementMode = (rProperty.Value >>= nTimeout);
1567 0 : if (mbAutomaticAdvancementMode)
1568 : {
1569 0 : maEventMultiplexer.setAutomaticTimeout( nTimeout );
1570 : }
1571 0 : maEventMultiplexer.setAutomaticMode( mbAutomaticAdvancementMode );
1572 0 : return true;
1573 : }
1574 :
1575 0 : if ( rProperty.Name == "UserPaintColor" )
1576 : {
1577 0 : sal_Int32 nColor(0);
1578 0 : if (rProperty.Value >>= nColor)
1579 : {
1580 : OSL_ENSURE( mbMouseVisible,
1581 : "setProperty(): User paint overrides invisible mouse" );
1582 :
1583 : // enable user paint
1584 0 : maUserPaintColor.reset( unoColor2RGBColor( nColor ) );
1585 0 : if( mpCurrentSlide && !mpCurrentSlide->isPaintOverlayActive() )
1586 0 : mpCurrentSlide->enablePaintOverlay();
1587 :
1588 0 : maEventMultiplexer.notifyUserPaintColor( *maUserPaintColor );
1589 : }
1590 : else
1591 : {
1592 : // disable user paint
1593 0 : maUserPaintColor.reset();
1594 0 : maEventMultiplexer.notifyUserPaintDisabled();
1595 0 : if( mpCurrentSlide )
1596 0 : mpCurrentSlide->disablePaintOverlay();
1597 : }
1598 :
1599 0 : resetCursor();
1600 :
1601 0 : return true;
1602 : }
1603 :
1604 : //adding support for erasing features in UserPaintOverlay
1605 0 : if ( rProperty.Name == "EraseAllInk" )
1606 : {
1607 0 : bool nEraseAllInk(false);
1608 0 : if (rProperty.Value >>= nEraseAllInk)
1609 : {
1610 : OSL_ENSURE( mbMouseVisible,
1611 : "setProperty(): User paint overrides invisible mouse" );
1612 :
1613 : // enable user paint
1614 0 : maEraseAllInk.reset( nEraseAllInk );
1615 0 : maEventMultiplexer.notifyEraseAllInk( *maEraseAllInk );
1616 : }
1617 :
1618 0 : return true;
1619 : }
1620 :
1621 0 : if ( rProperty.Name == "SwitchPenMode" )
1622 : {
1623 0 : bool nSwitchPenMode(false);
1624 0 : if (rProperty.Value >>= nSwitchPenMode)
1625 : {
1626 : OSL_ENSURE( mbMouseVisible,
1627 : "setProperty(): User paint overrides invisible mouse" );
1628 :
1629 0 : if(nSwitchPenMode == true){
1630 : // Switch to Pen Mode
1631 0 : maSwitchPenMode.reset( nSwitchPenMode );
1632 0 : maEventMultiplexer.notifySwitchPenMode();
1633 : }
1634 : }
1635 0 : return true;
1636 : }
1637 :
1638 0 : if ( rProperty.Name == "SwitchEraserMode" )
1639 : {
1640 0 : bool nSwitchEraserMode(false);
1641 0 : if (rProperty.Value >>= nSwitchEraserMode)
1642 : {
1643 : OSL_ENSURE( mbMouseVisible,
1644 : "setProperty(): User paint overrides invisible mouse" );
1645 0 : if(nSwitchEraserMode == true){
1646 : // switch to Eraser mode
1647 0 : maSwitchEraserMode.reset( nSwitchEraserMode );
1648 0 : maEventMultiplexer.notifySwitchEraserMode();
1649 : }
1650 : }
1651 :
1652 0 : return true;
1653 : }
1654 :
1655 0 : if ( rProperty.Name == "EraseInk" )
1656 : {
1657 0 : sal_Int32 nEraseInk(100);
1658 0 : if (rProperty.Value >>= nEraseInk)
1659 : {
1660 : OSL_ENSURE( mbMouseVisible,
1661 : "setProperty(): User paint overrides invisible mouse" );
1662 :
1663 : // enable user paint
1664 0 : maEraseInk.reset( nEraseInk );
1665 0 : maEventMultiplexer.notifyEraseInkWidth( *maEraseInk );
1666 : }
1667 :
1668 0 : return true;
1669 : }
1670 :
1671 : // new Property for pen's width
1672 0 : if ( rProperty.Name == "UserPaintStrokeWidth" )
1673 : {
1674 0 : double nWidth(4.0);
1675 0 : if (rProperty.Value >>= nWidth)
1676 : {
1677 : OSL_ENSURE( mbMouseVisible,"setProperty(): User paint overrides invisible mouse" );
1678 : // enable user paint stroke width
1679 0 : maUserPaintStrokeWidth = nWidth;
1680 0 : maEventMultiplexer.notifyUserPaintStrokeWidth( maUserPaintStrokeWidth );
1681 : }
1682 :
1683 0 : return true;
1684 : }
1685 :
1686 0 : if ( rProperty.Name == "AdvanceOnClick" )
1687 : {
1688 0 : sal_Bool bAdvanceOnClick = sal_False;
1689 0 : if (! (rProperty.Value >>= bAdvanceOnClick))
1690 0 : return false;
1691 0 : maUserEventQueue.setAdvanceOnClick( bAdvanceOnClick );
1692 0 : return true;
1693 : }
1694 :
1695 0 : if ( rProperty.Name == "DisableAnimationZOrder" )
1696 : {
1697 0 : sal_Bool bDisableAnimationZOrder = sal_False;
1698 0 : if (! (rProperty.Value >>= bDisableAnimationZOrder))
1699 0 : return false;
1700 0 : mbDisableAnimationZOrder = bDisableAnimationZOrder == sal_True;
1701 0 : return true;
1702 : }
1703 :
1704 0 : if ( rProperty.Name == "ImageAnimationsAllowed" )
1705 : {
1706 0 : if (! (rProperty.Value >>= mbImageAnimationsAllowed))
1707 0 : return false;
1708 :
1709 : // TODO(F3): Forward to slides!
1710 : // if( bOldValue != mbImageAnimationsAllowed )
1711 : // {
1712 : // if( mbImageAnimationsAllowed )
1713 : // maEventMultiplexer.notifyIntrinsicAnimationsEnabled();
1714 : // else
1715 : // maEventMultiplexer.notifyIntrinsicAnimationsDisabled();
1716 : // }
1717 :
1718 0 : return true;
1719 : }
1720 :
1721 0 : if ( rProperty.Name == "MouseVisible" )
1722 : {
1723 0 : if (! (rProperty.Value >>= mbMouseVisible))
1724 0 : return false;
1725 :
1726 0 : requestCursor(mnCurrentCursor);
1727 :
1728 0 : return true;
1729 : }
1730 :
1731 0 : if ( rProperty.Name == "ForceManualAdvance" )
1732 : {
1733 0 : return (rProperty.Value >>= mbForceManualAdvance);
1734 : }
1735 :
1736 0 : if ( rProperty.Name == "RehearseTimings" )
1737 : {
1738 0 : bool bRehearseTimings = false;
1739 0 : if (! (rProperty.Value >>= bRehearseTimings))
1740 0 : return false;
1741 :
1742 0 : if (bRehearseTimings)
1743 : {
1744 : // TODO(Q3): Move to slide
1745 : mpRehearseTimingsActivity = RehearseTimingsActivity::create(
1746 : SlideShowContext(
1747 : mpDummyPtr,
1748 : maEventQueue,
1749 : maEventMultiplexer,
1750 : maScreenUpdater,
1751 : maActivitiesQueue,
1752 : maUserEventQueue,
1753 : *this,
1754 : maViewContainer,
1755 0 : mxComponentContext) );
1756 : }
1757 0 : else if (mpRehearseTimingsActivity)
1758 : {
1759 : // removes timer from all views:
1760 0 : mpRehearseTimingsActivity->dispose();
1761 0 : mpRehearseTimingsActivity.reset();
1762 : }
1763 0 : return true;
1764 : }
1765 :
1766 0 : if ( rProperty.Name == "WaitSymbolBitmap" )
1767 : {
1768 0 : uno::Reference<rendering::XBitmap> xBitmap;
1769 0 : if (! (rProperty.Value >>= xBitmap))
1770 0 : return false;
1771 :
1772 : mpWaitSymbol = WaitSymbol::create( xBitmap,
1773 : maScreenUpdater,
1774 : maEventMultiplexer,
1775 0 : maViewContainer );
1776 :
1777 0 : return true;
1778 : }
1779 :
1780 0 : if (rProperty.Name.equalsAsciiL(
1781 0 : RTL_CONSTASCII_STRINGPARAM("NoSlideTransitions") ))
1782 : {
1783 0 : return (rProperty.Value >>= mbNoSlideTransitions);
1784 : }
1785 :
1786 0 : if ( rProperty.Name == "IsSoundEnabled" )
1787 : {
1788 0 : uno::Sequence<uno::Any> aValues;
1789 0 : uno::Reference<presentation::XSlideShowView> xView;
1790 0 : sal_Bool bValue (false);
1791 0 : if ((rProperty.Value >>= aValues)
1792 0 : && aValues.getLength()==2
1793 0 : && (aValues[0] >>= xView)
1794 0 : && (aValues[1] >>= bValue))
1795 : {
1796 : // Look up the view.
1797 0 : for (UnoViewVector::const_iterator
1798 0 : iView (maViewContainer.begin()),
1799 0 : iEnd (maViewContainer.end());
1800 : iView!=iEnd;
1801 : ++iView)
1802 : {
1803 0 : if (*iView && (*iView)->getUnoView()==xView)
1804 : {
1805 : // Store the flag at the view so that media shapes have
1806 : // access to it.
1807 0 : (*iView)->setIsSoundEnabled(bValue);
1808 0 : return true;
1809 : }
1810 : }
1811 0 : }
1812 : }
1813 :
1814 0 : return false;
1815 : }
1816 :
1817 0 : void SlideShowImpl::addSlideShowListener(
1818 : uno::Reference<presentation::XSlideShowListener> const& xListener )
1819 : throw (uno::RuntimeException)
1820 : {
1821 0 : osl::MutexGuard const guard( m_aMutex );
1822 :
1823 0 : if (isDisposed())
1824 0 : return;
1825 :
1826 : // container syncs with passed mutex ref
1827 0 : maListenerContainer.addInterface(xListener);
1828 : }
1829 :
1830 0 : void SlideShowImpl::removeSlideShowListener(
1831 : uno::Reference<presentation::XSlideShowListener> const& xListener )
1832 : throw (uno::RuntimeException)
1833 : {
1834 0 : osl::MutexGuard const guard( m_aMutex );
1835 :
1836 : // container syncs with passed mutex ref
1837 0 : maListenerContainer.removeInterface(xListener);
1838 0 : }
1839 :
1840 0 : void SlideShowImpl::addShapeEventListener(
1841 : uno::Reference<presentation::XShapeEventListener> const& xListener,
1842 : uno::Reference<drawing::XShape> const& xShape )
1843 : throw (uno::RuntimeException)
1844 : {
1845 0 : osl::MutexGuard const guard( m_aMutex );
1846 :
1847 0 : if (isDisposed())
1848 0 : return;
1849 :
1850 : // precondition: must only be called from the main thread!
1851 : DBG_TESTSOLARMUTEX();
1852 :
1853 0 : ShapeEventListenerMap::iterator aIter;
1854 0 : if( (aIter=maShapeEventListeners.find( xShape )) ==
1855 0 : maShapeEventListeners.end() )
1856 : {
1857 : // no entry for this shape -> create one
1858 : aIter = maShapeEventListeners.insert(
1859 : ShapeEventListenerMap::value_type(
1860 : xShape,
1861 : boost::shared_ptr<cppu::OInterfaceContainerHelper>(
1862 0 : new cppu::OInterfaceContainerHelper(m_aMutex)))).first;
1863 : }
1864 :
1865 : // add new listener to broadcaster
1866 0 : if( aIter->second.get() )
1867 0 : aIter->second->addInterface( xListener );
1868 :
1869 : maEventMultiplexer.notifyShapeListenerAdded(xListener,
1870 0 : xShape);
1871 : }
1872 :
1873 0 : void SlideShowImpl::removeShapeEventListener(
1874 : uno::Reference<presentation::XShapeEventListener> const& xListener,
1875 : uno::Reference<drawing::XShape> const& xShape )
1876 : throw (uno::RuntimeException)
1877 : {
1878 0 : osl::MutexGuard const guard( m_aMutex );
1879 :
1880 : // precondition: must only be called from the main thread!
1881 : DBG_TESTSOLARMUTEX();
1882 :
1883 0 : ShapeEventListenerMap::iterator aIter;
1884 0 : if( (aIter = maShapeEventListeners.find( xShape )) !=
1885 0 : maShapeEventListeners.end() )
1886 : {
1887 : // entry for this shape found -> remove listener from
1888 : // helper object
1889 0 : ENSURE_OR_THROW(
1890 : aIter->second.get(),
1891 : "SlideShowImpl::removeShapeEventListener(): "
1892 : "listener map contains NULL broadcast helper" );
1893 :
1894 0 : aIter->second->removeInterface( xListener );
1895 : }
1896 :
1897 : maEventMultiplexer.notifyShapeListenerRemoved(xListener,
1898 0 : xShape);
1899 0 : }
1900 :
1901 0 : void SlideShowImpl::setShapeCursor(
1902 : uno::Reference<drawing::XShape> const& xShape, sal_Int16 nPointerShape )
1903 : throw (uno::RuntimeException)
1904 : {
1905 0 : osl::MutexGuard const guard( m_aMutex );
1906 :
1907 0 : if (isDisposed())
1908 0 : return;
1909 :
1910 : // precondition: must only be called from the main thread!
1911 : DBG_TESTSOLARMUTEX();
1912 :
1913 0 : ShapeCursorMap::iterator aIter;
1914 0 : if( (aIter=maShapeCursors.find( xShape )) == maShapeCursors.end() )
1915 : {
1916 : // no entry for this shape -> create one
1917 0 : if( nPointerShape != awt::SystemPointer::ARROW )
1918 : {
1919 : // add new entry, unless shape shall display
1920 : // normal pointer arrow -> no need to handle that
1921 : // case
1922 : maShapeCursors.insert(
1923 : ShapeCursorMap::value_type(xShape,
1924 0 : nPointerShape) );
1925 : }
1926 : }
1927 0 : else if( nPointerShape == awt::SystemPointer::ARROW )
1928 : {
1929 : // shape shall display normal cursor -> can disable
1930 : // the cursor and clear the entry
1931 0 : maShapeCursors.erase( xShape );
1932 : }
1933 : else
1934 : {
1935 : // existing entry found, update with new cursor ID
1936 0 : aIter->second = nPointerShape;
1937 : }
1938 :
1939 : maEventMultiplexer.notifyShapeCursorChange(xShape,
1940 0 : nPointerShape);
1941 : }
1942 :
1943 0 : bool SlideShowImpl::requestCursor( sal_Int16 nCursorShape )
1944 : {
1945 0 : mnCurrentCursor = nCursorShape;
1946 :
1947 0 : const sal_Int16 nActualCursor = calcActiveCursor(mnCurrentCursor);
1948 :
1949 : // change all views to the requested cursor ID
1950 : std::for_each( maViewContainer.begin(),
1951 : maViewContainer.end(),
1952 : boost::bind( &View::setCursorShape,
1953 : _1,
1954 0 : nActualCursor ));
1955 :
1956 0 : return nActualCursor==nCursorShape;
1957 : }
1958 :
1959 0 : void SlideShowImpl::resetCursor()
1960 : {
1961 0 : mnCurrentCursor = awt::SystemPointer::ARROW;
1962 :
1963 : // change all views to the default cursor ID
1964 : std::for_each( maViewContainer.begin(),
1965 : maViewContainer.end(),
1966 : boost::bind( &View::setCursorShape,
1967 : _1,
1968 0 : calcActiveCursor(mnCurrentCursor) ));
1969 0 : }
1970 :
1971 0 : sal_Bool SlideShowImpl::update( double & nNextTimeout )
1972 : throw (uno::RuntimeException)
1973 : {
1974 0 : osl::MutexGuard const guard( m_aMutex );
1975 :
1976 0 : if (isDisposed())
1977 0 : return false;
1978 :
1979 : // precondition: update() must only be called from the
1980 : // main thread!
1981 : DBG_TESTSOLARMUTEX();
1982 :
1983 0 : if( mbShowPaused )
1984 : {
1985 : // commit frame (might be repaints pending)
1986 0 : maScreenUpdater.commitUpdates();
1987 :
1988 0 : return false;
1989 : }
1990 : else
1991 : {
1992 : // TODO(F2): re-evaluate whether that timer lagging makes
1993 : // sense.
1994 :
1995 : // hold timer, while processing the queues:
1996 : // 1. when there is more than one active activity this ensures the
1997 : // same time for all activities and events
1998 : // 2. processing of events may lead to creation of further events
1999 : // that have zero delay. While the timer is stopped these events
2000 : // are processed in the same run.
2001 : {
2002 : //Get a shared-ptr that outlives the scope-guard which will
2003 : //ensure that the pointed-to-item exists in the case of a
2004 : //::dispose clearing mpPresTimer
2005 0 : boost::shared_ptr<canvas::tools::ElapsedTime> xTimer(mpPresTimer);
2006 : comphelper::ScopeGuard scopeGuard(
2007 : boost::bind( &canvas::tools::ElapsedTime::releaseTimer,
2008 0 : boost::cref(xTimer) ) );
2009 0 : xTimer->holdTimer();
2010 :
2011 : // process queues
2012 0 : maEventQueue.process();
2013 0 : maActivitiesQueue.process();
2014 :
2015 : // commit frame to screen
2016 0 : maFrameSynchronization.Synchronize();
2017 0 : maScreenUpdater.commitUpdates();
2018 :
2019 : // TODO(Q3): remove need to call dequeued() from
2020 : // activities. feels like a wart.
2021 : //
2022 : // Rationale for ActivitiesQueue::processDequeued(): when
2023 : // an activity ends, it usually pushed the end state to
2024 : // the animated shape in question, and ends the animation
2025 : // (which, in turn, will usually disable shape sprite
2026 : // mode). Disabling shape sprite mode causes shape
2027 : // repaint, which, depending on slide content, takes
2028 : // considerably more time than sprite updates. Thus, the
2029 : // last animation step tends to look delayed. To
2030 : // camouflage this, reaching end position and disabling
2031 : // sprite mode is split into two (normal Activity::end(),
2032 : // and Activity::dequeued()). Now, the reason to call
2033 : // commitUpdates() twice here is caused by the unrelated
2034 : // fact that during wait cursor display/hide, the screen
2035 : // is updated, and shows hidden sprites, but, in case of
2036 : // leaving the second commitUpdates() call out and punting
2037 : // that to the next round, no updated static slide
2038 : // content. In short, the last shape animation of a slide
2039 : // tends to blink at its end.
2040 :
2041 : // process dequeued activities _after_ commit to screen
2042 0 : maActivitiesQueue.processDequeued();
2043 :
2044 : // commit frame to screen
2045 0 : maScreenUpdater.commitUpdates();
2046 : }
2047 : // Time held until here
2048 :
2049 0 : const bool bActivitiesLeft = (! maActivitiesQueue.isEmpty());
2050 0 : const bool bTimerEventsLeft = (! maEventQueue.isEmpty());
2051 0 : const bool bRet = (bActivitiesLeft || bTimerEventsLeft);
2052 :
2053 0 : if (bRet)
2054 : {
2055 : // calc nNextTimeout value:
2056 0 : if (bActivitiesLeft)
2057 : {
2058 : // Activity queue is not empty. Tell caller that we would
2059 : // like to render another frame.
2060 :
2061 : // Return a zero time-out to signal our caller to call us
2062 : // back as soon as possible. The actual timing, waiting the
2063 : // appropriate amount of time between frames, is then done
2064 : // by the maFrameSynchronization object.
2065 0 : nNextTimeout = 0;
2066 0 : maFrameSynchronization.Activate();
2067 : }
2068 : else
2069 : {
2070 : // timer events left:
2071 : // difference from current time (nota bene:
2072 : // time no longer held here!) to the next event in
2073 : // the event queue.
2074 :
2075 : // #i61190# Retrieve next timeout only _after_
2076 : // processing activity queue
2077 :
2078 : // ensure positive value:
2079 0 : nNextTimeout = std::max( 0.0, maEventQueue.nextTimeout() );
2080 :
2081 : // There is no active animation so the frame rate does not
2082 : // need to be synchronized.
2083 0 : maFrameSynchronization.Deactivate();
2084 : }
2085 :
2086 0 : mbSlideShowIdle = false;
2087 : }
2088 :
2089 : #if OSL_DEBUG_LEVEL >= 2 && defined(DBG_UTIL)
2090 : // when slideshow is idle, issue an XUpdatable::update() call
2091 : // exactly once after a previous animation sequence finished -
2092 : // this might trigger screen dumps on some canvas
2093 : // implementations
2094 : if( !mbSlideShowIdle &&
2095 : (!bRet ||
2096 : nNextTimeout > 1.0) )
2097 : {
2098 : UnoViewVector::const_iterator aCurr(maViewContainer.begin());
2099 : const UnoViewVector::const_iterator aEnd(maViewContainer.end());
2100 : while( aCurr != aEnd )
2101 : {
2102 : try
2103 : {
2104 : uno::Reference< presentation::XSlideShowView > xView( (*aCurr)->getUnoView(),
2105 : uno::UNO_QUERY_THROW );
2106 : uno::Reference< util::XUpdatable > xUpdatable( xView->getCanvas(),
2107 : uno::UNO_QUERY_THROW );
2108 : xUpdatable->update();
2109 : }
2110 : catch( uno::RuntimeException& )
2111 : {
2112 : throw;
2113 : }
2114 : catch( uno::Exception& )
2115 : {
2116 : OSL_FAIL( rtl::OUStringToOString(
2117 : comphelper::anyToString( cppu::getCaughtException() ),
2118 : RTL_TEXTENCODING_UTF8 ).getStr() );
2119 : }
2120 :
2121 : ++aCurr;
2122 : }
2123 :
2124 : mbSlideShowIdle = true;
2125 : }
2126 : #endif
2127 :
2128 0 : return bRet;
2129 0 : }
2130 : }
2131 :
2132 0 : void SlideShowImpl::notifySlideTransitionEnded( bool bPaintSlide )
2133 : {
2134 0 : osl::MutexGuard const guard( m_aMutex );
2135 :
2136 : OSL_ENSURE( !isDisposed(), "### already disposed!" );
2137 : OSL_ENSURE( mpCurrentSlide,
2138 : "notifySlideTransitionEnded(): Invalid current slide" );
2139 0 : if (mpCurrentSlide)
2140 : {
2141 0 : mpCurrentSlide->update_settings( !!maUserPaintColor, maUserPaintColor ? *maUserPaintColor : RGBColor(), maUserPaintStrokeWidth );
2142 :
2143 : // first init show, to give the animations
2144 : // the chance to register SlideStartEvents
2145 0 : const bool bBackgroundLayerRendered( !bPaintSlide );
2146 0 : mpCurrentSlide->show( bBackgroundLayerRendered );
2147 0 : maEventMultiplexer.notifySlideStartEvent();
2148 0 : }
2149 0 : }
2150 :
2151 0 : void queryAutomaticSlideTransition( uno::Reference<drawing::XDrawPage> const& xDrawPage,
2152 : double& nAutomaticNextSlideTimeout,
2153 : bool& bHasAutomaticNextSlide )
2154 : {
2155 : // retrieve slide change parameters from XDrawPage
2156 : // ===============================================
2157 :
2158 : uno::Reference< beans::XPropertySet > xPropSet( xDrawPage,
2159 0 : uno::UNO_QUERY );
2160 :
2161 0 : sal_Int32 nChange(0);
2162 0 : if( !xPropSet.is() ||
2163 : !getPropertyValue( nChange,
2164 : xPropSet,
2165 : ::rtl::OUString(
2166 0 : "Change")) )
2167 : {
2168 : OSL_TRACE(
2169 : "queryAutomaticSlideTransition(): "
2170 : "Could not extract slide change mode from XDrawPage - assuming <none>\n" );
2171 : }
2172 :
2173 0 : bHasAutomaticNextSlide = nChange == 1;
2174 :
2175 0 : if( !xPropSet.is() ||
2176 : !getPropertyValue( nAutomaticNextSlideTimeout,
2177 : xPropSet,
2178 : ::rtl::OUString(
2179 0 : "Duration")) )
2180 : {
2181 : OSL_TRACE(
2182 : "queryAutomaticSlideTransition(): "
2183 : "Could not extract slide transition timeout from "
2184 : "XDrawPage - assuming 1 sec\n" );
2185 0 : }
2186 0 : }
2187 :
2188 0 : void SlideShowImpl::notifySlideAnimationsEnded()
2189 : {
2190 0 : osl::MutexGuard const guard( m_aMutex );
2191 :
2192 : //Draw polygons above animations
2193 0 : mpCurrentSlide->drawPolygons();
2194 :
2195 : OSL_ENSURE( !isDisposed(), "### already disposed!" );
2196 :
2197 : // This struct will receive the (interruptable) event,
2198 : // that triggers the notifySlideEnded() method.
2199 0 : InterruptableEventPair aNotificationEvents;
2200 :
2201 0 : if( maEventMultiplexer.getAutomaticMode() )
2202 : {
2203 : OSL_ENSURE( ! mpRehearseTimingsActivity,
2204 : "unexpected: RehearseTimings mode!" );
2205 :
2206 : // schedule a slide end event, with automatic mode's
2207 : // delay
2208 : aNotificationEvents = makeInterruptableDelay(
2209 0 : boost::bind<void>( boost::mem_fn(&SlideShowImpl::notifySlideEnded), this, false ),
2210 0 : maEventMultiplexer.getAutomaticTimeout() );
2211 : }
2212 : else
2213 : {
2214 : OSL_ENSURE( mpCurrentSlide,
2215 : "notifySlideAnimationsEnded(): Invalid current slide!" );
2216 :
2217 0 : bool bHasAutomaticNextSlide=false;
2218 0 : double nAutomaticNextSlideTimeout=0.0;
2219 0 : queryAutomaticSlideTransition(mpCurrentSlide->getXDrawPage(),
2220 : nAutomaticNextSlideTimeout,
2221 0 : bHasAutomaticNextSlide);
2222 :
2223 : // check whether slide transition should happen
2224 : // 'automatically'. If yes, simply schedule the
2225 : // specified timeout.
2226 : // NOTE: mbForceManualAdvance and mpRehearseTimingsActivity
2227 : // override any individual slide setting, to always
2228 : // step slides manually.
2229 0 : if( !mbForceManualAdvance &&
2230 0 : !mpRehearseTimingsActivity &&
2231 : bHasAutomaticNextSlide )
2232 : {
2233 : aNotificationEvents = makeInterruptableDelay(
2234 0 : boost::bind<void>( boost::mem_fn(&SlideShowImpl::notifySlideEnded), this, false ),
2235 0 : nAutomaticNextSlideTimeout);
2236 :
2237 : // TODO(F2): Provide a mechanism to let the user override
2238 : // this automatic timeout via next()
2239 : }
2240 : else
2241 : {
2242 0 : if (mpRehearseTimingsActivity)
2243 0 : mpRehearseTimingsActivity->start();
2244 :
2245 : // generate click event. Thus, the user must
2246 : // trigger the actual end of a slide. No need to
2247 : // generate interruptable event here, there's no
2248 : // timeout involved.
2249 : aNotificationEvents.mpImmediateEvent =
2250 0 : makeEvent( boost::bind<void>(
2251 : boost::mem_fn(&SlideShowImpl::notifySlideEnded), this, false ),
2252 0 : "SlideShowImpl::notifySlideEnded");
2253 : }
2254 : }
2255 :
2256 : // register events on the queues. To make automatic slide
2257 : // changes interruptable, register the interruption event
2258 : // as a nextEffectEvent target. Note that the timeout
2259 : // event is optional (e.g. manual slide changes don't
2260 : // generate a timeout)
2261 : maUserEventQueue.registerNextEffectEvent(
2262 0 : aNotificationEvents.mpImmediateEvent );
2263 :
2264 0 : if( aNotificationEvents.mpTimeoutEvent )
2265 0 : maEventQueue.addEvent( aNotificationEvents.mpTimeoutEvent );
2266 :
2267 : // current slide's main sequence is over. Now should be
2268 : // the time to prefetch the next slide (if any), and
2269 : // prepare the initial slide bitmap (speeds up slide
2270 : // change setup time a lot). Show the wait cursor, this
2271 : // indeed might take some seconds.
2272 : {
2273 0 : WaitSymbolLock aLock (*this);
2274 :
2275 0 : if (! matches( mpPrefetchSlide,
2276 0 : mxPrefetchSlide, mxPrefetchAnimationNode ))
2277 : {
2278 : mpPrefetchSlide = makeSlide( mxPrefetchSlide, mxDrawPagesSupplier,
2279 0 : mxPrefetchAnimationNode );
2280 : }
2281 0 : if (mpPrefetchSlide)
2282 : {
2283 : // ignore return value, this is just to populate
2284 : // Slide's internal bitmap buffer, such that the time
2285 : // needed to generate the slide bitmap is not spent
2286 : // when the slide change is requested.
2287 0 : mpPrefetchSlide->getCurrentSlideBitmap( *maViewContainer.begin() );
2288 0 : }
2289 : } // finally
2290 :
2291 : maListenerContainer.forEach<presentation::XSlideShowListener>(
2292 0 : boost::mem_fn( &presentation::XSlideShowListener::slideAnimationsEnded ) );
2293 0 : }
2294 :
2295 0 : void SlideShowImpl::notifySlideEnded (const bool bReverse)
2296 : {
2297 0 : osl::MutexGuard const guard( m_aMutex );
2298 :
2299 : OSL_ENSURE( !isDisposed(), "### already disposed!" );
2300 :
2301 0 : if (mpRehearseTimingsActivity && !bReverse)
2302 : {
2303 0 : const double time = mpRehearseTimingsActivity->stop();
2304 0 : if (mpRehearseTimingsActivity->hasBeenClicked())
2305 : {
2306 : // save time at current drawpage:
2307 : uno::Reference<beans::XPropertySet> xPropSet(
2308 0 : mpCurrentSlide->getXDrawPage(), uno::UNO_QUERY );
2309 : OSL_ASSERT( xPropSet.is() );
2310 0 : if (xPropSet.is())
2311 : {
2312 0 : xPropSet->setPropertyValue(
2313 : OUSTR("Change"),
2314 0 : uno::Any( static_cast<sal_Int32>(1) ) );
2315 0 : xPropSet->setPropertyValue(
2316 : OUSTR("Duration"),
2317 0 : uno::Any( static_cast<sal_Int32>(time) ) );
2318 0 : }
2319 : }
2320 : }
2321 :
2322 0 : if (bReverse)
2323 0 : maEventMultiplexer.notifySlideEndEvent();
2324 :
2325 0 : stopShow(); // MUST call that: results in
2326 : // maUserEventQueue.clear(). What's more,
2327 : // stopShow()'s currSlide->hide() call is
2328 : // now also required, notifySlideEnded()
2329 : // relies on that
2330 : // unconditionally. Otherwise, genuine
2331 : // shape animations (drawing layer and
2332 : // GIF) will not be stopped.
2333 :
2334 : maListenerContainer.forEach<presentation::XSlideShowListener>(
2335 : boost::bind<void>(
2336 : ::boost::mem_fn(&presentation::XSlideShowListener::slideEnded),
2337 : _1,
2338 0 : sal_Bool(bReverse)));
2339 0 : }
2340 :
2341 0 : bool SlideShowImpl::notifyHyperLinkClicked( rtl::OUString const& hyperLink )
2342 : {
2343 0 : osl::MutexGuard const guard( m_aMutex );
2344 :
2345 : maListenerContainer.forEach<presentation::XSlideShowListener>(
2346 : boost::bind( &presentation::XSlideShowListener::hyperLinkClicked,
2347 : _1,
2348 0 : boost::cref(hyperLink) ));
2349 0 : return true;
2350 : }
2351 :
2352 : /** Notification from eventmultiplexer that an animation event has occoured.
2353 : This will be forewarded to all registered XSlideShoeListener
2354 : */
2355 0 : bool SlideShowImpl::handleAnimationEvent( const AnimationNodeSharedPtr& rNode )
2356 : {
2357 0 : osl::MutexGuard const guard( m_aMutex );
2358 :
2359 0 : uno::Reference<animations::XAnimationNode> xNode( rNode->getXAnimationNode() );
2360 :
2361 0 : switch( rNode->getState() )
2362 : {
2363 : case AnimationNode::ACTIVE:
2364 : maListenerContainer.forEach<presentation::XSlideShowListener>(
2365 : boost::bind( &animations::XAnimationListener::beginEvent,
2366 : _1,
2367 0 : boost::cref(xNode) ));
2368 0 : break;
2369 :
2370 : case AnimationNode::FROZEN:
2371 : case AnimationNode::ENDED:
2372 : maListenerContainer.forEach<presentation::XSlideShowListener>(
2373 : boost::bind( &animations::XAnimationListener::endEvent,
2374 : _1,
2375 0 : boost::cref(xNode) ));
2376 0 : if(mpCurrentSlide->isPaintOverlayActive())
2377 0 : mpCurrentSlide->drawPolygons();
2378 0 : break;
2379 : default:
2380 0 : break;
2381 : }
2382 :
2383 0 : return true;
2384 : }
2385 :
2386 : //===== FrameSynchronization ==================================================
2387 :
2388 0 : FrameSynchronization::FrameSynchronization (const double nFrameDuration)
2389 : : maTimer(),
2390 : mnFrameDuration(nFrameDuration),
2391 : mnNextFrameTargetTime(0),
2392 0 : mbIsActive(false)
2393 : {
2394 0 : MarkCurrentFrame();
2395 0 : }
2396 :
2397 0 : void FrameSynchronization::MarkCurrentFrame (void)
2398 : {
2399 0 : mnNextFrameTargetTime = maTimer.getElapsedTime() + mnFrameDuration;
2400 0 : }
2401 :
2402 0 : void FrameSynchronization::Synchronize (void)
2403 : {
2404 0 : if (mbIsActive)
2405 : {
2406 : // Do busy waiting for now.
2407 0 : while (maTimer.getElapsedTime() < mnNextFrameTargetTime)
2408 : ;
2409 : }
2410 :
2411 0 : MarkCurrentFrame();
2412 0 : }
2413 :
2414 0 : void FrameSynchronization::Activate (void)
2415 : {
2416 0 : mbIsActive = true;
2417 0 : }
2418 :
2419 0 : void FrameSynchronization::Deactivate (void)
2420 : {
2421 0 : mbIsActive = false;
2422 0 : }
2423 :
2424 : } // anon namespace
2425 :
2426 : namespace sdecl = comphelper::service_decl;
2427 0 : const sdecl::ServiceDecl slideShowDecl(
2428 : sdecl::class_<SlideShowImpl>(),
2429 : "com.sun.star.comp.presentation.SlideShow",
2430 0 : "com.sun.star.presentation.SlideShow" );
2431 :
2432 : // The C shared lib entry points
2433 0 : COMPHELPER_SERVICEDECL_EXPORTS1(slideshow, slideShowDecl)
2434 :
2435 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|