use insert function instead of for loop
[LibreOffice.git] / slideshow / source / engine / effectrewinder.cxx
blob4bfc8990673b01a5b4d51ebbe1ac2a75fc52142d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
31 #include <utility>
33 using ::com::sun::star::uno::Reference;
34 using namespace ::com::sun::star;
36 namespace slideshow::internal {
39 namespace {
41 class RewinderEventHandler : public EventHandler
43 public:
44 typedef ::std::function<bool ()> Action;
45 explicit RewinderEventHandler (Action aAction) : maAction(std::move(aAction)) {}
47 private:
48 const Action maAction;
49 virtual bool handleEvent() override { return maAction(); }
53 class RewinderAnimationEventHandler : public AnimationEventHandler
55 public:
56 typedef ::std::function<bool (const AnimationNodeSharedPtr& rpNode)> Action;
57 explicit RewinderAnimationEventHandler (Action aAction) : maAction(std::move(aAction)) {}
59 private:
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(),
79 mpSlideEndHandler(),
80 mpAnimationStartHandler(),
81 mnMainSequenceEffectCount(0),
82 mpAsynchronousRewindEvent(),
83 mxCurrentAnimationRootNode(),
84 mxCurrentSlide(),
85 mbNonUserTriggeredMainSequenceEffectSeen(false),
86 mbHasAdvancedTimeSetting(false)
88 initialize();
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
98 // is reset.
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);
111 mpSlideEndHandler =
112 std::make_shared<RewinderEventHandler>(
113 [this]() { return this->resetEffectCount(); } );
114 mrEventMultiplexer.addSlideEndHandler(mpSlideEndHandler);
118 EffectRewinder::~EffectRewinder()
120 dispose();
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);
167 if( xPropSet.is())
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);
184 return false;
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);
194 if (nSkipCount < 0)
196 if ( ! rPreviousSlideFunctor)
198 OSL_ASSERT(rPreviousSlideFunctor);
199 return false;
202 // No main sequence effects to rewind on the current slide.
203 // Go back to the previous slide.
204 mpAsynchronousRewindEvent = makeEvent(
205 ::std::bind(
206 &EffectRewinder::asynchronousRewindToPreviousSlide,
207 this,
208 rPreviousSlideFunctor),
209 u"EffectRewinder::asynchronousRewindToPreviousSlide"_ustr);
211 else
213 // The actual rewinding is done asynchronously so that we can safely
214 // call other methods.
215 mpAsynchronousRewindEvent = makeEvent(
216 ::std::bind(
217 &EffectRewinder::asynchronousRewind,
218 this,
219 nSkipCount,
220 true,
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);
238 return;
241 const int nTotalMainSequenceEffectCount (countMainSequenceEffects());
242 mpAsynchronousRewindEvent = makeEvent(
243 ::std::bind(
244 &EffectRewinder::asynchronousRewind,
245 this,
246 nTotalMainSequenceEffectCount,
247 false,
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());
264 aNodeQueue.pop();
266 // Does the current node belong to the main sequence?
267 if (xNode.is())
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())
284 aNodeQueue.push(
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
298 // animation.
299 mrEventMultiplexer.notifyNextEffect();
300 mrEventQueue.forceEmpty();
301 mrUserEventQueue.callSkipEffectEventHandler();
302 mrEventQueue.forceEmpty();
306 bool EffectRewinder::resetEffectCount()
308 mnMainSequenceEffectCount = 0;
309 return false;
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));
318 if ( ! pBaseNode)
319 return false;
321 BaseContainerNodeSharedPtr pParent (pBaseNode->getParentNode());
322 if ( ! (pParent && pParent->isMainSequenceRootNode()))
323 return false;
325 // This notification is only relevant for us when the effect is user
326 // triggered.
327 bool bIsUserTriggered (false);
329 Reference<animations::XAnimationNode> xNode (rpNode->getXAnimationNode());
330 if (xNode.is())
332 animations::Event aEvent;
333 if (xNode->getBegin() >>= aEvent)
334 bIsUserTriggered = (aEvent.Trigger == animations::EventTrigger::ON_NEXT);
337 if (bIsUserTriggered)
338 ++mnMainSequenceEffectCount;
339 else
340 mbNonUserTriggeredMainSequenceEffectSeen = true;
342 return false;
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(
360 ::std::bind(
361 &EffectRewinder::asynchronousRewind,
362 this,
363 nEffectCount,
364 false,
365 rSlideRewindFunctor),
366 u"EffectRewinder::asynchronousRewind"_ustr);
367 mrEventQueue.addEvent(mpAsynchronousRewindEvent);
369 else
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();
388 mpPaintLock.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: */