Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 :
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"
27 :
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>
35 :
36 : using ::com::sun::star::uno::Reference;
37 : using namespace ::com::sun::star;
38 :
39 : namespace slideshow { namespace internal {
40 :
41 :
42 : namespace {
43 :
44 : class RewinderEventHandler : public EventHandler
45 : {
46 : public:
47 : typedef ::boost::function<bool()> Action;
48 2 : RewinderEventHandler (const Action& rAction) : maAction(rAction) {}
49 4 : virtual ~RewinderEventHandler() {}
50 : private:
51 : const Action maAction;
52 0 : virtual bool handleEvent() SAL_OVERRIDE { return maAction(); }
53 : };
54 :
55 :
56 :
57 : class RewinderAnimationEventHandler : public AnimationEventHandler
58 : {
59 : public:
60 : typedef ::boost::function<bool(const AnimationNodeSharedPtr& rpNode)> Action;
61 1 : RewinderAnimationEventHandler (const Action& rAction) : maAction(rAction) {}
62 2 : virtual ~RewinderAnimationEventHandler() {}
63 : private:
64 : const Action maAction;
65 0 : virtual bool handleAnimationEvent (const AnimationNodeSharedPtr& rpNode) SAL_OVERRIDE
66 0 : { return maAction(rpNode); }
67 : };
68 :
69 :
70 :
71 : } // end of anonymous namespace
72 :
73 :
74 : //----- EffectRewinder --------------------------------------------------------------
75 :
76 1 : EffectRewinder::EffectRewinder (
77 : EventMultiplexer& rEventMultiplexer,
78 : EventQueue& rEventQueue,
79 : UserEventQueue& rUserEventQueue)
80 : : mrEventMultiplexer(rEventMultiplexer),
81 : mrEventQueue(rEventQueue),
82 : mrUserEventQueue(rUserEventQueue),
83 : mpSlideStartHandler(),
84 : mpSlideEndHandler(),
85 : mpAnimationStartHandler(),
86 : mnMainSequenceEffectCount(0),
87 : mpAsynchronousRewindEvent(),
88 : mxCurrentAnimationRootNode(),
89 1 : mbNonUserTriggeredMainSequenceEffectSeen(false)
90 : {
91 1 : initialize();
92 1 : }
93 :
94 :
95 :
96 :
97 1 : void EffectRewinder::initialize()
98 : {
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
103 : // is reset.
104 :
105 : mpAnimationStartHandler.reset(
106 : new RewinderAnimationEventHandler(
107 1 : ::boost::bind(&EffectRewinder::notifyAnimationStart, this, _1)));
108 1 : mrEventMultiplexer.addAnimationStartHandler(mpAnimationStartHandler);
109 :
110 : mpSlideStartHandler.reset(
111 : new RewinderEventHandler(
112 1 : ::boost::bind(&EffectRewinder::resetEffectCount, this)));
113 1 : mrEventMultiplexer.addSlideStartHandler(mpSlideStartHandler);
114 :
115 : mpSlideEndHandler.reset(
116 : new RewinderEventHandler(
117 1 : ::boost::bind(&EffectRewinder::resetEffectCount, this)));
118 1 : mrEventMultiplexer.addSlideEndHandler(mpSlideEndHandler);
119 1 : }
120 :
121 :
122 :
123 :
124 2 : EffectRewinder::~EffectRewinder()
125 : {
126 1 : dispose();
127 1 : }
128 :
129 :
130 :
131 :
132 2 : void EffectRewinder::dispose()
133 : {
134 2 : if (mpAsynchronousRewindEvent)
135 : {
136 0 : mpAsynchronousRewindEvent->dispose();
137 0 : mpAsynchronousRewindEvent.reset();
138 : }
139 :
140 2 : if (mpAnimationStartHandler)
141 : {
142 1 : mrEventMultiplexer.removeAnimationStartHandler(mpAnimationStartHandler);
143 1 : mpAnimationStartHandler.reset();
144 : }
145 :
146 2 : if (mpSlideStartHandler)
147 : {
148 1 : mrEventMultiplexer.removeSlideStartHandler(mpSlideStartHandler);
149 1 : mpSlideStartHandler.reset();
150 : }
151 :
152 2 : if (mpSlideEndHandler)
153 : {
154 1 : mrEventMultiplexer.removeSlideEndHandler(mpSlideEndHandler);
155 1 : mpSlideEndHandler.reset();
156 : }
157 2 : }
158 :
159 :
160 :
161 :
162 0 : void EffectRewinder::setRootAnimationNode (
163 : const uno::Reference<animations::XAnimationNode>& xRootNode)
164 : {
165 0 : mxCurrentAnimationRootNode = xRootNode;
166 0 : }
167 :
168 :
169 :
170 :
171 0 : bool EffectRewinder::rewind (
172 : const ::boost::shared_ptr<ScreenUpdater::UpdateLock>& rpPaintLock,
173 : const ::boost::function<void()>& rSlideRewindFunctor,
174 : const ::boost::function<void()>& rPreviousSlideFunctor)
175 : {
176 0 : mpPaintLock = rpPaintLock;
177 :
178 : // Do not allow nested rewinds.
179 0 : if (mpAsynchronousRewindEvent)
180 : {
181 : OSL_ASSERT( ! mpAsynchronousRewindEvent);
182 0 : return false;
183 : }
184 :
185 : // Abort (and skip over the rest of) any currently active animation.
186 0 : mrUserEventQueue.callSkipEffectEventHandler();
187 0 : mrEventQueue.forceEmpty();
188 :
189 0 : const int nSkipCount (mnMainSequenceEffectCount - 1);
190 0 : if (nSkipCount < 0)
191 : {
192 0 : if ( ! rPreviousSlideFunctor)
193 : {
194 : OSL_ASSERT(rPreviousSlideFunctor);
195 0 : return false;
196 : }
197 :
198 : // No main sequence effects to rewind on the current slide.
199 : // Go back to the previous slide.
200 0 : mpAsynchronousRewindEvent = makeEvent(
201 : ::boost::bind(
202 : &EffectRewinder::asynchronousRewindToPreviousSlide,
203 : this,
204 : rPreviousSlideFunctor),
205 0 : "EffectRewinder::asynchronousRewindToPreviousSlide");
206 : }
207 : else
208 : {
209 : // The actual rewinding is done asynchronously so that we can safely
210 : // call other methods.
211 0 : mpAsynchronousRewindEvent = makeEvent(
212 : ::boost::bind(
213 : &EffectRewinder::asynchronousRewind,
214 : this,
215 : nSkipCount,
216 : true,
217 : rSlideRewindFunctor),
218 0 : "EffectRewinder::asynchronousRewind");
219 : }
220 :
221 0 : if (mpAsynchronousRewindEvent)
222 0 : mrEventQueue.addEvent(mpAsynchronousRewindEvent);
223 :
224 0 : return mpAsynchronousRewindEvent.get()!=NULL;
225 : }
226 :
227 :
228 :
229 :
230 0 : void EffectRewinder::skipAllMainSequenceEffects()
231 : {
232 : // Do not allow nested rewinds.
233 0 : if (mpAsynchronousRewindEvent)
234 : {
235 : OSL_ASSERT(!mpAsynchronousRewindEvent);
236 0 : return;
237 : }
238 :
239 0 : const int nTotalMainSequenceEffectCount (countMainSequenceEffects());
240 0 : mpAsynchronousRewindEvent = makeEvent(
241 : ::boost::bind(
242 : &EffectRewinder::asynchronousRewind,
243 : this,
244 : nTotalMainSequenceEffectCount,
245 : false,
246 : ::boost::function<void()>()),
247 0 : "EffectRewinder::asynchronousRewind");
248 0 : mrEventQueue.addEvent(mpAsynchronousRewindEvent);
249 : }
250 :
251 :
252 :
253 :
254 0 : sal_Int32 EffectRewinder::countMainSequenceEffects()
255 : {
256 : // Determine the number of main sequence effects.
257 0 : sal_Int32 nMainSequenceNodeCount (0);
258 :
259 0 : ::std::queue<uno::Reference<animations::XAnimationNode> > aNodeQueue;
260 0 : aNodeQueue.push(mxCurrentAnimationRootNode);
261 0 : while ( ! aNodeQueue.empty())
262 : {
263 0 : const uno::Reference<animations::XAnimationNode> xNode (aNodeQueue.front());
264 0 : aNodeQueue.pop();
265 :
266 : // Does the current node belong to the main sequence?
267 0 : if (xNode.is())
268 : {
269 0 : animations::Event aEvent;
270 0 : if (xNode->getBegin() >>= aEvent)
271 0 : if (aEvent.Trigger == animations::EventTrigger::ON_NEXT)
272 0 : ++nMainSequenceNodeCount;
273 : }
274 :
275 : // If the current node is a container then prepare its children for investigation.
276 0 : uno::Reference<container::XEnumerationAccess> xEnumerationAccess (xNode, uno::UNO_QUERY);
277 0 : if (xEnumerationAccess.is())
278 : {
279 : uno::Reference<container::XEnumeration> xEnumeration (
280 0 : xEnumerationAccess->createEnumeration());
281 0 : if (xEnumeration.is())
282 0 : while (xEnumeration->hasMoreElements())
283 : {
284 : aNodeQueue.push(
285 : uno::Reference<animations::XAnimationNode>(
286 0 : xEnumeration->nextElement(), uno::UNO_QUERY));
287 0 : }
288 : }
289 0 : }
290 :
291 0 : return nMainSequenceNodeCount;
292 : }
293 :
294 :
295 :
296 :
297 0 : void EffectRewinder::skipSingleMainSequenceEffects()
298 : {
299 : // This basically just starts the next effect and then skips over its
300 : // animation.
301 0 : mrEventMultiplexer.notifyNextEffect();
302 0 : mrEventQueue.forceEmpty();
303 0 : mrUserEventQueue.callSkipEffectEventHandler();
304 0 : mrEventQueue.forceEmpty();
305 0 : }
306 :
307 :
308 :
309 :
310 0 : bool EffectRewinder::resetEffectCount()
311 : {
312 0 : mnMainSequenceEffectCount = 0;
313 0 : return false;
314 : }
315 :
316 :
317 :
318 :
319 0 : bool EffectRewinder::notifyAnimationStart (const AnimationNodeSharedPtr& rpNode)
320 : {
321 : // This notification is only relevant for us when the rpNode belongs to
322 : // the main sequence.
323 0 : BaseNodeSharedPtr pBaseNode (::boost::dynamic_pointer_cast<BaseNode>(rpNode));
324 0 : if ( ! pBaseNode)
325 0 : return false;
326 :
327 0 : BaseContainerNodeSharedPtr pParent (pBaseNode->getParentNode());
328 0 : if ( ! (pParent && pParent->isMainSequenceRootNode()))
329 0 : return false;
330 :
331 : // This notification is only relevant for us when the effect is user
332 : // triggered.
333 0 : bool bIsUserTriggered (false);
334 :
335 0 : Reference<animations::XAnimationNode> xNode (rpNode->getXAnimationNode());
336 0 : if (xNode.is())
337 : {
338 0 : animations::Event aEvent;
339 0 : if ((xNode->getBegin() >>= aEvent))
340 0 : bIsUserTriggered = (aEvent.Trigger == animations::EventTrigger::ON_NEXT);
341 : }
342 :
343 0 : if (bIsUserTriggered)
344 0 : ++mnMainSequenceEffectCount;
345 : else
346 0 : mbNonUserTriggeredMainSequenceEffectSeen = true;
347 :
348 0 : return false;
349 : }
350 :
351 :
352 :
353 :
354 0 : void EffectRewinder::asynchronousRewind (
355 : sal_Int32 nEffectCount,
356 : const bool bRedisplayCurrentSlide,
357 : const boost::function<void()>& rSlideRewindFunctor)
358 : {
359 : OSL_ASSERT(mpAsynchronousRewindEvent);
360 :
361 0 : if (bRedisplayCurrentSlide)
362 : {
363 0 : mpPaintLock->Activate();
364 : // Re-display the current slide.
365 0 : if (rSlideRewindFunctor)
366 0 : rSlideRewindFunctor();
367 0 : mpAsynchronousRewindEvent = makeEvent(
368 : ::boost::bind(
369 : &EffectRewinder::asynchronousRewind,
370 : this,
371 : nEffectCount,
372 : false,
373 : rSlideRewindFunctor),
374 0 : "EffectRewinder::asynchronousRewind");
375 0 : mrEventQueue.addEvent(mpAsynchronousRewindEvent);
376 : }
377 : else
378 : {
379 : // Process initial events and skip any animations that are started
380 : // when the slide is shown.
381 0 : mbNonUserTriggeredMainSequenceEffectSeen = false;
382 0 : mrEventQueue.forceEmpty();
383 0 : if (mbNonUserTriggeredMainSequenceEffectSeen)
384 : {
385 0 : mrUserEventQueue.callSkipEffectEventHandler();
386 0 : mrEventQueue.forceEmpty();
387 : }
388 :
389 0 : while (--nEffectCount >= 0)
390 0 : skipSingleMainSequenceEffects();
391 :
392 0 : mpAsynchronousRewindEvent.reset();
393 0 : mpPaintLock.reset();
394 : }
395 0 : }
396 :
397 :
398 :
399 :
400 0 : void EffectRewinder::asynchronousRewindToPreviousSlide (
401 : const ::boost::function<void()>& rSlideRewindFunctor)
402 : {
403 : OSL_ASSERT(mpAsynchronousRewindEvent);
404 :
405 0 : mpAsynchronousRewindEvent.reset();
406 0 : rSlideRewindFunctor();
407 0 : }
408 :
409 :
410 :
411 :
412 3 : } } // end of namespace ::slideshow::internal
413 :
414 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|