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