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 0 : 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 (void);
136 :
137 : /** When there is time left until the next frame is due then wait.
138 : Otherwise return without delay.
139 : */
140 : void Synchronize (void);
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 (void);
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 (void);
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 0 : 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 (void);
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 (void);
407 : void releaseWaitSymbol (void);
408 :
409 : class WaitSymbolLock {public:
410 0 : WaitSymbolLock(SlideShowImpl& rSlideShowImpl) : mrSlideShowImpl(rSlideShowImpl)
411 0 : { mrSlideShowImpl.requestWaitSymbol(); }
412 0 : ~WaitSymbolLock(void)
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 (void);
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 0 : 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 0 : SeparateListenerImpl( SlideShowImpl& rShow,
518 : ScreenUpdater& rScreenUpdater,
519 : EventQueue& rEventQueue ) :
520 : mrShow( rShow ),
521 : mrScreenUpdater( rScreenUpdater ),
522 0 : mrEventQueue( rEventQueue )
523 0 : {}
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 0 : 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 0 : 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 0 : 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 0 : mxComponentContext->getServiceManager() );
613 :
614 0 : if( xFactory.is() )
615 : {
616 : try
617 : {
618 : // #i82460# try to retrieve special transition factory
619 : mxOptionalTransitionFactory.set(
620 0 : xFactory->createInstanceWithContext(
621 : OUString("com.sun.star.presentation.TransitionFactory" ),
622 0 : mxComponentContext ),
623 0 : uno::UNO_QUERY );
624 : }
625 0 : catch (loader::CannotActivateFactoryException const&)
626 : {
627 : }
628 : }
629 :
630 : mpListener.reset( new SeparateListenerImpl(
631 : *this,
632 : maScreenUpdater,
633 0 : maEventQueue ));
634 0 : maEventMultiplexer.addSlideAnimationsEndHandler( mpListener );
635 0 : maEventMultiplexer.addViewRepaintHandler( mpListener );
636 0 : maEventMultiplexer.addHyperlinkHandler( mpListener, 0.0 );
637 0 : maEventMultiplexer.addAnimationStartHandler( mpListener );
638 0 : maEventMultiplexer.addAnimationEndHandler( mpListener );
639 0 : }
640 :
641 : // we are about to be disposed (someone call dispose() on us)
642 0 : void SlideShowImpl::disposing()
643 : {
644 0 : osl::MutexGuard const guard( m_aMutex );
645 :
646 0 : maEffectRewinder.dispose();
647 :
648 : // stop slide transition sound, if any:
649 0 : stopSlideTransitionSound();
650 :
651 0 : mxComponentContext.clear();
652 :
653 0 : if( mpCurrentSlideTransitionSound )
654 : {
655 0 : mpCurrentSlideTransitionSound->dispose();
656 0 : mpCurrentSlideTransitionSound.reset();
657 : }
658 :
659 0 : mpWaitSymbol.reset();
660 0 : mpPointerSymbol.reset();
661 :
662 0 : if( mpRehearseTimingsActivity )
663 : {
664 0 : mpRehearseTimingsActivity->dispose();
665 0 : mpRehearseTimingsActivity.reset();
666 : }
667 :
668 0 : if( mpListener )
669 : {
670 0 : maEventMultiplexer.removeSlideAnimationsEndHandler(mpListener);
671 0 : maEventMultiplexer.removeViewRepaintHandler(mpListener);
672 0 : maEventMultiplexer.removeHyperlinkHandler(mpListener);
673 0 : maEventMultiplexer.removeAnimationStartHandler( mpListener );
674 0 : maEventMultiplexer.removeAnimationEndHandler( mpListener );
675 :
676 0 : mpListener.reset();
677 : }
678 :
679 0 : maUserEventQueue.clear();
680 0 : maActivitiesQueue.clear();
681 0 : maEventMultiplexer.clear();
682 0 : maEventQueue.clear();
683 0 : mpPresTimer.reset();
684 0 : maShapeCursors.clear();
685 0 : maShapeEventListeners.clear();
686 :
687 : // send all listeners a disposing() that we are going down:
688 : maListenerContainer.disposeAndClear(
689 0 : lang::EventObject( static_cast<cppu::OWeakObject *>(this) ) );
690 :
691 0 : maViewContainer.dispose();
692 :
693 : // release slides:
694 0 : mxPrefetchAnimationNode.clear();
695 0 : mxPrefetchSlide.clear();
696 0 : mpPrefetchSlide.reset();
697 0 : mpCurrentSlide.reset();
698 0 : mpPreviousSlide.reset();
699 0 : }
700 :
701 : /// stops the current slide transition sound
702 0 : void SlideShowImpl::stopSlideTransitionSound()
703 : {
704 0 : if (mpCurrentSlideTransitionSound)
705 : {
706 0 : mpCurrentSlideTransitionSound->stopPlayback();
707 0 : mpCurrentSlideTransitionSound->dispose();
708 0 : mpCurrentSlideTransitionSound.reset();
709 : }
710 0 : }
711 :
712 0 : SoundPlayerSharedPtr SlideShowImpl::resetSlideTransitionSound( const uno::Any& rSound, bool bLoopSound )
713 : {
714 0 : sal_Bool bStopSound = sal_False;
715 0 : OUString url;
716 :
717 0 : if( !(rSound >>= bStopSound) )
718 0 : bStopSound = sal_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 : sal_Bool bLoopSound = sal_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 (void)
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 (void)
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 0 : maEventMultiplexer.notifySlideTransitionStarted();
1195 : maListenerContainer.forEach<presentation::XSlideShowListener>(
1196 0 : boost::mem_fn( &presentation::XSlideShowListener::slideTransitionStarted ) );
1197 :
1198 : // We are currently rewinding an effect. This lead us from the next
1199 : // slide to this one. To complete this we have to play back all main
1200 : // sequence effects on this slide.
1201 0 : if (bSkipAllMainSequenceEffects)
1202 0 : maEffectRewinder.skipAllMainSequenceEffects();
1203 : }
1204 :
1205 0 : void SlideShowImpl::redisplayCurrentSlide (void)
1206 : {
1207 0 : osl::MutexGuard const guard( m_aMutex );
1208 :
1209 0 : if (isDisposed())
1210 0 : return;
1211 :
1212 : // precondition: must only be called from the main thread!
1213 : DBG_TESTSOLARMUTEX();
1214 0 : stopShow();
1215 :
1216 : OSL_ENSURE( !maViewContainer.empty(), "### no views!" );
1217 0 : if (maViewContainer.empty())
1218 0 : return;
1219 :
1220 : // No transition effect on this slide - schedule slide
1221 : // effect start event right away.
1222 : maEventQueue.addEvent(
1223 0 : makeEvent(
1224 : boost::bind(
1225 : &SlideShowImpl::notifySlideTransitionEnded,
1226 : this,
1227 : true ),
1228 0 : "SlideShowImpl::notifySlideTransitionEnded"));
1229 :
1230 0 : maEventMultiplexer.notifySlideTransitionStarted();
1231 : maListenerContainer.forEach<presentation::XSlideShowListener>(
1232 0 : boost::mem_fn( &presentation::XSlideShowListener::slideTransitionStarted ) );
1233 : }
1234 :
1235 0 : sal_Bool SlideShowImpl::nextEffect() throw (uno::RuntimeException, std::exception)
1236 : {
1237 0 : osl::MutexGuard const guard( m_aMutex );
1238 :
1239 0 : if (isDisposed())
1240 0 : return false;
1241 :
1242 : // precondition: must only be called from the main thread!
1243 : DBG_TESTSOLARMUTEX();
1244 :
1245 0 : if (mbShowPaused)
1246 0 : return true;
1247 : else
1248 0 : return maEventMultiplexer.notifyNextEffect();
1249 : }
1250 :
1251 0 : sal_Bool SlideShowImpl::previousEffect() throw (uno::RuntimeException, std::exception)
1252 : {
1253 0 : osl::MutexGuard const guard( m_aMutex );
1254 :
1255 0 : if (isDisposed())
1256 0 : return false;
1257 :
1258 : // precondition: must only be called from the main thread!
1259 : DBG_TESTSOLARMUTEX();
1260 :
1261 0 : if (mbShowPaused)
1262 0 : return true;
1263 : else
1264 : {
1265 : return maEffectRewinder.rewind(
1266 : maScreenUpdater.createLock(false),
1267 : ::boost::bind<void>(::boost::mem_fn(&SlideShowImpl::redisplayCurrentSlide), this),
1268 0 : ::boost::bind<void>(::boost::mem_fn(&SlideShowImpl::rewindEffectToPreviousSlide), this));
1269 0 : }
1270 : }
1271 :
1272 0 : void SlideShowImpl::rewindEffectToPreviousSlide (void)
1273 : {
1274 : // Show the wait symbol now and prevent it from showing temporary slide
1275 : // content while effects are played back.
1276 0 : WaitSymbolLock aLock (*this);
1277 :
1278 : // A previous call to EffectRewinder::Rewind could not rewind the current
1279 : // effect because there are no effects on the current slide or none has
1280 : // yet been displayed. Go to the previous slide.
1281 0 : notifySlideEnded(true);
1282 :
1283 : // Process pending events once more in order to have the following
1284 : // screen update show the last effect. Not sure whether this should be
1285 : // necessary.
1286 0 : maEventQueue.forceEmpty();
1287 :
1288 : // We have to call the screen updater before the wait symbol is turned
1289 : // off. Otherwise the wait symbol would force the display of an
1290 : // intermediate state of the slide (before the effects are replayed.)
1291 0 : maScreenUpdater.commitUpdates();
1292 0 : }
1293 :
1294 0 : sal_Bool SlideShowImpl::startShapeActivity(
1295 : uno::Reference<drawing::XShape> const& /*xShape*/ )
1296 : throw (uno::RuntimeException, std::exception)
1297 : {
1298 0 : osl::MutexGuard const guard( m_aMutex );
1299 :
1300 : // precondition: must only be called from the main thread!
1301 : DBG_TESTSOLARMUTEX();
1302 :
1303 : // TODO(F3): NYI
1304 : OSL_FAIL( "not yet implemented!" );
1305 0 : return false;
1306 : }
1307 :
1308 0 : sal_Bool SlideShowImpl::stopShapeActivity(
1309 : uno::Reference<drawing::XShape> const& /*xShape*/ )
1310 : throw (uno::RuntimeException, std::exception)
1311 : {
1312 0 : osl::MutexGuard const guard( m_aMutex );
1313 :
1314 : // precondition: must only be called from the main thread!
1315 : DBG_TESTSOLARMUTEX();
1316 :
1317 : // TODO(F3): NYI
1318 : OSL_FAIL( "not yet implemented!" );
1319 0 : return false;
1320 : }
1321 :
1322 0 : sal_Bool SlideShowImpl::pause( sal_Bool bPauseShow )
1323 : throw (uno::RuntimeException, std::exception)
1324 : {
1325 0 : osl::MutexGuard const guard( m_aMutex );
1326 :
1327 0 : if (isDisposed())
1328 0 : return false;
1329 :
1330 : // precondition: must only be called from the main thread!
1331 : DBG_TESTSOLARMUTEX();
1332 :
1333 0 : if (bPauseShow)
1334 0 : mpPresTimer->pauseTimer();
1335 : else
1336 0 : mpPresTimer->continueTimer();
1337 :
1338 0 : maEventMultiplexer.notifyPauseMode(bPauseShow);
1339 :
1340 0 : mbShowPaused = bPauseShow;
1341 0 : return true;
1342 : }
1343 :
1344 0 : uno::Reference<drawing::XDrawPage> SlideShowImpl::getCurrentSlide()
1345 : throw (uno::RuntimeException, std::exception)
1346 : {
1347 0 : osl::MutexGuard const guard( m_aMutex );
1348 :
1349 0 : if (isDisposed())
1350 0 : return uno::Reference<drawing::XDrawPage>();
1351 :
1352 : // precondition: must only be called from the main thread!
1353 : DBG_TESTSOLARMUTEX();
1354 :
1355 0 : if (mpCurrentSlide)
1356 0 : return mpCurrentSlide->getXDrawPage();
1357 : else
1358 0 : return uno::Reference<drawing::XDrawPage>();
1359 : }
1360 :
1361 0 : sal_Bool SlideShowImpl::addView(
1362 : uno::Reference<presentation::XSlideShowView> const& xView )
1363 : throw (uno::RuntimeException, std::exception)
1364 : {
1365 0 : osl::MutexGuard const guard( m_aMutex );
1366 :
1367 0 : if (isDisposed())
1368 0 : return false;
1369 :
1370 : // precondition: must only be called from the main thread!
1371 : DBG_TESTSOLARMUTEX();
1372 :
1373 : // first of all, check if view has a valid canvas
1374 0 : ENSURE_OR_RETURN_FALSE( xView.is(), "addView(): Invalid view" );
1375 0 : ENSURE_OR_RETURN_FALSE( xView->getCanvas().is(),
1376 : "addView(): View does not provide a valid canvas" );
1377 :
1378 : UnoViewSharedPtr const pView( createSlideView(
1379 : xView,
1380 : maEventQueue,
1381 0 : maEventMultiplexer ));
1382 0 : if (!maViewContainer.addView( pView ))
1383 0 : return false; // view already added
1384 :
1385 : // initialize view content
1386 : // =======================
1387 :
1388 0 : if (mpCurrentSlide)
1389 : {
1390 : // set view transformation
1391 0 : const basegfx::B2ISize slideSize = mpCurrentSlide->getSlideSize();
1392 0 : pView->setViewSize( basegfx::B2DSize( slideSize.getX(),
1393 0 : slideSize.getY() ) );
1394 : }
1395 :
1396 : // clear view area (since its newly added,
1397 : // we need a clean slate)
1398 0 : pView->clearAll();
1399 :
1400 : // broadcast newly added view
1401 0 : maEventMultiplexer.notifyViewAdded( pView );
1402 :
1403 : // set current mouse ptr
1404 0 : pView->setCursorShape( calcActiveCursor(mnCurrentCursor) );
1405 :
1406 0 : return true;
1407 : }
1408 :
1409 0 : sal_Bool SlideShowImpl::removeView(
1410 : uno::Reference<presentation::XSlideShowView> const& xView )
1411 : throw (uno::RuntimeException, std::exception)
1412 : {
1413 0 : osl::MutexGuard const guard( m_aMutex );
1414 :
1415 : // precondition: must only be called from the main thread!
1416 : DBG_TESTSOLARMUTEX();
1417 :
1418 0 : ENSURE_OR_RETURN_FALSE( xView.is(), "removeView(): Invalid view" );
1419 :
1420 0 : UnoViewSharedPtr const pView( maViewContainer.removeView( xView ) );
1421 0 : if( !pView )
1422 0 : return false; // view was not added in the first place
1423 :
1424 : // remove view from EventMultiplexer (mouse events etc.)
1425 0 : maEventMultiplexer.notifyViewRemoved( pView );
1426 :
1427 0 : pView->_dispose();
1428 :
1429 0 : return true;
1430 : }
1431 :
1432 0 : void SlideShowImpl::registerUserPaintPolygons( const uno::Reference< lang::XMultiServiceFactory >& xDocFactory ) throw (uno::RuntimeException, std::exception)
1433 : {
1434 : //Retrieve Polygons if user ends presentation by context menu
1435 0 : if (mpCurrentSlide)
1436 : {
1437 0 : if(findPolygons(mpCurrentSlide->getXDrawPage()) != maPolygons.end())
1438 0 : maPolygons.erase(mpCurrentSlide->getXDrawPage());
1439 :
1440 0 : maPolygons.insert(make_pair(mpCurrentSlide->getXDrawPage(),mpCurrentSlide->getPolygons()));
1441 : }
1442 :
1443 : //Creating the layer for shapes
1444 : // query for the XLayerManager
1445 0 : uno::Reference< drawing::XLayerSupplier > xLayerSupplier(xDocFactory, uno::UNO_QUERY);
1446 0 : uno::Reference< container::XNameAccess > xNameAccess = xLayerSupplier->getLayerManager();
1447 :
1448 0 : uno::Reference< drawing::XLayerManager > xLayerManager(xNameAccess, uno::UNO_QUERY);
1449 : // create a layer and set its properties
1450 0 : uno::Reference< drawing::XLayer > xDrawnInSlideshow = xLayerManager->insertNewByIndex(xLayerManager->getCount());
1451 0 : uno::Reference< beans::XPropertySet > xLayerPropSet(xDrawnInSlideshow, uno::UNO_QUERY);
1452 :
1453 : //Layer Name which enables to catch annotations
1454 0 : OUString layerName = "DrawnInSlideshow";
1455 0 : uno::Any aPropLayer;
1456 :
1457 0 : aPropLayer <<= layerName;
1458 0 : xLayerPropSet->setPropertyValue("Name", aPropLayer);
1459 :
1460 0 : aPropLayer <<= true;
1461 0 : xLayerPropSet->setPropertyValue("IsVisible", aPropLayer);
1462 :
1463 0 : aPropLayer <<= false;
1464 0 : xLayerPropSet->setPropertyValue("IsLocked", aPropLayer);
1465 :
1466 0 : PolygonMap::iterator aIter=maPolygons.begin();
1467 :
1468 0 : PolyPolygonVector aPolygons;
1469 0 : ::cppcanvas::PolyPolygonSharedPtr pPolyPoly;
1470 0 : ::basegfx::B2DPolyPolygon b2DPolyPoly;
1471 :
1472 : //Register polygons for each slide
1473 0 : while(aIter!=maPolygons.end())
1474 : {
1475 0 : aPolygons = aIter->second;
1476 : //Get shapes for the slide
1477 0 : ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > Shapes(aIter->first, ::com::sun::star::uno::UNO_QUERY);
1478 : //Retrieve polygons for one slide
1479 0 : for( PolyPolygonVector::iterator aIterPoly=aPolygons.begin(),
1480 0 : aEnd=aPolygons.end();
1481 : aIterPoly!=aEnd; ++aIterPoly )
1482 : {
1483 0 : pPolyPoly = (*aIterPoly);
1484 0 : b2DPolyPoly = ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(pPolyPoly->getUNOPolyPolygon());
1485 :
1486 : //Normally there is only one polygon
1487 0 : for(sal_uInt32 i=0; i< b2DPolyPoly.count();i++)
1488 : {
1489 0 : const ::basegfx::B2DPolygon& aPoly = b2DPolyPoly.getB2DPolygon(i);
1490 0 : sal_uInt32 nPoints = aPoly.count();
1491 :
1492 0 : if( nPoints > 1)
1493 : {
1494 : //create the PolyLineShape
1495 0 : uno::Reference< uno::XInterface > polyshape(xDocFactory->createInstance(
1496 0 : OUString("com.sun.star.drawing.PolyLineShape") ) );
1497 0 : uno::Reference< drawing::XShape > rPolyShape(polyshape, uno::UNO_QUERY);
1498 :
1499 : //Add the shape to the slide
1500 0 : Shapes->add(rPolyShape);
1501 :
1502 : //Retrieve shape properties
1503 0 : uno::Reference< beans::XPropertySet > aXPropSet = uno::Reference< beans::XPropertySet >( rPolyShape, uno::UNO_QUERY );
1504 : //Construct a sequence of points sequence
1505 0 : drawing::PointSequenceSequence aRetval;
1506 : //Create only one sequence for one polygon
1507 0 : aRetval.realloc( 1 );
1508 : // Retrieve the sequence of points from aRetval
1509 0 : drawing::PointSequence* pOuterSequence = aRetval.getArray();
1510 : // Create 2 points in this sequence
1511 0 : pOuterSequence->realloc(nPoints);
1512 : // Get these points which are in an array
1513 0 : awt::Point* pInnerSequence = pOuterSequence->getArray();
1514 0 : for( sal_uInt32 n = 0; n < nPoints; n++ )
1515 : {
1516 : //Create a point from the polygon
1517 : *pInnerSequence++ = awt::Point(
1518 0 : basegfx::fround(aPoly.getB2DPoint(n).getX()),
1519 0 : basegfx::fround(aPoly.getB2DPoint(n).getY()));
1520 : }
1521 :
1522 : //Fill the properties
1523 : //Give the built PointSequenceSequence.
1524 0 : uno::Any aParam;
1525 0 : aParam <<= aRetval;
1526 0 : aXPropSet->setPropertyValue("PolyPolygon", aParam );
1527 :
1528 : //LineStyle : SOLID by default
1529 0 : uno::Any aAny;
1530 : drawing::LineStyle eLS;
1531 0 : eLS = drawing::LineStyle_SOLID;
1532 0 : aAny <<= eLS;
1533 0 : aXPropSet->setPropertyValue("LineStyle", aAny );
1534 :
1535 : //LineColor
1536 : sal_uInt32 nLineColor;
1537 0 : nLineColor = pPolyPoly->getRGBALineColor();
1538 : //Transform polygon color from RRGGBBAA to AARRGGBB
1539 0 : aAny <<= RGBAColor2UnoColor(nLineColor);
1540 0 : aXPropSet->setPropertyValue("LineColor", aAny );
1541 :
1542 : //LineWidth
1543 : double fLineWidth;
1544 0 : fLineWidth = pPolyPoly->getStrokeWidth();
1545 0 : aAny <<= (sal_Int32)fLineWidth;
1546 0 : aXPropSet->setPropertyValue("LineWidth", aAny );
1547 :
1548 : // make polygons special
1549 0 : xLayerManager->attachShapeToLayer(rPolyShape, xDrawnInSlideshow);
1550 : }
1551 0 : }
1552 : }
1553 0 : ++aIter;
1554 0 : }
1555 0 : }
1556 :
1557 0 : sal_Bool SlideShowImpl::setProperty( beans::PropertyValue const& rProperty )
1558 : throw (uno::RuntimeException, std::exception)
1559 : {
1560 0 : osl::MutexGuard const guard( m_aMutex );
1561 :
1562 0 : if (isDisposed())
1563 0 : return false;
1564 :
1565 : // precondition: must only be called from the main thread!
1566 : DBG_TESTSOLARMUTEX();
1567 :
1568 0 : if ( rProperty.Name == "AutomaticAdvancement" )
1569 : {
1570 0 : double nTimeout(0.0);
1571 0 : mbAutomaticAdvancementMode = (rProperty.Value >>= nTimeout);
1572 0 : if (mbAutomaticAdvancementMode)
1573 : {
1574 0 : maEventMultiplexer.setAutomaticTimeout( nTimeout );
1575 : }
1576 0 : maEventMultiplexer.setAutomaticMode( mbAutomaticAdvancementMode );
1577 0 : return true;
1578 : }
1579 :
1580 0 : if ( rProperty.Name == "UserPaintColor" )
1581 : {
1582 0 : sal_Int32 nColor(0);
1583 0 : if (rProperty.Value >>= nColor)
1584 : {
1585 : OSL_ENSURE( mbMouseVisible,
1586 : "setProperty(): User paint overrides invisible mouse" );
1587 :
1588 : // enable user paint
1589 0 : maUserPaintColor.reset( unoColor2RGBColor( nColor ) );
1590 0 : if( mpCurrentSlide && !mpCurrentSlide->isPaintOverlayActive() )
1591 0 : mpCurrentSlide->enablePaintOverlay();
1592 :
1593 0 : maEventMultiplexer.notifyUserPaintColor( *maUserPaintColor );
1594 : }
1595 : else
1596 : {
1597 : // disable user paint
1598 0 : maUserPaintColor.reset();
1599 0 : maEventMultiplexer.notifyUserPaintDisabled();
1600 0 : if( mpCurrentSlide )
1601 0 : mpCurrentSlide->disablePaintOverlay();
1602 : }
1603 :
1604 0 : resetCursor();
1605 :
1606 0 : return true;
1607 : }
1608 :
1609 : //adding support for erasing features in UserPaintOverlay
1610 0 : if ( rProperty.Name == "EraseAllInk" )
1611 : {
1612 0 : bool nEraseAllInk(false);
1613 0 : if (rProperty.Value >>= nEraseAllInk)
1614 : {
1615 : OSL_ENSURE( mbMouseVisible,
1616 : "setProperty(): User paint overrides invisible mouse" );
1617 :
1618 : // enable user paint
1619 0 : maEraseAllInk.reset( nEraseAllInk );
1620 0 : maEventMultiplexer.notifyEraseAllInk( *maEraseAllInk );
1621 : }
1622 :
1623 0 : return true;
1624 : }
1625 :
1626 0 : if ( rProperty.Name == "SwitchPenMode" )
1627 : {
1628 0 : bool nSwitchPenMode(false);
1629 0 : if (rProperty.Value >>= nSwitchPenMode)
1630 : {
1631 : OSL_ENSURE( mbMouseVisible,
1632 : "setProperty(): User paint overrides invisible mouse" );
1633 :
1634 0 : if(nSwitchPenMode == true){
1635 : // Switch to Pen Mode
1636 0 : maSwitchPenMode.reset( nSwitchPenMode );
1637 0 : maEventMultiplexer.notifySwitchPenMode();
1638 : }
1639 : }
1640 0 : return true;
1641 : }
1642 :
1643 0 : if ( rProperty.Name == "SwitchEraserMode" )
1644 : {
1645 0 : bool nSwitchEraserMode(false);
1646 0 : if (rProperty.Value >>= nSwitchEraserMode)
1647 : {
1648 : OSL_ENSURE( mbMouseVisible,
1649 : "setProperty(): User paint overrides invisible mouse" );
1650 0 : if(nSwitchEraserMode == true){
1651 : // switch to Eraser mode
1652 0 : maSwitchEraserMode.reset( nSwitchEraserMode );
1653 0 : maEventMultiplexer.notifySwitchEraserMode();
1654 : }
1655 : }
1656 :
1657 0 : return true;
1658 : }
1659 :
1660 0 : if ( rProperty.Name == "EraseInk" )
1661 : {
1662 0 : sal_Int32 nEraseInk(100);
1663 0 : if (rProperty.Value >>= nEraseInk)
1664 : {
1665 : OSL_ENSURE( mbMouseVisible,
1666 : "setProperty(): User paint overrides invisible mouse" );
1667 :
1668 : // enable user paint
1669 0 : maEraseInk.reset( nEraseInk );
1670 0 : maEventMultiplexer.notifyEraseInkWidth( *maEraseInk );
1671 : }
1672 :
1673 0 : return true;
1674 : }
1675 :
1676 : // new Property for pen's width
1677 0 : if ( rProperty.Name == "UserPaintStrokeWidth" )
1678 : {
1679 0 : double nWidth(4.0);
1680 0 : if (rProperty.Value >>= nWidth)
1681 : {
1682 : OSL_ENSURE( mbMouseVisible,"setProperty(): User paint overrides invisible mouse" );
1683 : // enable user paint stroke width
1684 0 : maUserPaintStrokeWidth = nWidth;
1685 0 : maEventMultiplexer.notifyUserPaintStrokeWidth( maUserPaintStrokeWidth );
1686 : }
1687 :
1688 0 : return true;
1689 : }
1690 :
1691 0 : if ( rProperty.Name == "AdvanceOnClick" )
1692 : {
1693 0 : sal_Bool bAdvanceOnClick = sal_False;
1694 0 : if (! (rProperty.Value >>= bAdvanceOnClick))
1695 0 : return false;
1696 0 : maUserEventQueue.setAdvanceOnClick( bAdvanceOnClick );
1697 0 : return true;
1698 : }
1699 :
1700 0 : if ( rProperty.Name == "DisableAnimationZOrder" )
1701 : {
1702 0 : sal_Bool bDisableAnimationZOrder = sal_False;
1703 0 : if (! (rProperty.Value >>= bDisableAnimationZOrder))
1704 0 : return false;
1705 0 : mbDisableAnimationZOrder = bDisableAnimationZOrder == sal_True;
1706 0 : return true;
1707 : }
1708 :
1709 0 : if ( rProperty.Name == "ImageAnimationsAllowed" )
1710 : {
1711 0 : if (! (rProperty.Value >>= mbImageAnimationsAllowed))
1712 0 : return false;
1713 :
1714 : // TODO(F3): Forward to slides!
1715 0 : return true;
1716 : }
1717 :
1718 0 : if ( rProperty.Name == "MouseVisible" )
1719 : {
1720 0 : if (! (rProperty.Value >>= mbMouseVisible))
1721 0 : return false;
1722 :
1723 0 : requestCursor(mnCurrentCursor);
1724 :
1725 0 : return true;
1726 : }
1727 :
1728 0 : if ( rProperty.Name == "ForceManualAdvance" )
1729 : {
1730 0 : return (rProperty.Value >>= mbForceManualAdvance);
1731 : }
1732 :
1733 0 : if ( rProperty.Name == "RehearseTimings" )
1734 : {
1735 0 : bool bRehearseTimings = false;
1736 0 : if (! (rProperty.Value >>= bRehearseTimings))
1737 0 : return false;
1738 :
1739 0 : if (bRehearseTimings)
1740 : {
1741 : // TODO(Q3): Move to slide
1742 0 : mpRehearseTimingsActivity = RehearseTimingsActivity::create(
1743 : SlideShowContext(
1744 : mpDummyPtr,
1745 : maEventQueue,
1746 : maEventMultiplexer,
1747 : maScreenUpdater,
1748 : maActivitiesQueue,
1749 : maUserEventQueue,
1750 : *this,
1751 : maViewContainer,
1752 0 : mxComponentContext) );
1753 : }
1754 0 : else if (mpRehearseTimingsActivity)
1755 : {
1756 : // removes timer from all views:
1757 0 : mpRehearseTimingsActivity->dispose();
1758 0 : mpRehearseTimingsActivity.reset();
1759 : }
1760 0 : return true;
1761 : }
1762 :
1763 0 : if ( rProperty.Name == "WaitSymbolBitmap" )
1764 : {
1765 0 : uno::Reference<rendering::XBitmap> xBitmap;
1766 0 : if (! (rProperty.Value >>= xBitmap))
1767 0 : return false;
1768 :
1769 0 : mpWaitSymbol = WaitSymbol::create( xBitmap,
1770 : maScreenUpdater,
1771 : maEventMultiplexer,
1772 0 : maViewContainer );
1773 :
1774 0 : return true;
1775 : }
1776 :
1777 0 : if ( rProperty.Name == "PointerSymbolBitmap" )
1778 : {
1779 0 : uno::Reference<rendering::XBitmap> xBitmap;
1780 0 : if (! (rProperty.Value >>= xBitmap))
1781 0 : return false;
1782 :
1783 0 : mpPointerSymbol = PointerSymbol::create( xBitmap,
1784 : maScreenUpdater,
1785 : maEventMultiplexer,
1786 0 : maViewContainer );
1787 :
1788 0 : return true;
1789 : }
1790 :
1791 0 : if ( rProperty.Name == "PointerVisible" )
1792 : {
1793 : bool visible;
1794 0 : if (!(rProperty.Value >>= visible))
1795 0 : return false;
1796 :
1797 0 : mpPointerSymbol->setVisible(visible);
1798 0 : return true;
1799 : }
1800 :
1801 0 : if ( rProperty.Name == "PointerPosition")
1802 : {
1803 0 : ::com::sun::star::geometry::RealPoint2D pos;
1804 0 : if (! (rProperty.Value >>= pos))
1805 0 : return false;
1806 :
1807 0 : mpPointerSymbol->viewsChanged(pos);
1808 0 : return true;
1809 : }
1810 :
1811 0 : if (rProperty.Name == "NoSlideTransitions" )
1812 : {
1813 0 : return (rProperty.Value >>= mbNoSlideTransitions);
1814 : }
1815 :
1816 0 : if ( rProperty.Name == "IsSoundEnabled" )
1817 : {
1818 0 : uno::Sequence<uno::Any> aValues;
1819 0 : uno::Reference<presentation::XSlideShowView> xView;
1820 0 : sal_Bool bValue (false);
1821 0 : if ((rProperty.Value >>= aValues)
1822 0 : && aValues.getLength()==2
1823 0 : && (aValues[0] >>= xView)
1824 0 : && (aValues[1] >>= bValue))
1825 : {
1826 : // Look up the view.
1827 0 : for (UnoViewVector::const_iterator
1828 0 : iView (maViewContainer.begin()),
1829 0 : iEnd (maViewContainer.end());
1830 : iView!=iEnd;
1831 : ++iView)
1832 : {
1833 0 : if (*iView && (*iView)->getUnoView()==xView)
1834 : {
1835 : // Store the flag at the view so that media shapes have
1836 : // access to it.
1837 0 : (*iView)->setIsSoundEnabled(bValue);
1838 0 : return true;
1839 : }
1840 : }
1841 0 : }
1842 : }
1843 :
1844 0 : return false;
1845 : }
1846 :
1847 0 : void SlideShowImpl::addSlideShowListener(
1848 : uno::Reference<presentation::XSlideShowListener> const& xListener )
1849 : throw (uno::RuntimeException, std::exception)
1850 : {
1851 0 : osl::MutexGuard const guard( m_aMutex );
1852 :
1853 0 : if (isDisposed())
1854 0 : return;
1855 :
1856 : // container syncs with passed mutex ref
1857 0 : maListenerContainer.addInterface(xListener);
1858 : }
1859 :
1860 0 : void SlideShowImpl::removeSlideShowListener(
1861 : uno::Reference<presentation::XSlideShowListener> const& xListener )
1862 : throw (uno::RuntimeException, std::exception)
1863 : {
1864 0 : osl::MutexGuard const guard( m_aMutex );
1865 :
1866 : // container syncs with passed mutex ref
1867 0 : maListenerContainer.removeInterface(xListener);
1868 0 : }
1869 :
1870 0 : void SlideShowImpl::addShapeEventListener(
1871 : uno::Reference<presentation::XShapeEventListener> const& xListener,
1872 : uno::Reference<drawing::XShape> const& xShape )
1873 : throw (uno::RuntimeException, std::exception)
1874 : {
1875 0 : osl::MutexGuard const guard( m_aMutex );
1876 :
1877 0 : if (isDisposed())
1878 0 : return;
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 : // no entry for this shape -> create one
1888 : aIter = maShapeEventListeners.insert(
1889 : ShapeEventListenerMap::value_type(
1890 : xShape,
1891 : boost::shared_ptr<cppu::OInterfaceContainerHelper>(
1892 0 : new cppu::OInterfaceContainerHelper(m_aMutex)))).first;
1893 : }
1894 :
1895 : // add new listener to broadcaster
1896 0 : if( aIter->second.get() )
1897 0 : aIter->second->addInterface( xListener );
1898 :
1899 : maEventMultiplexer.notifyShapeListenerAdded(xListener,
1900 0 : xShape);
1901 : }
1902 :
1903 0 : void SlideShowImpl::removeShapeEventListener(
1904 : uno::Reference<presentation::XShapeEventListener> const& xListener,
1905 : uno::Reference<drawing::XShape> const& xShape )
1906 : throw (uno::RuntimeException, std::exception)
1907 : {
1908 0 : osl::MutexGuard const guard( m_aMutex );
1909 :
1910 : // precondition: must only be called from the main thread!
1911 : DBG_TESTSOLARMUTEX();
1912 :
1913 0 : ShapeEventListenerMap::iterator aIter;
1914 0 : if( (aIter = maShapeEventListeners.find( xShape )) !=
1915 0 : maShapeEventListeners.end() )
1916 : {
1917 : // entry for this shape found -> remove listener from
1918 : // helper object
1919 0 : ENSURE_OR_THROW(
1920 : aIter->second.get(),
1921 : "SlideShowImpl::removeShapeEventListener(): "
1922 : "listener map contains NULL broadcast helper" );
1923 :
1924 0 : aIter->second->removeInterface( xListener );
1925 : }
1926 :
1927 : maEventMultiplexer.notifyShapeListenerRemoved(xListener,
1928 0 : xShape);
1929 0 : }
1930 :
1931 0 : void SlideShowImpl::setShapeCursor(
1932 : uno::Reference<drawing::XShape> const& xShape, sal_Int16 nPointerShape )
1933 : throw (uno::RuntimeException, std::exception)
1934 : {
1935 0 : osl::MutexGuard const guard( m_aMutex );
1936 :
1937 0 : if (isDisposed())
1938 0 : return;
1939 :
1940 : // precondition: must only be called from the main thread!
1941 : DBG_TESTSOLARMUTEX();
1942 :
1943 0 : ShapeCursorMap::iterator aIter;
1944 0 : if( (aIter=maShapeCursors.find( xShape )) == maShapeCursors.end() )
1945 : {
1946 : // no entry for this shape -> create one
1947 0 : if( nPointerShape != awt::SystemPointer::ARROW )
1948 : {
1949 : // add new entry, unless shape shall display
1950 : // normal pointer arrow -> no need to handle that
1951 : // case
1952 : maShapeCursors.insert(
1953 : ShapeCursorMap::value_type(xShape,
1954 0 : nPointerShape) );
1955 : }
1956 : }
1957 0 : else if( nPointerShape == awt::SystemPointer::ARROW )
1958 : {
1959 : // shape shall display normal cursor -> can disable
1960 : // the cursor and clear the entry
1961 0 : maShapeCursors.erase( xShape );
1962 : }
1963 : else
1964 : {
1965 : // existing entry found, update with new cursor ID
1966 0 : aIter->second = nPointerShape;
1967 : }
1968 :
1969 : maEventMultiplexer.notifyShapeCursorChange(xShape,
1970 0 : nPointerShape);
1971 : }
1972 :
1973 0 : bool SlideShowImpl::requestCursor( sal_Int16 nCursorShape )
1974 : {
1975 0 : mnCurrentCursor = nCursorShape;
1976 :
1977 0 : const sal_Int16 nActualCursor = calcActiveCursor(mnCurrentCursor);
1978 :
1979 : // change all views to the requested cursor ID
1980 : std::for_each( maViewContainer.begin(),
1981 : maViewContainer.end(),
1982 : boost::bind( &View::setCursorShape,
1983 : _1,
1984 0 : nActualCursor ));
1985 :
1986 0 : return nActualCursor==nCursorShape;
1987 : }
1988 :
1989 0 : void SlideShowImpl::resetCursor()
1990 : {
1991 0 : mnCurrentCursor = awt::SystemPointer::ARROW;
1992 :
1993 : // change all views to the default cursor ID
1994 : std::for_each( maViewContainer.begin(),
1995 : maViewContainer.end(),
1996 : boost::bind( &View::setCursorShape,
1997 : _1,
1998 0 : calcActiveCursor(mnCurrentCursor) ));
1999 0 : }
2000 :
2001 0 : sal_Bool SlideShowImpl::update( double & nNextTimeout )
2002 : throw (uno::RuntimeException, std::exception)
2003 : {
2004 0 : osl::MutexGuard const guard( m_aMutex );
2005 :
2006 0 : if (isDisposed())
2007 0 : return false;
2008 :
2009 : // precondition: update() must only be called from the
2010 : // main thread!
2011 : DBG_TESTSOLARMUTEX();
2012 :
2013 0 : if( mbShowPaused )
2014 : {
2015 : // commit frame (might be repaints pending)
2016 0 : maScreenUpdater.commitUpdates();
2017 :
2018 0 : return false;
2019 : }
2020 : else
2021 : {
2022 : // TODO(F2): re-evaluate whether that timer lagging makes
2023 : // sense.
2024 :
2025 : // hold timer, while processing the queues:
2026 : // 1. when there is more than one active activity this ensures the
2027 : // same time for all activities and events
2028 : // 2. processing of events may lead to creation of further events
2029 : // that have zero delay. While the timer is stopped these events
2030 : // are processed in the same run.
2031 : {
2032 : //Get a shared-ptr that outlives the scope-guard which will
2033 : //ensure that the pointed-to-item exists in the case of a
2034 : //::dispose clearing mpPresTimer
2035 0 : boost::shared_ptr<canvas::tools::ElapsedTime> xTimer(mpPresTimer);
2036 : comphelper::ScopeGuard scopeGuard(
2037 : boost::bind( &canvas::tools::ElapsedTime::releaseTimer,
2038 0 : boost::cref(xTimer) ) );
2039 0 : xTimer->holdTimer();
2040 :
2041 : // process queues
2042 0 : maEventQueue.process();
2043 :
2044 : // #i118671# the call above may execute a macro bound to an object. In
2045 : // that case this macro may have destroyed this local sliseshow so that it
2046 : // is disposed (see bugdoc at task). In that case, detect this and exit
2047 : // gently from this slideshow. Do not forget to disable the scoped
2048 : // call to mpPresTimer, this will be deleted if we are disposed.
2049 0 : if (isDisposed())
2050 : {
2051 0 : scopeGuard.dismiss();
2052 0 : return false;
2053 : }
2054 :
2055 0 : maActivitiesQueue.process();
2056 :
2057 : // commit frame to screen
2058 0 : maFrameSynchronization.Synchronize();
2059 0 : maScreenUpdater.commitUpdates();
2060 :
2061 : // TODO(Q3): remove need to call dequeued() from
2062 : // activities. feels like a wart.
2063 :
2064 : // Rationale for ActivitiesQueue::processDequeued(): when
2065 : // an activity ends, it usually pushed the end state to
2066 : // the animated shape in question, and ends the animation
2067 : // (which, in turn, will usually disable shape sprite
2068 : // mode). Disabling shape sprite mode causes shape
2069 : // repaint, which, depending on slide content, takes
2070 : // considerably more time than sprite updates. Thus, the
2071 : // last animation step tends to look delayed. To
2072 : // camouflage this, reaching end position and disabling
2073 : // sprite mode is split into two (normal Activity::end(),
2074 : // and Activity::dequeued()). Now, the reason to call
2075 : // commitUpdates() twice here is caused by the unrelated
2076 : // fact that during wait cursor display/hide, the screen
2077 : // is updated, and shows hidden sprites, but, in case of
2078 : // leaving the second commitUpdates() call out and punting
2079 : // that to the next round, no updated static slide
2080 : // content. In short, the last shape animation of a slide
2081 : // tends to blink at its end.
2082 :
2083 : // process dequeued activities _after_ commit to screen
2084 0 : maActivitiesQueue.processDequeued();
2085 :
2086 : // commit frame to screen
2087 0 : maScreenUpdater.commitUpdates();
2088 : }
2089 : // Time held until here
2090 :
2091 0 : const bool bActivitiesLeft = (! maActivitiesQueue.isEmpty());
2092 0 : const bool bTimerEventsLeft = (! maEventQueue.isEmpty());
2093 0 : const bool bRet = (bActivitiesLeft || bTimerEventsLeft);
2094 :
2095 0 : if (bRet)
2096 : {
2097 : // calc nNextTimeout value:
2098 0 : if (bActivitiesLeft)
2099 : {
2100 : // Activity queue is not empty. Tell caller that we would
2101 : // like to render another frame.
2102 :
2103 : // Return a zero time-out to signal our caller to call us
2104 : // back as soon as possible. The actual timing, waiting the
2105 : // appropriate amount of time between frames, is then done
2106 : // by the maFrameSynchronization object.
2107 0 : nNextTimeout = 0;
2108 0 : maFrameSynchronization.Activate();
2109 : }
2110 : else
2111 : {
2112 : // timer events left:
2113 : // difference from current time (nota bene:
2114 : // time no longer held here!) to the next event in
2115 : // the event queue.
2116 :
2117 : // #i61190# Retrieve next timeout only _after_
2118 : // processing activity queue
2119 :
2120 : // ensure positive value:
2121 0 : nNextTimeout = std::max( 0.0, maEventQueue.nextTimeout() );
2122 :
2123 : // There is no active animation so the frame rate does not
2124 : // need to be synchronized.
2125 0 : maFrameSynchronization.Deactivate();
2126 : }
2127 :
2128 0 : mbSlideShowIdle = false;
2129 : }
2130 :
2131 : #if OSL_DEBUG_LEVEL >= 2 && defined(DBG_UTIL)
2132 : // when slideshow is idle, issue an XUpdatable::update() call
2133 : // exactly once after a previous animation sequence finished -
2134 : // this might trigger screen dumps on some canvas
2135 : // implementations
2136 : if( !mbSlideShowIdle &&
2137 : (!bRet ||
2138 : nNextTimeout > 1.0) )
2139 : {
2140 : UnoViewVector::const_iterator aCurr(maViewContainer.begin());
2141 : const UnoViewVector::const_iterator aEnd(maViewContainer.end());
2142 : while( aCurr != aEnd )
2143 : {
2144 : try
2145 : {
2146 : uno::Reference< presentation::XSlideShowView > xView( (*aCurr)->getUnoView(),
2147 : uno::UNO_QUERY_THROW );
2148 : uno::Reference< util::XUpdatable > xUpdatable( xView->getCanvas(),
2149 : uno::UNO_QUERY_THROW );
2150 : xUpdatable->update();
2151 : }
2152 : catch( uno::RuntimeException& )
2153 : {
2154 : throw;
2155 : }
2156 : catch( uno::Exception& )
2157 : {
2158 : OSL_FAIL( OUStringToOString(
2159 : comphelper::anyToString( cppu::getCaughtException() ),
2160 : RTL_TEXTENCODING_UTF8 ).getStr() );
2161 : }
2162 :
2163 : ++aCurr;
2164 : }
2165 :
2166 : mbSlideShowIdle = true;
2167 : }
2168 : #endif
2169 :
2170 0 : return bRet;
2171 0 : }
2172 : }
2173 :
2174 0 : void SlideShowImpl::notifySlideTransitionEnded( bool bPaintSlide )
2175 : {
2176 0 : osl::MutexGuard const guard( m_aMutex );
2177 :
2178 : OSL_ENSURE( !isDisposed(), "### already disposed!" );
2179 : OSL_ENSURE( mpCurrentSlide,
2180 : "notifySlideTransitionEnded(): Invalid current slide" );
2181 0 : if (mpCurrentSlide)
2182 : {
2183 0 : mpCurrentSlide->update_settings( !!maUserPaintColor, maUserPaintColor ? *maUserPaintColor : RGBColor(), maUserPaintStrokeWidth );
2184 :
2185 : // first init show, to give the animations
2186 : // the chance to register SlideStartEvents
2187 0 : const bool bBackgroundLayerRendered( !bPaintSlide );
2188 0 : mpCurrentSlide->show( bBackgroundLayerRendered );
2189 0 : maEventMultiplexer.notifySlideStartEvent();
2190 0 : }
2191 0 : }
2192 :
2193 0 : void queryAutomaticSlideTransition( uno::Reference<drawing::XDrawPage> const& xDrawPage,
2194 : double& nAutomaticNextSlideTimeout,
2195 : bool& bHasAutomaticNextSlide )
2196 : {
2197 : // retrieve slide change parameters from XDrawPage
2198 : // ===============================================
2199 :
2200 : uno::Reference< beans::XPropertySet > xPropSet( xDrawPage,
2201 0 : uno::UNO_QUERY );
2202 :
2203 0 : sal_Int32 nChange(0);
2204 0 : if( !xPropSet.is() ||
2205 : !getPropertyValue( nChange,
2206 : xPropSet,
2207 : OUString(
2208 0 : "Change")) )
2209 : {
2210 : OSL_TRACE(
2211 : "queryAutomaticSlideTransition(): "
2212 : "Could not extract slide change mode from XDrawPage - assuming <none>\n" );
2213 : }
2214 :
2215 0 : bHasAutomaticNextSlide = nChange == 1;
2216 :
2217 0 : if( !xPropSet.is() ||
2218 : !getPropertyValue( nAutomaticNextSlideTimeout,
2219 : xPropSet,
2220 : OUString(
2221 0 : "HighResDuration")) )
2222 : {
2223 : OSL_TRACE(
2224 : "queryAutomaticSlideTransition(): "
2225 : "Could not extract slide transition timeout from "
2226 : "XDrawPage - assuming 1 sec\n" );
2227 0 : }
2228 0 : }
2229 :
2230 0 : void SlideShowImpl::notifySlideAnimationsEnded()
2231 : {
2232 0 : osl::MutexGuard const guard( m_aMutex );
2233 :
2234 : //Draw polygons above animations
2235 0 : mpCurrentSlide->drawPolygons();
2236 :
2237 : OSL_ENSURE( !isDisposed(), "### already disposed!" );
2238 :
2239 : // This struct will receive the (interruptable) event,
2240 : // that triggers the notifySlideEnded() method.
2241 0 : InterruptableEventPair aNotificationEvents;
2242 :
2243 0 : if( maEventMultiplexer.getAutomaticMode() )
2244 : {
2245 : OSL_ENSURE( ! mpRehearseTimingsActivity,
2246 : "unexpected: RehearseTimings mode!" );
2247 :
2248 : // schedule a slide end event, with automatic mode's
2249 : // delay
2250 0 : aNotificationEvents = makeInterruptableDelay(
2251 0 : boost::bind<void>( boost::mem_fn(&SlideShowImpl::notifySlideEnded), this, false ),
2252 0 : maEventMultiplexer.getAutomaticTimeout() );
2253 : }
2254 : else
2255 : {
2256 : OSL_ENSURE( mpCurrentSlide,
2257 : "notifySlideAnimationsEnded(): Invalid current slide!" );
2258 :
2259 0 : bool bHasAutomaticNextSlide=false;
2260 0 : double nAutomaticNextSlideTimeout=0.0;
2261 0 : queryAutomaticSlideTransition(mpCurrentSlide->getXDrawPage(),
2262 : nAutomaticNextSlideTimeout,
2263 0 : bHasAutomaticNextSlide);
2264 :
2265 : // check whether slide transition should happen
2266 : // 'automatically'. If yes, simply schedule the
2267 : // specified timeout.
2268 : // NOTE: mbForceManualAdvance and mpRehearseTimingsActivity
2269 : // override any individual slide setting, to always
2270 : // step slides manually.
2271 0 : if( !mbForceManualAdvance &&
2272 0 : !mpRehearseTimingsActivity &&
2273 : bHasAutomaticNextSlide )
2274 : {
2275 0 : aNotificationEvents = makeInterruptableDelay(
2276 0 : boost::bind<void>( boost::mem_fn(&SlideShowImpl::notifySlideEnded), this, false ),
2277 0 : nAutomaticNextSlideTimeout);
2278 :
2279 : // TODO(F2): Provide a mechanism to let the user override
2280 : // this automatic timeout via next()
2281 : }
2282 : else
2283 : {
2284 0 : if (mpRehearseTimingsActivity)
2285 0 : mpRehearseTimingsActivity->start();
2286 :
2287 : // generate click event. Thus, the user must
2288 : // trigger the actual end of a slide. No need to
2289 : // generate interruptable event here, there's no
2290 : // timeout involved.
2291 0 : aNotificationEvents.mpImmediateEvent =
2292 0 : makeEvent( boost::bind<void>(
2293 : boost::mem_fn(&SlideShowImpl::notifySlideEnded), this, false ),
2294 0 : "SlideShowImpl::notifySlideEnded");
2295 : }
2296 : }
2297 :
2298 : // register events on the queues. To make automatic slide
2299 : // changes interruptable, register the interruption event
2300 : // as a nextEffectEvent target. Note that the timeout
2301 : // event is optional (e.g. manual slide changes don't
2302 : // generate a timeout)
2303 : maUserEventQueue.registerNextEffectEvent(
2304 0 : aNotificationEvents.mpImmediateEvent );
2305 :
2306 0 : if( aNotificationEvents.mpTimeoutEvent )
2307 0 : maEventQueue.addEvent( aNotificationEvents.mpTimeoutEvent );
2308 :
2309 : // current slide's main sequence is over. Now should be
2310 : // the time to prefetch the next slide (if any), and
2311 : // prepare the initial slide bitmap (speeds up slide
2312 : // change setup time a lot). Show the wait cursor, this
2313 : // indeed might take some seconds.
2314 : {
2315 0 : WaitSymbolLock aLock (*this);
2316 :
2317 0 : if (! matches( mpPrefetchSlide,
2318 0 : mxPrefetchSlide, mxPrefetchAnimationNode ))
2319 : {
2320 0 : mpPrefetchSlide = makeSlide( mxPrefetchSlide, mxDrawPagesSupplier,
2321 0 : mxPrefetchAnimationNode );
2322 : }
2323 0 : if (mpPrefetchSlide)
2324 : {
2325 : // ignore return value, this is just to populate
2326 : // Slide's internal bitmap buffer, such that the time
2327 : // needed to generate the slide bitmap is not spent
2328 : // when the slide change is requested.
2329 0 : mpPrefetchSlide->getCurrentSlideBitmap( *maViewContainer.begin() );
2330 0 : }
2331 : } // finally
2332 :
2333 : maListenerContainer.forEach<presentation::XSlideShowListener>(
2334 0 : boost::mem_fn( &presentation::XSlideShowListener::slideAnimationsEnded ) );
2335 0 : }
2336 :
2337 0 : void SlideShowImpl::notifySlideEnded (const bool bReverse)
2338 : {
2339 0 : osl::MutexGuard const guard( m_aMutex );
2340 :
2341 : OSL_ENSURE( !isDisposed(), "### already disposed!" );
2342 :
2343 0 : if (mpRehearseTimingsActivity && !bReverse)
2344 : {
2345 0 : const double time = mpRehearseTimingsActivity->stop();
2346 0 : if (mpRehearseTimingsActivity->hasBeenClicked())
2347 : {
2348 : // save time at current drawpage:
2349 : uno::Reference<beans::XPropertySet> xPropSet(
2350 0 : mpCurrentSlide->getXDrawPage(), uno::UNO_QUERY );
2351 : OSL_ASSERT( xPropSet.is() );
2352 0 : if (xPropSet.is())
2353 : {
2354 0 : xPropSet->setPropertyValue(
2355 : "Change",
2356 0 : uno::Any( static_cast<sal_Int32>(1) ) );
2357 0 : xPropSet->setPropertyValue(
2358 : "Duration",
2359 0 : uno::Any( static_cast<sal_Int32>(time) ) );
2360 0 : }
2361 : }
2362 : }
2363 :
2364 0 : if (bReverse)
2365 0 : maEventMultiplexer.notifySlideEndEvent();
2366 :
2367 0 : stopShow(); // MUST call that: results in
2368 : // maUserEventQueue.clear(). What's more,
2369 : // stopShow()'s currSlide->hide() call is
2370 : // now also required, notifySlideEnded()
2371 : // relies on that
2372 : // unconditionally. Otherwise, genuine
2373 : // shape animations (drawing layer and
2374 : // GIF) will not be stopped.
2375 :
2376 : maListenerContainer.forEach<presentation::XSlideShowListener>(
2377 : boost::bind<void>(
2378 : ::boost::mem_fn(&presentation::XSlideShowListener::slideEnded),
2379 : _1,
2380 0 : sal_Bool(bReverse)));
2381 0 : }
2382 :
2383 0 : bool SlideShowImpl::notifyHyperLinkClicked( OUString const& hyperLink )
2384 : {
2385 0 : osl::MutexGuard const guard( m_aMutex );
2386 :
2387 : maListenerContainer.forEach<presentation::XSlideShowListener>(
2388 : boost::bind( &presentation::XSlideShowListener::hyperLinkClicked,
2389 : _1,
2390 0 : boost::cref(hyperLink) ));
2391 0 : return true;
2392 : }
2393 :
2394 : /** Notification from eventmultiplexer that an animation event has occoured.
2395 : This will be forewarded to all registered XSlideShoeListener
2396 : */
2397 0 : bool SlideShowImpl::handleAnimationEvent( const AnimationNodeSharedPtr& rNode )
2398 : {
2399 0 : osl::MutexGuard const guard( m_aMutex );
2400 :
2401 0 : uno::Reference<animations::XAnimationNode> xNode( rNode->getXAnimationNode() );
2402 :
2403 0 : switch( rNode->getState() )
2404 : {
2405 : case AnimationNode::ACTIVE:
2406 : maListenerContainer.forEach<presentation::XSlideShowListener>(
2407 : boost::bind( &animations::XAnimationListener::beginEvent,
2408 : _1,
2409 0 : boost::cref(xNode) ));
2410 0 : break;
2411 :
2412 : case AnimationNode::FROZEN:
2413 : case AnimationNode::ENDED:
2414 : maListenerContainer.forEach<presentation::XSlideShowListener>(
2415 : boost::bind( &animations::XAnimationListener::endEvent,
2416 : _1,
2417 0 : boost::cref(xNode) ));
2418 0 : if(mpCurrentSlide->isPaintOverlayActive())
2419 0 : mpCurrentSlide->drawPolygons();
2420 0 : break;
2421 : default:
2422 0 : break;
2423 : }
2424 :
2425 0 : return true;
2426 : }
2427 :
2428 : //===== FrameSynchronization ==================================================
2429 :
2430 0 : FrameSynchronization::FrameSynchronization (const double nFrameDuration)
2431 : : maTimer(),
2432 : mnFrameDuration(nFrameDuration),
2433 : mnNextFrameTargetTime(0),
2434 0 : mbIsActive(false)
2435 : {
2436 0 : MarkCurrentFrame();
2437 0 : }
2438 :
2439 0 : void FrameSynchronization::MarkCurrentFrame (void)
2440 : {
2441 0 : mnNextFrameTargetTime = maTimer.getElapsedTime() + mnFrameDuration;
2442 0 : }
2443 :
2444 0 : void FrameSynchronization::Synchronize (void)
2445 : {
2446 0 : if (mbIsActive)
2447 : {
2448 : // Do busy waiting for now.
2449 0 : while (maTimer.getElapsedTime() < mnNextFrameTargetTime)
2450 : ;
2451 : }
2452 :
2453 0 : MarkCurrentFrame();
2454 0 : }
2455 :
2456 0 : void FrameSynchronization::Activate (void)
2457 : {
2458 0 : mbIsActive = true;
2459 0 : }
2460 :
2461 0 : void FrameSynchronization::Deactivate (void)
2462 : {
2463 0 : mbIsActive = false;
2464 0 : }
2465 :
2466 : } // anon namespace
2467 :
2468 : namespace sdecl = comphelper::service_decl;
2469 0 : const sdecl::ServiceDecl slideShowDecl(
2470 : sdecl::class_<SlideShowImpl>(),
2471 : "com.sun.star.comp.presentation.SlideShow",
2472 0 : "com.sun.star.presentation.SlideShow" );
2473 :
2474 : // The C shared lib entry points
2475 0 : COMPHELPER_SERVICEDECL_EXPORTS1(slideshow, slideShowDecl)
2476 :
2477 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|