1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 29*cdf0e10cSrcweir #include "precompiled_slideshow.hxx" 30*cdf0e10cSrcweir 31*cdf0e10cSrcweir // must be first 32*cdf0e10cSrcweir #include <canvas/debug.hxx> 33*cdf0e10cSrcweir #include <canvas/verbosetrace.hxx> 34*cdf0e10cSrcweir 35*cdf0e10cSrcweir #include <com/sun/star/drawing/XShape.hpp> 36*cdf0e10cSrcweir #include <com/sun/star/animations/XAnimate.hpp> 37*cdf0e10cSrcweir #include <com/sun/star/animations/AnimationNodeType.hpp> 38*cdf0e10cSrcweir #include <com/sun/star/presentation/EffectNodeType.hpp> 39*cdf0e10cSrcweir #include <com/sun/star/presentation/TextAnimationType.hpp> 40*cdf0e10cSrcweir #include <com/sun/star/animations/XAnimateSet.hpp> 41*cdf0e10cSrcweir #include <com/sun/star/animations/XIterateContainer.hpp> 42*cdf0e10cSrcweir #include <com/sun/star/presentation/ShapeAnimationSubType.hpp> 43*cdf0e10cSrcweir #include <com/sun/star/animations/XAnimateMotion.hpp> 44*cdf0e10cSrcweir #include <com/sun/star/animations/XAnimateColor.hpp> 45*cdf0e10cSrcweir #include <com/sun/star/animations/XAnimateTransform.hpp> 46*cdf0e10cSrcweir #include <com/sun/star/animations/AnimationTransformType.hpp> 47*cdf0e10cSrcweir #include <com/sun/star/animations/XTransitionFilter.hpp> 48*cdf0e10cSrcweir #include <com/sun/star/animations/XAudio.hpp> 49*cdf0e10cSrcweir #include <com/sun/star/presentation/ParagraphTarget.hpp> 50*cdf0e10cSrcweir #include <com/sun/star/beans/XPropertySet.hpp> 51*cdf0e10cSrcweir #include <animations/animationnodehelper.hxx> 52*cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx> 53*cdf0e10cSrcweir 54*cdf0e10cSrcweir #include "animationnodefactory.hxx" 55*cdf0e10cSrcweir #include "paralleltimecontainer.hxx" 56*cdf0e10cSrcweir #include "sequentialtimecontainer.hxx" 57*cdf0e10cSrcweir #include "propertyanimationnode.hxx" 58*cdf0e10cSrcweir #include "animationsetnode.hxx" 59*cdf0e10cSrcweir #include "animationpathmotionnode.hxx" 60*cdf0e10cSrcweir #include "animationcolornode.hxx" 61*cdf0e10cSrcweir #include "animationtransformnode.hxx" 62*cdf0e10cSrcweir #include "animationtransitionfilternode.hxx" 63*cdf0e10cSrcweir #include "animationaudionode.hxx" 64*cdf0e10cSrcweir #include "animationcommandnode.hxx" 65*cdf0e10cSrcweir #include "nodetools.hxx" 66*cdf0e10cSrcweir #include "tools.hxx" 67*cdf0e10cSrcweir 68*cdf0e10cSrcweir #include <boost/bind.hpp> 69*cdf0e10cSrcweir 70*cdf0e10cSrcweir using namespace ::com::sun::star; 71*cdf0e10cSrcweir 72*cdf0e10cSrcweir namespace slideshow { 73*cdf0e10cSrcweir namespace internal { 74*cdf0e10cSrcweir 75*cdf0e10cSrcweir namespace { 76*cdf0e10cSrcweir 77*cdf0e10cSrcweir // forward declaration needed by NodeCreator 78*cdf0e10cSrcweir BaseNodeSharedPtr implCreateAnimationNode( 79*cdf0e10cSrcweir const uno::Reference< animations::XAnimationNode >& xNode, 80*cdf0e10cSrcweir const BaseContainerNodeSharedPtr& rParent, 81*cdf0e10cSrcweir const NodeContext& rContext ); 82*cdf0e10cSrcweir 83*cdf0e10cSrcweir class NodeCreator 84*cdf0e10cSrcweir { 85*cdf0e10cSrcweir public: 86*cdf0e10cSrcweir NodeCreator( BaseContainerNodeSharedPtr& rParent, 87*cdf0e10cSrcweir const NodeContext& rContext ) 88*cdf0e10cSrcweir : mrParent( rParent ), mrContext( rContext ) {} 89*cdf0e10cSrcweir 90*cdf0e10cSrcweir void operator()( 91*cdf0e10cSrcweir const uno::Reference< animations::XAnimationNode >& xChildNode ) const 92*cdf0e10cSrcweir { 93*cdf0e10cSrcweir createChild( xChildNode, mrContext ); 94*cdf0e10cSrcweir } 95*cdf0e10cSrcweir 96*cdf0e10cSrcweir protected: 97*cdf0e10cSrcweir void createChild( 98*cdf0e10cSrcweir const uno::Reference< animations::XAnimationNode >& xChildNode, 99*cdf0e10cSrcweir const NodeContext& rContext ) const 100*cdf0e10cSrcweir { 101*cdf0e10cSrcweir BaseNodeSharedPtr pChild( implCreateAnimationNode( xChildNode, 102*cdf0e10cSrcweir mrParent, 103*cdf0e10cSrcweir rContext ) ); 104*cdf0e10cSrcweir 105*cdf0e10cSrcweir OSL_ENSURE( pChild, 106*cdf0e10cSrcweir "NodeCreator::operator(): child creation failed" ); 107*cdf0e10cSrcweir 108*cdf0e10cSrcweir // TODO(Q1): This yields circular references, which, it seems, is 109*cdf0e10cSrcweir // unavoidable here 110*cdf0e10cSrcweir if( pChild ) 111*cdf0e10cSrcweir mrParent->appendChildNode( pChild ); 112*cdf0e10cSrcweir } 113*cdf0e10cSrcweir 114*cdf0e10cSrcweir BaseContainerNodeSharedPtr& mrParent; 115*cdf0e10cSrcweir const NodeContext& mrContext; 116*cdf0e10cSrcweir }; 117*cdf0e10cSrcweir 118*cdf0e10cSrcweir /** Same as NodeCreator, only that NodeContext's 119*cdf0e10cSrcweir SubsetShape is cloned for every child node. 120*cdf0e10cSrcweir 121*cdf0e10cSrcweir This is used for iterated animation node generation 122*cdf0e10cSrcweir */ 123*cdf0e10cSrcweir class CloningNodeCreator : private NodeCreator 124*cdf0e10cSrcweir { 125*cdf0e10cSrcweir public: 126*cdf0e10cSrcweir CloningNodeCreator( BaseContainerNodeSharedPtr& rParent, 127*cdf0e10cSrcweir const NodeContext& rContext ) 128*cdf0e10cSrcweir : NodeCreator( rParent, rContext ) {} 129*cdf0e10cSrcweir 130*cdf0e10cSrcweir void operator()( 131*cdf0e10cSrcweir const uno::Reference< animations::XAnimationNode >& xChildNode ) const 132*cdf0e10cSrcweir { 133*cdf0e10cSrcweir NodeContext aContext( mrContext ); 134*cdf0e10cSrcweir 135*cdf0e10cSrcweir // TODO(Q1): There's a catch here. If you clone a 136*cdf0e10cSrcweir // subset whose actual subsetting has already been 137*cdf0e10cSrcweir // realized (i.e. if enableSubsetShape() has been 138*cdf0e10cSrcweir // called already), and the original of your clone 139*cdf0e10cSrcweir // goes out of scope, then your subset will be 140*cdf0e10cSrcweir // gone (SubsettableShapeManager::revokeSubset() be 141*cdf0e10cSrcweir // called). As of now, this behaviour is not 142*cdf0e10cSrcweir // triggered here (we either clone, XOR we enable 143*cdf0e10cSrcweir // subset initially), but one might consider 144*cdf0e10cSrcweir // reworking DrawShape/ShapeSubset to avoid this. 145*cdf0e10cSrcweir 146*cdf0e10cSrcweir // clone ShapeSubset, since each node needs their 147*cdf0e10cSrcweir // own version of the ShapeSubset (otherwise, 148*cdf0e10cSrcweir // e.g. activity counting does not work - subset 149*cdf0e10cSrcweir // would be removed after first animation node 150*cdf0e10cSrcweir // disables it). 151*cdf0e10cSrcweir // 152*cdf0e10cSrcweir // NOTE: this is only a problem for animation 153*cdf0e10cSrcweir // nodes that explicitely call 154*cdf0e10cSrcweir // disableSubsetShape(). Independent shape subsets 155*cdf0e10cSrcweir // (like those created for ParagraphTargets) 156*cdf0e10cSrcweir // solely rely on the ShapeSubset destructor to 157*cdf0e10cSrcweir // normalize things, which does the right thing 158*cdf0e10cSrcweir // here: the subset is only removed after _the 159*cdf0e10cSrcweir // last_ animation node releases the shared ptr. 160*cdf0e10cSrcweir aContext.mpMasterShapeSubset.reset( 161*cdf0e10cSrcweir new ShapeSubset( *aContext.mpMasterShapeSubset ) ); 162*cdf0e10cSrcweir 163*cdf0e10cSrcweir createChild( xChildNode, aContext ); 164*cdf0e10cSrcweir } 165*cdf0e10cSrcweir }; 166*cdf0e10cSrcweir 167*cdf0e10cSrcweir /** Create animation nodes for text iterations 168*cdf0e10cSrcweir 169*cdf0e10cSrcweir This method clones the animation nodes below xIterNode 170*cdf0e10cSrcweir for every iterated shape entity. 171*cdf0e10cSrcweir */ 172*cdf0e10cSrcweir bool implCreateIteratedNodes( 173*cdf0e10cSrcweir const uno::Reference< animations::XIterateContainer >& xIterNode, 174*cdf0e10cSrcweir BaseContainerNodeSharedPtr& rParent, 175*cdf0e10cSrcweir const NodeContext& rContext ) 176*cdf0e10cSrcweir { 177*cdf0e10cSrcweir ENSURE_OR_THROW( xIterNode.is(), 178*cdf0e10cSrcweir "implCreateIteratedNodes(): Invalid node" ); 179*cdf0e10cSrcweir 180*cdf0e10cSrcweir const double nIntervalTimeout( xIterNode->getIterateInterval() ); 181*cdf0e10cSrcweir 182*cdf0e10cSrcweir // valid iterate interval? We're ruling out monstrous 183*cdf0e10cSrcweir // values here, to avoid pseudo 'hangs' in the 184*cdf0e10cSrcweir // presentation 185*cdf0e10cSrcweir if( nIntervalTimeout < 0.0 || 186*cdf0e10cSrcweir nIntervalTimeout > 1000.0 ) 187*cdf0e10cSrcweir { 188*cdf0e10cSrcweir return false; // not an active iteration 189*cdf0e10cSrcweir } 190*cdf0e10cSrcweir 191*cdf0e10cSrcweir if( ::basegfx::fTools::equalZero( nIntervalTimeout ) ) 192*cdf0e10cSrcweir OSL_TRACE( "implCreateIteratedNodes(): " 193*cdf0e10cSrcweir "iterate interval close to zero, there's " 194*cdf0e10cSrcweir "no point in defining such an effect " 195*cdf0e10cSrcweir "(visually equivalent to whole-shape effect)" ); 196*cdf0e10cSrcweir 197*cdf0e10cSrcweir // Determine target shape (or subset) 198*cdf0e10cSrcweir // ================================== 199*cdf0e10cSrcweir 200*cdf0e10cSrcweir // TODO(E1): I'm not too sure what to expect here... 201*cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( 202*cdf0e10cSrcweir xIterNode->getTarget().hasValue(), 203*cdf0e10cSrcweir "implCreateIteratedNodes(): no target on ITERATE node" ); 204*cdf0e10cSrcweir 205*cdf0e10cSrcweir uno::Reference< drawing::XShape > xTargetShape( xIterNode->getTarget(), 206*cdf0e10cSrcweir uno::UNO_QUERY ); 207*cdf0e10cSrcweir 208*cdf0e10cSrcweir presentation::ParagraphTarget aTarget; 209*cdf0e10cSrcweir sal_Int16 nSubItem( xIterNode->getSubItem() ); 210*cdf0e10cSrcweir bool bParagraphTarget( false ); 211*cdf0e10cSrcweir 212*cdf0e10cSrcweir if( !xTargetShape.is() ) 213*cdf0e10cSrcweir { 214*cdf0e10cSrcweir // no shape provided. Maybe a ParagraphTarget? 215*cdf0e10cSrcweir if( !(xIterNode->getTarget() >>= aTarget) ) 216*cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( 217*cdf0e10cSrcweir false, 218*cdf0e10cSrcweir "implCreateIteratedNodes(): could not extract any " 219*cdf0e10cSrcweir "target information" ); 220*cdf0e10cSrcweir 221*cdf0e10cSrcweir xTargetShape = aTarget.Shape; 222*cdf0e10cSrcweir 223*cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( 224*cdf0e10cSrcweir xTargetShape.is(), 225*cdf0e10cSrcweir "implCreateIteratedNodes(): invalid shape in ParagraphTarget" ); 226*cdf0e10cSrcweir 227*cdf0e10cSrcweir // we've a paragraph target to iterate over, thus, 228*cdf0e10cSrcweir // the whole animation container refers only to 229*cdf0e10cSrcweir // the text 230*cdf0e10cSrcweir nSubItem = presentation::ShapeAnimationSubType::ONLY_TEXT; 231*cdf0e10cSrcweir 232*cdf0e10cSrcweir bParagraphTarget = true; 233*cdf0e10cSrcweir } 234*cdf0e10cSrcweir 235*cdf0e10cSrcweir // Lookup shape, and fill NodeContext 236*cdf0e10cSrcweir // ================================== 237*cdf0e10cSrcweir 238*cdf0e10cSrcweir AttributableShapeSharedPtr pTargetShape( 239*cdf0e10cSrcweir lookupAttributableShape( rContext.maContext.mpSubsettableShapeManager, 240*cdf0e10cSrcweir xTargetShape ) ); 241*cdf0e10cSrcweir 242*cdf0e10cSrcweir const DocTreeNodeSupplier& rTreeNodeSupplier( 243*cdf0e10cSrcweir pTargetShape->getTreeNodeSupplier() ); 244*cdf0e10cSrcweir 245*cdf0e10cSrcweir ShapeSubsetSharedPtr pTargetSubset; 246*cdf0e10cSrcweir 247*cdf0e10cSrcweir NodeContext aContext( rContext ); 248*cdf0e10cSrcweir 249*cdf0e10cSrcweir // paragraph targets already need a subset as the 250*cdf0e10cSrcweir // master shape (they're representing only a single 251*cdf0e10cSrcweir // paragraph) 252*cdf0e10cSrcweir if( bParagraphTarget ) 253*cdf0e10cSrcweir { 254*cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( 255*cdf0e10cSrcweir aTarget.Paragraph >= 0 && 256*cdf0e10cSrcweir rTreeNodeSupplier.getNumberOfTreeNodes( 257*cdf0e10cSrcweir DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ) > aTarget.Paragraph, 258*cdf0e10cSrcweir "implCreateIteratedNodes(): paragraph index out of range" ); 259*cdf0e10cSrcweir 260*cdf0e10cSrcweir pTargetSubset.reset( 261*cdf0e10cSrcweir new ShapeSubset( 262*cdf0e10cSrcweir pTargetShape, 263*cdf0e10cSrcweir // retrieve index aTarget.Paragraph of 264*cdf0e10cSrcweir // type PARAGRAPH from this shape 265*cdf0e10cSrcweir rTreeNodeSupplier.getTreeNode( 266*cdf0e10cSrcweir aTarget.Paragraph, 267*cdf0e10cSrcweir DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ), 268*cdf0e10cSrcweir rContext.maContext.mpSubsettableShapeManager ) ); 269*cdf0e10cSrcweir 270*cdf0e10cSrcweir // iterate target is not the whole shape, but only 271*cdf0e10cSrcweir // the selected paragraph - subset _must_ be 272*cdf0e10cSrcweir // independent, to be able to affect visibility 273*cdf0e10cSrcweir // independent of master shape 274*cdf0e10cSrcweir aContext.mbIsIndependentSubset = true; 275*cdf0e10cSrcweir 276*cdf0e10cSrcweir // already enable parent subset right here, to 277*cdf0e10cSrcweir // make potentially generated subsets subtract 278*cdf0e10cSrcweir // their content from the parent subset (and not 279*cdf0e10cSrcweir // the original shape). Otherwise, already 280*cdf0e10cSrcweir // subsetted parents (e.g. paragraphs) would not 281*cdf0e10cSrcweir // have their characters removed, when the child 282*cdf0e10cSrcweir // iterations start. 283*cdf0e10cSrcweir // Furthermore, the setup of initial shape 284*cdf0e10cSrcweir // attributes of course needs the subset shape 285*cdf0e10cSrcweir // generated, to apply e.g. visibility changes. 286*cdf0e10cSrcweir pTargetSubset->enableSubsetShape(); 287*cdf0e10cSrcweir } 288*cdf0e10cSrcweir else 289*cdf0e10cSrcweir { 290*cdf0e10cSrcweir pTargetSubset.reset( 291*cdf0e10cSrcweir new ShapeSubset( pTargetShape, 292*cdf0e10cSrcweir rContext.maContext.mpSubsettableShapeManager )); 293*cdf0e10cSrcweir } 294*cdf0e10cSrcweir 295*cdf0e10cSrcweir aContext.mpMasterShapeSubset = pTargetSubset; 296*cdf0e10cSrcweir uno::Reference< animations::XAnimationNode > xNode( xIterNode, 297*cdf0e10cSrcweir uno::UNO_QUERY_THROW ); 298*cdf0e10cSrcweir 299*cdf0e10cSrcweir // Generate subsets 300*cdf0e10cSrcweir // ================ 301*cdf0e10cSrcweir 302*cdf0e10cSrcweir if( bParagraphTarget || 303*cdf0e10cSrcweir nSubItem != presentation::ShapeAnimationSubType::ONLY_TEXT ) 304*cdf0e10cSrcweir { 305*cdf0e10cSrcweir // prepend with animations for 306*cdf0e10cSrcweir // full Shape (will be subtracted 307*cdf0e10cSrcweir // from the subset parts within 308*cdf0e10cSrcweir // the Shape::createSubset() 309*cdf0e10cSrcweir // method). For ONLY_TEXT effects, 310*cdf0e10cSrcweir // we skip this part, to animate 311*cdf0e10cSrcweir // only the text. 312*cdf0e10cSrcweir // 313*cdf0e10cSrcweir // OR 314*cdf0e10cSrcweir // 315*cdf0e10cSrcweir // prepend with subset animation for full 316*cdf0e10cSrcweir // _paragraph_, from which the individual 317*cdf0e10cSrcweir // paragraph subsets are subtracted. Note that the 318*cdf0e10cSrcweir // subitem is superfluous here, we always assume 319*cdf0e10cSrcweir // ONLY_TEXT, if a paragraph is referenced as the 320*cdf0e10cSrcweir // master of an iteration effect. 321*cdf0e10cSrcweir NodeCreator aCreator( rParent, aContext ); 322*cdf0e10cSrcweir if( !::anim::for_each_childNode( xNode, 323*cdf0e10cSrcweir aCreator ) ) 324*cdf0e10cSrcweir { 325*cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( 326*cdf0e10cSrcweir false, 327*cdf0e10cSrcweir "implCreateIteratedNodes(): iterated child node creation failed" ); 328*cdf0e10cSrcweir } 329*cdf0e10cSrcweir } 330*cdf0e10cSrcweir 331*cdf0e10cSrcweir // TODO(F2): This does not do the correct 332*cdf0e10cSrcweir // thing. Having nSubItem be set to ONLY_BACKGROUND 333*cdf0e10cSrcweir // should result in the text staying unanimated in the 334*cdf0e10cSrcweir // foreground, while the shape moves in the background 335*cdf0e10cSrcweir // (this behaviour is perfectly possible with the 336*cdf0e10cSrcweir // slideshow engine, only that the text won't be 337*cdf0e10cSrcweir // currently visible, because animations are always in 338*cdf0e10cSrcweir // the foreground) 339*cdf0e10cSrcweir if( nSubItem != presentation::ShapeAnimationSubType::ONLY_BACKGROUND ) 340*cdf0e10cSrcweir { 341*cdf0e10cSrcweir // determine type of subitem iteration (logical 342*cdf0e10cSrcweir // text unit to animate) 343*cdf0e10cSrcweir DocTreeNode::NodeType eIterateNodeType( 344*cdf0e10cSrcweir DocTreeNode::NODETYPE_LOGICAL_CHARACTER_CELL ); 345*cdf0e10cSrcweir 346*cdf0e10cSrcweir switch( xIterNode->getIterateType() ) 347*cdf0e10cSrcweir { 348*cdf0e10cSrcweir case presentation::TextAnimationType::BY_PARAGRAPH: 349*cdf0e10cSrcweir eIterateNodeType = DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH; 350*cdf0e10cSrcweir break; 351*cdf0e10cSrcweir 352*cdf0e10cSrcweir case presentation::TextAnimationType::BY_WORD: 353*cdf0e10cSrcweir eIterateNodeType = DocTreeNode::NODETYPE_LOGICAL_WORD; 354*cdf0e10cSrcweir break; 355*cdf0e10cSrcweir 356*cdf0e10cSrcweir case presentation::TextAnimationType::BY_LETTER: 357*cdf0e10cSrcweir eIterateNodeType = DocTreeNode::NODETYPE_LOGICAL_CHARACTER_CELL; 358*cdf0e10cSrcweir break; 359*cdf0e10cSrcweir 360*cdf0e10cSrcweir default: 361*cdf0e10cSrcweir ENSURE_OR_THROW( 362*cdf0e10cSrcweir false, "implCreateIteratedNodes(): " 363*cdf0e10cSrcweir "Unexpected IterateType on XIterateContainer"); 364*cdf0e10cSrcweir break; 365*cdf0e10cSrcweir } 366*cdf0e10cSrcweir 367*cdf0e10cSrcweir if( bParagraphTarget && 368*cdf0e10cSrcweir eIterateNodeType != DocTreeNode::NODETYPE_LOGICAL_WORD && 369*cdf0e10cSrcweir eIterateNodeType != DocTreeNode::NODETYPE_LOGICAL_CHARACTER_CELL ) 370*cdf0e10cSrcweir { 371*cdf0e10cSrcweir // will not animate the whole paragraph, when 372*cdf0e10cSrcweir // only the paragraph is animated at all. 373*cdf0e10cSrcweir OSL_ENSURE( false, 374*cdf0e10cSrcweir "implCreateIteratedNodes(): Ignoring paragraph iteration for paragraph master" ); 375*cdf0e10cSrcweir } 376*cdf0e10cSrcweir else 377*cdf0e10cSrcweir { 378*cdf0e10cSrcweir // setup iteration parameters 379*cdf0e10cSrcweir // -------------------------- 380*cdf0e10cSrcweir 381*cdf0e10cSrcweir // iterate target is the whole shape (or the 382*cdf0e10cSrcweir // whole parent subshape), thus, can save 383*cdf0e10cSrcweir // loads of subset shapes by generating them 384*cdf0e10cSrcweir // only when the effects become active - 385*cdf0e10cSrcweir // before and after the effect active 386*cdf0e10cSrcweir // duration, all attributes are shared by 387*cdf0e10cSrcweir // master shape and subset (since the iterated 388*cdf0e10cSrcweir // effects are all the same). 389*cdf0e10cSrcweir aContext.mbIsIndependentSubset = false; 390*cdf0e10cSrcweir 391*cdf0e10cSrcweir // determine number of nodes for given subitem 392*cdf0e10cSrcweir // type 393*cdf0e10cSrcweir sal_Int32 nTreeNodes( 0 ); 394*cdf0e10cSrcweir if( bParagraphTarget ) 395*cdf0e10cSrcweir { 396*cdf0e10cSrcweir // create the iterated subset _relative_ to 397*cdf0e10cSrcweir // the given paragraph index (i.e. animate the 398*cdf0e10cSrcweir // given subset type, but only when it's part 399*cdf0e10cSrcweir // of the given paragraph) 400*cdf0e10cSrcweir nTreeNodes = rTreeNodeSupplier.getNumberOfSubsetTreeNodes( 401*cdf0e10cSrcweir pTargetSubset->getSubset(), 402*cdf0e10cSrcweir eIterateNodeType ); 403*cdf0e10cSrcweir } 404*cdf0e10cSrcweir else 405*cdf0e10cSrcweir { 406*cdf0e10cSrcweir // generate normal subset 407*cdf0e10cSrcweir nTreeNodes = rTreeNodeSupplier.getNumberOfTreeNodes( 408*cdf0e10cSrcweir eIterateNodeType ); 409*cdf0e10cSrcweir } 410*cdf0e10cSrcweir 411*cdf0e10cSrcweir 412*cdf0e10cSrcweir // iterate node, generate copies of the children for each subset 413*cdf0e10cSrcweir // ------------------------------------------------------------- 414*cdf0e10cSrcweir 415*cdf0e10cSrcweir // NodeContext::mnStartDelay contains additional node delay. 416*cdf0e10cSrcweir // This will make the duplicated nodes for each iteration start 417*cdf0e10cSrcweir // increasingly later. 418*cdf0e10cSrcweir aContext.mnStartDelay = nIntervalTimeout; 419*cdf0e10cSrcweir 420*cdf0e10cSrcweir for( sal_Int32 i=0; i<nTreeNodes; ++i ) 421*cdf0e10cSrcweir { 422*cdf0e10cSrcweir // create subset with the corresponding tree nodes 423*cdf0e10cSrcweir if( bParagraphTarget ) 424*cdf0e10cSrcweir { 425*cdf0e10cSrcweir // create subsets relative to paragraph subset 426*cdf0e10cSrcweir aContext.mpMasterShapeSubset.reset( 427*cdf0e10cSrcweir new ShapeSubset( 428*cdf0e10cSrcweir pTargetSubset, 429*cdf0e10cSrcweir rTreeNodeSupplier.getSubsetTreeNode( 430*cdf0e10cSrcweir pTargetSubset->getSubset(), 431*cdf0e10cSrcweir i, 432*cdf0e10cSrcweir eIterateNodeType ) ) ); 433*cdf0e10cSrcweir } 434*cdf0e10cSrcweir else 435*cdf0e10cSrcweir { 436*cdf0e10cSrcweir // create subsets from main shape 437*cdf0e10cSrcweir aContext.mpMasterShapeSubset.reset( 438*cdf0e10cSrcweir new ShapeSubset( pTargetSubset, 439*cdf0e10cSrcweir rTreeNodeSupplier.getTreeNode( 440*cdf0e10cSrcweir i, 441*cdf0e10cSrcweir eIterateNodeType ) ) ); 442*cdf0e10cSrcweir } 443*cdf0e10cSrcweir 444*cdf0e10cSrcweir CloningNodeCreator aCreator( rParent, aContext ); 445*cdf0e10cSrcweir if( !::anim::for_each_childNode( xNode, 446*cdf0e10cSrcweir aCreator ) ) 447*cdf0e10cSrcweir { 448*cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( 449*cdf0e10cSrcweir false, "implCreateIteratedNodes(): " 450*cdf0e10cSrcweir "iterated child node creation failed" ); 451*cdf0e10cSrcweir } 452*cdf0e10cSrcweir 453*cdf0e10cSrcweir aContext.mnStartDelay += nIntervalTimeout; 454*cdf0e10cSrcweir } 455*cdf0e10cSrcweir } 456*cdf0e10cSrcweir } 457*cdf0e10cSrcweir 458*cdf0e10cSrcweir // done with iterate child generation 459*cdf0e10cSrcweir return true; 460*cdf0e10cSrcweir } 461*cdf0e10cSrcweir 462*cdf0e10cSrcweir BaseNodeSharedPtr implCreateAnimationNode( 463*cdf0e10cSrcweir const uno::Reference< animations::XAnimationNode >& xNode, 464*cdf0e10cSrcweir const BaseContainerNodeSharedPtr& rParent, 465*cdf0e10cSrcweir const NodeContext& rContext ) 466*cdf0e10cSrcweir { 467*cdf0e10cSrcweir ENSURE_OR_THROW( xNode.is(), 468*cdf0e10cSrcweir "implCreateAnimationNode(): invalid XAnimationNode" ); 469*cdf0e10cSrcweir 470*cdf0e10cSrcweir BaseNodeSharedPtr pCreatedNode; 471*cdf0e10cSrcweir BaseContainerNodeSharedPtr pCreatedContainer; 472*cdf0e10cSrcweir 473*cdf0e10cSrcweir // create the internal node, corresponding to xNode 474*cdf0e10cSrcweir switch( xNode->getType() ) 475*cdf0e10cSrcweir { 476*cdf0e10cSrcweir case animations::AnimationNodeType::CUSTOM: 477*cdf0e10cSrcweir OSL_ENSURE( false, "implCreateAnimationNode(): " 478*cdf0e10cSrcweir "CUSTOM not yet implemented" ); 479*cdf0e10cSrcweir return pCreatedNode; 480*cdf0e10cSrcweir 481*cdf0e10cSrcweir case animations::AnimationNodeType::PAR: 482*cdf0e10cSrcweir pCreatedNode = pCreatedContainer = BaseContainerNodeSharedPtr( 483*cdf0e10cSrcweir new ParallelTimeContainer( xNode, rParent, rContext ) ); 484*cdf0e10cSrcweir break; 485*cdf0e10cSrcweir 486*cdf0e10cSrcweir case animations::AnimationNodeType::ITERATE: 487*cdf0e10cSrcweir // map iterate container to ParallelTimeContainer. 488*cdf0e10cSrcweir // the iterating functionality is to be found 489*cdf0e10cSrcweir // below, (see method implCreateIteratedNodes) 490*cdf0e10cSrcweir pCreatedNode = pCreatedContainer = BaseContainerNodeSharedPtr( 491*cdf0e10cSrcweir new ParallelTimeContainer( xNode, rParent, rContext ) ); 492*cdf0e10cSrcweir break; 493*cdf0e10cSrcweir 494*cdf0e10cSrcweir case animations::AnimationNodeType::SEQ: 495*cdf0e10cSrcweir pCreatedNode = pCreatedContainer = BaseContainerNodeSharedPtr( 496*cdf0e10cSrcweir new SequentialTimeContainer( xNode, rParent, rContext ) ); 497*cdf0e10cSrcweir break; 498*cdf0e10cSrcweir 499*cdf0e10cSrcweir case animations::AnimationNodeType::ANIMATE: 500*cdf0e10cSrcweir pCreatedNode.reset( new PropertyAnimationNode( 501*cdf0e10cSrcweir xNode, rParent, rContext ) ); 502*cdf0e10cSrcweir break; 503*cdf0e10cSrcweir 504*cdf0e10cSrcweir case animations::AnimationNodeType::SET: 505*cdf0e10cSrcweir pCreatedNode.reset( new AnimationSetNode( 506*cdf0e10cSrcweir xNode, rParent, rContext ) ); 507*cdf0e10cSrcweir break; 508*cdf0e10cSrcweir 509*cdf0e10cSrcweir case animations::AnimationNodeType::ANIMATEMOTION: 510*cdf0e10cSrcweir pCreatedNode.reset( new AnimationPathMotionNode( 511*cdf0e10cSrcweir xNode, rParent, rContext ) ); 512*cdf0e10cSrcweir break; 513*cdf0e10cSrcweir 514*cdf0e10cSrcweir case animations::AnimationNodeType::ANIMATECOLOR: 515*cdf0e10cSrcweir pCreatedNode.reset( new AnimationColorNode( 516*cdf0e10cSrcweir xNode, rParent, rContext ) ); 517*cdf0e10cSrcweir break; 518*cdf0e10cSrcweir 519*cdf0e10cSrcweir case animations::AnimationNodeType::ANIMATETRANSFORM: 520*cdf0e10cSrcweir pCreatedNode.reset( new AnimationTransformNode( 521*cdf0e10cSrcweir xNode, rParent, rContext ) ); 522*cdf0e10cSrcweir break; 523*cdf0e10cSrcweir 524*cdf0e10cSrcweir case animations::AnimationNodeType::TRANSITIONFILTER: 525*cdf0e10cSrcweir pCreatedNode.reset( new AnimationTransitionFilterNode( 526*cdf0e10cSrcweir xNode, rParent, rContext ) ); 527*cdf0e10cSrcweir break; 528*cdf0e10cSrcweir 529*cdf0e10cSrcweir case animations::AnimationNodeType::AUDIO: 530*cdf0e10cSrcweir pCreatedNode.reset( new AnimationAudioNode( 531*cdf0e10cSrcweir xNode, rParent, rContext ) ); 532*cdf0e10cSrcweir break; 533*cdf0e10cSrcweir 534*cdf0e10cSrcweir case animations::AnimationNodeType::COMMAND: 535*cdf0e10cSrcweir pCreatedNode.reset( new AnimationCommandNode( 536*cdf0e10cSrcweir xNode, rParent, rContext ) ); 537*cdf0e10cSrcweir break; 538*cdf0e10cSrcweir 539*cdf0e10cSrcweir default: 540*cdf0e10cSrcweir OSL_ENSURE( false, "implCreateAnimationNode(): " 541*cdf0e10cSrcweir "invalid AnimationNodeType" ); 542*cdf0e10cSrcweir return pCreatedNode; 543*cdf0e10cSrcweir } 544*cdf0e10cSrcweir 545*cdf0e10cSrcweir // TODO(Q1): This yields circular references, which, it seems, is 546*cdf0e10cSrcweir // unavoidable here 547*cdf0e10cSrcweir 548*cdf0e10cSrcweir // HACK: node objects need shared_ptr to themselves, 549*cdf0e10cSrcweir // which we pass them here. 550*cdf0e10cSrcweir pCreatedNode->setSelf( pCreatedNode ); 551*cdf0e10cSrcweir 552*cdf0e10cSrcweir // if we've got a container node object, recursively add 553*cdf0e10cSrcweir // its children 554*cdf0e10cSrcweir if( pCreatedContainer ) 555*cdf0e10cSrcweir { 556*cdf0e10cSrcweir uno::Reference< animations::XIterateContainer > xIterNode( 557*cdf0e10cSrcweir xNode, uno::UNO_QUERY ); 558*cdf0e10cSrcweir 559*cdf0e10cSrcweir // when this node is an XIterateContainer with 560*cdf0e10cSrcweir // active iterations, this method will generate 561*cdf0e10cSrcweir // the appropriate children 562*cdf0e10cSrcweir if( xIterNode.is() ) 563*cdf0e10cSrcweir { 564*cdf0e10cSrcweir // note that implCreateIteratedNodes() might 565*cdf0e10cSrcweir // choose not to generate any child nodes 566*cdf0e10cSrcweir // (e.g. when the iterate timeout is outside 567*cdf0e10cSrcweir // sensible limits). Then, no child nodes are 568*cdf0e10cSrcweir // generated at all, since typically, child 569*cdf0e10cSrcweir // node attribute are incomplete for iteration 570*cdf0e10cSrcweir // children. 571*cdf0e10cSrcweir implCreateIteratedNodes( xIterNode, 572*cdf0e10cSrcweir pCreatedContainer, 573*cdf0e10cSrcweir rContext ); 574*cdf0e10cSrcweir } 575*cdf0e10cSrcweir else 576*cdf0e10cSrcweir { 577*cdf0e10cSrcweir // no iterate subset node, just plain child generation now 578*cdf0e10cSrcweir NodeCreator aCreator( pCreatedContainer, rContext ); 579*cdf0e10cSrcweir if( !::anim::for_each_childNode( xNode, aCreator ) ) 580*cdf0e10cSrcweir { 581*cdf0e10cSrcweir OSL_ENSURE( false, "implCreateAnimationNode(): " 582*cdf0e10cSrcweir "child node creation failed" ); 583*cdf0e10cSrcweir return BaseNodeSharedPtr(); 584*cdf0e10cSrcweir } 585*cdf0e10cSrcweir } 586*cdf0e10cSrcweir } 587*cdf0e10cSrcweir 588*cdf0e10cSrcweir return pCreatedNode; 589*cdf0e10cSrcweir } 590*cdf0e10cSrcweir 591*cdf0e10cSrcweir } // anon namespace 592*cdf0e10cSrcweir 593*cdf0e10cSrcweir AnimationNodeSharedPtr AnimationNodeFactory::createAnimationNode( 594*cdf0e10cSrcweir const uno::Reference< animations::XAnimationNode >& xNode, 595*cdf0e10cSrcweir const ::basegfx::B2DVector& rSlideSize, 596*cdf0e10cSrcweir const SlideShowContext& rContext ) 597*cdf0e10cSrcweir { 598*cdf0e10cSrcweir ENSURE_OR_THROW( 599*cdf0e10cSrcweir xNode.is(), 600*cdf0e10cSrcweir "AnimationNodeFactory::createAnimationNode(): invalid XAnimationNode" ); 601*cdf0e10cSrcweir 602*cdf0e10cSrcweir return BaseNodeSharedPtr( implCreateAnimationNode( 603*cdf0e10cSrcweir xNode, 604*cdf0e10cSrcweir BaseContainerNodeSharedPtr(), // no parent 605*cdf0e10cSrcweir NodeContext( rContext, 606*cdf0e10cSrcweir rSlideSize ))); 607*cdf0e10cSrcweir } 608*cdf0e10cSrcweir 609*cdf0e10cSrcweir #if defined(VERBOSE) && defined(DBG_UTIL) 610*cdf0e10cSrcweir void AnimationNodeFactory::showTree( AnimationNodeSharedPtr& pRootNode ) 611*cdf0e10cSrcweir { 612*cdf0e10cSrcweir if( pRootNode ) 613*cdf0e10cSrcweir DEBUG_NODES_SHOWTREE( boost::dynamic_pointer_cast<BaseContainerNode>( 614*cdf0e10cSrcweir pRootNode).get() ); 615*cdf0e10cSrcweir } 616*cdf0e10cSrcweir #endif 617*cdf0e10cSrcweir 618*cdf0e10cSrcweir } // namespace internal 619*cdf0e10cSrcweir } // namespace slideshow 620*cdf0e10cSrcweir 621