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