1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: slideshowimpl.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "precompiled_slideshow.hxx"
33 #include "effectrewinder.hxx"
34 #include "eventqueue.hxx"
35 #include "usereventqueue.hxx"
36 #include "mouseeventhandler.hxx"
37 #include "animationnodes/basecontainernode.hxx"
38 #include "delayevent.hxx"
40 #include <com/sun/star/awt/MouseEvent.hpp>
41 #include <com/sun/star/animations/Event.hpp>
42 #include <com/sun/star/animations/EventTrigger.hpp>
43 #include <com/sun/star/container/XEnumerationAccess.hpp>
44 #include <boost/function.hpp>
45 #include <boost/bind.hpp>
46 #include <boost/enable_shared_from_this.hpp>
48 using ::com::sun::star::uno::Reference
;
49 using namespace ::com::sun::star
;
51 namespace slideshow
{ namespace internal
{
56 class RewinderEventHandler
: public EventHandler
59 typedef ::boost::function
<bool(void)> Action
;
60 RewinderEventHandler (const Action
& rAction
) : maAction(rAction
) {}
61 virtual ~RewinderEventHandler (void) {}
63 const Action maAction
;
64 virtual bool handleEvent (void) { return maAction(); }
69 class RewinderAnimationEventHandler
: public AnimationEventHandler
72 typedef ::boost::function
<bool(const AnimationNodeSharedPtr
& rpNode
)> Action
;
73 RewinderAnimationEventHandler (const Action
& rAction
) : maAction(rAction
) {}
74 virtual ~RewinderAnimationEventHandler (void) {}
76 const Action maAction
;
77 virtual bool handleAnimationEvent (const AnimationNodeSharedPtr
& rpNode
)
78 { return maAction(rpNode
); }
83 } // end of anonymous namespace
86 //----- EffectRewinder --------------------------------------------------------------
88 EffectRewinder::EffectRewinder (
89 EventMultiplexer
& rEventMultiplexer
,
90 EventQueue
& rEventQueue
,
91 UserEventQueue
& rUserEventQueue
)
92 : mrEventMultiplexer(rEventMultiplexer
),
93 mrEventQueue(rEventQueue
),
94 mrUserEventQueue(rUserEventQueue
),
95 mpSlideStartHandler(),
97 mpAnimationStartHandler(),
98 mnMainSequenceEffectCount(0),
99 mpAsynchronousRewindEvent(),
100 mxCurrentAnimationRootNode(),
101 mbNonUserTriggeredMainSequenceEffectSeen(false)
109 void EffectRewinder::initialize (void)
111 // Add some event handlers so that we are informed when
112 // a) an animation is started (we then check whether that belongs to a
113 // main sequence effect and if so, increase the respective counter),
114 // b,c) a slide was started or ended (in which case the effect counter
117 mpAnimationStartHandler
.reset(
118 new RewinderAnimationEventHandler(
119 ::boost::bind(&EffectRewinder::notifyAnimationStart
, this, _1
)));
120 mrEventMultiplexer
.addAnimationStartHandler(mpAnimationStartHandler
);
122 mpSlideStartHandler
.reset(
123 new RewinderEventHandler(
124 ::boost::bind(&EffectRewinder::resetEffectCount
, this)));
125 mrEventMultiplexer
.addSlideStartHandler(mpSlideStartHandler
);
127 mpSlideEndHandler
.reset(
128 new RewinderEventHandler(
129 ::boost::bind(&EffectRewinder::resetEffectCount
, this)));
130 mrEventMultiplexer
.addSlideEndHandler(mpSlideEndHandler
);
136 EffectRewinder::~EffectRewinder (void)
144 void EffectRewinder::dispose (void)
146 if (mpAsynchronousRewindEvent
)
148 mpAsynchronousRewindEvent
->dispose();
149 mpAsynchronousRewindEvent
.reset();
152 if (mpAnimationStartHandler
)
154 mrEventMultiplexer
.removeAnimationStartHandler(mpAnimationStartHandler
);
155 mpAnimationStartHandler
.reset();
158 if (mpSlideStartHandler
)
160 mrEventMultiplexer
.removeSlideStartHandler(mpSlideStartHandler
);
161 mpSlideStartHandler
.reset();
164 if (mpSlideEndHandler
)
166 mrEventMultiplexer
.removeSlideEndHandler(mpSlideEndHandler
);
167 mpSlideEndHandler
.reset();
174 void EffectRewinder::setRootAnimationNode (
175 const uno::Reference
<animations::XAnimationNode
>& xRootNode
)
177 mxCurrentAnimationRootNode
= xRootNode
;
183 bool EffectRewinder::rewind (
184 const ::boost::shared_ptr
<ScreenUpdater::UpdateLock
>& rpPaintLock
,
185 const ::boost::function
<void(void)>& rSlideRewindFunctor
,
186 const ::boost::function
<void(void)>& rPreviousSlideFunctor
)
188 mpPaintLock
= rpPaintLock
;
190 // Do not allow nested rewinds.
191 if (mpAsynchronousRewindEvent
)
193 OSL_ASSERT( ! mpAsynchronousRewindEvent
);
197 // Abort (and skip over the rest of) any currently active animation.
198 mrUserEventQueue
.callSkipEffectEventHandler();
199 mrEventQueue
.forceEmpty();
201 const int nSkipCount (mnMainSequenceEffectCount
- 1);
204 if ( ! rPreviousSlideFunctor
)
206 OSL_ASSERT(rPreviousSlideFunctor
);
210 // No main sequence effects to rewind on the current slide.
211 // Go back to the previous slide.
212 mpAsynchronousRewindEvent
= makeEvent(
214 &EffectRewinder::asynchronousRewindToPreviousSlide
,
216 rPreviousSlideFunctor
));
220 // The actual rewinding is done asynchronously so that we can safely
221 // call other methods.
222 mpAsynchronousRewindEvent
= makeEvent(
224 &EffectRewinder::asynchronousRewind
,
228 rSlideRewindFunctor
));
231 if (mpAsynchronousRewindEvent
)
232 mrEventQueue
.addEvent(mpAsynchronousRewindEvent
);
234 return mpAsynchronousRewindEvent
.get()!=NULL
;
240 void EffectRewinder::skipAllMainSequenceEffects (void)
242 // Do not allow nested rewinds.
243 if (mpAsynchronousRewindEvent
)
245 OSL_ASSERT(!mpAsynchronousRewindEvent
);
249 const int nTotalMainSequenceEffectCount (countMainSequenceEffects());
250 mpAsynchronousRewindEvent
= makeEvent(
252 &EffectRewinder::asynchronousRewind
,
254 nTotalMainSequenceEffectCount
,
256 ::boost::function
<void(void)>()));
257 mrEventQueue
.addEvent(mpAsynchronousRewindEvent
);
263 sal_Int32
EffectRewinder::countMainSequenceEffects (void)
265 // Determine the number of main sequence effects.
266 sal_Int32
nMainSequenceNodeCount (0);
268 ::std::queue
<uno::Reference
<animations::XAnimationNode
> > aNodeQueue
;
269 aNodeQueue
.push(mxCurrentAnimationRootNode
);
270 while ( ! aNodeQueue
.empty())
272 const uno::Reference
<animations::XAnimationNode
> xNode (aNodeQueue
.front());
275 // Does the current node belong to the main sequence?
278 animations::Event aEvent
;
279 if (xNode
->getBegin() >>= aEvent
)
280 if (aEvent
.Trigger
== animations::EventTrigger::ON_NEXT
)
281 ++nMainSequenceNodeCount
;
284 // If the current node is a container then prepare its children for investigation.
285 uno::Reference
<container::XEnumerationAccess
> xEnumerationAccess (xNode
, uno::UNO_QUERY
);
286 if (xEnumerationAccess
.is())
288 uno::Reference
<container::XEnumeration
> xEnumeration (
289 xEnumerationAccess
->createEnumeration());
290 if (xEnumeration
.is())
291 while (xEnumeration
->hasMoreElements())
294 uno::Reference
<animations::XAnimationNode
>(
295 xEnumeration
->nextElement(), uno::UNO_QUERY
));
300 return nMainSequenceNodeCount
;
302 // // Skip all main sequence nodes.
303 // SkipSomeMainSequenceEffects(nMainSequenceNodeCount);
309 void EffectRewinder::skipSomeMainSequenceEffects (sal_Int32 nSkipCount
)
311 while (--nSkipCount
>= 0)
312 skipSingleMainSequenceEffects();
318 void EffectRewinder::skipSingleMainSequenceEffects (void)
320 // This basically just starts the next effect and then skips over its
322 mrEventMultiplexer
.notifyNextEffect();
323 mrEventQueue
.forceEmpty();
324 mrUserEventQueue
.callSkipEffectEventHandler();
325 mrEventQueue
.forceEmpty();
331 bool EffectRewinder::resetEffectCount (void)
333 mnMainSequenceEffectCount
= 0;
340 bool EffectRewinder::notifyAnimationStart (const AnimationNodeSharedPtr
& rpNode
)
342 // This notification is only relevant for us when the rpNode belongs to
343 // the main sequence.
344 BaseNodeSharedPtr
pBaseNode (::boost::dynamic_pointer_cast
<BaseNode
>(rpNode
));
348 BaseContainerNodeSharedPtr
pParent (pBaseNode
->getParentNode());
349 if ( ! (pParent
&& pParent
->isMainSequenceRootNode()))
352 // This notification is only relevant for us when the effect is user
354 bool bIsUserTriggered (false);
356 Reference
<animations::XAnimationNode
> xNode (rpNode
->getXAnimationNode());
359 animations::Event aEvent
;
360 if ((xNode
->getBegin() >>= aEvent
))
361 bIsUserTriggered
= (aEvent
.Trigger
== animations::EventTrigger::ON_NEXT
);
364 if (bIsUserTriggered
)
365 ++mnMainSequenceEffectCount
;
367 mbNonUserTriggeredMainSequenceEffectSeen
= true;
375 void EffectRewinder::asynchronousRewind (
376 sal_Int32 nEffectCount
,
377 const bool bRedisplayCurrentSlide
,
378 const boost::function
<void(void)>& rSlideRewindFunctor
)
380 OSL_ASSERT(mpAsynchronousRewindEvent
);
382 if (bRedisplayCurrentSlide
)
384 mpPaintLock
->Activate();
385 // Re-display the current slide.
386 if (rSlideRewindFunctor
)
387 rSlideRewindFunctor();
388 mpAsynchronousRewindEvent
= makeEvent(
390 &EffectRewinder::asynchronousRewind
,
394 rSlideRewindFunctor
));
395 mrEventQueue
.addEventForNextRound(mpAsynchronousRewindEvent
);
399 // Process initial events and skip any animations that are started
400 // when the slide is shown.
401 mbNonUserTriggeredMainSequenceEffectSeen
= false;
402 mrEventQueue
.forceEmpty();
403 if (mbNonUserTriggeredMainSequenceEffectSeen
)
405 mrUserEventQueue
.callSkipEffectEventHandler();
406 mrEventQueue
.forceEmpty();
409 while (--nEffectCount
>= 0)
410 skipSingleMainSequenceEffects();
412 mpAsynchronousRewindEvent
.reset();
420 void EffectRewinder::asynchronousRewindToPreviousSlide (
421 const ::boost::function
<void(void)>& rSlideRewindFunctor
)
423 OSL_ASSERT(mpAsynchronousRewindEvent
);
425 mpAsynchronousRewindEvent
.reset();
426 rSlideRewindFunctor();
432 } } // end of namespace ::slideshow::internal