2005-01-21 16:06:19 +00:00
|
|
|
/*************************************************************************
|
|
|
|
*
|
2005-09-07 19:43:57 +00:00
|
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
2005-01-21 16:06:19 +00:00
|
|
|
*
|
2005-09-07 19:43:57 +00:00
|
|
|
* $RCSfile: basenode.cxx,v $
|
2005-01-21 16:06:19 +00:00
|
|
|
*
|
2006-09-17 07:35:39 +00:00
|
|
|
* $Revision: 1.8 $
|
2005-01-21 16:06:19 +00:00
|
|
|
*
|
2006-09-17 07:35:39 +00:00
|
|
|
* last change: $Author: obo $ $Date: 2006-09-17 08:35:39 $
|
2005-01-21 16:06:19 +00:00
|
|
|
*
|
2005-09-07 19:43:57 +00:00
|
|
|
* The Contents of this file are made available subject to
|
|
|
|
* the terms of GNU Lesser General Public License Version 2.1.
|
2005-01-21 16:06:19 +00:00
|
|
|
*
|
|
|
|
*
|
2005-09-07 19:43:57 +00:00
|
|
|
* GNU Lesser General Public License Version 2.1
|
|
|
|
* =============================================
|
|
|
|
* Copyright 2005 by Sun Microsystems, Inc.
|
|
|
|
* 901 San Antonio Road, Palo Alto, CA 94303, USA
|
2005-01-21 16:06:19 +00:00
|
|
|
*
|
2005-09-07 19:43:57 +00:00
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License version 2.1, as published by the Free Software Foundation.
|
2005-01-21 16:06:19 +00:00
|
|
|
*
|
2005-09-07 19:43:57 +00:00
|
|
|
* This library 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 for more details.
|
2005-01-21 16:06:19 +00:00
|
|
|
*
|
2005-09-07 19:43:57 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
|
|
* MA 02111-1307 USA
|
2005-01-21 16:06:19 +00:00
|
|
|
*
|
|
|
|
************************************************************************/
|
|
|
|
|
2006-09-17 07:35:39 +00:00
|
|
|
// MARKER(update_precomp.py): autogen include statement, do not remove
|
|
|
|
#include "precompiled_slideshow.hxx"
|
|
|
|
|
2005-01-21 16:06:19 +00:00
|
|
|
// must be first
|
2005-10-11 07:43:18 +00:00
|
|
|
#include "canvas/debug.hxx"
|
|
|
|
#include "canvas/verbosetrace.hxx"
|
|
|
|
#include "basenode.hxx"
|
|
|
|
#include "basecontainernode.hxx"
|
|
|
|
#include "delayevent.hxx"
|
|
|
|
#include "tools.hxx"
|
|
|
|
#include "nodetools.hxx"
|
|
|
|
#include "generateevent.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 "boost/bind.hpp"
|
2005-01-21 16:06:19 +00:00
|
|
|
#include <vector>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <iterator>
|
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
namespace css = com::sun::star;
|
2005-10-11 07:43:18 +00:00
|
|
|
using namespace css;
|
|
|
|
|
|
|
|
namespace presentation {
|
|
|
|
namespace internal {
|
|
|
|
|
|
|
|
namespace {
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
typedef int StateTransitionTable[17];
|
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
// State transition tables
|
|
|
|
// =========================================================================
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
const int* getStateTransitionTable( sal_Int16 nRestartMode,
|
|
|
|
sal_Int16 nFillMode )
|
2005-01-21 16:06:19 +00:00
|
|
|
{
|
2006-07-26 06:34:56 +00:00
|
|
|
// TODO(F2): restart issues in below tables
|
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
// 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;
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
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;
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
return *tableGuide[ 3*nFillValue + nRestartValue ];
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
/// 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)
|
2006-07-26 06:34:56 +00:00
|
|
|
beans::NamedValue const aSearchKey(
|
2005-10-11 07:43:18 +00:00
|
|
|
rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) ),
|
|
|
|
uno::makeAny( css::presentation::EffectNodeType::MAIN_SEQUENCE ) );
|
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
uno::Sequence<beans::NamedValue> const userData(xNode->getUserData());
|
2005-10-11 07:43:18 +00:00
|
|
|
return findNamedValue( userData, aSearchKey );
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
} // anon namespace
|
|
|
|
|
|
|
|
// BaseNode implementation
|
|
|
|
//=========================================================================
|
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
/** 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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void clear() {
|
|
|
|
if (meToState != INVALID) {
|
|
|
|
OSL_ASSERT( (mpNode->meCurrentStateTransition & meToState) != 0 );
|
|
|
|
mpNode->meCurrentStateTransition &= ~meToState;
|
|
|
|
meToState = INVALID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
BaseNode *const mpNode;
|
|
|
|
NodeState meToState;
|
|
|
|
};
|
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
BaseNode::BaseNode(
|
|
|
|
const uno::Reference< animations::XAnimationNode >& xNode,
|
|
|
|
const BaseContainerNodeSharedPtr& rParent,
|
|
|
|
const NodeContext& rContext )
|
|
|
|
: maContext( rContext.maContext ),
|
|
|
|
maDeactivatingListeners(),
|
2006-07-26 06:34:56 +00:00
|
|
|
mxAnimationNode( xNode ),
|
2005-10-11 07:43:18 +00:00
|
|
|
mpParent( rParent ),
|
|
|
|
mpSelf(),
|
|
|
|
mpStateTransitionTable( NULL ),
|
|
|
|
mnStartDelay( rContext.mnStartDelay ),
|
|
|
|
meCurrState( UNRESOLVED ),
|
2006-07-26 06:34:56 +00:00
|
|
|
meCurrentStateTransition( 0 ),
|
|
|
|
mpCurrentEvent(),
|
2005-10-11 07:43:18 +00:00
|
|
|
mbIsMainSequenceRootNode( isMainSequenceRootNode_( xNode ) )
|
|
|
|
{
|
2006-07-26 06:34:56 +00:00
|
|
|
ENSURE_AND_THROW( mxAnimationNode.is(),
|
2005-10-11 07:43:18 +00:00
|
|
|
"BaseNode::BaseNode(): Invalid XAnimationNode" );
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
// setup state transition table
|
|
|
|
mpStateTransitionTable = getStateTransitionTable( getRestartMode(),
|
|
|
|
getFillMode() );
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
void BaseNode::dispose()
|
|
|
|
{
|
|
|
|
meCurrState = INVALID;
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
// discharge a loaded event, if any:
|
|
|
|
if (mpCurrentEvent) {
|
|
|
|
mpCurrentEvent->dispose();
|
|
|
|
mpCurrentEvent.reset();
|
|
|
|
}
|
2005-10-11 07:43:18 +00:00
|
|
|
maDeactivatingListeners.clear();
|
2006-07-26 06:34:56 +00:00
|
|
|
mxAnimationNode.clear();
|
2005-10-11 07:43:18 +00:00
|
|
|
mpParent.reset();
|
|
|
|
mpSelf.reset();
|
|
|
|
maContext.dispose();
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
|
|
|
|
sal_Int16 BaseNode::getRestartMode()
|
2005-10-11 07:43:18 +00:00
|
|
|
{
|
2006-07-26 06:34:56 +00:00
|
|
|
const sal_Int16 nTmp( mxAnimationNode->getRestart() );
|
|
|
|
return (nTmp != animations::AnimationRestart::DEFAULT &&
|
|
|
|
nTmp != animations::AnimationRestart::INHERIT)
|
|
|
|
? nTmp : getRestartDefaultMode();
|
2005-10-11 07:43:18 +00:00
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
sal_Int16 BaseNode::getFillMode()
|
2005-10-11 07:43:18 +00:00
|
|
|
{
|
2006-07-26 06:34:56 +00:00
|
|
|
const sal_Int16 nTmp( mxAnimationNode->getFill() );
|
|
|
|
const sal_Int16 nFill((nTmp != animations::AnimationFill::DEFAULT &&
|
|
|
|
nTmp != animations::AnimationFill::INHERIT)
|
|
|
|
? nTmp : getFillDefaultMode());
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
sal_Int16 BaseNode::getFillDefaultMode() const
|
|
|
|
{
|
|
|
|
sal_Int16 nFillDefault = mxAnimationNode->getFillDefault();
|
|
|
|
if (nFillDefault == animations::AnimationFill::DEFAULT) {
|
|
|
|
nFillDefault = (mpParent.get() != 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.get() != 0
|
|
|
|
? mpParent->getRestartDefaultMode()
|
|
|
|
: animations::AnimationRestart::ALWAYS);
|
|
|
|
}
|
|
|
|
return nRestartDefaultMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
uno::Reference<animations::XAnimationNode> BaseNode::getXAnimationNode() const
|
|
|
|
{
|
|
|
|
return mxAnimationNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BaseNode::init()
|
|
|
|
{
|
|
|
|
if (! checkValidNode())
|
|
|
|
return false;
|
2005-10-11 07:43:18 +00:00
|
|
|
meCurrState = UNRESOLVED;
|
2006-07-26 06:34:56 +00:00
|
|
|
// discharge a loaded event, if any:
|
|
|
|
if (mpCurrentEvent) {
|
|
|
|
mpCurrentEvent->dispose();
|
|
|
|
mpCurrentEvent.reset();
|
|
|
|
}
|
|
|
|
return init_st(); // may call derived class
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BaseNode::init_st()
|
|
|
|
{
|
2005-10-11 07:43:18 +00:00
|
|
|
return true;
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
bool BaseNode::resolve()
|
|
|
|
{
|
2006-07-26 06:34:56 +00:00
|
|
|
if (! checkValidNode())
|
|
|
|
return false;
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
OSL_ASSERT( meCurrState != RESOLVED );
|
|
|
|
if (inStateOrTransition( RESOLVED ))
|
|
|
|
return true;
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
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 );
|
|
|
|
maContext.mrEventQueue.addEvent( mpCurrentEvent );
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
bool BaseNode::resolve_st()
|
|
|
|
{
|
2005-10-11 07:43:18 +00:00
|
|
|
return true;
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
bool BaseNode::activate()
|
|
|
|
{
|
2006-07-26 06:34:56 +00:00
|
|
|
if (! checkValidNode())
|
|
|
|
return false;
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
OSL_ASSERT( meCurrState != ACTIVE );
|
|
|
|
if (inStateOrTransition( ACTIVE ))
|
|
|
|
return true;
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
StateTransition st(this);
|
|
|
|
if (st.enter( ACTIVE )) {
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
activate_st(); // calling derived class
|
|
|
|
|
|
|
|
st.commit(); // changing state
|
|
|
|
|
|
|
|
maContext.mrEventMultiplexer.notifyAnimationStart( mpSelf );
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BaseNode::activate_st()
|
|
|
|
{
|
2005-10-11 07:43:18 +00:00
|
|
|
scheduleDeactivationEvent();
|
2006-07-26 06:34:56 +00:00
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
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 );
|
|
|
|
}
|
2005-10-11 07:43:18 +00:00
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
void BaseNode::deactivate()
|
|
|
|
{
|
2006-07-26 06:34:56 +00:00
|
|
|
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();
|
2005-10-11 07:43:18 +00:00
|
|
|
}
|
2006-07-26 06:34:56 +00:00
|
|
|
// state has changed either to FROZEN or ENDED
|
|
|
|
}
|
|
|
|
|
|
|
|
void BaseNode::deactivate_st( NodeState )
|
|
|
|
{
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
void BaseNode::end()
|
|
|
|
{
|
|
|
|
bool const bIsFrozenOrInTransitionToFrozen = inStateOrTransition( FROZEN );
|
|
|
|
if (inStateOrTransition( ENDED ) || !checkValidNode())
|
2005-10-11 07:43:18 +00:00
|
|
|
return;
|
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
// 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();
|
2005-10-11 07:43:18 +00:00
|
|
|
|
2006-07-26 06:34:56 +00:00
|
|
|
// discharge a loaded event, before going on:
|
|
|
|
if (mpCurrentEvent) {
|
|
|
|
mpCurrentEvent->dispose();
|
|
|
|
mpCurrentEvent.reset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BaseNode::notifyDeactivating( const AnimationNodeSharedPtr& rNotifier )
|
|
|
|
{
|
|
|
|
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
|
|
|
|
{
|
2005-10-11 07:43:18 +00:00
|
|
|
// notify all listeners
|
2006-07-26 06:34:56 +00:00
|
|
|
std::for_each( maDeactivatingListeners.begin(),
|
|
|
|
maDeactivatingListeners.end(),
|
|
|
|
boost::bind( &AnimationNode::notifyDeactivating, _1,
|
|
|
|
boost::cref(mpSelf) ) );
|
2005-10-11 07:43:18 +00:00
|
|
|
|
|
|
|
// 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();
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
AnimationNode::NodeState BaseNode::getState() const
|
|
|
|
{
|
|
|
|
return meCurrState;
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
bool BaseNode::registerDeactivatingListener(
|
|
|
|
const AnimationNodeSharedPtr& rNotifee )
|
|
|
|
{
|
2006-07-26 06:34:56 +00:00
|
|
|
if (! checkValidNode())
|
2005-10-11 07:43:18 +00:00
|
|
|
return false;
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
ENSURE_AND_RETURN(
|
|
|
|
rNotifee.get(),
|
|
|
|
"BaseNode::registerDeactivatingListener(): invalid notifee" );
|
|
|
|
maDeactivatingListeners.push_back( rNotifee );
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
return true;
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
void BaseNode::setSelf( const BaseNodeSharedPtr& rSelf )
|
|
|
|
{
|
|
|
|
ENSURE_AND_THROW( rSelf.get() == this,
|
|
|
|
"BaseNode::setSelf(): got ptr to different object" );
|
|
|
|
ENSURE_AND_THROW( !mpSelf.get(),
|
|
|
|
"BaseNode::setSelf(): called multiple times" );
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
mpSelf = rSelf;
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
// Debug
|
|
|
|
//=========================================================================
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
#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
|
2006-07-26 06:34:56 +00:00
|
|
|
uno::Reference<animations::XAnimate> const xAnimate( mxAnimationNode,
|
|
|
|
uno::UNO_QUERY );
|
2005-10-11 07:43:18 +00:00
|
|
|
if( xAnimate.is() )
|
|
|
|
{
|
|
|
|
uno::Reference< drawing::XShape > xTargetShape( xAnimate->getTarget(),
|
|
|
|
uno::UNO_QUERY );
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
if( !xTargetShape.is() )
|
2005-01-21 16:06:19 +00:00
|
|
|
{
|
2005-10-11 07:43:18 +00:00
|
|
|
::com::sun::star::presentation::ParagraphTarget aTarget;
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
// no shape provided. Maybe a ParagraphTarget?
|
|
|
|
if( (xAnimate->getTarget() >>= aTarget) )
|
|
|
|
xTargetShape = aTarget.Shape;
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
if( xTargetShape.is() )
|
2005-01-21 16:06:19 +00:00
|
|
|
{
|
2005-10-11 07:43:18 +00:00
|
|
|
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 ) );
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
VERBOSE_TRACE( "Node info: n0x%X, name \"%s\"",
|
2005-01-21 16:06:19 +00:00
|
|
|
(const char*)this+debugGetCurrentOffset(),
|
2005-10-11 07:43:18 +00:00
|
|
|
rAsciiName.getStr() );
|
2005-01-21 16:06:19 +00:00
|
|
|
}
|
|
|
|
}
|
2005-10-11 07:43:18 +00:00
|
|
|
}
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
const char* BaseNode::getDescription() const
|
|
|
|
{
|
|
|
|
return "BaseNode";
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
void BaseNode::showTreeFromWithin() const
|
|
|
|
{
|
|
|
|
// find root node
|
|
|
|
BaseNodeSharedPtr pCurrNode( mpSelf );
|
|
|
|
while( pCurrNode->mpParent.get() ) pCurrNode = pCurrNode->mpParent;
|
2005-01-21 16:06:19 +00:00
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
pCurrNode->showState();
|
|
|
|
}
|
2005-01-21 16:06:19 +00:00
|
|
|
#endif
|
|
|
|
|
2005-10-11 07:43:18 +00:00
|
|
|
} // namespace internal
|
|
|
|
} // namespace presentation
|
|
|
|
|