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 <basecontainernode.hxx>
25 #include <delayevent.hxx>
27 #include <com/sun/star/animations/Event.hpp>
28 #include <com/sun/star/animations/EventTrigger.hpp>
29 #include <com/sun/star/container/XEnumerationAccess.hpp>
30 #include <com/sun/star/beans/XPropertySet.hpp>
32 using ::com::sun::star::uno::Reference
;
33 using namespace ::com::sun::star
;
35 namespace slideshow::internal
{
40 class RewinderEventHandler
: public EventHandler
43 typedef ::std::function
<bool ()> Action
;
44 explicit RewinderEventHandler (const Action
& rAction
) : maAction(rAction
) {}
47 const Action maAction
;
48 virtual bool handleEvent() override
{ return maAction(); }
52 class RewinderAnimationEventHandler
: public AnimationEventHandler
55 typedef ::std::function
<bool (const AnimationNodeSharedPtr
& rpNode
)> Action
;
56 explicit RewinderAnimationEventHandler (const Action
& rAction
) : maAction(rAction
) {}
59 const Action maAction
;
60 virtual bool handleAnimationEvent (const AnimationNodeSharedPtr
& rpNode
) override
61 { return maAction(rpNode
); }
65 } // end of anonymous namespace
68 //----- EffectRewinder --------------------------------------------------------------
70 EffectRewinder::EffectRewinder (
71 EventMultiplexer
& rEventMultiplexer
,
72 EventQueue
& rEventQueue
,
73 UserEventQueue
& rUserEventQueue
)
74 : mrEventMultiplexer(rEventMultiplexer
),
75 mrEventQueue(rEventQueue
),
76 mrUserEventQueue(rUserEventQueue
),
77 mpSlideStartHandler(),
79 mpAnimationStartHandler(),
80 mnMainSequenceEffectCount(0),
81 mpAsynchronousRewindEvent(),
82 mxCurrentAnimationRootNode(),
84 mbNonUserTriggeredMainSequenceEffectSeen(false),
85 mbHasAdvancedTimeSetting(false)
91 void EffectRewinder::initialize()
93 // Add some event handlers so that we are informed when
94 // a) an animation is started (we then check whether that belongs to a
95 // main sequence effect and if so, increase the respective counter),
96 // b,c) a slide was started or ended (in which case the effect counter
99 mpAnimationStartHandler
=
100 std::make_shared
<RewinderAnimationEventHandler
>(
101 [this]( const AnimationNodeSharedPtr
& pNode
)
102 { return this->notifyAnimationStart( pNode
); } );
103 mrEventMultiplexer
.addAnimationStartHandler(mpAnimationStartHandler
);
105 mpSlideStartHandler
=
106 std::make_shared
<RewinderEventHandler
>(
107 [this]() { return this->resetEffectCount(); } );
108 mrEventMultiplexer
.addSlideStartHandler(mpSlideStartHandler
);
111 std::make_shared
<RewinderEventHandler
>(
112 [this]() { return this->resetEffectCount(); } );
113 mrEventMultiplexer
.addSlideEndHandler(mpSlideEndHandler
);
117 EffectRewinder::~EffectRewinder()
123 void EffectRewinder::dispose()
125 if (mpAsynchronousRewindEvent
)
127 mpAsynchronousRewindEvent
->dispose();
128 mpAsynchronousRewindEvent
.reset();
131 if (mpAnimationStartHandler
)
133 mrEventMultiplexer
.removeAnimationStartHandler(mpAnimationStartHandler
);
134 mpAnimationStartHandler
.reset();
137 if (mpSlideStartHandler
)
139 mrEventMultiplexer
.removeSlideStartHandler(mpSlideStartHandler
);
140 mpSlideStartHandler
.reset();
143 if (mpSlideEndHandler
)
145 mrEventMultiplexer
.removeSlideEndHandler(mpSlideEndHandler
);
146 mpSlideEndHandler
.reset();
151 void EffectRewinder::setRootAnimationNode (
152 const uno::Reference
<animations::XAnimationNode
>& xRootNode
)
154 mxCurrentAnimationRootNode
= xRootNode
;
157 void EffectRewinder::setCurrentSlide (
158 const uno::Reference
<drawing::XDrawPage
>& xSlide
)
160 mxCurrentSlide
= xSlide
;
162 // Check if the current slide has advance time setting or not
163 uno::Reference
< beans::XPropertySet
> xPropSet( mxCurrentSlide
, uno::UNO_QUERY
);
164 sal_Int32
nChange(0);
167 getPropertyValue( nChange
, xPropSet
, "Change");
169 mbHasAdvancedTimeSetting
= nChange
;
172 bool EffectRewinder::rewind (
173 const ::std::shared_ptr
<ScreenUpdater::UpdateLock
>& rpPaintLock
,
174 const ::std::function
<void ()>& rSlideRewindFunctor
,
175 const ::std::function
<void ()>& rPreviousSlideFunctor
)
177 mpPaintLock
= rpPaintLock
;
179 // Do not allow nested rewinds.
180 if (mpAsynchronousRewindEvent
)
182 OSL_ASSERT( ! mpAsynchronousRewindEvent
);
186 // Abort (and skip over the rest of) any currently active animation.
187 mrUserEventQueue
.callSkipEffectEventHandler();
189 if (!mbHasAdvancedTimeSetting
)
190 mrEventQueue
.forceEmpty();
192 const int nSkipCount (mnMainSequenceEffectCount
- 1);
195 if ( ! rPreviousSlideFunctor
)
197 OSL_ASSERT(rPreviousSlideFunctor
);
201 // No main sequence effects to rewind on the current slide.
202 // Go back to the previous slide.
203 mpAsynchronousRewindEvent
= makeEvent(
205 &EffectRewinder::asynchronousRewindToPreviousSlide
,
207 rPreviousSlideFunctor
),
208 "EffectRewinder::asynchronousRewindToPreviousSlide");
212 // The actual rewinding is done asynchronously so that we can safely
213 // call other methods.
214 mpAsynchronousRewindEvent
= makeEvent(
216 &EffectRewinder::asynchronousRewind
,
220 rSlideRewindFunctor
),
221 "EffectRewinder::asynchronousRewind");
224 if (mpAsynchronousRewindEvent
)
225 mrEventQueue
.addEvent(mpAsynchronousRewindEvent
);
227 return bool(mpAsynchronousRewindEvent
);
231 void EffectRewinder::skipAllMainSequenceEffects()
233 // Do not allow nested rewinds.
234 if (mpAsynchronousRewindEvent
)
236 OSL_ASSERT(!mpAsynchronousRewindEvent
);
240 const int nTotalMainSequenceEffectCount (countMainSequenceEffects());
241 mpAsynchronousRewindEvent
= makeEvent(
243 &EffectRewinder::asynchronousRewind
,
245 nTotalMainSequenceEffectCount
,
247 ::std::function
<void ()>()),
248 "EffectRewinder::asynchronousRewind");
249 mrEventQueue
.addEvent(mpAsynchronousRewindEvent
);
253 sal_Int32
EffectRewinder::countMainSequenceEffects()
255 // Determine the number of main sequence effects.
256 sal_Int32
nMainSequenceNodeCount (0);
258 ::std::queue
<uno::Reference
<animations::XAnimationNode
> > aNodeQueue
;
259 aNodeQueue
.push(mxCurrentAnimationRootNode
);
260 while ( ! aNodeQueue
.empty())
262 const uno::Reference
<animations::XAnimationNode
> xNode (aNodeQueue
.front());
265 // Does the current node belong to the main sequence?
268 animations::Event aEvent
;
269 if (xNode
->getBegin() >>= aEvent
)
270 if (aEvent
.Trigger
== animations::EventTrigger::ON_NEXT
)
271 ++nMainSequenceNodeCount
;
274 // If the current node is a container then prepare its children for investigation.
275 uno::Reference
<container::XEnumerationAccess
> xEnumerationAccess (xNode
, uno::UNO_QUERY
);
276 if (xEnumerationAccess
.is())
278 uno::Reference
<container::XEnumeration
> xEnumeration (
279 xEnumerationAccess
->createEnumeration());
280 if (xEnumeration
.is())
281 while (xEnumeration
->hasMoreElements())
284 uno::Reference
<animations::XAnimationNode
>(
285 xEnumeration
->nextElement(), uno::UNO_QUERY
));
290 return nMainSequenceNodeCount
;
294 void EffectRewinder::skipSingleMainSequenceEffects()
296 // This basically just starts the next effect and then skips over its
298 mrEventMultiplexer
.notifyNextEffect();
299 mrEventQueue
.forceEmpty();
300 mrUserEventQueue
.callSkipEffectEventHandler();
301 mrEventQueue
.forceEmpty();
305 bool EffectRewinder::resetEffectCount()
307 mnMainSequenceEffectCount
= 0;
312 bool EffectRewinder::notifyAnimationStart (const AnimationNodeSharedPtr
& rpNode
)
314 // This notification is only relevant for us when the rpNode belongs to
315 // the main sequence.
316 BaseNodeSharedPtr
pBaseNode (::std::dynamic_pointer_cast
<BaseNode
>(rpNode
));
320 BaseContainerNodeSharedPtr
pParent (pBaseNode
->getParentNode());
321 if ( ! (pParent
&& pParent
->isMainSequenceRootNode()))
324 // This notification is only relevant for us when the effect is user
326 bool bIsUserTriggered (false);
328 Reference
<animations::XAnimationNode
> xNode (rpNode
->getXAnimationNode());
331 animations::Event aEvent
;
332 if (xNode
->getBegin() >>= aEvent
)
333 bIsUserTriggered
= (aEvent
.Trigger
== animations::EventTrigger::ON_NEXT
);
336 if (bIsUserTriggered
)
337 ++mnMainSequenceEffectCount
;
339 mbNonUserTriggeredMainSequenceEffectSeen
= true;
345 void EffectRewinder::asynchronousRewind (
346 sal_Int32 nEffectCount
,
347 const bool bRedisplayCurrentSlide
,
348 const std::function
<void ()>& rSlideRewindFunctor
)
350 OSL_ASSERT(mpAsynchronousRewindEvent
);
352 if (bRedisplayCurrentSlide
)
354 mpPaintLock
->Activate();
355 // Re-display the current slide.
356 if (rSlideRewindFunctor
)
357 rSlideRewindFunctor();
358 mpAsynchronousRewindEvent
= makeEvent(
360 &EffectRewinder::asynchronousRewind
,
364 rSlideRewindFunctor
),
365 "EffectRewinder::asynchronousRewind");
366 mrEventQueue
.addEvent(mpAsynchronousRewindEvent
);
370 // Process initial events and skip any animations that are started
371 // when the slide is shown.
372 mbNonUserTriggeredMainSequenceEffectSeen
= false;
374 if (!mbHasAdvancedTimeSetting
)
375 mrEventQueue
.forceEmpty();
377 if (mbNonUserTriggeredMainSequenceEffectSeen
)
379 mrUserEventQueue
.callSkipEffectEventHandler();
380 mrEventQueue
.forceEmpty();
383 while (--nEffectCount
>= 0)
384 skipSingleMainSequenceEffects();
386 mpAsynchronousRewindEvent
.reset();
392 void EffectRewinder::asynchronousRewindToPreviousSlide (
393 const ::std::function
<void ()>& rSlideRewindFunctor
)
395 OSL_ASSERT(mpAsynchronousRewindEvent
);
397 mpAsynchronousRewindEvent
.reset();
398 rSlideRewindFunctor();
402 } // end of namespace ::slideshow::internal
404 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */