1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include "precompiled_slideshow.hxx"
25
26 #include "effectrewinder.hxx"
27 #include "eventqueue.hxx"
28 #include "usereventqueue.hxx"
29 #include "mouseeventhandler.hxx"
30 #include "animationnodes/basecontainernode.hxx"
31 #include "delayevent.hxx"
32
33 #include <com/sun/star/awt/MouseEvent.hpp>
34 #include <com/sun/star/animations/Event.hpp>
35 #include <com/sun/star/animations/EventTrigger.hpp>
36 #include <com/sun/star/container/XEnumerationAccess.hpp>
37 #include <boost/function.hpp>
38 #include <boost/bind.hpp>
39 #include <boost/enable_shared_from_this.hpp>
40
41 using ::com::sun::star::uno::Reference;
42 using namespace ::com::sun::star;
43
44 namespace slideshow { namespace internal {
45
46
47 namespace {
48
49 class RewinderEventHandler : public EventHandler
50 {
51 public:
52 typedef ::boost::function<bool(void)> Action;
RewinderEventHandler(const Action & rAction)53 RewinderEventHandler (const Action& rAction) : maAction(rAction) {}
~RewinderEventHandler(void)54 virtual ~RewinderEventHandler (void) {}
55 private:
56 const Action maAction;
handleEvent(void)57 virtual bool handleEvent (void) { return maAction(); }
58 };
59
60
61
62 class RewinderAnimationEventHandler : public AnimationEventHandler
63 {
64 public:
65 typedef ::boost::function<bool(const AnimationNodeSharedPtr& rpNode)> Action;
RewinderAnimationEventHandler(const Action & rAction)66 RewinderAnimationEventHandler (const Action& rAction) : maAction(rAction) {}
~RewinderAnimationEventHandler(void)67 virtual ~RewinderAnimationEventHandler (void) {}
68 private:
69 const Action maAction;
handleAnimationEvent(const AnimationNodeSharedPtr & rpNode)70 virtual bool handleAnimationEvent (const AnimationNodeSharedPtr& rpNode)
71 { return maAction(rpNode); }
72 };
73
74
75
76 } // end of anonymous namespace
77
78
79 //----- EffectRewinder --------------------------------------------------------------
80
EffectRewinder(EventMultiplexer & rEventMultiplexer,EventQueue & rEventQueue,UserEventQueue & rUserEventQueue)81 EffectRewinder::EffectRewinder (
82 EventMultiplexer& rEventMultiplexer,
83 EventQueue& rEventQueue,
84 UserEventQueue& rUserEventQueue)
85 : mrEventMultiplexer(rEventMultiplexer),
86 mrEventQueue(rEventQueue),
87 mrUserEventQueue(rUserEventQueue),
88 mpSlideStartHandler(),
89 mpSlideEndHandler(),
90 mpAnimationStartHandler(),
91 mnMainSequenceEffectCount(0),
92 mpAsynchronousRewindEvent(),
93 mxCurrentAnimationRootNode(),
94 mbNonUserTriggeredMainSequenceEffectSeen(false)
95 {
96 initialize();
97 }
98
99
100
101
initialize(void)102 void EffectRewinder::initialize (void)
103 {
104 // Add some event handlers so that we are informed when
105 // a) an animation is started (we then check whether that belongs to a
106 // main sequence effect and if so, increase the respective counter),
107 // b,c) a slide was started or ended (in which case the effect counter
108 // is reset.
109
110 mpAnimationStartHandler.reset(
111 new RewinderAnimationEventHandler(
112 ::boost::bind(&EffectRewinder::notifyAnimationStart, this, _1)));
113 mrEventMultiplexer.addAnimationStartHandler(mpAnimationStartHandler);
114
115 mpSlideStartHandler.reset(
116 new RewinderEventHandler(
117 ::boost::bind(&EffectRewinder::resetEffectCount, this)));
118 mrEventMultiplexer.addSlideStartHandler(mpSlideStartHandler);
119
120 mpSlideEndHandler.reset(
121 new RewinderEventHandler(
122 ::boost::bind(&EffectRewinder::resetEffectCount, this)));
123 mrEventMultiplexer.addSlideEndHandler(mpSlideEndHandler);
124 }
125
126
127
128
~EffectRewinder(void)129 EffectRewinder::~EffectRewinder (void)
130 {
131 dispose();
132 }
133
134
135
136
dispose(void)137 void EffectRewinder::dispose (void)
138 {
139 if (mpAsynchronousRewindEvent)
140 {
141 mpAsynchronousRewindEvent->dispose();
142 mpAsynchronousRewindEvent.reset();
143 }
144
145 if (mpAnimationStartHandler)
146 {
147 mrEventMultiplexer.removeAnimationStartHandler(mpAnimationStartHandler);
148 mpAnimationStartHandler.reset();
149 }
150
151 if (mpSlideStartHandler)
152 {
153 mrEventMultiplexer.removeSlideStartHandler(mpSlideStartHandler);
154 mpSlideStartHandler.reset();
155 }
156
157 if (mpSlideEndHandler)
158 {
159 mrEventMultiplexer.removeSlideEndHandler(mpSlideEndHandler);
160 mpSlideEndHandler.reset();
161 }
162 }
163
164
165
166
setRootAnimationNode(const uno::Reference<animations::XAnimationNode> & xRootNode)167 void EffectRewinder::setRootAnimationNode (
168 const uno::Reference<animations::XAnimationNode>& xRootNode)
169 {
170 mxCurrentAnimationRootNode = xRootNode;
171 }
172
173
174
175
rewind(const::boost::shared_ptr<ScreenUpdater::UpdateLock> & rpPaintLock,const::boost::function<void (void)> & rSlideRewindFunctor,const::boost::function<void (void)> & rPreviousSlideFunctor)176 bool EffectRewinder::rewind (
177 const ::boost::shared_ptr<ScreenUpdater::UpdateLock>& rpPaintLock,
178 const ::boost::function<void(void)>& rSlideRewindFunctor,
179 const ::boost::function<void(void)>& rPreviousSlideFunctor)
180 {
181 mpPaintLock = rpPaintLock;
182
183 // Do not allow nested rewinds.
184 if (mpAsynchronousRewindEvent)
185 {
186 OSL_ASSERT( ! mpAsynchronousRewindEvent);
187 return false;
188 }
189
190 // Abort (and skip over the rest of) any currently active animation.
191 mrUserEventQueue.callSkipEffectEventHandler();
192 mrEventQueue.forceEmpty();
193
194 const int nSkipCount (mnMainSequenceEffectCount - 1);
195 if (nSkipCount < 0)
196 {
197 if ( ! rPreviousSlideFunctor)
198 {
199 OSL_ASSERT(rPreviousSlideFunctor);
200 return false;
201 }
202
203 // No main sequence effects to rewind on the current slide.
204 // Go back to the previous slide.
205 mpAsynchronousRewindEvent = makeEvent(
206 ::boost::bind(
207 &EffectRewinder::asynchronousRewindToPreviousSlide,
208 this,
209 rPreviousSlideFunctor),
210 "EffectRewinder::asynchronousRewindToPreviousSlide");
211 }
212 else
213 {
214 // The actual rewinding is done asynchronously so that we can safely
215 // call other methods.
216 mpAsynchronousRewindEvent = makeEvent(
217 ::boost::bind(
218 &EffectRewinder::asynchronousRewind,
219 this,
220 nSkipCount,
221 true,
222 rSlideRewindFunctor),
223 "EffectRewinder::asynchronousRewind");
224 }
225
226 if (mpAsynchronousRewindEvent)
227 mrEventQueue.addEvent(mpAsynchronousRewindEvent);
228
229 return mpAsynchronousRewindEvent.get()!=NULL;
230 }
231
232
233
234
skipAllMainSequenceEffects(void)235 void EffectRewinder::skipAllMainSequenceEffects (void)
236 {
237 // Do not allow nested rewinds.
238 if (mpAsynchronousRewindEvent)
239 {
240 OSL_ASSERT(!mpAsynchronousRewindEvent);
241 return;
242 }
243
244 const int nTotalMainSequenceEffectCount (countMainSequenceEffects());
245 mpAsynchronousRewindEvent = makeEvent(
246 ::boost::bind(
247 &EffectRewinder::asynchronousRewind,
248 this,
249 nTotalMainSequenceEffectCount,
250 false,
251 ::boost::function<void(void)>()),
252 "EffectRewinder::asynchronousRewind");
253 mrEventQueue.addEvent(mpAsynchronousRewindEvent);
254 }
255
256
257
258
countMainSequenceEffects(void)259 sal_Int32 EffectRewinder::countMainSequenceEffects (void)
260 {
261 // Determine the number of main sequence effects.
262 sal_Int32 nMainSequenceNodeCount (0);
263
264 ::std::queue<uno::Reference<animations::XAnimationNode> > aNodeQueue;
265 aNodeQueue.push(mxCurrentAnimationRootNode);
266 while ( ! aNodeQueue.empty())
267 {
268 const uno::Reference<animations::XAnimationNode> xNode (aNodeQueue.front());
269 aNodeQueue.pop();
270
271 // Does the current node belong to the main sequence?
272 if (xNode.is())
273 {
274 animations::Event aEvent;
275 if (xNode->getBegin() >>= aEvent)
276 if (aEvent.Trigger == animations::EventTrigger::ON_NEXT)
277 ++nMainSequenceNodeCount;
278 }
279
280 // If the current node is a container then prepare its children for investigation.
281 uno::Reference<container::XEnumerationAccess> xEnumerationAccess (xNode, uno::UNO_QUERY);
282 if (xEnumerationAccess.is())
283 {
284 uno::Reference<container::XEnumeration> xEnumeration (
285 xEnumerationAccess->createEnumeration());
286 if (xEnumeration.is())
287 while (xEnumeration->hasMoreElements())
288 {
289 aNodeQueue.push(
290 uno::Reference<animations::XAnimationNode>(
291 xEnumeration->nextElement(), uno::UNO_QUERY));
292 }
293 }
294 }
295
296 return nMainSequenceNodeCount;
297
298 // // Skip all main sequence nodes.
299 // SkipSomeMainSequenceEffects(nMainSequenceNodeCount);
300 }
301
302
303
304
skipSomeMainSequenceEffects(sal_Int32 nSkipCount)305 void EffectRewinder::skipSomeMainSequenceEffects (sal_Int32 nSkipCount)
306 {
307 while (--nSkipCount >= 0)
308 skipSingleMainSequenceEffects();
309 }
310
311
312
313
skipSingleMainSequenceEffects(void)314 void EffectRewinder::skipSingleMainSequenceEffects (void)
315 {
316 // This basically just starts the next effect and then skips over its
317 // animation.
318 mrEventMultiplexer.notifyNextEffect();
319 mrEventQueue.forceEmpty();
320 mrUserEventQueue.callSkipEffectEventHandler();
321 mrEventQueue.forceEmpty();
322 }
323
324
325
326
resetEffectCount(void)327 bool EffectRewinder::resetEffectCount (void)
328 {
329 mnMainSequenceEffectCount = 0;
330 return false;
331 }
332
333
334
335
notifyAnimationStart(const AnimationNodeSharedPtr & rpNode)336 bool EffectRewinder::notifyAnimationStart (const AnimationNodeSharedPtr& rpNode)
337 {
338 // This notification is only relevant for us when the rpNode belongs to
339 // the main sequence.
340 BaseNodeSharedPtr pBaseNode (::boost::dynamic_pointer_cast<BaseNode>(rpNode));
341 if ( ! pBaseNode)
342 return false;
343
344 BaseContainerNodeSharedPtr pParent (pBaseNode->getParentNode());
345 if ( ! (pParent && pParent->isMainSequenceRootNode()))
346 return false;
347
348 // This notification is only relevant for us when the effect is user
349 // triggered.
350 bool bIsUserTriggered (false);
351
352 Reference<animations::XAnimationNode> xNode (rpNode->getXAnimationNode());
353 if (xNode.is())
354 {
355 animations::Event aEvent;
356 if ((xNode->getBegin() >>= aEvent))
357 bIsUserTriggered = (aEvent.Trigger == animations::EventTrigger::ON_NEXT);
358 }
359
360 if (bIsUserTriggered)
361 ++mnMainSequenceEffectCount;
362 else
363 mbNonUserTriggeredMainSequenceEffectSeen = true;
364
365 return false;
366 }
367
368
369
370
asynchronousRewind(sal_Int32 nEffectCount,const bool bRedisplayCurrentSlide,const boost::function<void (void)> & rSlideRewindFunctor)371 void EffectRewinder::asynchronousRewind (
372 sal_Int32 nEffectCount,
373 const bool bRedisplayCurrentSlide,
374 const boost::function<void(void)>& rSlideRewindFunctor)
375 {
376 OSL_ASSERT(mpAsynchronousRewindEvent);
377
378 if (bRedisplayCurrentSlide)
379 {
380 mpPaintLock->Activate();
381 // Re-display the current slide.
382 if (rSlideRewindFunctor)
383 rSlideRewindFunctor();
384 mpAsynchronousRewindEvent = makeEvent(
385 ::boost::bind(
386 &EffectRewinder::asynchronousRewind,
387 this,
388 nEffectCount,
389 false,
390 rSlideRewindFunctor),
391 "EffectRewinder::asynchronousRewind");
392 mrEventQueue.addEvent(mpAsynchronousRewindEvent);
393 }
394 else
395 {
396 // Process initial events and skip any animations that are started
397 // when the slide is shown.
398 mbNonUserTriggeredMainSequenceEffectSeen = false;
399 mrEventQueue.forceEmpty();
400 if (mbNonUserTriggeredMainSequenceEffectSeen)
401 {
402 mrUserEventQueue.callSkipEffectEventHandler();
403 mrEventQueue.forceEmpty();
404 }
405
406 while (--nEffectCount >= 0)
407 skipSingleMainSequenceEffects();
408
409 mpAsynchronousRewindEvent.reset();
410 mpPaintLock.reset();
411 }
412 }
413
414
415
416
asynchronousRewindToPreviousSlide(const::boost::function<void (void)> & rSlideRewindFunctor)417 void EffectRewinder::asynchronousRewindToPreviousSlide (
418 const ::boost::function<void(void)>& rSlideRewindFunctor)
419 {
420 OSL_ASSERT(mpAsynchronousRewindEvent);
421
422 mpAsynchronousRewindEvent.reset();
423 rSlideRewindFunctor();
424 }
425
426
427
428
429 } } // end of namespace ::slideshow::internal
430