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