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 : : // must be first
22 : : #include <canvas/debug.hxx>
23 : : #include <canvas/verbosetrace.hxx>
24 : :
25 : : #include <com/sun/star/animations/XAnimate.hpp>
26 : : #include <com/sun/star/presentation/ParagraphTarget.hpp>
27 : : #include <com/sun/star/animations/AnimationFill.hpp>
28 : : #include <com/sun/star/animations/AnimationRestart.hpp>
29 : : #include <com/sun/star/presentation/EffectNodeType.hpp>
30 : : #include <com/sun/star/beans/XPropertySet.hpp>
31 : :
32 : : #include "basenode.hxx"
33 : : #include "eventmultiplexer.hxx"
34 : : #include "basecontainernode.hxx"
35 : : #include "eventqueue.hxx"
36 : : #include "delayevent.hxx"
37 : : #include "tools.hxx"
38 : : #include "nodetools.hxx"
39 : : #include "generateevent.hxx"
40 : :
41 : : #include <boost/bind.hpp>
42 : : #include <vector>
43 : : #include <algorithm>
44 : : #include <iterator>
45 : :
46 : : using namespace ::com::sun::star;
47 : :
48 : : namespace slideshow {
49 : : namespace internal {
50 : :
51 : : namespace {
52 : :
53 : : typedef int StateTransitionTable[17];
54 : :
55 : : // State transition tables
56 : : // =========================================================================
57 : :
58 : 0 : const int* getStateTransitionTable( sal_Int16 nRestartMode,
59 : : sal_Int16 nFillMode )
60 : : {
61 : : // TODO(F2): restart issues in below tables
62 : :
63 : : // transition table for restart=NEVER, fill=REMOVE
64 : : static const StateTransitionTable stateTransitionTable_Never_Remove = {
65 : : AnimationNode::INVALID,
66 : : AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED
67 : : AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED
68 : : AnimationNode::INVALID,
69 : : AnimationNode::ENDED, // active successors for ACTIVE: no freeze here
70 : : AnimationNode::INVALID,
71 : : AnimationNode::INVALID,
72 : : AnimationNode::INVALID,
73 : : AnimationNode::INVALID, // active successors for FROZEN: this state is unreachable here
74 : : AnimationNode::INVALID,
75 : : AnimationNode::INVALID,
76 : : AnimationNode::INVALID,
77 : : AnimationNode::INVALID,
78 : : AnimationNode::INVALID,
79 : : AnimationNode::INVALID,
80 : : AnimationNode::INVALID,
81 : : AnimationNode::ENDED // active successors for ENDED: this state is a sink here (cannot restart)
82 : : };
83 : :
84 : : // transition table for restart=WHEN_NOT_ACTIVE, fill=REMOVE
85 : : static const StateTransitionTable stateTransitionTable_NotActive_Remove = {
86 : : AnimationNode::INVALID,
87 : : AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED
88 : : AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED
89 : : AnimationNode::INVALID,
90 : : AnimationNode::ENDED, // active successors for ACTIVE: no freeze here
91 : : AnimationNode::INVALID,
92 : : AnimationNode::INVALID,
93 : : AnimationNode::INVALID,
94 : : AnimationNode::INVALID, // active successors for FROZEN:
95 : : // this state is unreachable here
96 : : AnimationNode::INVALID,
97 : : AnimationNode::INVALID,
98 : : AnimationNode::INVALID,
99 : : AnimationNode::INVALID,
100 : : AnimationNode::INVALID,
101 : : AnimationNode::INVALID,
102 : : AnimationNode::INVALID,
103 : : AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE // active successors for ENDED:
104 : : // restart possible when ended
105 : : };
106 : :
107 : : // transition table for restart=ALWAYS, fill=REMOVE
108 : : static const StateTransitionTable stateTransitionTable_Always_Remove = {
109 : : AnimationNode::INVALID,
110 : : AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED
111 : : AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED
112 : : AnimationNode::INVALID,
113 : : AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED, // active successors for ACTIVE: restart
114 : : AnimationNode::INVALID,
115 : : AnimationNode::INVALID,
116 : : AnimationNode::INVALID,
117 : : AnimationNode::INVALID, // active successors for FROZEN:
118 : : // this state is unreachable here
119 : : AnimationNode::INVALID,
120 : : AnimationNode::INVALID,
121 : : AnimationNode::INVALID,
122 : : AnimationNode::INVALID,
123 : : AnimationNode::INVALID,
124 : : AnimationNode::INVALID,
125 : : AnimationNode::INVALID,
126 : : AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED // active successors for ENDED: restart
127 : : };
128 : :
129 : : // transition table for restart=NEVER, fill=FREEZE
130 : : static const StateTransitionTable stateTransitionTable_Never_Freeze = {
131 : : AnimationNode::INVALID,
132 : : AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED
133 : : AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED
134 : : AnimationNode::INVALID,
135 : : AnimationNode::FROZEN|AnimationNode::ENDED, // active successors for ACTIVE: freeze object
136 : : AnimationNode::INVALID,
137 : : AnimationNode::INVALID,
138 : : AnimationNode::INVALID,
139 : : AnimationNode::ENDED, // active successors for FROZEN: end
140 : : AnimationNode::INVALID,
141 : : AnimationNode::INVALID,
142 : : AnimationNode::INVALID,
143 : : AnimationNode::INVALID,
144 : : AnimationNode::INVALID,
145 : : AnimationNode::INVALID,
146 : : AnimationNode::INVALID,
147 : : AnimationNode::ENDED, // active successors for ENDED: this state is a sink here (cannot restart)
148 : : };
149 : :
150 : : // transition table for restart=WHEN_NOT_ACTIVE, fill=FREEZE
151 : : static const StateTransitionTable stateTransitionTable_NotActive_Freeze = {
152 : : AnimationNode::INVALID,
153 : : AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED
154 : : AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED
155 : : AnimationNode::INVALID,
156 : : AnimationNode::FROZEN|AnimationNode::ENDED, // active successors for ACTIVE: freeze object
157 : : AnimationNode::INVALID,
158 : : AnimationNode::INVALID,
159 : : AnimationNode::INVALID,
160 : : AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE, // active successors for FROZEN:
161 : : // restart possible when ended
162 : : AnimationNode::INVALID,
163 : : AnimationNode::INVALID,
164 : : AnimationNode::INVALID,
165 : : AnimationNode::INVALID,
166 : : AnimationNode::INVALID,
167 : : AnimationNode::INVALID,
168 : : AnimationNode::INVALID,
169 : : AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE // active successors for ENDED:
170 : : // restart possible when ended
171 : : };
172 : :
173 : : // transition table for restart=ALWAYS, fill=FREEZE
174 : : static const StateTransitionTable stateTransitionTable_Always_Freeze = {
175 : : AnimationNode::INVALID,
176 : : AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED
177 : : AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED
178 : : AnimationNode::INVALID,
179 : : AnimationNode::FROZEN|AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED, // active successors for ACTIVE:
180 : : // end object, restart
181 : : AnimationNode::INVALID,
182 : : AnimationNode::INVALID,
183 : : AnimationNode::INVALID,
184 : : AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE, // active successors for FROZEN: restart possible
185 : : AnimationNode::INVALID,
186 : : AnimationNode::INVALID,
187 : : AnimationNode::INVALID,
188 : : AnimationNode::INVALID,
189 : : AnimationNode::INVALID,
190 : : AnimationNode::INVALID,
191 : : AnimationNode::INVALID,
192 : : AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED // active successors for ENDED: restart
193 : : };
194 : :
195 : : static const StateTransitionTable* tableGuide[] = {
196 : : &stateTransitionTable_Never_Remove,
197 : : &stateTransitionTable_NotActive_Remove,
198 : : &stateTransitionTable_Always_Remove,
199 : : &stateTransitionTable_Never_Freeze,
200 : : &stateTransitionTable_NotActive_Freeze,
201 : : &stateTransitionTable_Always_Freeze
202 : : };
203 : :
204 : : int nRestartValue;
205 : 0 : switch( nRestartMode ) {
206 : : default:
207 : : case animations::AnimationRestart::DEFAULT:
208 : : // same value: animations::AnimationRestart::INHERIT:
209 : : OSL_FAIL(
210 : : "getStateTransitionTable(): unexpected case for restart" );
211 : : // FALLTHROUGH intended
212 : : case animations::AnimationRestart::NEVER:
213 : 0 : nRestartValue = 0;
214 : 0 : break;
215 : : case animations::AnimationRestart::WHEN_NOT_ACTIVE:
216 : 0 : nRestartValue = 1;
217 : 0 : break;
218 : : case animations::AnimationRestart::ALWAYS:
219 : 0 : nRestartValue = 2;
220 : 0 : break;
221 : : }
222 : :
223 : : int nFillValue;
224 : 0 : switch( nFillMode ) {
225 : : default:
226 : : case animations::AnimationFill::AUTO:
227 : : case animations::AnimationFill::DEFAULT:
228 : : // same value: animations::AnimationFill::INHERIT:
229 : : OSL_FAIL(
230 : : "getStateTransitionTable(): unexpected case for fill" );
231 : : // FALLTHROUGH intended
232 : : case animations::AnimationFill::REMOVE:
233 : 0 : nFillValue = 0;
234 : 0 : break;
235 : : case animations::AnimationFill::FREEZE:
236 : : case animations::AnimationFill::HOLD:
237 : : case animations::AnimationFill::TRANSITION:
238 : 0 : nFillValue = 1;
239 : 0 : break;
240 : : }
241 : :
242 : 0 : return *tableGuide[ 3*nFillValue + nRestartValue ];
243 : : }
244 : :
245 : : /// Little helper predicate, to detect main sequence root node
246 : 0 : bool isMainSequenceRootNode_(
247 : : const uno::Reference< animations::XAnimationNode >& xNode )
248 : : {
249 : : // detect main sequence root node (need that for
250 : : // end-of-mainsequence signalling below)
251 : : beans::NamedValue const aSearchKey(
252 : : rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) ),
253 : 0 : uno::makeAny( presentation::EffectNodeType::MAIN_SEQUENCE ) );
254 : :
255 : 0 : uno::Sequence<beans::NamedValue> const userData(xNode->getUserData());
256 : 0 : return findNamedValue( userData, aSearchKey );
257 : : }
258 : :
259 : : } // anon namespace
260 : :
261 : : // BaseNode implementation
262 : : //=========================================================================
263 : :
264 : : /** state transition handling
265 : : */
266 : : class BaseNode::StateTransition : private boost::noncopyable
267 : : {
268 : : public:
269 : : enum Options { NONE, FORCE };
270 : :
271 : 0 : explicit StateTransition( BaseNode * pNode )
272 : 0 : : mpNode(pNode), meToState(INVALID) {}
273 : :
274 : 0 : ~StateTransition() {
275 : 0 : clear();
276 : 0 : }
277 : :
278 : 0 : bool enter( NodeState eToState, int options = NONE )
279 : : {
280 : : OSL_ENSURE( meToState == INVALID,
281 : : "### commit() before enter()ing again!" );
282 : 0 : if (meToState != INVALID)
283 : 0 : return false;
284 : 0 : bool const bForce = ((options & FORCE) != 0);
285 : 0 : if (!bForce && !mpNode->isTransition( mpNode->meCurrState, eToState ))
286 : 0 : return false;
287 : : // recursion detection:
288 : 0 : if ((mpNode->meCurrentStateTransition & eToState) != 0)
289 : 0 : return false; // already in wanted transition
290 : : // mark transition:
291 : 0 : mpNode->meCurrentStateTransition |= eToState;
292 : 0 : meToState = eToState;
293 : 0 : return true; // in transition
294 : : }
295 : :
296 : 0 : void commit() {
297 : : OSL_ENSURE( meToState != INVALID, "### nothing to commit!" );
298 : 0 : if (meToState != INVALID) {
299 : 0 : mpNode->meCurrState = meToState;
300 : 0 : clear();
301 : : }
302 : 0 : }
303 : :
304 : 0 : void clear() {
305 : 0 : if (meToState != INVALID) {
306 : : OSL_ASSERT( (mpNode->meCurrentStateTransition & meToState) != 0 );
307 : 0 : mpNode->meCurrentStateTransition &= ~meToState;
308 : 0 : meToState = INVALID;
309 : : }
310 : 0 : }
311 : :
312 : : private:
313 : : BaseNode *const mpNode;
314 : : NodeState meToState;
315 : : };
316 : :
317 : 0 : BaseNode::BaseNode( const uno::Reference< animations::XAnimationNode >& xNode,
318 : : const BaseContainerNodeSharedPtr& rParent,
319 : : const NodeContext& rContext ) :
320 : : maContext( rContext.maContext ),
321 : : maDeactivatingListeners(),
322 : : mxAnimationNode( xNode ),
323 : : mpParent( rParent ),
324 : : mpSelf(),
325 : : mpStateTransitionTable( NULL ),
326 : : mnStartDelay( rContext.mnStartDelay ),
327 : : meCurrState( UNRESOLVED ),
328 : : meCurrentStateTransition( 0 ),
329 : : mpCurrentEvent(),
330 : 0 : mbIsMainSequenceRootNode( isMainSequenceRootNode_( xNode ) )
331 : : {
332 : 0 : ENSURE_OR_THROW( mxAnimationNode.is(),
333 : : "BaseNode::BaseNode(): Invalid XAnimationNode" );
334 : :
335 : : // setup state transition table
336 : 0 : mpStateTransitionTable = getStateTransitionTable( getRestartMode(),
337 : 0 : getFillMode() );
338 : 0 : }
339 : :
340 : 0 : void BaseNode::dispose()
341 : : {
342 : 0 : meCurrState = INVALID;
343 : :
344 : : // discharge a loaded event, if any:
345 : 0 : if (mpCurrentEvent) {
346 : 0 : mpCurrentEvent->dispose();
347 : 0 : mpCurrentEvent.reset();
348 : : }
349 : 0 : maDeactivatingListeners.clear();
350 : 0 : mxAnimationNode.clear();
351 : 0 : mpParent.reset();
352 : 0 : mpSelf.reset();
353 : 0 : maContext.dispose();
354 : 0 : }
355 : :
356 : :
357 : 0 : sal_Int16 BaseNode::getRestartMode()
358 : : {
359 : 0 : const sal_Int16 nTmp( mxAnimationNode->getRestart() );
360 : : return (nTmp != animations::AnimationRestart::DEFAULT &&
361 : : nTmp != animations::AnimationRestart::INHERIT)
362 : 0 : ? nTmp : getRestartDefaultMode();
363 : : }
364 : :
365 : 0 : sal_Int16 BaseNode::getFillMode()
366 : : {
367 : 0 : const sal_Int16 nTmp( mxAnimationNode->getFill() );
368 : : const sal_Int16 nFill((nTmp != animations::AnimationFill::DEFAULT &&
369 : : nTmp != animations::AnimationFill::INHERIT)
370 : 0 : ? nTmp : getFillDefaultMode());
371 : :
372 : : // For AUTO fill mode, SMIL specifies that fill mode is FREEZE,
373 : : // if no explicit active duration is given
374 : : // (no duration, end, repeatCount or repeatDuration given),
375 : : // and REMOVE otherwise
376 : 0 : if( nFill == animations::AnimationFill::AUTO ) {
377 : 0 : return (isIndefiniteTiming( mxAnimationNode->getDuration() ) &&
378 : 0 : isIndefiniteTiming( mxAnimationNode->getEnd() ) &&
379 : 0 : !mxAnimationNode->getRepeatCount().hasValue() &&
380 : 0 : isIndefiniteTiming( mxAnimationNode->getRepeatDuration() ))
381 : : ? animations::AnimationFill::FREEZE
382 : 0 : : animations::AnimationFill::REMOVE;
383 : : }
384 : : else {
385 : 0 : return nFill;
386 : : }
387 : : }
388 : :
389 : 0 : sal_Int16 BaseNode::getFillDefaultMode() const
390 : : {
391 : 0 : sal_Int16 nFillDefault = mxAnimationNode->getFillDefault();
392 : 0 : if (nFillDefault == animations::AnimationFill::DEFAULT) {
393 : 0 : nFillDefault = (mpParent != 0
394 : 0 : ? mpParent->getFillDefaultMode()
395 : 0 : : animations::AnimationFill::AUTO);
396 : : }
397 : 0 : return nFillDefault;
398 : : }
399 : :
400 : 0 : sal_Int16 BaseNode::getRestartDefaultMode() const
401 : : {
402 : 0 : sal_Int16 nRestartDefaultMode = mxAnimationNode->getRestartDefault();
403 : 0 : if (nRestartDefaultMode == animations::AnimationRestart::DEFAULT) {
404 : 0 : nRestartDefaultMode = (mpParent != 0
405 : 0 : ? mpParent->getRestartDefaultMode()
406 : 0 : : animations::AnimationRestart::ALWAYS);
407 : : }
408 : 0 : return nRestartDefaultMode;
409 : : }
410 : :
411 : 0 : uno::Reference<animations::XAnimationNode> BaseNode::getXAnimationNode() const
412 : : {
413 : 0 : return mxAnimationNode;
414 : : }
415 : :
416 : 0 : bool BaseNode::init()
417 : : {
418 : 0 : if (! checkValidNode())
419 : 0 : return false;
420 : 0 : meCurrState = UNRESOLVED;
421 : : // discharge a loaded event, if any:
422 : 0 : if (mpCurrentEvent) {
423 : 0 : mpCurrentEvent->dispose();
424 : 0 : mpCurrentEvent.reset();
425 : : }
426 : 0 : return init_st(); // may call derived class
427 : : }
428 : :
429 : 0 : bool BaseNode::init_st()
430 : : {
431 : 0 : return true;
432 : : }
433 : :
434 : 0 : bool BaseNode::resolve()
435 : : {
436 : 0 : if (! checkValidNode())
437 : 0 : return false;
438 : :
439 : : OSL_ASSERT( meCurrState != RESOLVED );
440 : 0 : if (inStateOrTransition( RESOLVED ))
441 : 0 : return true;
442 : :
443 : 0 : StateTransition st(this);
444 : 0 : if (st.enter( RESOLVED ) &&
445 : 0 : isTransition( RESOLVED, ACTIVE ) &&
446 : 0 : resolve_st() /* may call derived class */)
447 : : {
448 : 0 : st.commit(); // changing state
449 : :
450 : : // discharge a loaded event, if any:
451 : 0 : if (mpCurrentEvent)
452 : 0 : mpCurrentEvent->dispose();
453 : :
454 : : // schedule activation event:
455 : :
456 : : // This method takes the NodeContext::mnStartDelay value into account,
457 : : // to cater for iterate container time shifts. We cannot put different
458 : : // iterations of the iterate container's children into different
459 : : // subcontainer (such as a 'DelayContainer', which delays resolving its
460 : : // children by a fixed amount), since all iterations' nodes must be
461 : : // resolved at the same time (otherwise, the delayed subset creation
462 : : // will not work, i.e. deactivate the subsets too late in the master
463 : : // shape).
464 : 0 : uno::Any const aBegin( mxAnimationNode->getBegin() );
465 : 0 : if (aBegin.hasValue()) {
466 : : mpCurrentEvent = generateEvent(
467 : : aBegin, boost::bind( &AnimationNode::activate, mpSelf ),
468 : 0 : maContext, mnStartDelay );
469 : : }
470 : : else {
471 : : // For some leaf nodes, PPT import yields empty begin time,
472 : : // although semantically, it should be 0.0
473 : : // TODO(F3): That should really be provided by the PPT import
474 : :
475 : : // schedule delayed activation event. Take iterate node
476 : : // timeout into account
477 : 0 : mpCurrentEvent = makeDelay(
478 : : boost::bind( &AnimationNode::activate, mpSelf ),
479 : : mnStartDelay,
480 : 0 : "AnimationNode::activate with delay");
481 : 0 : maContext.mrEventQueue.addEvent( mpCurrentEvent );
482 : : }
483 : :
484 : 0 : return true;
485 : : }
486 : 0 : return false;
487 : : }
488 : :
489 : 0 : bool BaseNode::resolve_st()
490 : : {
491 : 0 : return true;
492 : : }
493 : :
494 : :
495 : 0 : bool BaseNode::activate()
496 : : {
497 : 0 : if (! checkValidNode())
498 : 0 : return false;
499 : :
500 : : OSL_ASSERT( meCurrState != ACTIVE );
501 : 0 : if (inStateOrTransition( ACTIVE ))
502 : 0 : return true;
503 : :
504 : 0 : StateTransition st(this);
505 : 0 : if (st.enter( ACTIVE )) {
506 : :
507 : 0 : activate_st(); // calling derived class
508 : :
509 : 0 : st.commit(); // changing state
510 : :
511 : 0 : maContext.mrEventMultiplexer.notifyAnimationStart( mpSelf );
512 : :
513 : 0 : return true;
514 : : }
515 : :
516 : 0 : return false;
517 : : }
518 : :
519 : 0 : void BaseNode::activate_st()
520 : : {
521 : 0 : scheduleDeactivationEvent();
522 : 0 : }
523 : :
524 : 0 : void BaseNode::scheduleDeactivationEvent( EventSharedPtr const& pEvent )
525 : : {
526 : 0 : if (mpCurrentEvent) {
527 : 0 : mpCurrentEvent->dispose();
528 : 0 : mpCurrentEvent.reset();
529 : : }
530 : 0 : if (pEvent) {
531 : 0 : if (maContext.mrEventQueue.addEvent( pEvent ))
532 : 0 : mpCurrentEvent = pEvent;
533 : : }
534 : : else {
535 : : // This method need not take the
536 : : // NodeContext::mnStartDelay value into account,
537 : : // because the deactivation event is only scheduled
538 : : // when the effect is started: the timeout is then
539 : : // already respected.
540 : :
541 : : // xxx todo:
542 : : // think about set node, anim base node!
543 : : // if anim base node has no activity, this is called to schedule deactivatiion,
544 : : // but what if it does not schedule anything?
545 : :
546 : : // TODO(F2): Handle end time attribute, too
547 : : mpCurrentEvent = generateEvent(
548 : 0 : mxAnimationNode->getDuration(),
549 : : boost::bind( &AnimationNode::deactivate, mpSelf ),
550 : 0 : maContext, 0.0 );
551 : : }
552 : 0 : }
553 : :
554 : 0 : void BaseNode::deactivate()
555 : : {
556 : 0 : if (inStateOrTransition( ENDED | FROZEN ) || !checkValidNode())
557 : 0 : return;
558 : :
559 : 0 : if (isTransition( meCurrState, FROZEN, false /* no OSL_ASSERT */ )) {
560 : : // do transition to FROZEN:
561 : 0 : StateTransition st(this);
562 : 0 : if (st.enter( FROZEN, StateTransition::FORCE )) {
563 : :
564 : 0 : deactivate_st( FROZEN );
565 : 0 : st.commit();
566 : :
567 : 0 : notifyEndListeners();
568 : :
569 : : // discharge a loaded event, before going on:
570 : 0 : if (mpCurrentEvent) {
571 : 0 : mpCurrentEvent->dispose();
572 : 0 : mpCurrentEvent.reset();
573 : : }
574 : 0 : }
575 : : }
576 : : else {
577 : : // use end instead:
578 : 0 : end();
579 : : }
580 : : // state has changed either to FROZEN or ENDED
581 : : }
582 : :
583 : 0 : void BaseNode::deactivate_st( NodeState )
584 : : {
585 : 0 : }
586 : :
587 : 0 : void BaseNode::end()
588 : : {
589 : 0 : bool const bIsFrozenOrInTransitionToFrozen = inStateOrTransition( FROZEN );
590 : 0 : if (inStateOrTransition( ENDED ) || !checkValidNode())
591 : 0 : return;
592 : :
593 : : // END must always be reachable. If not, that's an error in the
594 : : // transition tables
595 : : OSL_ENSURE( isTransition( meCurrState, ENDED ),
596 : : "end state not reachable in transition table" );
597 : :
598 : 0 : StateTransition st(this);
599 : 0 : if (st.enter( ENDED, StateTransition::FORCE )) {
600 : :
601 : 0 : deactivate_st( ENDED );
602 : 0 : st.commit(); // changing state
603 : :
604 : : // if is FROZEN or is to be FROZEN, then
605 : : // will/already notified deactivating listeners
606 : 0 : if (!bIsFrozenOrInTransitionToFrozen)
607 : 0 : notifyEndListeners();
608 : :
609 : : // discharge a loaded event, before going on:
610 : 0 : if (mpCurrentEvent) {
611 : 0 : mpCurrentEvent->dispose();
612 : 0 : mpCurrentEvent.reset();
613 : : }
614 : 0 : }
615 : : }
616 : :
617 : 0 : void BaseNode::notifyDeactivating( const AnimationNodeSharedPtr& rNotifier )
618 : : {
619 : : (void) rNotifier; // avoid warning
620 : : OSL_ASSERT( rNotifier->getState() == FROZEN ||
621 : : rNotifier->getState() == ENDED );
622 : : // TODO(F1): for end sync functionality, this might indeed be used some day
623 : 0 : }
624 : :
625 : 0 : void BaseNode::notifyEndListeners() const
626 : : {
627 : : // notify all listeners
628 : : std::for_each( maDeactivatingListeners.begin(),
629 : : maDeactivatingListeners.end(),
630 : : boost::bind( &AnimationNode::notifyDeactivating, _1,
631 : 0 : boost::cref(mpSelf) ) );
632 : :
633 : : // notify state change
634 : 0 : maContext.mrEventMultiplexer.notifyAnimationEnd( mpSelf );
635 : :
636 : : // notify main sequence end (iff we're the main
637 : : // sequence root node). This is because the main
638 : : // sequence determines the active duration of the
639 : : // slide. All other sequences are secondary, in that
640 : : // they don't prevent a slide change from happening,
641 : : // even if they have not been completed. In other
642 : : // words, all sequences except the main sequence are
643 : : // optional for the slide lifetime.
644 : 0 : if (isMainSequenceRootNode())
645 : 0 : maContext.mrEventMultiplexer.notifySlideAnimationsEnd();
646 : 0 : }
647 : :
648 : 0 : AnimationNode::NodeState BaseNode::getState() const
649 : : {
650 : 0 : return meCurrState;
651 : : }
652 : :
653 : 0 : bool BaseNode::registerDeactivatingListener(
654 : : const AnimationNodeSharedPtr& rNotifee )
655 : : {
656 : 0 : if (! checkValidNode())
657 : 0 : return false;
658 : :
659 : 0 : ENSURE_OR_RETURN_FALSE(
660 : : rNotifee,
661 : : "BaseNode::registerDeactivatingListener(): invalid notifee" );
662 : 0 : maDeactivatingListeners.push_back( rNotifee );
663 : :
664 : 0 : return true;
665 : : }
666 : :
667 : 0 : void BaseNode::setSelf( const BaseNodeSharedPtr& rSelf )
668 : : {
669 : 0 : ENSURE_OR_THROW( rSelf.get() == this,
670 : : "BaseNode::setSelf(): got ptr to different object" );
671 : 0 : ENSURE_OR_THROW( !mpSelf,
672 : : "BaseNode::setSelf(): called multiple times" );
673 : :
674 : 0 : mpSelf = rSelf;
675 : 0 : }
676 : :
677 : : // Debug
678 : : //=========================================================================
679 : :
680 : : #if OSL_DEBUG_LEVEL >= 2 && defined(DBG_UTIL)
681 : : void BaseNode::showState() const
682 : : {
683 : : const AnimationNode::NodeState eNodeState( getState() );
684 : :
685 : : if( eNodeState == AnimationNode::INVALID )
686 : : VERBOSE_TRACE( "Node state: n0x%X [label=\"%s\",style=filled,"
687 : : "fillcolor=\"0.5,0.2,0.5\"]",
688 : : (const char*)this+debugGetCurrentOffset(),
689 : : getDescription() );
690 : : else
691 : : VERBOSE_TRACE( "Node state: n0x%X [label=\"%s\",style=filled,"
692 : : "fillcolor=\"%f,1.0,1.0\"]",
693 : : (const char*)this+debugGetCurrentOffset(),
694 : : getDescription(),
695 : : log(double(getState()))/4.0 );
696 : :
697 : : // determine additional node information
698 : : uno::Reference<animations::XAnimate> const xAnimate( mxAnimationNode,
699 : : uno::UNO_QUERY );
700 : : if( xAnimate.is() )
701 : : {
702 : : uno::Reference< drawing::XShape > xTargetShape( xAnimate->getTarget(),
703 : : uno::UNO_QUERY );
704 : :
705 : : if( !xTargetShape.is() )
706 : : {
707 : : ::com::sun::star::presentation::ParagraphTarget aTarget;
708 : :
709 : : // no shape provided. Maybe a ParagraphTarget?
710 : : if( (xAnimate->getTarget() >>= aTarget) )
711 : : xTargetShape = aTarget.Shape;
712 : : }
713 : :
714 : : if( xTargetShape.is() )
715 : : {
716 : : uno::Reference< beans::XPropertySet > xPropSet( xTargetShape,
717 : : uno::UNO_QUERY );
718 : :
719 : : // read shape name
720 : : ::rtl::OUString aName;
721 : : if( (xPropSet->getPropertyValue(
722 : : ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Name") ) )
723 : : >>= aName) )
724 : : {
725 : : const ::rtl::OString& rAsciiName(
726 : : ::rtl::OUStringToOString( aName,
727 : : RTL_TEXTENCODING_ASCII_US ) );
728 : :
729 : : VERBOSE_TRACE( "Node info: n0x%X, name \"%s\"",
730 : : (const char*)this+debugGetCurrentOffset(),
731 : : rAsciiName.getStr() );
732 : : }
733 : : }
734 : : }
735 : : }
736 : :
737 : : const char* BaseNode::getDescription() const
738 : : {
739 : : return "BaseNode";
740 : : }
741 : :
742 : : #endif
743 : :
744 : : } // namespace internal
745 : 0 : } // namespace slideshow
746 : :
747 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|