Branch data 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(void)> Action;
48 : 0 : RewinderEventHandler (const Action& rAction) : maAction(rAction) {}
49 : 0 : virtual ~RewinderEventHandler (void) {}
50 : : private:
51 : : const Action maAction;
52 : 0 : virtual bool handleEvent (void) { return maAction(); }
53 : : };
54 : :
55 : :
56 : :
57 : : class RewinderAnimationEventHandler : public AnimationEventHandler
58 : : {
59 : : public:
60 : : typedef ::boost::function<bool(const AnimationNodeSharedPtr& rpNode)> Action;
61 : 0 : RewinderAnimationEventHandler (const Action& rAction) : maAction(rAction) {}
62 : 0 : virtual ~RewinderAnimationEventHandler (void) {}
63 : : private:
64 : : const Action maAction;
65 : 0 : virtual bool handleAnimationEvent (const AnimationNodeSharedPtr& rpNode)
66 : 0 : { return maAction(rpNode); }
67 : : };
68 : :
69 : :
70 : :
71 : : } // end of anonymous namespace
72 : :
73 : :
74 : : //----- EffectRewinder --------------------------------------------------------------
75 : :
76 : 0 : 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 : 0 : mbNonUserTriggeredMainSequenceEffectSeen(false)
90 : : {
91 : 0 : initialize();
92 : 0 : }
93 : :
94 : :
95 : :
96 : :
97 : 0 : void EffectRewinder::initialize (void)
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 : 0 : ::boost::bind(&EffectRewinder::notifyAnimationStart, this, _1)));
108 : 0 : mrEventMultiplexer.addAnimationStartHandler(mpAnimationStartHandler);
109 : :
110 : : mpSlideStartHandler.reset(
111 : : new RewinderEventHandler(
112 : 0 : ::boost::bind(&EffectRewinder::resetEffectCount, this)));
113 : 0 : mrEventMultiplexer.addSlideStartHandler(mpSlideStartHandler);
114 : :
115 : : mpSlideEndHandler.reset(
116 : : new RewinderEventHandler(
117 : 0 : ::boost::bind(&EffectRewinder::resetEffectCount, this)));
118 : 0 : mrEventMultiplexer.addSlideEndHandler(mpSlideEndHandler);
119 : 0 : }
120 : :
121 : :
122 : :
123 : :
124 : 0 : EffectRewinder::~EffectRewinder (void)
125 : : {
126 : 0 : dispose();
127 : 0 : }
128 : :
129 : :
130 : :
131 : :
132 : 0 : void EffectRewinder::dispose (void)
133 : : {
134 : 0 : if (mpAsynchronousRewindEvent)
135 : : {
136 : 0 : mpAsynchronousRewindEvent->dispose();
137 : 0 : mpAsynchronousRewindEvent.reset();
138 : : }
139 : :
140 : 0 : if (mpAnimationStartHandler)
141 : : {
142 : 0 : mrEventMultiplexer.removeAnimationStartHandler(mpAnimationStartHandler);
143 : 0 : mpAnimationStartHandler.reset();
144 : : }
145 : :
146 : 0 : if (mpSlideStartHandler)
147 : : {
148 : 0 : mrEventMultiplexer.removeSlideStartHandler(mpSlideStartHandler);
149 : 0 : mpSlideStartHandler.reset();
150 : : }
151 : :
152 : 0 : if (mpSlideEndHandler)
153 : : {
154 : 0 : mrEventMultiplexer.removeSlideEndHandler(mpSlideEndHandler);
155 : 0 : mpSlideEndHandler.reset();
156 : : }
157 : 0 : }
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(void)>& rSlideRewindFunctor,
174 : : const ::boost::function<void(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 (void)
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(void)>()),
247 : 0 : "EffectRewinder::asynchronousRewind");
248 : 0 : mrEventQueue.addEvent(mpAsynchronousRewindEvent);
249 : : }
250 : :
251 : :
252 : :
253 : :
254 : 0 : sal_Int32 EffectRewinder::countMainSequenceEffects (void)
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 (void)
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 (void)
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(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(void)>& rSlideRewindFunctor)
402 : : {
403 : : OSL_ASSERT(mpAsynchronousRewindEvent);
404 : :
405 : 0 : mpAsynchronousRewindEvent.reset();
406 : 0 : rSlideRewindFunctor();
407 : 0 : }
408 : :
409 : :
410 : :
411 : :
412 : 0 : } } // end of namespace ::slideshow::internal
413 : :
414 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|