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>
33 using ::com::sun::star::uno::Reference
;
34 using namespace ::com::sun::star
;
36 namespace slideshow::internal
{
41 class RewinderEventHandler
: public EventHandler
44 typedef ::std::function
<bool ()> Action
;
45 explicit RewinderEventHandler (Action aAction
) : maAction(std::move(aAction
)) {}
48 const Action maAction
;
49 virtual bool handleEvent() override
{ return maAction(); }
53 class RewinderAnimationEventHandler
: public AnimationEventHandler
56 typedef ::std::function
<bool (const AnimationNodeSharedPtr
& rpNode
)> Action
;
57 explicit RewinderAnimationEventHandler (Action aAction
) : maAction(std::move(aAction
)) {}
60 const Action maAction
;
61 virtual bool handleAnimationEvent (const AnimationNodeSharedPtr
& rpNode
) override
62 { return maAction(rpNode
); }
66 } // end of anonymous namespace
69 //----- EffectRewinder --------------------------------------------------------------
71 EffectRewinder::EffectRewinder (
72 EventMultiplexer
& rEventMultiplexer
,
73 EventQueue
& rEventQueue
,
74 UserEventQueue
& rUserEventQueue
)
75 : mrEventMultiplexer(rEventMultiplexer
),
76 mrEventQueue(rEventQueue
),
77 mrUserEventQueue(rUserEventQueue
),
78 mpSlideStartHandler(),
80 mpAnimationStartHandler(),
81 mnMainSequenceEffectCount(0),
82 mpAsynchronousRewindEvent(),
83 mxCurrentAnimationRootNode(),
85 mbNonUserTriggeredMainSequenceEffectSeen(false),
86 mbHasAdvancedTimeSetting(false)
92 void EffectRewinder::initialize()
94 // Add some event handlers so that we are informed when
95 // a) an animation is started (we then check whether that belongs to a
96 // main sequence effect and if so, increase the respective counter),
97 // b,c) a slide was started or ended (in which case the effect counter
100 mpAnimationStartHandler
=
101 std::make_shared
<RewinderAnimationEventHandler
>(
102 [this]( const AnimationNodeSharedPtr
& pNode
)
103 { return this->notifyAnimationStart( pNode
); } );
104 mrEventMultiplexer
.addAnimationStartHandler(mpAnimationStartHandler
);
106 mpSlideStartHandler
=
107 std::make_shared
<RewinderEventHandler
>(
108 [this]() { return this->resetEffectCount(); } );
109 mrEventMultiplexer
.addSlideStartHandler(mpSlideStartHandler
);
112 std::make_shared
<RewinderEventHandler
>(
113 [this]() { return this->resetEffectCount(); } );
114 mrEventMultiplexer
.addSlideEndHandler(mpSlideEndHandler
);
118 EffectRewinder::~EffectRewinder()
124 void EffectRewinder::dispose()
126 if (mpAsynchronousRewindEvent
)
128 mpAsynchronousRewindEvent
->dispose();
129 mpAsynchronousRewindEvent
.reset();
132 if (mpAnimationStartHandler
)
134 mrEventMultiplexer
.removeAnimationStartHandler(mpAnimationStartHandler
);
135 mpAnimationStartHandler
.reset();
138 if (mpSlideStartHandler
)
140 mrEventMultiplexer
.removeSlideStartHandler(mpSlideStartHandler
);
141 mpSlideStartHandler
.reset();
144 if (mpSlideEndHandler
)
146 mrEventMultiplexer
.removeSlideEndHandler(mpSlideEndHandler
);
147 mpSlideEndHandler
.reset();
152 void EffectRewinder::setRootAnimationNode (
153 const uno::Reference
<animations::XAnimationNode
>& xRootNode
)
155 mxCurrentAnimationRootNode
= xRootNode
;
158 void EffectRewinder::setCurrentSlide (
159 const uno::Reference
<drawing::XDrawPage
>& xSlide
)
161 mxCurrentSlide
= xSlide
;
163 // Check if the current slide has advance time setting or not
164 uno::Reference
< beans::XPropertySet
> xPropSet( mxCurrentSlide
, uno::UNO_QUERY
);
165 sal_Int32
nChange(0);
168 getPropertyValue( nChange
, xPropSet
, u
"Change"_ustr
);
170 mbHasAdvancedTimeSetting
= nChange
;
173 bool EffectRewinder::rewind (
174 const ::std::shared_ptr
<ScreenUpdater::UpdateLock
>& rpPaintLock
,
175 const ::std::function
<void ()>& rSlideRewindFunctor
,
176 const ::std::function
<void ()>& rPreviousSlideFunctor
)
178 mpPaintLock
= rpPaintLock
;
180 // Do not allow nested rewinds.
181 if (mpAsynchronousRewindEvent
)
183 OSL_ASSERT( ! mpAsynchronousRewindEvent
);
187 // Abort (and skip over the rest of) any currently active animation.
188 mrUserEventQueue
.callSkipEffectEventHandler();
190 if (!mbHasAdvancedTimeSetting
)
191 mrEventQueue
.forceEmpty();
193 const int nSkipCount (mnMainSequenceEffectCount
- 1);
196 if ( ! rPreviousSlideFunctor
)
198 OSL_ASSERT(rPreviousSlideFunctor
);
202 // No main sequence effects to rewind on the current slide.
203 // Go back to the previous slide.
204 mpAsynchronousRewindEvent
= makeEvent(
206 &EffectRewinder::asynchronousRewindToPreviousSlide
,
208 rPreviousSlideFunctor
),
209 u
"EffectRewinder::asynchronousRewindToPreviousSlide"_ustr
);
213 // The actual rewinding is done asynchronously so that we can safely
214 // call other methods.
215 mpAsynchronousRewindEvent
= makeEvent(
217 &EffectRewinder::asynchronousRewind
,
221 rSlideRewindFunctor
),
222 u
"EffectRewinder::asynchronousRewind"_ustr
);
225 if (mpAsynchronousRewindEvent
)
226 mrEventQueue
.addEvent(mpAsynchronousRewindEvent
);
228 return bool(mpAsynchronousRewindEvent
);
232 void EffectRewinder::skipAllMainSequenceEffects()
234 // Do not allow nested rewinds.
235 if (mpAsynchronousRewindEvent
)
237 OSL_ASSERT(!mpAsynchronousRewindEvent
);
241 const int nTotalMainSequenceEffectCount (countMainSequenceEffects());
242 mpAsynchronousRewindEvent
= makeEvent(
244 &EffectRewinder::asynchronousRewind
,
246 nTotalMainSequenceEffectCount
,
248 ::std::function
<void ()>()),
249 u
"EffectRewinder::asynchronousRewind"_ustr
);
250 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
;
295 void EffectRewinder::skipSingleMainSequenceEffects()
297 // This basically just starts the next effect and then skips over its
299 mrEventMultiplexer
.notifyNextEffect();
300 mrEventQueue
.forceEmpty();
301 mrUserEventQueue
.callSkipEffectEventHandler();
302 mrEventQueue
.forceEmpty();
306 bool EffectRewinder::resetEffectCount()
308 mnMainSequenceEffectCount
= 0;
313 bool EffectRewinder::notifyAnimationStart (const AnimationNodeSharedPtr
& rpNode
)
315 // This notification is only relevant for us when the rpNode belongs to
316 // the main sequence.
317 BaseNodeSharedPtr
pBaseNode (::std::dynamic_pointer_cast
<BaseNode
>(rpNode
));
321 BaseContainerNodeSharedPtr
pParent (pBaseNode
->getParentNode());
322 if ( ! (pParent
&& pParent
->isMainSequenceRootNode()))
325 // This notification is only relevant for us when the effect is user
327 bool bIsUserTriggered (false);
329 Reference
<animations::XAnimationNode
> xNode (rpNode
->getXAnimationNode());
332 animations::Event aEvent
;
333 if (xNode
->getBegin() >>= aEvent
)
334 bIsUserTriggered
= (aEvent
.Trigger
== animations::EventTrigger::ON_NEXT
);
337 if (bIsUserTriggered
)
338 ++mnMainSequenceEffectCount
;
340 mbNonUserTriggeredMainSequenceEffectSeen
= true;
346 void EffectRewinder::asynchronousRewind (
347 sal_Int32 nEffectCount
,
348 const bool bRedisplayCurrentSlide
,
349 const std::function
<void ()>& rSlideRewindFunctor
)
351 OSL_ASSERT(mpAsynchronousRewindEvent
);
353 if (bRedisplayCurrentSlide
)
355 mpPaintLock
->Activate();
356 // Re-display the current slide.
357 if (rSlideRewindFunctor
)
358 rSlideRewindFunctor();
359 mpAsynchronousRewindEvent
= makeEvent(
361 &EffectRewinder::asynchronousRewind
,
365 rSlideRewindFunctor
),
366 u
"EffectRewinder::asynchronousRewind"_ustr
);
367 mrEventQueue
.addEvent(mpAsynchronousRewindEvent
);
371 // Process initial events and skip any animations that are started
372 // when the slide is shown.
373 mbNonUserTriggeredMainSequenceEffectSeen
= false;
375 if (!mbHasAdvancedTimeSetting
)
376 mrEventQueue
.forceEmpty();
378 if (mbNonUserTriggeredMainSequenceEffectSeen
)
380 mrUserEventQueue
.callSkipEffectEventHandler();
381 mrEventQueue
.forceEmpty();
384 while (--nEffectCount
>= 0)
385 skipSingleMainSequenceEffects();
387 mpAsynchronousRewindEvent
.reset();
393 void EffectRewinder::asynchronousRewindToPreviousSlide (
394 const ::std::function
<void ()>& rSlideRewindFunctor
)
396 OSL_ASSERT(mpAsynchronousRewindEvent
);
398 mpAsynchronousRewindEvent
.reset();
399 rSlideRewindFunctor();
403 } // end of namespace ::slideshow::internal
405 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */