1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include "effectrewinder.hxx"
22 #include "eventqueue.hxx"
23 #include "usereventqueue.hxx"
24 #include "mouseeventhandler.hxx"
25 #include "animationnodes/basecontainernode.hxx"
26 #include "delayevent.hxx"
28 #include <com/sun/star/awt/MouseEvent.hpp>
29 #include <com/sun/star/animations/Event.hpp>
30 #include <com/sun/star/animations/EventTrigger.hpp>
31 #include <com/sun/star/container/XEnumerationAccess.hpp>
32 #include <boost/function.hpp>
33 #include <boost/bind.hpp>
34 #include <boost/enable_shared_from_this.hpp>
36 using ::com::sun::star::uno::Reference
;
37 using namespace ::com::sun::star
;
39 namespace slideshow
{ namespace internal
{
44 class RewinderEventHandler
: public EventHandler
47 typedef ::boost::function
<bool()> Action
;
48 RewinderEventHandler (const Action
& rAction
) : maAction(rAction
) {}
49 virtual ~RewinderEventHandler() {}
51 const Action maAction
;
52 virtual bool handleEvent() SAL_OVERRIDE
{ return maAction(); }
57 class RewinderAnimationEventHandler
: public AnimationEventHandler
60 typedef ::boost::function
<bool(const AnimationNodeSharedPtr
& rpNode
)> Action
;
61 RewinderAnimationEventHandler (const Action
& rAction
) : maAction(rAction
) {}
62 virtual ~RewinderAnimationEventHandler() {}
64 const Action maAction
;
65 virtual bool handleAnimationEvent (const AnimationNodeSharedPtr
& rpNode
) SAL_OVERRIDE
66 { return maAction(rpNode
); }
71 } // end of anonymous namespace
74 //----- EffectRewinder --------------------------------------------------------------
76 EffectRewinder::EffectRewinder (
77 EventMultiplexer
& rEventMultiplexer
,
78 EventQueue
& rEventQueue
,
79 UserEventQueue
& rUserEventQueue
)
80 : mrEventMultiplexer(rEventMultiplexer
),
81 mrEventQueue(rEventQueue
),
82 mrUserEventQueue(rUserEventQueue
),
83 mpSlideStartHandler(),
85 mpAnimationStartHandler(),
86 mnMainSequenceEffectCount(0),
87 mpAsynchronousRewindEvent(),
88 mxCurrentAnimationRootNode(),
89 mbNonUserTriggeredMainSequenceEffectSeen(false)
97 void EffectRewinder::initialize()
99 // Add some event handlers so that we are informed when
100 // a) an animation is started (we then check whether that belongs to a
101 // main sequence effect and if so, increase the respective counter),
102 // b,c) a slide was started or ended (in which case the effect counter
105 mpAnimationStartHandler
.reset(
106 new RewinderAnimationEventHandler(
107 ::boost::bind(&EffectRewinder::notifyAnimationStart
, this, _1
)));
108 mrEventMultiplexer
.addAnimationStartHandler(mpAnimationStartHandler
);
110 mpSlideStartHandler
.reset(
111 new RewinderEventHandler(
112 ::boost::bind(&EffectRewinder::resetEffectCount
, this)));
113 mrEventMultiplexer
.addSlideStartHandler(mpSlideStartHandler
);
115 mpSlideEndHandler
.reset(
116 new RewinderEventHandler(
117 ::boost::bind(&EffectRewinder::resetEffectCount
, this)));
118 mrEventMultiplexer
.addSlideEndHandler(mpSlideEndHandler
);
124 EffectRewinder::~EffectRewinder()
132 void EffectRewinder::dispose()
134 if (mpAsynchronousRewindEvent
)
136 mpAsynchronousRewindEvent
->dispose();
137 mpAsynchronousRewindEvent
.reset();
140 if (mpAnimationStartHandler
)
142 mrEventMultiplexer
.removeAnimationStartHandler(mpAnimationStartHandler
);
143 mpAnimationStartHandler
.reset();
146 if (mpSlideStartHandler
)
148 mrEventMultiplexer
.removeSlideStartHandler(mpSlideStartHandler
);
149 mpSlideStartHandler
.reset();
152 if (mpSlideEndHandler
)
154 mrEventMultiplexer
.removeSlideEndHandler(mpSlideEndHandler
);
155 mpSlideEndHandler
.reset();
162 void EffectRewinder::setRootAnimationNode (
163 const uno::Reference
<animations::XAnimationNode
>& xRootNode
)
165 mxCurrentAnimationRootNode
= xRootNode
;
171 bool EffectRewinder::rewind (
172 const ::boost::shared_ptr
<ScreenUpdater::UpdateLock
>& rpPaintLock
,
173 const ::boost::function
<void()>& rSlideRewindFunctor
,
174 const ::boost::function
<void()>& rPreviousSlideFunctor
)
176 mpPaintLock
= rpPaintLock
;
178 // Do not allow nested rewinds.
179 if (mpAsynchronousRewindEvent
)
181 OSL_ASSERT( ! mpAsynchronousRewindEvent
);
185 // Abort (and skip over the rest of) any currently active animation.
186 mrUserEventQueue
.callSkipEffectEventHandler();
187 mrEventQueue
.forceEmpty();
189 const int nSkipCount (mnMainSequenceEffectCount
- 1);
192 if ( ! rPreviousSlideFunctor
)
194 OSL_ASSERT(rPreviousSlideFunctor
);
198 // No main sequence effects to rewind on the current slide.
199 // Go back to the previous slide.
200 mpAsynchronousRewindEvent
= makeEvent(
202 &EffectRewinder::asynchronousRewindToPreviousSlide
,
204 rPreviousSlideFunctor
),
205 "EffectRewinder::asynchronousRewindToPreviousSlide");
209 // The actual rewinding is done asynchronously so that we can safely
210 // call other methods.
211 mpAsynchronousRewindEvent
= makeEvent(
213 &EffectRewinder::asynchronousRewind
,
217 rSlideRewindFunctor
),
218 "EffectRewinder::asynchronousRewind");
221 if (mpAsynchronousRewindEvent
)
222 mrEventQueue
.addEvent(mpAsynchronousRewindEvent
);
224 return mpAsynchronousRewindEvent
.get()!=NULL
;
230 void EffectRewinder::skipAllMainSequenceEffects()
232 // Do not allow nested rewinds.
233 if (mpAsynchronousRewindEvent
)
235 OSL_ASSERT(!mpAsynchronousRewindEvent
);
239 const int nTotalMainSequenceEffectCount (countMainSequenceEffects());
240 mpAsynchronousRewindEvent
= makeEvent(
242 &EffectRewinder::asynchronousRewind
,
244 nTotalMainSequenceEffectCount
,
246 ::boost::function
<void()>()),
247 "EffectRewinder::asynchronousRewind");
248 mrEventQueue
.addEvent(mpAsynchronousRewindEvent
);
254 sal_Int32
EffectRewinder::countMainSequenceEffects()
256 // Determine the number of main sequence effects.
257 sal_Int32
nMainSequenceNodeCount (0);
259 ::std::queue
<uno::Reference
<animations::XAnimationNode
> > aNodeQueue
;
260 aNodeQueue
.push(mxCurrentAnimationRootNode
);
261 while ( ! aNodeQueue
.empty())
263 const uno::Reference
<animations::XAnimationNode
> xNode (aNodeQueue
.front());
266 // Does the current node belong to the main sequence?
269 animations::Event aEvent
;
270 if (xNode
->getBegin() >>= aEvent
)
271 if (aEvent
.Trigger
== animations::EventTrigger::ON_NEXT
)
272 ++nMainSequenceNodeCount
;
275 // If the current node is a container then prepare its children for investigation.
276 uno::Reference
<container::XEnumerationAccess
> xEnumerationAccess (xNode
, uno::UNO_QUERY
);
277 if (xEnumerationAccess
.is())
279 uno::Reference
<container::XEnumeration
> xEnumeration (
280 xEnumerationAccess
->createEnumeration());
281 if (xEnumeration
.is())
282 while (xEnumeration
->hasMoreElements())
285 uno::Reference
<animations::XAnimationNode
>(
286 xEnumeration
->nextElement(), uno::UNO_QUERY
));
291 return nMainSequenceNodeCount
;
297 void EffectRewinder::skipSingleMainSequenceEffects()
299 // This basically just starts the next effect and then skips over its
301 mrEventMultiplexer
.notifyNextEffect();
302 mrEventQueue
.forceEmpty();
303 mrUserEventQueue
.callSkipEffectEventHandler();
304 mrEventQueue
.forceEmpty();
310 bool EffectRewinder::resetEffectCount()
312 mnMainSequenceEffectCount
= 0;
319 bool EffectRewinder::notifyAnimationStart (const AnimationNodeSharedPtr
& rpNode
)
321 // This notification is only relevant for us when the rpNode belongs to
322 // the main sequence.
323 BaseNodeSharedPtr
pBaseNode (::boost::dynamic_pointer_cast
<BaseNode
>(rpNode
));
327 BaseContainerNodeSharedPtr
pParent (pBaseNode
->getParentNode());
328 if ( ! (pParent
&& pParent
->isMainSequenceRootNode()))
331 // This notification is only relevant for us when the effect is user
333 bool bIsUserTriggered (false);
335 Reference
<animations::XAnimationNode
> xNode (rpNode
->getXAnimationNode());
338 animations::Event aEvent
;
339 if ((xNode
->getBegin() >>= aEvent
))
340 bIsUserTriggered
= (aEvent
.Trigger
== animations::EventTrigger::ON_NEXT
);
343 if (bIsUserTriggered
)
344 ++mnMainSequenceEffectCount
;
346 mbNonUserTriggeredMainSequenceEffectSeen
= true;
354 void EffectRewinder::asynchronousRewind (
355 sal_Int32 nEffectCount
,
356 const bool bRedisplayCurrentSlide
,
357 const boost::function
<void()>& rSlideRewindFunctor
)
359 OSL_ASSERT(mpAsynchronousRewindEvent
);
361 if (bRedisplayCurrentSlide
)
363 mpPaintLock
->Activate();
364 // Re-display the current slide.
365 if (rSlideRewindFunctor
)
366 rSlideRewindFunctor();
367 mpAsynchronousRewindEvent
= makeEvent(
369 &EffectRewinder::asynchronousRewind
,
373 rSlideRewindFunctor
),
374 "EffectRewinder::asynchronousRewind");
375 mrEventQueue
.addEvent(mpAsynchronousRewindEvent
);
379 // Process initial events and skip any animations that are started
380 // when the slide is shown.
381 mbNonUserTriggeredMainSequenceEffectSeen
= false;
382 mrEventQueue
.forceEmpty();
383 if (mbNonUserTriggeredMainSequenceEffectSeen
)
385 mrUserEventQueue
.callSkipEffectEventHandler();
386 mrEventQueue
.forceEmpty();
389 while (--nEffectCount
>= 0)
390 skipSingleMainSequenceEffects();
392 mpAsynchronousRewindEvent
.reset();
400 void EffectRewinder::asynchronousRewindToPreviousSlide (
401 const ::boost::function
<void()>& rSlideRewindFunctor
)
403 OSL_ASSERT(mpAsynchronousRewindEvent
);
405 mpAsynchronousRewindEvent
.reset();
406 rSlideRewindFunctor();
412 } } // end of namespace ::slideshow::internal
414 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */