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 : #include "pointersymbol.hxx"
99 :
100 : #include <boost/noncopyable.hpp>
101 : #include <boost/bind.hpp>
102 :
103 : #include <map>
104 : #include <vector>
105 : #include <iterator>
106 : #include <string>
107 : #include <algorithm>
108 : #include <stdio.h>
109 : #include <iostream>
110 :
111 : using namespace com::sun::star;
112 : using namespace ::slideshow::internal;
113 :
114 : namespace {
115 :
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.
121 : */
122 1 : class FrameSynchronization
123 : {
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.
129 : */
130 : FrameSynchronization (const double nFrameDuration);
131 :
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.
134 : */
135 : void MarkCurrentFrame();
136 :
137 : /** When there is time left until the next frame is due then wait.
138 : Otherwise return without delay.
139 : */
140 : void Synchronize();
141 :
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.
145 : */
146 : void Activate();
147 :
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.
151 : */
152 : void Deactivate();
153 :
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.
158 : */
159 : canvas::tools::ElapsedTime maTimer;
160 : /** Time between the display of frames. Enforced only when mbIsActive
161 : is <TRUE/>.
162 : */
163 : const double mnFrameDuration;
164 : /** Time (of maTimer) when the next frame shall be displayed.
165 : Synchronize() will wait until this time.
166 : */
167 : double mnNextFrameTargetTime;
168 : /** Synchronize() will wait only when this flag is <TRUE/>. Otherwise
169 : it returns immediately.
170 : */
171 : bool mbIsActive;
172 : };
173 :
174 : /******************************************************************************
175 :
176 : SlideShowImpl
177 :
178 : This class encapsulates the slideshow presentation viewer.
179 :
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).
184 :
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).
190 :
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).
204 :
205 : ******************************************************************************/
206 :
207 : typedef cppu::WeakComponentImplHelper1<presentation::XSlideShow> SlideShowImplBase;
208 :
209 : typedef ::std::vector< ::cppcanvas::PolyPolygonSharedPtr> PolyPolygonVector;
210 :
211 : /// Maps XDrawPage for annotations persistence
212 : typedef ::std::map< ::com::sun::star::uno::Reference<
213 : ::com::sun::star::drawing::XDrawPage>,
214 : PolyPolygonVector> PolygonMap;
215 :
216 1 : class SlideShowImpl : private cppu::BaseMutex,
217 : public CursorManager,
218 : public SlideShowImplBase
219 : {
220 : public:
221 : explicit SlideShowImpl(
222 : uno::Reference<uno::XComponentContext> const& xContext );
223 :
224 : /** Notify that the transition phase of the current slide
225 : has ended.
226 :
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.
233 :
234 : This method notifies the end of the first phase.
235 :
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.
240 : */
241 : void notifySlideTransitionEnded( bool bPaintSlide );
242 :
243 : /** Notify that the shape animation phase of the current slide
244 : has ended.
245 :
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.
252 :
253 : This method notifies the end of the second phase.
254 : */
255 : void notifySlideAnimationsEnded();
256 :
257 : /** Notify that the slide has ended.
258 :
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.
265 :
266 : This method notifies the end of the third phase.
267 : */
268 : void notifySlideEnded (const bool bReverse);
269 :
270 : /** Notification from eventmultiplexer that a hyperlink
271 : has been clicked.
272 : */
273 : bool notifyHyperLinkClicked( OUString const& hyperLink );
274 :
275 : /** Notification from eventmultiplexer that an animation event has occoured.
276 : This will be forewarded to all registered XSlideShowListener
277 : */
278 : bool handleAnimationEvent( const AnimationNodeSharedPtr& rNode );
279 :
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;
328 :
329 : // CursorManager
330 :
331 :
332 : virtual bool requestCursor( sal_Int16 nCursorShape ) SAL_OVERRIDE;
333 : virtual void resetCursor() SAL_OVERRIDE;
334 :
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.
339 : */
340 : void redisplayCurrentSlide();
341 :
342 : protected:
343 : // WeakComponentImplHelperBase
344 : virtual void SAL_CALL disposing() SAL_OVERRIDE;
345 :
346 0 : bool isDisposed() const
347 : {
348 0 : return (rBHelper.bDisposed || rBHelper.bInDispose);
349 : }
350 :
351 : private:
352 : struct SeparateListenerImpl; friend struct SeparateListenerImpl;
353 : class PrefetchPropertiesFunc; friend class PrefetchPropertiesFunc;
354 :
355 : /// Stop currently running show.
356 : void stopShow();
357 :
358 : ///Find a polygons vector in maPolygons (map)
359 : PolygonMap::iterator findPolygons( uno::Reference<drawing::XDrawPage> const& xDrawPage);
360 :
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 );
366 :
367 : /// Checks whether the given slide/animation node matches mpPrefetchSlide
368 0 : static bool matches(
369 : SlideSharedPtr const& pSlide,
370 : uno::Reference<drawing::XDrawPage> const& xSlide,
371 : uno::Reference<animations::XAnimationNode> const& xNode )
372 : {
373 0 : if (pSlide)
374 0 : return (pSlide->getXDrawPage() == xSlide &&
375 0 : pSlide->getXAnimationNode() == xNode);
376 : else
377 0 : return (!xSlide.is() && !xNode.is());
378 : }
379 :
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 );
383 :
384 : /// stops the current slide transition sound
385 : void stopSlideTransitionSound();
386 :
387 : /** Prepare a slide transition
388 :
389 : This method registers all necessary events and
390 : activities for a slide transition.
391 :
392 : @return the slide change activity, or NULL for no transition effect
393 : */
394 : ActivitySharedPtr createSlideTransition(
395 : const uno::Reference< drawing::XDrawPage >& xDrawPage,
396 : const SlideSharedPtr& rLeavingSlide,
397 : const SlideSharedPtr& rEnteringSlide,
398 : const EventSharedPtr& rTransitionEndEvent );
399 :
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.
403 :
404 : Do not call this method directly. Use WaitSymbolLock instead.
405 : */
406 : void requestWaitSymbol();
407 : void releaseWaitSymbol();
408 :
409 : class WaitSymbolLock {public:
410 0 : WaitSymbolLock(SlideShowImpl& rSlideShowImpl) : mrSlideShowImpl(rSlideShowImpl)
411 0 : { mrSlideShowImpl.requestWaitSymbol(); }
412 0 : ~WaitSymbolLock()
413 0 : { mrSlideShowImpl.releaseWaitSymbol(); }
414 : private: SlideShowImpl& mrSlideShowImpl;
415 : };
416 :
417 : /// Filter requested cursor shape against hard slideshow cursors (wait, etc.)
418 : sal_Int16 calcActiveCursor( sal_Int16 nCursorShape ) const;
419 :
420 : /** This method is called asynchronously to finish the rewinding of an
421 : effect to the previous slide that was initiated earlier.
422 : */
423 : void rewindEffectToPreviousSlide();
424 :
425 : /// all registered views
426 : UnoViewContainer maViewContainer;
427 :
428 : /// all registered slide show listeners
429 : cppu::OInterfaceContainerHelper maListenerContainer;
430 :
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;
435 :
436 : //map of vector of Polygons, containing polygons drawn on each slide.
437 : PolygonMap maPolygons;
438 :
439 : boost::optional<RGBColor> maUserPaintColor;
440 :
441 : double maUserPaintStrokeWidth;
442 :
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
449 :
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;
457 :
458 : boost::shared_ptr<SeparateListenerImpl> mpListener;
459 :
460 : boost::shared_ptr<RehearseTimingsActivity> mpRehearseTimingsActivity;
461 : boost::shared_ptr<WaitSymbol> mpWaitSymbol;
462 :
463 : boost::shared_ptr<PointerSymbol> mpPointerSymbol;
464 :
465 : /// the current slide transition sound object:
466 : SoundPlayerSharedPtr mpCurrentSlideTransitionSound;
467 :
468 : uno::Reference<uno::XComponentContext> mxComponentContext;
469 : uno::Reference<
470 : presentation::XTransitionFactory> mxOptionalTransitionFactory;
471 :
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;
484 :
485 : sal_Int16 mnCurrentCursor;
486 :
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;
496 :
497 : EffectRewinder maEffectRewinder;
498 : FrameSynchronization maFrameSynchronization;
499 : };
500 :
501 : /** Separate event listener for animation, view and hyperlink events.
502 :
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
506 : */
507 2 : struct SlideShowImpl::SeparateListenerImpl : public EventHandler,
508 : public ViewRepaintHandler,
509 : public HyperlinkHandler,
510 : public AnimationEventHandler,
511 : private boost::noncopyable
512 : {
513 : SlideShowImpl& mrShow;
514 : ScreenUpdater& mrScreenUpdater;
515 : EventQueue& mrEventQueue;
516 :
517 1 : SeparateListenerImpl( SlideShowImpl& rShow,
518 : ScreenUpdater& rScreenUpdater,
519 : EventQueue& rEventQueue ) :
520 : mrShow( rShow ),
521 : mrScreenUpdater( rScreenUpdater ),
522 1 : mrEventQueue( rEventQueue )
523 1 : {}
524 :
525 : // EventHandler
526 0 : virtual bool handleEvent() SAL_OVERRIDE
527 : {
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 0 : makeEvent(
538 : boost::bind( &SlideShowImpl::notifySlideAnimationsEnded, boost::ref(mrShow) ),
539 0 : "SlideShowImpl::notifySlideAnimationsEnded"));
540 0 : return true;
541 : }
542 :
543 : // ViewRepaintHandler
544 0 : virtual void viewClobbered( const UnoViewSharedPtr& rView ) SAL_OVERRIDE
545 : {
546 : // given view needs repaint, request update
547 0 : mrScreenUpdater.notifyUpdate(rView, true);
548 0 : }
549 :
550 : // HyperlinkHandler
551 0 : virtual bool handleHyperlink( OUString const& rLink ) SAL_OVERRIDE
552 : {
553 0 : return mrShow.notifyHyperLinkClicked(rLink);
554 : }
555 :
556 : // AnimationEventHandler
557 0 : virtual bool handleAnimationEvent( const AnimationNodeSharedPtr& rNode ) SAL_OVERRIDE
558 : {
559 0 : return mrShow.handleAnimationEvent(rNode);
560 : }
561 : };
562 :
563 1 : 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 1 : 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 2 : maFrameSynchronization(1.0 / FrameRate::PreferredFramesPerSecond)
606 :
607 : {
608 : // keep care not constructing any UNO references to this inside ctor,
609 : // shift that code to create()!
610 :
611 : uno::Reference<lang::XMultiComponentFactory> xFactory(
612 1 : mxComponentContext->getServiceManager() );
613 :
614 1 : if( xFactory.is() )
615 : {
616 : try
617 : {
618 : // #i82460# try to retrieve special transition factory
619 : mxOptionalTransitionFactory.set(
620 1 : xFactory->createInstanceWithContext(
621 : OUString("com.sun.star.presentation.TransitionFactory" ),
622 1 : mxComponentContext ),
623 1 : uno::UNO_QUERY );
624 : }
625 0 : catch (loader::CannotActivateFactoryException const&)
626 : {
627 : }
628 : }
629 :
630 : mpListener.reset( new SeparateListenerImpl(
631 : *this,
632 : maScreenUpdater,
633 1 : maEventQueue ));
634 1 : maEventMultiplexer.addSlideAnimationsEndHandler( mpListener );
635 1 : maEventMultiplexer.addViewRepaintHandler( mpListener );
636 1 : maEventMultiplexer.addHyperlinkHandler( mpListener, 0.0 );
637 1 : maEventMultiplexer.addAnimationStartHandler( mpListener );
638 1 : maEventMultiplexer.addAnimationEndHandler( mpListener );
639 1 : }
640 :
641 : // we are about to be disposed (someone call dispose() on us)
642 1 : void SlideShowImpl::disposing()
643 : {
644 1 : osl::MutexGuard const guard( m_aMutex );
645 :
646 1 : maEffectRewinder.dispose();
647 :
648 : // stop slide transition sound, if any:
649 1 : stopSlideTransitionSound();
650 :
651 1 : mxComponentContext.clear();
652 :
653 1 : if( mpCurrentSlideTransitionSound )
654 : {
655 0 : mpCurrentSlideTransitionSound->dispose();
656 0 : mpCurrentSlideTransitionSound.reset();
657 : }
658 :
659 1 : mpWaitSymbol.reset();
660 1 : mpPointerSymbol.reset();
661 :
662 1 : if( mpRehearseTimingsActivity )
663 : {
664 0 : mpRehearseTimingsActivity->dispose();
665 0 : mpRehearseTimingsActivity.reset();
666 : }
667 :
668 1 : if( mpListener )
669 : {
670 1 : maEventMultiplexer.removeSlideAnimationsEndHandler(mpListener);
671 1 : maEventMultiplexer.removeViewRepaintHandler(mpListener);
672 1 : maEventMultiplexer.removeHyperlinkHandler(mpListener);
673 1 : maEventMultiplexer.removeAnimationStartHandler( mpListener );
674 1 : maEventMultiplexer.removeAnimationEndHandler( mpListener );
675 :
676 1 : mpListener.reset();
677 : }
678 :
679 1 : maUserEventQueue.clear();
680 1 : maActivitiesQueue.clear();
681 1 : maEventMultiplexer.clear();
682 1 : maEventQueue.clear();
683 1 : mpPresTimer.reset();
684 1 : maShapeCursors.clear();
685 1 : maShapeEventListeners.clear();
686 :
687 : // send all listeners a disposing() that we are going down:
688 : maListenerContainer.disposeAndClear(
689 1 : lang::EventObject( static_cast<cppu::OWeakObject *>(this) ) );
690 :
691 1 : maViewContainer.dispose();
692 :
693 : // release slides:
694 1 : mxPrefetchAnimationNode.clear();
695 1 : mxPrefetchSlide.clear();
696 1 : mpPrefetchSlide.reset();
697 1 : mpCurrentSlide.reset();
698 1 : mpPreviousSlide.reset();
699 1 : }
700 :
701 : /// stops the current slide transition sound
702 1 : void SlideShowImpl::stopSlideTransitionSound()
703 : {
704 1 : if (mpCurrentSlideTransitionSound)
705 : {
706 0 : mpCurrentSlideTransitionSound->stopPlayback();
707 0 : mpCurrentSlideTransitionSound->dispose();
708 0 : mpCurrentSlideTransitionSound.reset();
709 : }
710 1 : }
711 :
712 0 : SoundPlayerSharedPtr SlideShowImpl::resetSlideTransitionSound( const uno::Any& rSound, bool bLoopSound )
713 : {
714 0 : bool bStopSound = false;
715 0 : OUString url;
716 :
717 0 : if( !(rSound >>= bStopSound) )
718 0 : bStopSound = false;
719 0 : rSound >>= url;
720 :
721 0 : if( !bStopSound && url.isEmpty() )
722 0 : return SoundPlayerSharedPtr();
723 :
724 0 : stopSlideTransitionSound();
725 :
726 0 : if (!url.isEmpty())
727 : {
728 : try
729 : {
730 0 : mpCurrentSlideTransitionSound = SoundPlayer::create(
731 0 : maEventMultiplexer, url, mxComponentContext );
732 0 : mpCurrentSlideTransitionSound->setPlaybackLoop( bLoopSound );
733 : }
734 0 : catch (lang::NoSupportException const&)
735 : {
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).
740 : }
741 : }
742 0 : return mpCurrentSlideTransitionSound;
743 : }
744 :
745 0 : ActivitySharedPtr SlideShowImpl::createSlideTransition(
746 : const uno::Reference< drawing::XDrawPage >& xDrawPage,
747 : const SlideSharedPtr& rLeavingSlide,
748 : const SlideSharedPtr& rEnteringSlide,
749 : const EventSharedPtr& rTransitionEndEvent)
750 : {
751 0 : ENSURE_OR_THROW( !maViewContainer.empty(),
752 : "createSlideTransition(): No views" );
753 0 : ENSURE_OR_THROW( rEnteringSlide,
754 : "createSlideTransition(): No entering slide" );
755 :
756 : // return empty transition, if slide transitions
757 : // are disabled.
758 0 : if (mbNoSlideTransitions)
759 0 : return ActivitySharedPtr();
760 :
761 : // retrieve slide change parameters from XDrawPage
762 : uno::Reference< beans::XPropertySet > xPropSet( xDrawPage,
763 0 : uno::UNO_QUERY );
764 :
765 0 : if( !xPropSet.is() )
766 : {
767 : OSL_TRACE( "createSlideTransition(): "
768 : "Slide has no PropertySet - assuming no transition\n" );
769 0 : return ActivitySharedPtr();
770 : }
771 :
772 0 : sal_Int16 nTransitionType(0);
773 0 : if( !getPropertyValue( nTransitionType,
774 : xPropSet,
775 0 : "TransitionType") )
776 : {
777 : OSL_TRACE( "createSlideTransition(): "
778 : "Could not extract slide transition type from XDrawPage - assuming no transition\n" );
779 0 : return ActivitySharedPtr();
780 : }
781 :
782 0 : sal_Int16 nTransitionSubType(0);
783 0 : if( !getPropertyValue( nTransitionSubType,
784 : xPropSet,
785 0 : "TransitionSubtype") )
786 : {
787 : OSL_TRACE( "createSlideTransition(): "
788 : "Could not extract slide transition subtype from XDrawPage - assuming no transition\n" );
789 0 : return ActivitySharedPtr();
790 : }
791 :
792 0 : bool bTransitionDirection(false);
793 0 : if( !getPropertyValue( bTransitionDirection,
794 : xPropSet,
795 0 : "TransitionDirection") )
796 : {
797 : OSL_TRACE( "createSlideTransition(): "
798 : "Could not extract slide transition direction from XDrawPage - assuming default direction\n" );
799 : }
800 :
801 0 : sal_Int32 aUnoColor(0);
802 0 : if( !getPropertyValue( aUnoColor,
803 : xPropSet,
804 0 : "TransitionFadeColor") )
805 : {
806 : OSL_TRACE( "createSlideTransition(): "
807 : "Could not extract slide transition fade color from XDrawPage - assuming black\n" );
808 : }
809 :
810 0 : const RGBColor aTransitionFadeColor( unoColor2RGBColor( aUnoColor ));
811 :
812 0 : uno::Any aSound;
813 0 : bool bLoopSound = false;
814 :
815 0 : if( !getPropertyValue( aSound, xPropSet, "Sound") )
816 : OSL_TRACE( "createSlideTransition(): Could not determine transition sound effect URL from XDrawPage - using no sound" );
817 :
818 0 : if( !getPropertyValue( bLoopSound, xPropSet, "LoopSound" ) )
819 : OSL_TRACE( "createSlideTransition(): Could not get slide property 'LoopSound' - using no sound" );
820 :
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 0 : resetSlideTransitionSound( aSound, bLoopSound ) ));
834 :
835 0 : if( !pTransition )
836 0 : return ActivitySharedPtr(); // no transition effect has been
837 : // generated. Normally, that means
838 : // that simply no transition is
839 : // set on this slide.
840 :
841 0 : double nTransitionDuration(0.0);
842 0 : if( !getPropertyValue( nTransitionDuration,
843 : xPropSet,
844 0 : "TransitionDuration") )
845 : {
846 : OSL_TRACE( "createSlideTransition(): "
847 : "Could not extract slide transition duration from XDrawPage - assuming no transition\n" );
848 0 : return ActivitySharedPtr();
849 : }
850 :
851 0 : sal_Int32 nMinFrames(5);
852 0 : if( !getPropertyValue( nMinFrames,
853 : xPropSet,
854 0 : "MinimalFrameNumber") )
855 : {
856 : OSL_TRACE( "createSlideTransition(): "
857 : "No minimal number of frames given - assuming 5\n" );
858 : }
859 :
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 0 : "Animation::prefetch"));
871 :
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 0 : basegfx::B2DSize( rEnteringSlide->getSlideSize() ) ),
886 : pTransition,
887 0 : true ));
888 : }
889 :
890 0 : PolygonMap::iterator SlideShowImpl::findPolygons( uno::Reference<drawing::XDrawPage> const& xDrawPage)
891 : {
892 : // TODO(P2) : Optimze research in the map.
893 0 : bool bFound = false;
894 0 : PolygonMap::iterator aIter=maPolygons.begin();
895 :
896 0 : while(aIter!=maPolygons.end() && !bFound)
897 : {
898 0 : if(aIter->first == xDrawPage)
899 0 : bFound = true;
900 : else
901 0 : ++aIter;
902 : }
903 :
904 0 : return aIter;
905 : }
906 :
907 0 : SlideSharedPtr SlideShowImpl::makeSlide(
908 : uno::Reference<drawing::XDrawPage> const& xDrawPage,
909 : uno::Reference<drawing::XDrawPagesSupplier> const& xDrawPages,
910 : uno::Reference<animations::XAnimationNode> const& xRootNode )
911 : {
912 0 : if( !xDrawPage.is() )
913 0 : return SlideSharedPtr();
914 :
915 : //Retrieve polygons for the current slide
916 0 : PolygonMap::iterator aIter;
917 0 : aIter = findPolygons(xDrawPage);
918 :
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 0 : (aIter != maPolygons.end()) ? aIter->second : PolyPolygonVector(),
933 0 : maUserPaintColor ? *maUserPaintColor : RGBColor(),
934 : maUserPaintStrokeWidth,
935 0 : !!maUserPaintColor,
936 : mbImageAnimationsAllowed,
937 0 : mbDisableAnimationZOrder) );
938 :
939 : // prefetch show content (reducing latency for slide
940 : // bitmap and effect start later on)
941 0 : pSlide->prefetch();
942 :
943 0 : return pSlide;
944 : }
945 :
946 0 : void SlideShowImpl::requestWaitSymbol()
947 : {
948 0 : ++mnWaitSymbolRequestCount;
949 : OSL_ASSERT(mnWaitSymbolRequestCount>0);
950 :
951 0 : if (mnWaitSymbolRequestCount == 1)
952 : {
953 0 : if( !mpWaitSymbol )
954 : {
955 : // fall back to cursor
956 0 : requestCursor(calcActiveCursor(mnCurrentCursor));
957 : }
958 : else
959 0 : mpWaitSymbol->show();
960 : }
961 0 : }
962 :
963 0 : void SlideShowImpl::releaseWaitSymbol()
964 : {
965 0 : --mnWaitSymbolRequestCount;
966 : OSL_ASSERT(mnWaitSymbolRequestCount>=0);
967 :
968 0 : if (mnWaitSymbolRequestCount == 0)
969 : {
970 0 : if( !mpWaitSymbol )
971 : {
972 : // fall back to cursor
973 0 : requestCursor(calcActiveCursor(mnCurrentCursor));
974 : }
975 : else
976 0 : mpWaitSymbol->hide();
977 : }
978 0 : }
979 :
980 0 : sal_Int16 SlideShowImpl::calcActiveCursor( sal_Int16 nCursorShape ) const
981 : {
982 0 : if( mnWaitSymbolRequestCount>0 && !mpWaitSymbol ) // enforce wait cursor
983 0 : nCursorShape = awt::SystemPointer::WAIT;
984 0 : else if( !mbMouseVisible ) // enforce INVISIBLE
985 0 : nCursorShape = awt::SystemPointer::INVISIBLE;
986 0 : else if( maUserPaintColor &&
987 0 : nCursorShape == awt::SystemPointer::ARROW )
988 0 : nCursorShape = awt::SystemPointer::PEN;
989 :
990 0 : return nCursorShape;
991 : }
992 :
993 0 : void SlideShowImpl::stopShow()
994 : {
995 : // Force-end running animation
996 : // ===========================
997 0 : if (mpCurrentSlide)
998 : {
999 0 : mpCurrentSlide->hide();
1000 : //Register polygons in the map
1001 0 : if(findPolygons(mpCurrentSlide->getXDrawPage()) != maPolygons.end())
1002 0 : maPolygons.erase(mpCurrentSlide->getXDrawPage());
1003 :
1004 0 : maPolygons.insert(make_pair(mpCurrentSlide->getXDrawPage(),mpCurrentSlide->getPolygons()));
1005 : }
1006 :
1007 : // clear all queues
1008 0 : maEventQueue.clear();
1009 0 : maActivitiesQueue.clear();
1010 :
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 0 : maUserEventQueue.clear();
1019 :
1020 : // re-enable automatic effect advancement
1021 : // (maEventQueue.clear() above might have killed
1022 : // maEventMultiplexer's tick events)
1023 0 : if (mbAutomaticAdvancementMode)
1024 : {
1025 : // toggle automatic mode (enabling just again is
1026 : // ignored by EventMultiplexer)
1027 0 : maEventMultiplexer.setAutomaticMode( false );
1028 0 : maEventMultiplexer.setAutomaticMode( true );
1029 : }
1030 0 : }
1031 :
1032 : class SlideShowImpl::PrefetchPropertiesFunc
1033 : {
1034 : public:
1035 0 : PrefetchPropertiesFunc( SlideShowImpl * that_,
1036 : bool& rbSkipAllMainSequenceEffects,
1037 : bool& rbSkipSlideTransition)
1038 : : mpSlideShowImpl(that_),
1039 : mrbSkipAllMainSequenceEffects(rbSkipAllMainSequenceEffects),
1040 0 : mrbSkipSlideTransition(rbSkipSlideTransition)
1041 0 : {}
1042 :
1043 0 : void operator()( beans::PropertyValue const& rProperty ) const {
1044 0 : if (rProperty.Name == "Prefetch" )
1045 : {
1046 0 : uno::Sequence<uno::Any> seq;
1047 0 : if ((rProperty.Value >>= seq) && seq.getLength() == 2)
1048 : {
1049 0 : seq[0] >>= mpSlideShowImpl->mxPrefetchSlide;
1050 0 : seq[1] >>= mpSlideShowImpl->mxPrefetchAnimationNode;
1051 0 : }
1052 : }
1053 0 : else if ( rProperty.Name == "SkipAllMainSequenceEffects" )
1054 : {
1055 0 : rProperty.Value >>= mrbSkipAllMainSequenceEffects;
1056 : }
1057 0 : else if ( rProperty.Name == "SkipSlideTransition" )
1058 : {
1059 0 : rProperty.Value >>= mrbSkipSlideTransition;
1060 : }
1061 : else
1062 : {
1063 : OSL_FAIL( OUStringToOString(
1064 : rProperty.Name, RTL_TEXTENCODING_UTF8 ).getStr() );
1065 : }
1066 0 : }
1067 : private:
1068 : SlideShowImpl *const mpSlideShowImpl;
1069 : bool& mrbSkipAllMainSequenceEffects;
1070 : bool& mrbSkipSlideTransition;
1071 : };
1072 :
1073 0 : 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)
1079 : {
1080 0 : osl::MutexGuard const guard( m_aMutex );
1081 :
1082 0 : if (isDisposed())
1083 0 : return;
1084 :
1085 0 : maEffectRewinder.setRootAnimationNode(xRootNode);
1086 :
1087 : // precondition: must only be called from the main thread!
1088 : DBG_TESTSOLARMUTEX();
1089 :
1090 0 : mxDrawPagesSupplier = xDrawPages;
1091 :
1092 0 : 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.
1100 :
1101 0 : bool bSkipAllMainSequenceEffects (false);
1102 0 : bool bSkipSlideTransition (false);
1103 : std::for_each( rProperties.getConstArray(),
1104 0 : rProperties.getConstArray() + rProperties.getLength(),
1105 0 : PrefetchPropertiesFunc(this, bSkipAllMainSequenceEffects, bSkipSlideTransition) );
1106 :
1107 : OSL_ENSURE( !maViewContainer.empty(), "### no views!" );
1108 0 : if (maViewContainer.empty())
1109 0 : return;
1110 :
1111 : // this here might take some time
1112 : {
1113 0 : WaitSymbolLock aLock (*this);
1114 :
1115 0 : mpPreviousSlide = mpCurrentSlide;
1116 0 : mpCurrentSlide.reset();
1117 :
1118 0 : if (matches( mpPrefetchSlide, xSlide, xRootNode ))
1119 : {
1120 : // prefetched slide matches:
1121 0 : mpCurrentSlide = mpPrefetchSlide;
1122 : }
1123 : else
1124 0 : mpCurrentSlide = makeSlide( xSlide, xDrawPages, xRootNode );
1125 :
1126 : OSL_ASSERT( mpCurrentSlide );
1127 0 : if (mpCurrentSlide)
1128 : {
1129 0 : basegfx::B2DSize oldSlideSize;
1130 0 : if( mpPreviousSlide )
1131 0 : oldSlideSize = basegfx::B2DSize( mpPreviousSlide->getSlideSize() );
1132 :
1133 0 : basegfx::B2DSize const slideSize( mpCurrentSlide->getSlideSize() );
1134 :
1135 : // push new transformation to all views, if size changed
1136 0 : if( !mpPreviousSlide || oldSlideSize != slideSize )
1137 : {
1138 : std::for_each( maViewContainer.begin(),
1139 : maViewContainer.end(),
1140 : boost::bind( &View::setViewSize, _1,
1141 0 : boost::cref(slideSize) ));
1142 :
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 0 : maEventMultiplexer.notifyViewsChanged();
1148 : }
1149 :
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 0 : mpCurrentSlide->getXDrawPage(),
1156 : mpPreviousSlide,
1157 : mpCurrentSlide,
1158 0 : makeEvent(
1159 : boost::bind(
1160 : &SlideShowImpl::notifySlideTransitionEnded,
1161 : this,
1162 : false ),
1163 0 : "SlideShowImpl::notifySlideTransitionEnded")));
1164 :
1165 0 : if (bSkipSlideTransition)
1166 : {
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 0 : pSlideChangeActivity.reset();
1172 : }
1173 :
1174 0 : if (pSlideChangeActivity)
1175 : {
1176 : // factory generated a slide transition - activate it!
1177 0 : maActivitiesQueue.addActivity( pSlideChangeActivity );
1178 : }
1179 : else
1180 : {
1181 : // no transition effect on this slide - schedule slide
1182 : // effect start event right away.
1183 : maEventQueue.addEvent(
1184 0 : makeEvent(
1185 : boost::bind(
1186 : &SlideShowImpl::notifySlideTransitionEnded,
1187 : this,
1188 : true ),
1189 0 : "SlideShowImpl::notifySlideTransitionEnded"));
1190 0 : }
1191 0 : }
1192 : } // finally
1193 :
1194 : maListenerContainer.forEach<presentation::XSlideShowListener>(
1195 0 : boost::mem_fn( &presentation::XSlideShowListener::slideTransitionStarted ) );
1196 :
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 0 : if (bSkipAllMainSequenceEffects)
1201 0 : maEffectRewinder.skipAllMainSequenceEffects();
1202 : }
1203 :
1204 0 : void SlideShowImpl::redisplayCurrentSlide()
1205 : {
1206 0 : osl::MutexGuard const guard( m_aMutex );
1207 :
1208 0 : if (isDisposed())
1209 0 : return;
1210 :
1211 : // precondition: must only be called from the main thread!
1212 : DBG_TESTSOLARMUTEX();
1213 0 : stopShow();
1214 :
1215 : OSL_ENSURE( !maViewContainer.empty(), "### no views!" );
1216 0 : if (maViewContainer.empty())
1217 0 : return;
1218 :
1219 : // No transition effect on this slide - schedule slide
1220 : // effect start event right away.
1221 : maEventQueue.addEvent(
1222 0 : makeEvent(
1223 : boost::bind(
1224 : &SlideShowImpl::notifySlideTransitionEnded,
1225 : this,
1226 : true ),
1227 0 : "SlideShowImpl::notifySlideTransitionEnded"));
1228 :
1229 : maListenerContainer.forEach<presentation::XSlideShowListener>(
1230 0 : boost::mem_fn( &presentation::XSlideShowListener::slideTransitionStarted ) );
1231 : }
1232 :
1233 0 : sal_Bool SlideShowImpl::nextEffect() throw (uno::RuntimeException, std::exception)
1234 : {
1235 0 : osl::MutexGuard const guard( m_aMutex );
1236 :
1237 0 : if (isDisposed())
1238 0 : return false;
1239 :
1240 : // precondition: must only be called from the main thread!
1241 : DBG_TESTSOLARMUTEX();
1242 :
1243 0 : if (mbShowPaused)
1244 0 : return true;
1245 : else
1246 0 : return maEventMultiplexer.notifyNextEffect();
1247 : }
1248 :
1249 0 : sal_Bool SlideShowImpl::previousEffect() throw (uno::RuntimeException, std::exception)
1250 : {
1251 0 : osl::MutexGuard const guard( m_aMutex );
1252 :
1253 0 : if (isDisposed())
1254 0 : return false;
1255 :
1256 : // precondition: must only be called from the main thread!
1257 : DBG_TESTSOLARMUTEX();
1258 :
1259 0 : if (mbShowPaused)
1260 0 : return true;
1261 : else
1262 : {
1263 : return maEffectRewinder.rewind(
1264 : maScreenUpdater.createLock(false),
1265 : ::boost::bind<void>(::boost::mem_fn(&SlideShowImpl::redisplayCurrentSlide), this),
1266 0 : ::boost::bind<void>(::boost::mem_fn(&SlideShowImpl::rewindEffectToPreviousSlide), this));
1267 0 : }
1268 : }
1269 :
1270 0 : void SlideShowImpl::rewindEffectToPreviousSlide()
1271 : {
1272 : // Show the wait symbol now and prevent it from showing temporary slide
1273 : // content while effects are played back.
1274 0 : WaitSymbolLock aLock (*this);
1275 :
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 0 : notifySlideEnded(true);
1280 :
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 0 : maEventQueue.forceEmpty();
1285 :
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 0 : maScreenUpdater.commitUpdates();
1290 0 : }
1291 :
1292 0 : sal_Bool SlideShowImpl::startShapeActivity(
1293 : uno::Reference<drawing::XShape> const& /*xShape*/ )
1294 : throw (uno::RuntimeException, std::exception)
1295 : {
1296 0 : osl::MutexGuard const guard( m_aMutex );
1297 :
1298 : // precondition: must only be called from the main thread!
1299 : DBG_TESTSOLARMUTEX();
1300 :
1301 : // TODO(F3): NYI
1302 : OSL_FAIL( "not yet implemented!" );
1303 0 : return false;
1304 : }
1305 :
1306 0 : sal_Bool SlideShowImpl::stopShapeActivity(
1307 : uno::Reference<drawing::XShape> const& /*xShape*/ )
1308 : throw (uno::RuntimeException, std::exception)
1309 : {
1310 0 : osl::MutexGuard const guard( m_aMutex );
1311 :
1312 : // precondition: must only be called from the main thread!
1313 : DBG_TESTSOLARMUTEX();
1314 :
1315 : // TODO(F3): NYI
1316 : OSL_FAIL( "not yet implemented!" );
1317 0 : return false;
1318 : }
1319 :
1320 0 : sal_Bool SlideShowImpl::pause( sal_Bool bPauseShow )
1321 : throw (uno::RuntimeException, std::exception)
1322 : {
1323 0 : osl::MutexGuard const guard( m_aMutex );
1324 :
1325 0 : if (isDisposed())
1326 0 : return false;
1327 :
1328 : // precondition: must only be called from the main thread!
1329 : DBG_TESTSOLARMUTEX();
1330 :
1331 0 : if (bPauseShow)
1332 0 : mpPresTimer->pauseTimer();
1333 : else
1334 0 : mpPresTimer->continueTimer();
1335 :
1336 0 : maEventMultiplexer.notifyPauseMode(bPauseShow);
1337 :
1338 0 : mbShowPaused = bPauseShow;
1339 0 : return true;
1340 : }
1341 :
1342 0 : uno::Reference<drawing::XDrawPage> SlideShowImpl::getCurrentSlide()
1343 : throw (uno::RuntimeException, std::exception)
1344 : {
1345 0 : osl::MutexGuard const guard( m_aMutex );
1346 :
1347 0 : if (isDisposed())
1348 0 : return uno::Reference<drawing::XDrawPage>();
1349 :
1350 : // precondition: must only be called from the main thread!
1351 : DBG_TESTSOLARMUTEX();
1352 :
1353 0 : if (mpCurrentSlide)
1354 0 : return mpCurrentSlide->getXDrawPage();
1355 : else
1356 0 : return uno::Reference<drawing::XDrawPage>();
1357 : }
1358 :
1359 0 : sal_Bool SlideShowImpl::addView(
1360 : uno::Reference<presentation::XSlideShowView> const& xView )
1361 : throw (uno::RuntimeException, std::exception)
1362 : {
1363 0 : osl::MutexGuard const guard( m_aMutex );
1364 :
1365 0 : if (isDisposed())
1366 0 : return false;
1367 :
1368 : // precondition: must only be called from the main thread!
1369 : DBG_TESTSOLARMUTEX();
1370 :
1371 : // first of all, check if view has a valid canvas
1372 0 : ENSURE_OR_RETURN_FALSE( xView.is(), "addView(): Invalid view" );
1373 0 : ENSURE_OR_RETURN_FALSE( xView->getCanvas().is(),
1374 : "addView(): View does not provide a valid canvas" );
1375 :
1376 : UnoViewSharedPtr const pView( createSlideView(
1377 : xView,
1378 : maEventQueue,
1379 0 : maEventMultiplexer ));
1380 0 : if (!maViewContainer.addView( pView ))
1381 0 : return false; // view already added
1382 :
1383 : // initialize view content
1384 : // =======================
1385 :
1386 0 : if (mpCurrentSlide)
1387 : {
1388 : // set view transformation
1389 0 : const basegfx::B2ISize slideSize = mpCurrentSlide->getSlideSize();
1390 0 : pView->setViewSize( basegfx::B2DSize( slideSize.getX(),
1391 0 : slideSize.getY() ) );
1392 : }
1393 :
1394 : // clear view area (since its newly added,
1395 : // we need a clean slate)
1396 0 : pView->clearAll();
1397 :
1398 : // broadcast newly added view
1399 0 : maEventMultiplexer.notifyViewAdded( pView );
1400 :
1401 : // set current mouse ptr
1402 0 : pView->setCursorShape( calcActiveCursor(mnCurrentCursor) );
1403 :
1404 0 : return true;
1405 : }
1406 :
1407 0 : sal_Bool SlideShowImpl::removeView(
1408 : uno::Reference<presentation::XSlideShowView> const& xView )
1409 : throw (uno::RuntimeException, std::exception)
1410 : {
1411 0 : osl::MutexGuard const guard( m_aMutex );
1412 :
1413 : // precondition: must only be called from the main thread!
1414 : DBG_TESTSOLARMUTEX();
1415 :
1416 0 : ENSURE_OR_RETURN_FALSE( xView.is(), "removeView(): Invalid view" );
1417 :
1418 0 : UnoViewSharedPtr const pView( maViewContainer.removeView( xView ) );
1419 0 : if( !pView )
1420 0 : return false; // view was not added in the first place
1421 :
1422 : // remove view from EventMultiplexer (mouse events etc.)
1423 0 : maEventMultiplexer.notifyViewRemoved( pView );
1424 :
1425 0 : pView->_dispose();
1426 :
1427 0 : return true;
1428 : }
1429 :
1430 0 : void SlideShowImpl::registerUserPaintPolygons( const uno::Reference< lang::XMultiServiceFactory >& xDocFactory ) throw (uno::RuntimeException, std::exception)
1431 : {
1432 : //Retrieve Polygons if user ends presentation by context menu
1433 0 : if (mpCurrentSlide)
1434 : {
1435 0 : if(findPolygons(mpCurrentSlide->getXDrawPage()) != maPolygons.end())
1436 0 : maPolygons.erase(mpCurrentSlide->getXDrawPage());
1437 :
1438 0 : maPolygons.insert(make_pair(mpCurrentSlide->getXDrawPage(),mpCurrentSlide->getPolygons()));
1439 : }
1440 :
1441 : //Creating the layer for shapes
1442 : // query for the XLayerManager
1443 0 : uno::Reference< drawing::XLayerSupplier > xLayerSupplier(xDocFactory, uno::UNO_QUERY);
1444 0 : uno::Reference< container::XNameAccess > xNameAccess = xLayerSupplier->getLayerManager();
1445 :
1446 0 : uno::Reference< drawing::XLayerManager > xLayerManager(xNameAccess, uno::UNO_QUERY);
1447 : // create a layer and set its properties
1448 0 : uno::Reference< drawing::XLayer > xDrawnInSlideshow = xLayerManager->insertNewByIndex(xLayerManager->getCount());
1449 0 : uno::Reference< beans::XPropertySet > xLayerPropSet(xDrawnInSlideshow, uno::UNO_QUERY);
1450 :
1451 : //Layer Name which enables to catch annotations
1452 0 : OUString layerName = "DrawnInSlideshow";
1453 0 : uno::Any aPropLayer;
1454 :
1455 0 : aPropLayer <<= layerName;
1456 0 : xLayerPropSet->setPropertyValue("Name", aPropLayer);
1457 :
1458 0 : aPropLayer <<= true;
1459 0 : xLayerPropSet->setPropertyValue("IsVisible", aPropLayer);
1460 :
1461 0 : aPropLayer <<= false;
1462 0 : xLayerPropSet->setPropertyValue("IsLocked", aPropLayer);
1463 :
1464 0 : PolygonMap::iterator aIter=maPolygons.begin();
1465 :
1466 0 : PolyPolygonVector aPolygons;
1467 0 : ::cppcanvas::PolyPolygonSharedPtr pPolyPoly;
1468 0 : ::basegfx::B2DPolyPolygon b2DPolyPoly;
1469 :
1470 : //Register polygons for each slide
1471 0 : while(aIter!=maPolygons.end())
1472 : {
1473 0 : aPolygons = aIter->second;
1474 : //Get shapes for the slide
1475 0 : ::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 0 : for( PolyPolygonVector::iterator aIterPoly=aPolygons.begin(),
1478 0 : aEnd=aPolygons.end();
1479 : aIterPoly!=aEnd; ++aIterPoly )
1480 : {
1481 0 : pPolyPoly = (*aIterPoly);
1482 0 : b2DPolyPoly = ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(pPolyPoly->getUNOPolyPolygon());
1483 :
1484 : //Normally there is only one polygon
1485 0 : for(sal_uInt32 i=0; i< b2DPolyPoly.count();i++)
1486 : {
1487 0 : const ::basegfx::B2DPolygon& aPoly = b2DPolyPoly.getB2DPolygon(i);
1488 0 : sal_uInt32 nPoints = aPoly.count();
1489 :
1490 0 : if( nPoints > 1)
1491 : {
1492 : //create the PolyLineShape
1493 0 : uno::Reference< uno::XInterface > polyshape(xDocFactory->createInstance(
1494 0 : OUString("com.sun.star.drawing.PolyLineShape") ) );
1495 0 : uno::Reference< drawing::XShape > rPolyShape(polyshape, uno::UNO_QUERY);
1496 :
1497 : //Add the shape to the slide
1498 0 : Shapes->add(rPolyShape);
1499 :
1500 : //Retrieve shape properties
1501 0 : uno::Reference< beans::XPropertySet > aXPropSet = uno::Reference< beans::XPropertySet >( rPolyShape, uno::UNO_QUERY );
1502 : //Construct a sequence of points sequence
1503 0 : drawing::PointSequenceSequence aRetval;
1504 : //Create only one sequence for one polygon
1505 0 : aRetval.realloc( 1 );
1506 : // Retrieve the sequence of points from aRetval
1507 0 : drawing::PointSequence* pOuterSequence = aRetval.getArray();
1508 : // Create 2 points in this sequence
1509 0 : pOuterSequence->realloc(nPoints);
1510 : // Get these points which are in an array
1511 0 : awt::Point* pInnerSequence = pOuterSequence->getArray();
1512 0 : for( sal_uInt32 n = 0; n < nPoints; n++ )
1513 : {
1514 : //Create a point from the polygon
1515 : *pInnerSequence++ = awt::Point(
1516 0 : basegfx::fround(aPoly.getB2DPoint(n).getX()),
1517 0 : basegfx::fround(aPoly.getB2DPoint(n).getY()));
1518 : }
1519 :
1520 : //Fill the properties
1521 : //Give the built PointSequenceSequence.
1522 0 : uno::Any aParam;
1523 0 : aParam <<= aRetval;
1524 0 : aXPropSet->setPropertyValue("PolyPolygon", aParam );
1525 :
1526 : //LineStyle : SOLID by default
1527 0 : uno::Any aAny;
1528 : drawing::LineStyle eLS;
1529 0 : eLS = drawing::LineStyle_SOLID;
1530 0 : aAny <<= eLS;
1531 0 : aXPropSet->setPropertyValue("LineStyle", aAny );
1532 :
1533 : //LineColor
1534 : sal_uInt32 nLineColor;
1535 0 : nLineColor = pPolyPoly->getRGBALineColor();
1536 : //Transform polygon color from RRGGBBAA to AARRGGBB
1537 0 : aAny <<= RGBAColor2UnoColor(nLineColor);
1538 0 : aXPropSet->setPropertyValue("LineColor", aAny );
1539 :
1540 : //LineWidth
1541 : double fLineWidth;
1542 0 : fLineWidth = pPolyPoly->getStrokeWidth();
1543 0 : aAny <<= (sal_Int32)fLineWidth;
1544 0 : aXPropSet->setPropertyValue("LineWidth", aAny );
1545 :
1546 : // make polygons special
1547 0 : xLayerManager->attachShapeToLayer(rPolyShape, xDrawnInSlideshow);
1548 : }
1549 0 : }
1550 : }
1551 0 : ++aIter;
1552 0 : }
1553 0 : }
1554 :
1555 0 : sal_Bool SlideShowImpl::setProperty( beans::PropertyValue const& rProperty )
1556 : throw (uno::RuntimeException, std::exception)
1557 : {
1558 0 : osl::MutexGuard const guard( m_aMutex );
1559 :
1560 0 : if (isDisposed())
1561 0 : return false;
1562 :
1563 : // precondition: must only be called from the main thread!
1564 : DBG_TESTSOLARMUTEX();
1565 :
1566 0 : if ( rProperty.Name == "AutomaticAdvancement" )
1567 : {
1568 0 : double nTimeout(0.0);
1569 0 : mbAutomaticAdvancementMode = (rProperty.Value >>= nTimeout);
1570 0 : if (mbAutomaticAdvancementMode)
1571 : {
1572 0 : maEventMultiplexer.setAutomaticTimeout( nTimeout );
1573 : }
1574 0 : maEventMultiplexer.setAutomaticMode( mbAutomaticAdvancementMode );
1575 0 : return true;
1576 : }
1577 :
1578 0 : if ( rProperty.Name == "UserPaintColor" )
1579 : {
1580 0 : sal_Int32 nColor(0);
1581 0 : if (rProperty.Value >>= nColor)
1582 : {
1583 : OSL_ENSURE( mbMouseVisible,
1584 : "setProperty(): User paint overrides invisible mouse" );
1585 :
1586 : // enable user paint
1587 0 : maUserPaintColor.reset( unoColor2RGBColor( nColor ) );
1588 0 : if( mpCurrentSlide && !mpCurrentSlide->isPaintOverlayActive() )
1589 0 : mpCurrentSlide->enablePaintOverlay();
1590 :
1591 0 : maEventMultiplexer.notifyUserPaintColor( *maUserPaintColor );
1592 : }
1593 : else
1594 : {
1595 : // disable user paint
1596 0 : maUserPaintColor.reset();
1597 0 : maEventMultiplexer.notifyUserPaintDisabled();
1598 0 : if( mpCurrentSlide )
1599 0 : mpCurrentSlide->disablePaintOverlay();
1600 : }
1601 :
1602 0 : resetCursor();
1603 :
1604 0 : return true;
1605 : }
1606 :
1607 : //adding support for erasing features in UserPaintOverlay
1608 0 : if ( rProperty.Name == "EraseAllInk" )
1609 : {
1610 0 : bool nEraseAllInk(false);
1611 0 : if (rProperty.Value >>= nEraseAllInk)
1612 : {
1613 : OSL_ENSURE( mbMouseVisible,
1614 : "setProperty(): User paint overrides invisible mouse" );
1615 :
1616 : // enable user paint
1617 0 : maEraseAllInk.reset( nEraseAllInk );
1618 0 : maEventMultiplexer.notifyEraseAllInk( *maEraseAllInk );
1619 : }
1620 :
1621 0 : return true;
1622 : }
1623 :
1624 0 : if ( rProperty.Name == "SwitchPenMode" )
1625 : {
1626 0 : bool nSwitchPenMode(false);
1627 0 : if (rProperty.Value >>= nSwitchPenMode)
1628 : {
1629 : OSL_ENSURE( mbMouseVisible,
1630 : "setProperty(): User paint overrides invisible mouse" );
1631 :
1632 0 : if(nSwitchPenMode){
1633 : // Switch to Pen Mode
1634 0 : maSwitchPenMode.reset( nSwitchPenMode );
1635 0 : maEventMultiplexer.notifySwitchPenMode();
1636 : }
1637 : }
1638 0 : return true;
1639 : }
1640 :
1641 0 : if ( rProperty.Name == "SwitchEraserMode" )
1642 : {
1643 0 : bool nSwitchEraserMode(false);
1644 0 : if (rProperty.Value >>= nSwitchEraserMode)
1645 : {
1646 : OSL_ENSURE( mbMouseVisible,
1647 : "setProperty(): User paint overrides invisible mouse" );
1648 0 : if(nSwitchEraserMode){
1649 : // switch to Eraser mode
1650 0 : maSwitchEraserMode.reset( nSwitchEraserMode );
1651 0 : maEventMultiplexer.notifySwitchEraserMode();
1652 : }
1653 : }
1654 :
1655 0 : return true;
1656 : }
1657 :
1658 0 : if ( rProperty.Name == "EraseInk" )
1659 : {
1660 0 : sal_Int32 nEraseInk(100);
1661 0 : if (rProperty.Value >>= nEraseInk)
1662 : {
1663 : OSL_ENSURE( mbMouseVisible,
1664 : "setProperty(): User paint overrides invisible mouse" );
1665 :
1666 : // enable user paint
1667 0 : maEraseInk.reset( nEraseInk );
1668 0 : maEventMultiplexer.notifyEraseInkWidth( *maEraseInk );
1669 : }
1670 :
1671 0 : return true;
1672 : }
1673 :
1674 : // new Property for pen's width
1675 0 : if ( rProperty.Name == "UserPaintStrokeWidth" )
1676 : {
1677 0 : double nWidth(4.0);
1678 0 : if (rProperty.Value >>= nWidth)
1679 : {
1680 : OSL_ENSURE( mbMouseVisible,"setProperty(): User paint overrides invisible mouse" );
1681 : // enable user paint stroke width
1682 0 : maUserPaintStrokeWidth = nWidth;
1683 0 : maEventMultiplexer.notifyUserPaintStrokeWidth( maUserPaintStrokeWidth );
1684 : }
1685 :
1686 0 : return true;
1687 : }
1688 :
1689 0 : if ( rProperty.Name == "AdvanceOnClick" )
1690 : {
1691 0 : bool bAdvanceOnClick = false;
1692 0 : if (! (rProperty.Value >>= bAdvanceOnClick))
1693 0 : return false;
1694 0 : maUserEventQueue.setAdvanceOnClick( bAdvanceOnClick );
1695 0 : return true;
1696 : }
1697 :
1698 0 : if ( rProperty.Name == "DisableAnimationZOrder" )
1699 : {
1700 0 : bool bDisableAnimationZOrder = false;
1701 0 : if (! (rProperty.Value >>= bDisableAnimationZOrder))
1702 0 : return false;
1703 0 : mbDisableAnimationZOrder = bDisableAnimationZOrder;
1704 0 : return true;
1705 : }
1706 :
1707 0 : if ( rProperty.Name == "ImageAnimationsAllowed" )
1708 : {
1709 0 : if (! (rProperty.Value >>= mbImageAnimationsAllowed))
1710 0 : return false;
1711 :
1712 : // TODO(F3): Forward to slides!
1713 0 : return true;
1714 : }
1715 :
1716 0 : if ( rProperty.Name == "MouseVisible" )
1717 : {
1718 0 : if (! (rProperty.Value >>= mbMouseVisible))
1719 0 : return false;
1720 :
1721 0 : requestCursor(mnCurrentCursor);
1722 :
1723 0 : return true;
1724 : }
1725 :
1726 0 : if ( rProperty.Name == "ForceManualAdvance" )
1727 : {
1728 0 : return (rProperty.Value >>= mbForceManualAdvance);
1729 : }
1730 :
1731 0 : if ( rProperty.Name == "RehearseTimings" )
1732 : {
1733 0 : bool bRehearseTimings = false;
1734 0 : if (! (rProperty.Value >>= bRehearseTimings))
1735 0 : return false;
1736 :
1737 0 : if (bRehearseTimings)
1738 : {
1739 : // TODO(Q3): Move to slide
1740 0 : mpRehearseTimingsActivity = RehearseTimingsActivity::create(
1741 : SlideShowContext(
1742 : mpDummyPtr,
1743 : maEventQueue,
1744 : maEventMultiplexer,
1745 : maScreenUpdater,
1746 : maActivitiesQueue,
1747 : maUserEventQueue,
1748 : *this,
1749 : maViewContainer,
1750 0 : mxComponentContext) );
1751 : }
1752 0 : else if (mpRehearseTimingsActivity)
1753 : {
1754 : // removes timer from all views:
1755 0 : mpRehearseTimingsActivity->dispose();
1756 0 : mpRehearseTimingsActivity.reset();
1757 : }
1758 0 : return true;
1759 : }
1760 :
1761 0 : if ( rProperty.Name == "WaitSymbolBitmap" )
1762 : {
1763 0 : uno::Reference<rendering::XBitmap> xBitmap;
1764 0 : if (! (rProperty.Value >>= xBitmap))
1765 0 : return false;
1766 :
1767 0 : mpWaitSymbol = WaitSymbol::create( xBitmap,
1768 : maScreenUpdater,
1769 : maEventMultiplexer,
1770 0 : maViewContainer );
1771 :
1772 0 : return true;
1773 : }
1774 :
1775 0 : if ( rProperty.Name == "PointerSymbolBitmap" )
1776 : {
1777 0 : uno::Reference<rendering::XBitmap> xBitmap;
1778 0 : if (! (rProperty.Value >>= xBitmap))
1779 0 : return false;
1780 :
1781 0 : mpPointerSymbol = PointerSymbol::create( xBitmap,
1782 : maScreenUpdater,
1783 : maEventMultiplexer,
1784 0 : maViewContainer );
1785 :
1786 0 : return true;
1787 : }
1788 :
1789 0 : if ( rProperty.Name == "PointerVisible" )
1790 : {
1791 : bool visible;
1792 0 : if (!(rProperty.Value >>= visible))
1793 0 : return false;
1794 :
1795 0 : mpPointerSymbol->setVisible(visible);
1796 0 : return true;
1797 : }
1798 :
1799 0 : if ( rProperty.Name == "PointerPosition")
1800 : {
1801 0 : ::com::sun::star::geometry::RealPoint2D pos;
1802 0 : if (! (rProperty.Value >>= pos))
1803 0 : return false;
1804 :
1805 0 : mpPointerSymbol->viewsChanged(pos);
1806 0 : return true;
1807 : }
1808 :
1809 0 : if (rProperty.Name == "NoSlideTransitions" )
1810 : {
1811 0 : return (rProperty.Value >>= mbNoSlideTransitions);
1812 : }
1813 :
1814 0 : if ( rProperty.Name == "IsSoundEnabled" )
1815 : {
1816 0 : uno::Sequence<uno::Any> aValues;
1817 0 : uno::Reference<presentation::XSlideShowView> xView;
1818 0 : bool bValue (false);
1819 0 : if ((rProperty.Value >>= aValues)
1820 0 : && aValues.getLength()==2
1821 0 : && (aValues[0] >>= xView)
1822 0 : && (aValues[1] >>= bValue))
1823 : {
1824 : // Look up the view.
1825 0 : for (UnoViewVector::const_iterator
1826 0 : iView (maViewContainer.begin()),
1827 0 : iEnd (maViewContainer.end());
1828 : iView!=iEnd;
1829 : ++iView)
1830 : {
1831 0 : if (*iView && (*iView)->getUnoView()==xView)
1832 : {
1833 : // Store the flag at the view so that media shapes have
1834 : // access to it.
1835 0 : (*iView)->setIsSoundEnabled(bValue);
1836 0 : return true;
1837 : }
1838 : }
1839 0 : }
1840 : }
1841 :
1842 0 : return false;
1843 : }
1844 :
1845 0 : void SlideShowImpl::addSlideShowListener(
1846 : uno::Reference<presentation::XSlideShowListener> const& xListener )
1847 : throw (uno::RuntimeException, std::exception)
1848 : {
1849 0 : osl::MutexGuard const guard( m_aMutex );
1850 :
1851 0 : if (isDisposed())
1852 0 : return;
1853 :
1854 : // container syncs with passed mutex ref
1855 0 : maListenerContainer.addInterface(xListener);
1856 : }
1857 :
1858 0 : void SlideShowImpl::removeSlideShowListener(
1859 : uno::Reference<presentation::XSlideShowListener> const& xListener )
1860 : throw (uno::RuntimeException, std::exception)
1861 : {
1862 0 : osl::MutexGuard const guard( m_aMutex );
1863 :
1864 : // container syncs with passed mutex ref
1865 0 : maListenerContainer.removeInterface(xListener);
1866 0 : }
1867 :
1868 0 : void SlideShowImpl::addShapeEventListener(
1869 : uno::Reference<presentation::XShapeEventListener> const& xListener,
1870 : uno::Reference<drawing::XShape> const& xShape )
1871 : throw (uno::RuntimeException, std::exception)
1872 : {
1873 0 : osl::MutexGuard const guard( m_aMutex );
1874 :
1875 0 : if (isDisposed())
1876 0 : return;
1877 :
1878 : // precondition: must only be called from the main thread!
1879 : DBG_TESTSOLARMUTEX();
1880 :
1881 0 : ShapeEventListenerMap::iterator aIter;
1882 0 : if( (aIter=maShapeEventListeners.find( xShape )) ==
1883 0 : maShapeEventListeners.end() )
1884 : {
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 0 : new cppu::OInterfaceContainerHelper(m_aMutex)))).first;
1891 : }
1892 :
1893 : // add new listener to broadcaster
1894 0 : if( aIter->second.get() )
1895 0 : aIter->second->addInterface( xListener );
1896 :
1897 : maEventMultiplexer.notifyShapeListenerAdded(xListener,
1898 0 : xShape);
1899 : }
1900 :
1901 0 : void SlideShowImpl::removeShapeEventListener(
1902 : uno::Reference<presentation::XShapeEventListener> const& xListener,
1903 : uno::Reference<drawing::XShape> const& xShape )
1904 : throw (uno::RuntimeException, std::exception)
1905 : {
1906 0 : osl::MutexGuard const guard( m_aMutex );
1907 :
1908 : // precondition: must only be called from the main thread!
1909 : DBG_TESTSOLARMUTEX();
1910 :
1911 0 : ShapeEventListenerMap::iterator aIter;
1912 0 : if( (aIter = maShapeEventListeners.find( xShape )) !=
1913 0 : maShapeEventListeners.end() )
1914 : {
1915 : // entry for this shape found -> remove listener from
1916 : // helper object
1917 0 : ENSURE_OR_THROW(
1918 : aIter->second.get(),
1919 : "SlideShowImpl::removeShapeEventListener(): "
1920 : "listener map contains NULL broadcast helper" );
1921 :
1922 0 : aIter->second->removeInterface( xListener );
1923 : }
1924 :
1925 : maEventMultiplexer.notifyShapeListenerRemoved(xListener,
1926 0 : xShape);
1927 0 : }
1928 :
1929 0 : void SlideShowImpl::setShapeCursor(
1930 : uno::Reference<drawing::XShape> const& xShape, sal_Int16 nPointerShape )
1931 : throw (uno::RuntimeException, std::exception)
1932 : {
1933 0 : osl::MutexGuard const guard( m_aMutex );
1934 :
1935 0 : if (isDisposed())
1936 0 : return;
1937 :
1938 : // precondition: must only be called from the main thread!
1939 : DBG_TESTSOLARMUTEX();
1940 :
1941 0 : ShapeCursorMap::iterator aIter;
1942 0 : if( (aIter=maShapeCursors.find( xShape )) == maShapeCursors.end() )
1943 : {
1944 : // no entry for this shape -> create one
1945 0 : if( nPointerShape != awt::SystemPointer::ARROW )
1946 : {
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 0 : nPointerShape) );
1953 : }
1954 : }
1955 0 : else if( nPointerShape == awt::SystemPointer::ARROW )
1956 : {
1957 : // shape shall display normal cursor -> can disable
1958 : // the cursor and clear the entry
1959 0 : maShapeCursors.erase( xShape );
1960 : }
1961 : else
1962 : {
1963 : // existing entry found, update with new cursor ID
1964 0 : aIter->second = nPointerShape;
1965 : }
1966 :
1967 : maEventMultiplexer.notifyShapeCursorChange(xShape,
1968 0 : nPointerShape);
1969 : }
1970 :
1971 0 : bool SlideShowImpl::requestCursor( sal_Int16 nCursorShape )
1972 : {
1973 0 : mnCurrentCursor = nCursorShape;
1974 :
1975 0 : const sal_Int16 nActualCursor = calcActiveCursor(mnCurrentCursor);
1976 :
1977 : // change all views to the requested cursor ID
1978 : std::for_each( maViewContainer.begin(),
1979 : maViewContainer.end(),
1980 : boost::bind( &View::setCursorShape,
1981 : _1,
1982 0 : nActualCursor ));
1983 :
1984 0 : return nActualCursor==nCursorShape;
1985 : }
1986 :
1987 0 : void SlideShowImpl::resetCursor()
1988 : {
1989 0 : mnCurrentCursor = awt::SystemPointer::ARROW;
1990 :
1991 : // change all views to the default cursor ID
1992 : std::for_each( maViewContainer.begin(),
1993 : maViewContainer.end(),
1994 : boost::bind( &View::setCursorShape,
1995 : _1,
1996 0 : calcActiveCursor(mnCurrentCursor) ));
1997 0 : }
1998 :
1999 0 : sal_Bool SlideShowImpl::update( double & nNextTimeout )
2000 : throw (uno::RuntimeException, std::exception)
2001 : {
2002 0 : osl::MutexGuard const guard( m_aMutex );
2003 :
2004 0 : if (isDisposed())
2005 0 : return false;
2006 :
2007 : // precondition: update() must only be called from the
2008 : // main thread!
2009 : DBG_TESTSOLARMUTEX();
2010 :
2011 0 : if( mbShowPaused )
2012 : {
2013 : // commit frame (might be repaints pending)
2014 0 : maScreenUpdater.commitUpdates();
2015 :
2016 0 : return false;
2017 : }
2018 : else
2019 : {
2020 : // TODO(F2): re-evaluate whether that timer lagging makes
2021 : // sense.
2022 :
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.
2029 : {
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 0 : boost::shared_ptr<canvas::tools::ElapsedTime> xTimer(mpPresTimer);
2034 : comphelper::ScopeGuard scopeGuard(
2035 : boost::bind( &canvas::tools::ElapsedTime::releaseTimer,
2036 0 : boost::cref(xTimer) ) );
2037 0 : xTimer->holdTimer();
2038 :
2039 : // process queues
2040 0 : maEventQueue.process();
2041 :
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 0 : if (isDisposed())
2048 : {
2049 0 : scopeGuard.dismiss();
2050 0 : return false;
2051 : }
2052 :
2053 0 : maActivitiesQueue.process();
2054 :
2055 : // commit frame to screen
2056 0 : maFrameSynchronization.Synchronize();
2057 0 : maScreenUpdater.commitUpdates();
2058 :
2059 : // TODO(Q3): remove need to call dequeued() from
2060 : // activities. feels like a wart.
2061 :
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.
2080 :
2081 : // process dequeued activities _after_ commit to screen
2082 0 : maActivitiesQueue.processDequeued();
2083 :
2084 : // commit frame to screen
2085 0 : maScreenUpdater.commitUpdates();
2086 : }
2087 : // Time held until here
2088 :
2089 0 : const bool bActivitiesLeft = (! maActivitiesQueue.isEmpty());
2090 0 : const bool bTimerEventsLeft = (! maEventQueue.isEmpty());
2091 0 : const bool bRet = (bActivitiesLeft || bTimerEventsLeft);
2092 :
2093 0 : if (bRet)
2094 : {
2095 : // calc nNextTimeout value:
2096 0 : if (bActivitiesLeft)
2097 : {
2098 : // Activity queue is not empty. Tell caller that we would
2099 : // like to render another frame.
2100 :
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 0 : nNextTimeout = 0;
2106 0 : maFrameSynchronization.Activate();
2107 : }
2108 : else
2109 : {
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.
2114 :
2115 : // #i61190# Retrieve next timeout only _after_
2116 : // processing activity queue
2117 :
2118 : // ensure positive value:
2119 0 : nNextTimeout = std::max( 0.0, maEventQueue.nextTimeout() );
2120 :
2121 : // There is no active animation so the frame rate does not
2122 : // need to be synchronized.
2123 0 : maFrameSynchronization.Deactivate();
2124 : }
2125 :
2126 0 : mbSlideShowIdle = false;
2127 : }
2128 :
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) )
2137 : {
2138 : UnoViewVector::const_iterator aCurr(maViewContainer.begin());
2139 : const UnoViewVector::const_iterator aEnd(maViewContainer.end());
2140 : while( aCurr != aEnd )
2141 : {
2142 : try
2143 : {
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();
2149 : }
2150 : catch( uno::RuntimeException& )
2151 : {
2152 : throw;
2153 : }
2154 : catch( uno::Exception& )
2155 : {
2156 : OSL_FAIL( OUStringToOString(
2157 : comphelper::anyToString( cppu::getCaughtException() ),
2158 : RTL_TEXTENCODING_UTF8 ).getStr() );
2159 : }
2160 :
2161 : ++aCurr;
2162 : }
2163 :
2164 : mbSlideShowIdle = true;
2165 : }
2166 : #endif
2167 :
2168 0 : return bRet;
2169 0 : }
2170 : }
2171 :
2172 0 : void SlideShowImpl::notifySlideTransitionEnded( bool bPaintSlide )
2173 : {
2174 0 : osl::MutexGuard const guard( m_aMutex );
2175 :
2176 : OSL_ENSURE( !isDisposed(), "### already disposed!" );
2177 : OSL_ENSURE( mpCurrentSlide,
2178 : "notifySlideTransitionEnded(): Invalid current slide" );
2179 0 : if (mpCurrentSlide)
2180 : {
2181 0 : mpCurrentSlide->update_settings( !!maUserPaintColor, maUserPaintColor ? *maUserPaintColor : RGBColor(), maUserPaintStrokeWidth );
2182 :
2183 : // first init show, to give the animations
2184 : // the chance to register SlideStartEvents
2185 0 : const bool bBackgroundLayerRendered( !bPaintSlide );
2186 0 : mpCurrentSlide->show( bBackgroundLayerRendered );
2187 0 : maEventMultiplexer.notifySlideStartEvent();
2188 0 : }
2189 0 : }
2190 :
2191 0 : void queryAutomaticSlideTransition( uno::Reference<drawing::XDrawPage> const& xDrawPage,
2192 : double& nAutomaticNextSlideTimeout,
2193 : bool& bHasAutomaticNextSlide )
2194 : {
2195 : // retrieve slide change parameters from XDrawPage
2196 : // ===============================================
2197 :
2198 : uno::Reference< beans::XPropertySet > xPropSet( xDrawPage,
2199 0 : uno::UNO_QUERY );
2200 :
2201 0 : sal_Int32 nChange(0);
2202 0 : if( !xPropSet.is() ||
2203 : !getPropertyValue( nChange,
2204 : xPropSet,
2205 : OUString(
2206 0 : "Change")) )
2207 : {
2208 : OSL_TRACE(
2209 : "queryAutomaticSlideTransition(): "
2210 : "Could not extract slide change mode from XDrawPage - assuming <none>\n" );
2211 : }
2212 :
2213 0 : bHasAutomaticNextSlide = nChange == 1;
2214 :
2215 0 : if( !xPropSet.is() ||
2216 : !getPropertyValue( nAutomaticNextSlideTimeout,
2217 : xPropSet,
2218 : OUString(
2219 0 : "HighResDuration")) )
2220 : {
2221 : OSL_TRACE(
2222 : "queryAutomaticSlideTransition(): "
2223 : "Could not extract slide transition timeout from "
2224 : "XDrawPage - assuming 1 sec\n" );
2225 0 : }
2226 0 : }
2227 :
2228 0 : void SlideShowImpl::notifySlideAnimationsEnded()
2229 : {
2230 0 : osl::MutexGuard const guard( m_aMutex );
2231 :
2232 : //Draw polygons above animations
2233 0 : mpCurrentSlide->drawPolygons();
2234 :
2235 : OSL_ENSURE( !isDisposed(), "### already disposed!" );
2236 :
2237 : // This struct will receive the (interruptable) event,
2238 : // that triggers the notifySlideEnded() method.
2239 0 : InterruptableEventPair aNotificationEvents;
2240 :
2241 0 : if( maEventMultiplexer.getAutomaticMode() )
2242 : {
2243 : OSL_ENSURE( ! mpRehearseTimingsActivity,
2244 : "unexpected: RehearseTimings mode!" );
2245 :
2246 : // schedule a slide end event, with automatic mode's
2247 : // delay
2248 0 : aNotificationEvents = makeInterruptableDelay(
2249 0 : boost::bind<void>( boost::mem_fn(&SlideShowImpl::notifySlideEnded), this, false ),
2250 0 : maEventMultiplexer.getAutomaticTimeout() );
2251 : }
2252 : else
2253 : {
2254 : OSL_ENSURE( mpCurrentSlide,
2255 : "notifySlideAnimationsEnded(): Invalid current slide!" );
2256 :
2257 0 : bool bHasAutomaticNextSlide=false;
2258 0 : double nAutomaticNextSlideTimeout=0.0;
2259 0 : queryAutomaticSlideTransition(mpCurrentSlide->getXDrawPage(),
2260 : nAutomaticNextSlideTimeout,
2261 0 : bHasAutomaticNextSlide);
2262 :
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 0 : if( !mbForceManualAdvance &&
2270 0 : !mpRehearseTimingsActivity &&
2271 : bHasAutomaticNextSlide )
2272 : {
2273 0 : aNotificationEvents = makeInterruptableDelay(
2274 0 : boost::bind<void>( boost::mem_fn(&SlideShowImpl::notifySlideEnded), this, false ),
2275 0 : nAutomaticNextSlideTimeout);
2276 :
2277 : // TODO(F2): Provide a mechanism to let the user override
2278 : // this automatic timeout via next()
2279 : }
2280 : else
2281 : {
2282 0 : if (mpRehearseTimingsActivity)
2283 0 : mpRehearseTimingsActivity->start();
2284 :
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 0 : aNotificationEvents.mpImmediateEvent =
2290 0 : makeEvent( boost::bind<void>(
2291 : boost::mem_fn(&SlideShowImpl::notifySlideEnded), this, false ),
2292 0 : "SlideShowImpl::notifySlideEnded");
2293 : }
2294 : }
2295 :
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 0 : aNotificationEvents.mpImmediateEvent );
2303 :
2304 0 : if( aNotificationEvents.mpTimeoutEvent )
2305 0 : maEventQueue.addEvent( aNotificationEvents.mpTimeoutEvent );
2306 :
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.
2312 : {
2313 0 : WaitSymbolLock aLock (*this);
2314 :
2315 0 : if (! matches( mpPrefetchSlide,
2316 0 : mxPrefetchSlide, mxPrefetchAnimationNode ))
2317 : {
2318 0 : mpPrefetchSlide = makeSlide( mxPrefetchSlide, mxDrawPagesSupplier,
2319 0 : mxPrefetchAnimationNode );
2320 : }
2321 0 : if (mpPrefetchSlide)
2322 : {
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 0 : mpPrefetchSlide->getCurrentSlideBitmap( *maViewContainer.begin() );
2328 0 : }
2329 : } // finally
2330 :
2331 : maListenerContainer.forEach<presentation::XSlideShowListener>(
2332 0 : boost::mem_fn( &presentation::XSlideShowListener::slideAnimationsEnded ) );
2333 0 : }
2334 :
2335 0 : void SlideShowImpl::notifySlideEnded (const bool bReverse)
2336 : {
2337 0 : osl::MutexGuard const guard( m_aMutex );
2338 :
2339 : OSL_ENSURE( !isDisposed(), "### already disposed!" );
2340 :
2341 0 : if (mpRehearseTimingsActivity && !bReverse)
2342 : {
2343 0 : const double time = mpRehearseTimingsActivity->stop();
2344 0 : if (mpRehearseTimingsActivity->hasBeenClicked())
2345 : {
2346 : // save time at current drawpage:
2347 : uno::Reference<beans::XPropertySet> xPropSet(
2348 0 : mpCurrentSlide->getXDrawPage(), uno::UNO_QUERY );
2349 : OSL_ASSERT( xPropSet.is() );
2350 0 : if (xPropSet.is())
2351 : {
2352 0 : xPropSet->setPropertyValue(
2353 : "Change",
2354 0 : uno::Any( static_cast<sal_Int32>(1) ) );
2355 0 : xPropSet->setPropertyValue(
2356 : "Duration",
2357 0 : uno::Any( static_cast<sal_Int32>(time) ) );
2358 0 : }
2359 : }
2360 : }
2361 :
2362 0 : if (bReverse)
2363 0 : maEventMultiplexer.notifySlideEndEvent();
2364 :
2365 0 : 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.
2373 :
2374 : maListenerContainer.forEach<presentation::XSlideShowListener>(
2375 : boost::bind<void>(
2376 : ::boost::mem_fn(&presentation::XSlideShowListener::slideEnded),
2377 : _1,
2378 0 : bReverse));
2379 0 : }
2380 :
2381 0 : bool SlideShowImpl::notifyHyperLinkClicked( OUString const& hyperLink )
2382 : {
2383 0 : osl::MutexGuard const guard( m_aMutex );
2384 :
2385 : maListenerContainer.forEach<presentation::XSlideShowListener>(
2386 : boost::bind( &presentation::XSlideShowListener::hyperLinkClicked,
2387 : _1,
2388 0 : boost::cref(hyperLink) ));
2389 0 : return true;
2390 : }
2391 :
2392 : /** Notification from eventmultiplexer that an animation event has occoured.
2393 : This will be forewarded to all registered XSlideShoeListener
2394 : */
2395 0 : bool SlideShowImpl::handleAnimationEvent( const AnimationNodeSharedPtr& rNode )
2396 : {
2397 0 : osl::MutexGuard const guard( m_aMutex );
2398 :
2399 0 : uno::Reference<animations::XAnimationNode> xNode( rNode->getXAnimationNode() );
2400 :
2401 0 : switch( rNode->getState() )
2402 : {
2403 : case AnimationNode::ACTIVE:
2404 : maListenerContainer.forEach<presentation::XSlideShowListener>(
2405 : boost::bind( &animations::XAnimationListener::beginEvent,
2406 : _1,
2407 0 : boost::cref(xNode) ));
2408 0 : break;
2409 :
2410 : case AnimationNode::FROZEN:
2411 : case AnimationNode::ENDED:
2412 : maListenerContainer.forEach<presentation::XSlideShowListener>(
2413 : boost::bind( &animations::XAnimationListener::endEvent,
2414 : _1,
2415 0 : boost::cref(xNode) ));
2416 0 : if(mpCurrentSlide->isPaintOverlayActive())
2417 0 : mpCurrentSlide->drawPolygons();
2418 0 : break;
2419 : default:
2420 0 : break;
2421 : }
2422 :
2423 0 : return true;
2424 : }
2425 :
2426 : //===== FrameSynchronization ==================================================
2427 :
2428 1 : FrameSynchronization::FrameSynchronization (const double nFrameDuration)
2429 : : maTimer(),
2430 : mnFrameDuration(nFrameDuration),
2431 : mnNextFrameTargetTime(0),
2432 1 : mbIsActive(false)
2433 : {
2434 1 : MarkCurrentFrame();
2435 1 : }
2436 :
2437 1 : void FrameSynchronization::MarkCurrentFrame()
2438 : {
2439 1 : mnNextFrameTargetTime = maTimer.getElapsedTime() + mnFrameDuration;
2440 1 : }
2441 :
2442 0 : void FrameSynchronization::Synchronize()
2443 : {
2444 0 : if (mbIsActive)
2445 : {
2446 : // Do busy waiting for now.
2447 0 : while (maTimer.getElapsedTime() < mnNextFrameTargetTime)
2448 : ;
2449 : }
2450 :
2451 0 : MarkCurrentFrame();
2452 0 : }
2453 :
2454 0 : void FrameSynchronization::Activate()
2455 : {
2456 0 : mbIsActive = true;
2457 0 : }
2458 :
2459 0 : void FrameSynchronization::Deactivate()
2460 : {
2461 0 : mbIsActive = false;
2462 0 : }
2463 :
2464 : } // anon namespace
2465 :
2466 : namespace sdecl = comphelper::service_decl;
2467 2 : const sdecl::ServiceDecl slideShowDecl(
2468 : sdecl::class_<SlideShowImpl>(),
2469 : "com.sun.star.comp.presentation.SlideShow",
2470 2 : "com.sun.star.presentation.SlideShow" );
2471 :
2472 : // The C shared lib entry points
2473 4 : COMPHELPER_SERVICEDECL_EXPORTS1(slideshow, slideShowDecl)
2474 :
2475 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|