merge the formfield patch from ooo-build
[ooovba.git] / slideshow / source / engine / effectrewinder.cxx
blobb7db66774090a3e9102a7975b64e271f99edf0e8
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: slideshowimpl.cxx,v $
10 * $Revision: 1.10 $
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 {
54 namespace {
56 class RewinderEventHandler : public EventHandler
58 public:
59 typedef ::boost::function<bool(void)> Action;
60 RewinderEventHandler (const Action& rAction) : maAction(rAction) {}
61 virtual ~RewinderEventHandler (void) {}
62 private:
63 const Action maAction;
64 virtual bool handleEvent (void) { return maAction(); }
69 class RewinderAnimationEventHandler : public AnimationEventHandler
71 public:
72 typedef ::boost::function<bool(const AnimationNodeSharedPtr& rpNode)> Action;
73 RewinderAnimationEventHandler (const Action& rAction) : maAction(rAction) {}
74 virtual ~RewinderAnimationEventHandler (void) {}
75 private:
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(),
96 mpSlideEndHandler(),
97 mpAnimationStartHandler(),
98 mnMainSequenceEffectCount(0),
99 mpAsynchronousRewindEvent(),
100 mxCurrentAnimationRootNode(),
101 mbNonUserTriggeredMainSequenceEffectSeen(false)
103 initialize();
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
115 // is reset.
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)
138 dispose();
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);
194 return false;
197 // Abort (and skip over the rest of) any currently active animation.
198 mrUserEventQueue.callSkipEffectEventHandler();
199 mrEventQueue.forceEmpty();
201 const int nSkipCount (mnMainSequenceEffectCount - 1);
202 if (nSkipCount < 0)
204 if ( ! rPreviousSlideFunctor)
206 OSL_ASSERT(rPreviousSlideFunctor);
207 return false;
210 // No main sequence effects to rewind on the current slide.
211 // Go back to the previous slide.
212 mpAsynchronousRewindEvent = makeEvent(
213 ::boost::bind(
214 &EffectRewinder::asynchronousRewindToPreviousSlide,
215 this,
216 rPreviousSlideFunctor));
218 else
220 // The actual rewinding is done asynchronously so that we can safely
221 // call other methods.
222 mpAsynchronousRewindEvent = makeEvent(
223 ::boost::bind(
224 &EffectRewinder::asynchronousRewind,
225 this,
226 nSkipCount,
227 true,
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);
246 return;
249 const int nTotalMainSequenceEffectCount (countMainSequenceEffects());
250 mpAsynchronousRewindEvent = makeEvent(
251 ::boost::bind(
252 &EffectRewinder::asynchronousRewind,
253 this,
254 nTotalMainSequenceEffectCount,
255 false,
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());
273 aNodeQueue.pop();
275 // Does the current node belong to the main sequence?
276 if (xNode.is())
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())
293 aNodeQueue.push(
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
321 // animation.
322 mrEventMultiplexer.notifyNextEffect();
323 mrEventQueue.forceEmpty();
324 mrUserEventQueue.callSkipEffectEventHandler();
325 mrEventQueue.forceEmpty();
331 bool EffectRewinder::resetEffectCount (void)
333 mnMainSequenceEffectCount = 0;
334 return false;
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));
345 if ( ! pBaseNode)
346 return false;
348 BaseContainerNodeSharedPtr pParent (pBaseNode->getParentNode());
349 if ( ! (pParent && pParent->isMainSequenceRootNode()))
350 return false;
352 // This notification is only relevant for us when the effect is user
353 // triggered.
354 bool bIsUserTriggered (false);
356 Reference<animations::XAnimationNode> xNode (rpNode->getXAnimationNode());
357 if (xNode.is())
359 animations::Event aEvent;
360 if ((xNode->getBegin() >>= aEvent))
361 bIsUserTriggered = (aEvent.Trigger == animations::EventTrigger::ON_NEXT);
364 if (bIsUserTriggered)
365 ++mnMainSequenceEffectCount;
366 else
367 mbNonUserTriggeredMainSequenceEffectSeen = true;
369 return false;
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(
389 ::boost::bind(
390 &EffectRewinder::asynchronousRewind,
391 this,
392 nEffectCount,
393 false,
394 rSlideRewindFunctor));
395 mrEventQueue.addEventForNextRound(mpAsynchronousRewindEvent);
397 else
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();
413 mpPaintLock.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