diff options
Diffstat (limited to 'slideshow/source/engine/animationnodes/basenode.cxx')
-rw-r--r-- | slideshow/source/engine/animationnodes/basenode.cxx | 769 |
1 files changed, 769 insertions, 0 deletions
diff --git a/slideshow/source/engine/animationnodes/basenode.cxx b/slideshow/source/engine/animationnodes/basenode.cxx new file mode 100644 index 000000000000..b0cfa99c34f5 --- /dev/null +++ b/slideshow/source/engine/animationnodes/basenode.cxx @@ -0,0 +1,769 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_slideshow.hxx" + +// must be first +#include <canvas/debug.hxx> +#include <canvas/verbosetrace.hxx> + +#include <com/sun/star/animations/XAnimate.hpp> +#include <com/sun/star/presentation/ParagraphTarget.hpp> +#include <com/sun/star/animations/AnimationFill.hpp> +#include <com/sun/star/animations/AnimationRestart.hpp> +#include <com/sun/star/presentation/EffectNodeType.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include "basenode.hxx" +#include "eventmultiplexer.hxx" +#include "basecontainernode.hxx" +#include "eventqueue.hxx" +#include "delayevent.hxx" +#include "tools.hxx" +#include "nodetools.hxx" +#include "generateevent.hxx" +#include "debug.hxx" + +#include <boost/bind.hpp> +#include <vector> +#include <algorithm> +#include <iterator> + +using namespace ::com::sun::star; + +namespace slideshow { +namespace internal { + +namespace { + +typedef int StateTransitionTable[17]; + +// State transition tables +// ========================================================================= + +const int* getStateTransitionTable( sal_Int16 nRestartMode, + sal_Int16 nFillMode ) +{ + // TODO(F2): restart issues in below tables + + // transition table for restart=NEVER, fill=REMOVE + static const StateTransitionTable stateTransitionTable_Never_Remove = { + AnimationNode::INVALID, + AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED + AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED + AnimationNode::INVALID, + AnimationNode::ENDED, // active successors for ACTIVE: no freeze here + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, // active successors for FROZEN: this state is unreachable here + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::ENDED // active successors for ENDED: this state is a sink here (cannot restart) + }; + + // transition table for restart=WHEN_NOT_ACTIVE, fill=REMOVE + static const StateTransitionTable stateTransitionTable_NotActive_Remove = { + AnimationNode::INVALID, + AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED + AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED + AnimationNode::INVALID, + AnimationNode::ENDED, // active successors for ACTIVE: no freeze here + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, // active successors for FROZEN: + // this state is unreachable here + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE // active successors for ENDED: + // restart possible when ended + }; + + // transition table for restart=ALWAYS, fill=REMOVE + static const StateTransitionTable stateTransitionTable_Always_Remove = { + AnimationNode::INVALID, + AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED + AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED + AnimationNode::INVALID, + AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED, // active successors for ACTIVE: restart + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, // active successors for FROZEN: + // this state is unreachable here + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED // active successors for ENDED: restart + }; + + // transition table for restart=NEVER, fill=FREEZE + static const StateTransitionTable stateTransitionTable_Never_Freeze = { + AnimationNode::INVALID, + AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED + AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED + AnimationNode::INVALID, + AnimationNode::FROZEN|AnimationNode::ENDED, // active successors for ACTIVE: freeze object + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::ENDED, // active successors for FROZEN: end + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::ENDED, // active successors for ENDED: this state is a sink here (cannot restart) + }; + + // transition table for restart=WHEN_NOT_ACTIVE, fill=FREEZE + static const StateTransitionTable stateTransitionTable_NotActive_Freeze = { + AnimationNode::INVALID, + AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED + AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED + AnimationNode::INVALID, + AnimationNode::FROZEN|AnimationNode::ENDED, // active successors for ACTIVE: freeze object + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE, // active successors for FROZEN: + // restart possible when ended + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE // active successors for ENDED: + // restart possible when ended + }; + + // transition table for restart=ALWAYS, fill=FREEZE + static const StateTransitionTable stateTransitionTable_Always_Freeze = { + AnimationNode::INVALID, + AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED + AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED + AnimationNode::INVALID, + AnimationNode::FROZEN|AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED, // active successors for ACTIVE: + // end object, restart + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE, // active successors for FROZEN: restart possible + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::INVALID, + AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED // active successors for ENDED: restart + }; + + static const StateTransitionTable* tableGuide[] = { + &stateTransitionTable_Never_Remove, + &stateTransitionTable_NotActive_Remove, + &stateTransitionTable_Always_Remove, + &stateTransitionTable_Never_Freeze, + &stateTransitionTable_NotActive_Freeze, + &stateTransitionTable_Always_Freeze + }; + + int nRestartValue; + switch( nRestartMode ) { + default: + case animations::AnimationRestart::DEFAULT: + // same value: animations::AnimationRestart::INHERIT: + OSL_ENSURE( + false, "getStateTransitionTable(): unexpected case for restart" ); + // FALLTHROUGH intended + case animations::AnimationRestart::NEVER: + nRestartValue = 0; + break; + case animations::AnimationRestart::WHEN_NOT_ACTIVE: + nRestartValue = 1; + break; + case animations::AnimationRestart::ALWAYS: + nRestartValue = 2; + break; + } + + int nFillValue; + switch( nFillMode ) { + default: + case animations::AnimationFill::AUTO: + case animations::AnimationFill::DEFAULT: + // same value: animations::AnimationFill::INHERIT: + OSL_ENSURE( + false, "getStateTransitionTable(): unexpected case for fill" ); + // FALLTHROUGH intended + case animations::AnimationFill::REMOVE: + nFillValue = 0; + break; + case animations::AnimationFill::FREEZE: + case animations::AnimationFill::HOLD: + case animations::AnimationFill::TRANSITION: + nFillValue = 1; + break; + } + + return *tableGuide[ 3*nFillValue + nRestartValue ]; +} + +/// Little helper predicate, to detect main sequence root node +bool isMainSequenceRootNode_( + const uno::Reference< animations::XAnimationNode >& xNode ) +{ + // detect main sequence root node (need that for + // end-of-mainsequence signalling below) + beans::NamedValue const aSearchKey( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) ), + uno::makeAny( presentation::EffectNodeType::MAIN_SEQUENCE ) ); + + uno::Sequence<beans::NamedValue> const userData(xNode->getUserData()); + return findNamedValue( userData, aSearchKey ); +} + +} // anon namespace + +// BaseNode implementation +//========================================================================= + +/** state transition handling + */ +class BaseNode::StateTransition : private boost::noncopyable +{ +public: + enum Options { NONE, FORCE }; + + explicit StateTransition( BaseNode * pNode ) + : mpNode(pNode), meToState(INVALID) {} + + ~StateTransition() { + clear(); + } + + bool enter( NodeState eToState, int options = NONE ) + { + OSL_ENSURE( meToState == INVALID, + "### commit() before enter()ing again!" ); + if (meToState != INVALID) + return false; + bool const bForce = ((options & FORCE) != 0); + if (!bForce && !mpNode->isTransition( mpNode->meCurrState, eToState )) + return false; + // recursion detection: + if ((mpNode->meCurrentStateTransition & eToState) != 0) + return false; // already in wanted transition + // mark transition: + mpNode->meCurrentStateTransition |= eToState; + meToState = eToState; + return true; // in transition + } + + void commit() { + OSL_ENSURE( meToState != INVALID, "### nothing to commit!" ); + if (meToState != INVALID) { + mpNode->meCurrState = meToState; + clear(); + } + + // Uncomment the following line to write the node tree to file on + // every state change of one of its nodes. + // Debug_ShowNodeTree(mpNode->mpSelf); + } + + void clear() { + if (meToState != INVALID) { + OSL_ASSERT( (mpNode->meCurrentStateTransition & meToState) != 0 ); + mpNode->meCurrentStateTransition &= ~meToState; + meToState = INVALID; + } + } + +private: + BaseNode *const mpNode; + NodeState meToState; +}; + +BaseNode::BaseNode( const uno::Reference< animations::XAnimationNode >& xNode, + const BaseContainerNodeSharedPtr& rParent, + const NodeContext& rContext ) : + maContext( rContext.maContext ), + maDeactivatingListeners(), + mxAnimationNode( xNode ), + mpParent( rParent ), + mpSelf(), + mpStateTransitionTable( NULL ), + mnStartDelay( rContext.mnStartDelay ), + meCurrState( UNRESOLVED ), + meCurrentStateTransition( 0 ), + mpCurrentEvent(), + mbIsMainSequenceRootNode( isMainSequenceRootNode_( xNode ) ) +{ + ENSURE_OR_THROW( mxAnimationNode.is(), + "BaseNode::BaseNode(): Invalid XAnimationNode" ); + + // setup state transition table + mpStateTransitionTable = getStateTransitionTable( getRestartMode(), + getFillMode() ); +} + +void BaseNode::dispose() +{ + meCurrState = INVALID; + + // discharge a loaded event, if any: + if (mpCurrentEvent) { + mpCurrentEvent->dispose(); + mpCurrentEvent.reset(); + } + maDeactivatingListeners.clear(); + mxAnimationNode.clear(); + mpParent.reset(); + mpSelf.reset(); + maContext.dispose(); +} + + +sal_Int16 BaseNode::getRestartMode() +{ + const sal_Int16 nTmp( mxAnimationNode->getRestart() ); + return (nTmp != animations::AnimationRestart::DEFAULT && + nTmp != animations::AnimationRestart::INHERIT) + ? nTmp : getRestartDefaultMode(); +} + +sal_Int16 BaseNode::getFillMode() +{ + const sal_Int16 nTmp( mxAnimationNode->getFill() ); + const sal_Int16 nFill((nTmp != animations::AnimationFill::DEFAULT && + nTmp != animations::AnimationFill::INHERIT) + ? nTmp : getFillDefaultMode()); + + // For AUTO fill mode, SMIL specifies that fill mode is FREEZE, + // if no explicit active duration is given + // (no duration, end, repeatCount or repeatDuration given), + // and REMOVE otherwise + if( nFill == animations::AnimationFill::AUTO ) { + return (isIndefiniteTiming( mxAnimationNode->getDuration() ) && + isIndefiniteTiming( mxAnimationNode->getEnd() ) && + !mxAnimationNode->getRepeatCount().hasValue() && + isIndefiniteTiming( mxAnimationNode->getRepeatDuration() )) + ? animations::AnimationFill::FREEZE + : animations::AnimationFill::REMOVE; + } + else { + return nFill; + } +} + +sal_Int16 BaseNode::getFillDefaultMode() const +{ + sal_Int16 nFillDefault = mxAnimationNode->getFillDefault(); + if (nFillDefault == animations::AnimationFill::DEFAULT) { + nFillDefault = (mpParent != 0 + ? mpParent->getFillDefaultMode() + : animations::AnimationFill::AUTO); + } + return nFillDefault; +} + +sal_Int16 BaseNode::getRestartDefaultMode() const +{ + sal_Int16 nRestartDefaultMode = mxAnimationNode->getRestartDefault(); + if (nRestartDefaultMode == animations::AnimationRestart::DEFAULT) { + nRestartDefaultMode = (mpParent != 0 + ? mpParent->getRestartDefaultMode() + : animations::AnimationRestart::ALWAYS); + } + return nRestartDefaultMode; +} + +uno::Reference<animations::XAnimationNode> BaseNode::getXAnimationNode() const +{ + return mxAnimationNode; +} + +bool BaseNode::init() +{ + if (! checkValidNode()) + return false; + meCurrState = UNRESOLVED; + // discharge a loaded event, if any: + if (mpCurrentEvent) { + mpCurrentEvent->dispose(); + mpCurrentEvent.reset(); + } + return init_st(); // may call derived class +} + +bool BaseNode::init_st() +{ + return true; +} + +bool BaseNode::resolve() +{ + if (! checkValidNode()) + return false; + + OSL_ASSERT( meCurrState != RESOLVED ); + if (inStateOrTransition( RESOLVED )) + return true; + + StateTransition st(this); + if (st.enter( RESOLVED ) && + isTransition( RESOLVED, ACTIVE ) && + resolve_st() /* may call derived class */) + { + st.commit(); // changing state + + // discharge a loaded event, if any: + if (mpCurrentEvent) + mpCurrentEvent->dispose(); + + // schedule activation event: + + // This method takes the NodeContext::mnStartDelay value into account, + // to cater for iterate container time shifts. We cannot put different + // iterations of the iterate container's children into different + // subcontainer (such as a 'DelayContainer', which delays resolving its + // children by a fixed amount), since all iterations' nodes must be + // resolved at the same time (otherwise, the delayed subset creation + // will not work, i.e. deactivate the subsets too late in the master + // shape). + uno::Any const aBegin( mxAnimationNode->getBegin() ); + if (aBegin.hasValue()) { + mpCurrentEvent = generateEvent( + aBegin, boost::bind( &AnimationNode::activate, mpSelf ), + maContext, mnStartDelay ); + } + else { + // For some leaf nodes, PPT import yields empty begin time, + // although semantically, it should be 0.0 + // TODO(F3): That should really be provided by the PPT import + + // schedule delayed activation event. Take iterate node + // timeout into account + mpCurrentEvent = makeDelay( + boost::bind( &AnimationNode::activate, mpSelf ), + mnStartDelay, + "AnimationNode::activate with delay"); + maContext.mrEventQueue.addEvent( mpCurrentEvent ); + } + + return true; + } + return false; +} + +bool BaseNode::resolve_st() +{ + return true; +} + + +bool BaseNode::activate() +{ + if (! checkValidNode()) + return false; + + OSL_ASSERT( meCurrState != ACTIVE ); + if (inStateOrTransition( ACTIVE )) + return true; + + StateTransition st(this); + if (st.enter( ACTIVE )) { + + activate_st(); // calling derived class + + st.commit(); // changing state + + maContext.mrEventMultiplexer.notifyAnimationStart( mpSelf ); + + return true; + } + + return false; +} + +void BaseNode::activate_st() +{ + scheduleDeactivationEvent(); +} + +void BaseNode::scheduleDeactivationEvent( EventSharedPtr const& pEvent ) +{ + if (mpCurrentEvent) { + mpCurrentEvent->dispose(); + mpCurrentEvent.reset(); + } + if (pEvent) { + if (maContext.mrEventQueue.addEvent( pEvent )) + mpCurrentEvent = pEvent; + } + else { + // This method need not take the + // NodeContext::mnStartDelay value into account, + // because the deactivation event is only scheduled + // when the effect is started: the timeout is then + // already respected. + + // xxx todo: + // think about set node, anim base node! + // if anim base node has no activity, this is called to schedule deactivatiion, + // but what if it does not schedule anything? + + // TODO(F2): Handle end time attribute, too + mpCurrentEvent = generateEvent( + mxAnimationNode->getDuration(), + boost::bind( &AnimationNode::deactivate, mpSelf ), + maContext, 0.0 ); + } +} + +void BaseNode::deactivate() +{ + if (inStateOrTransition( ENDED | FROZEN ) || !checkValidNode()) + return; + + if (isTransition( meCurrState, FROZEN, false /* no OSL_ASSERT */ )) { + // do transition to FROZEN: + StateTransition st(this); + if (st.enter( FROZEN, StateTransition::FORCE )) { + + deactivate_st( FROZEN ); + st.commit(); + + notifyEndListeners(); + + // discharge a loaded event, before going on: + if (mpCurrentEvent) { + mpCurrentEvent->dispose(); + mpCurrentEvent.reset(); + } + } + } + else { + // use end instead: + end(); + } + // state has changed either to FROZEN or ENDED +} + +void BaseNode::deactivate_st( NodeState ) +{ +} + +void BaseNode::end() +{ + bool const bIsFrozenOrInTransitionToFrozen = inStateOrTransition( FROZEN ); + if (inStateOrTransition( ENDED ) || !checkValidNode()) + return; + + // END must always be reachable. If not, that's an error in the + // transition tables + OSL_ENSURE( isTransition( meCurrState, ENDED ), + "end state not reachable in transition table" ); + + StateTransition st(this); + if (st.enter( ENDED, StateTransition::FORCE )) { + + deactivate_st( ENDED ); + st.commit(); // changing state + + // if is FROZEN or is to be FROZEN, then + // will/already notified deactivating listeners + if (!bIsFrozenOrInTransitionToFrozen) + notifyEndListeners(); + + // discharge a loaded event, before going on: + if (mpCurrentEvent) { + mpCurrentEvent->dispose(); + mpCurrentEvent.reset(); + } + } +} + +void BaseNode::notifyDeactivating( const AnimationNodeSharedPtr& rNotifier ) +{ + (void) rNotifier; // avoid warning + OSL_ASSERT( rNotifier->getState() == FROZEN || + rNotifier->getState() == ENDED ); + // TODO(F1): for end sync functionality, this might indeed be used some day +} + +void BaseNode::notifyEndListeners() const +{ + // notify all listeners + std::for_each( maDeactivatingListeners.begin(), + maDeactivatingListeners.end(), + boost::bind( &AnimationNode::notifyDeactivating, _1, + boost::cref(mpSelf) ) ); + + // notify state change + maContext.mrEventMultiplexer.notifyAnimationEnd( mpSelf ); + + // notify main sequence end (iff we're the main + // sequence root node). This is because the main + // sequence determines the active duration of the + // slide. All other sequences are secondary, in that + // they don't prevent a slide change from happening, + // even if they have not been completed. In other + // words, all sequences except the main sequence are + // optional for the slide lifetime. + if (isMainSequenceRootNode()) + maContext.mrEventMultiplexer.notifySlideAnimationsEnd(); +} + +AnimationNode::NodeState BaseNode::getState() const +{ + return meCurrState; +} + +bool BaseNode::registerDeactivatingListener( + const AnimationNodeSharedPtr& rNotifee ) +{ + if (! checkValidNode()) + return false; + + ENSURE_OR_RETURN_FALSE( + rNotifee, + "BaseNode::registerDeactivatingListener(): invalid notifee" ); + maDeactivatingListeners.push_back( rNotifee ); + + return true; +} + +void BaseNode::setSelf( const BaseNodeSharedPtr& rSelf ) +{ + ENSURE_OR_THROW( rSelf.get() == this, + "BaseNode::setSelf(): got ptr to different object" ); + ENSURE_OR_THROW( !mpSelf, + "BaseNode::setSelf(): called multiple times" ); + + mpSelf = rSelf; +} + +// Debug +//========================================================================= + +#if defined(VERBOSE) && defined(DBG_UTIL) +void BaseNode::showState() const +{ + const AnimationNode::NodeState eNodeState( getState() ); + + if( eNodeState == AnimationNode::INVALID ) + VERBOSE_TRACE( "Node state: n0x%X [label=\"%s\",style=filled," + "fillcolor=\"0.5,0.2,0.5\"]", + (const char*)this+debugGetCurrentOffset(), + getDescription() ); + else + VERBOSE_TRACE( "Node state: n0x%X [label=\"%s\",style=filled," + "fillcolor=\"%f,1.0,1.0\"]", + (const char*)this+debugGetCurrentOffset(), + getDescription(), + log(double(getState()))/4.0 ); + + // determine additional node information + uno::Reference<animations::XAnimate> const xAnimate( mxAnimationNode, + uno::UNO_QUERY ); + if( xAnimate.is() ) + { + uno::Reference< drawing::XShape > xTargetShape( xAnimate->getTarget(), + uno::UNO_QUERY ); + + if( !xTargetShape.is() ) + { + ::com::sun::star::presentation::ParagraphTarget aTarget; + + // no shape provided. Maybe a ParagraphTarget? + if( (xAnimate->getTarget() >>= aTarget) ) + xTargetShape = aTarget.Shape; + } + + if( xTargetShape.is() ) + { + uno::Reference< beans::XPropertySet > xPropSet( xTargetShape, + uno::UNO_QUERY ); + + // read shape name + ::rtl::OUString aName; + if( (xPropSet->getPropertyValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Name") ) ) + >>= aName) ) + { + const ::rtl::OString& rAsciiName( + ::rtl::OUStringToOString( aName, + RTL_TEXTENCODING_ASCII_US ) ); + + VERBOSE_TRACE( "Node info: n0x%X, name \"%s\"", + (const char*)this+debugGetCurrentOffset(), + rAsciiName.getStr() ); + } + } + } +} + +const char* BaseNode::getDescription() const +{ + return "BaseNode"; +} + +void BaseNode::showTreeFromWithin() const +{ + // find root node + BaseNodeSharedPtr pCurrNode( mpSelf ); + while( pCurrNode->mpParent ) pCurrNode = pCurrNode->mpParent; + + pCurrNode->showState(); +} +#endif + +} // namespace internal +} // namespace slideshow + |