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 #include "oox/ppt/timenode.hxx" 29 30 #include <boost/bind.hpp> 31 32 #include <com/sun/star/beans/XPropertySet.hpp> 33 #include <com/sun/star/beans/NamedValue.hpp> 34 #include <com/sun/star/container/XEnumerationAccess.hpp> 35 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 36 #include <com/sun/star/frame/XModel.hpp> 37 #include <com/sun/star/animations/XAnimateColor.hpp> 38 #include <com/sun/star/animations/XAnimateMotion.hpp> 39 #include <com/sun/star/animations/XAnimateTransform.hpp> 40 #include <com/sun/star/animations/XCommand.hpp> 41 #include <com/sun/star/animations/XIterateContainer.hpp> 42 #include <com/sun/star/animations/XAnimationNodeSupplier.hpp> 43 #include <com/sun/star/animations/XTimeContainer.hpp> 44 #include <com/sun/star/animations/AnimationNodeType.hpp> 45 #include <com/sun/star/animations/Event.hpp> 46 #include <com/sun/star/animations/EventTrigger.hpp> 47 #include <com/sun/star/presentation/EffectNodeType.hpp> 48 49 #include "oox/helper/helper.hxx" 50 #include "oox/core/xmlfilterbase.hxx" 51 52 using ::rtl::OUString; 53 using namespace ::oox::core; 54 using namespace ::com::sun::star::beans; 55 using namespace ::com::sun::star::container; 56 using namespace ::com::sun::star::uno; 57 using namespace ::com::sun::star::lang; 58 using namespace ::com::sun::star::animations; 59 using namespace ::com::sun::star::frame; 60 using namespace ::com::sun::star::presentation; 61 62 namespace oox { namespace ppt { 63 64 OUString TimeNode::getServiceName( sal_Int16 nNodeType ) 65 { 66 OUString sServiceName; 67 switch( nNodeType ) 68 { 69 case AnimationNodeType::PAR: 70 // sServiceName = CREATE_OUSTRING("com.sun.star.animations.IterateContainer"); 71 sServiceName = CREATE_OUSTRING("com.sun.star.animations.ParallelTimeContainer"); 72 break; 73 case AnimationNodeType::SEQ: 74 sServiceName = CREATE_OUSTRING("com.sun.star.animations.SequenceTimeContainer"); 75 break; 76 case AnimationNodeType::ANIMATE: 77 sServiceName = CREATE_OUSTRING("com.sun.star.animations.Animate"); 78 break; 79 case AnimationNodeType::ANIMATECOLOR: 80 sServiceName = CREATE_OUSTRING("com.sun.star.animations.AnimateColor"); 81 break; 82 case AnimationNodeType::TRANSITIONFILTER: 83 sServiceName = CREATE_OUSTRING("com.sun.star.animations.TransitionFilter"); 84 break; 85 case AnimationNodeType::ANIMATEMOTION: 86 sServiceName = CREATE_OUSTRING("com.sun.star.animations.AnimateMotion"); 87 break; 88 case AnimationNodeType::ANIMATETRANSFORM: 89 sServiceName = CREATE_OUSTRING("com.sun.star.animations.AnimateTransform"); 90 break; 91 case AnimationNodeType::COMMAND: 92 sServiceName = CREATE_OUSTRING("com.sun.star.animations.Command"); 93 break; 94 case AnimationNodeType::SET: 95 sServiceName = CREATE_OUSTRING("com.sun.star.animations.AnimateSet"); 96 break; 97 case AnimationNodeType::AUDIO: 98 sServiceName = CREATE_OUSTRING("com.sun.star.animations.Audio"); 99 break; 100 default: 101 OSL_TRACE( "OOX: uhandled type %x", nNodeType ); 102 break; 103 } 104 return sServiceName; 105 } 106 107 108 109 TimeNode::TimeNode( sal_Int16 nNodeType ) 110 : mnNodeType( nNodeType ) 111 , mbHasEndSyncValue( false ) 112 { 113 } 114 115 116 TimeNode::~TimeNode() 117 { 118 } 119 120 // BEGIN CUT&PASTE from sd/source/filter/ppt/pptinanimations.hxx 121 // -------------------------------------------------------------------- 122 static void fixMainSequenceTiming( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) 123 { 124 try 125 { 126 bool bFirst = true; 127 Reference< XEnumerationAccess > xEA( xNode, UNO_QUERY_THROW ); 128 Reference< XEnumeration > xE( xEA->createEnumeration(), UNO_QUERY_THROW ); 129 while( xE->hasMoreElements() ) 130 { 131 // click node 132 Reference< XAnimationNode > xClickNode( xE->nextElement(), UNO_QUERY ); 133 134 Event aEvent; 135 aEvent.Trigger = EventTrigger::ON_NEXT; 136 aEvent.Repeat = 0; 137 xClickNode->setBegin( makeAny( aEvent ) ); 138 139 if( bFirst ) 140 { 141 bFirst = false; 142 Reference< XEnumerationAccess > xEA2( xClickNode, UNO_QUERY_THROW ); 143 Reference< XEnumeration > xE2( xEA2->createEnumeration(), UNO_QUERY_THROW ); 144 if( xE2->hasMoreElements() ) 145 { 146 // with node 147 xE2->nextElement() >>= xEA2; 148 if( xEA2.is() ) 149 xE2.query( xEA2->createEnumeration() ); 150 else 151 xE2.clear(); 152 153 if( xE2.is() && xE2->hasMoreElements() ) 154 { 155 Reference< XAnimationNode > xEffectNode( xE2->nextElement(), UNO_QUERY_THROW ); 156 const Sequence< NamedValue > aUserData( xEffectNode->getUserData() ); 157 const NamedValue* p = aUserData.getConstArray(); 158 sal_Int32 nLength = aUserData.getLength(); 159 while( nLength-- ) 160 { 161 if( p->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "node-type" ) ) ) 162 { 163 sal_Int16 nNodeType = 0; 164 p->Value >>= nNodeType; 165 if( nNodeType != ::com::sun::star::presentation::EffectNodeType::ON_CLICK ) 166 { 167 // first effect does not start on click, so correct 168 // first click nodes begin to 0s 169 xClickNode->setBegin( makeAny( (double)0.0 ) ); 170 break; 171 } 172 } 173 p++; 174 } 175 } 176 } 177 } 178 } 179 } 180 catch( Exception& e ) 181 { 182 (void)e; 183 OSL_TRACE("fixMainSequenceTiming(), exception caught!" ); 184 } 185 } 186 187 // -------------------------------------------------------------------- 188 189 static void fixInteractiveSequenceTiming( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) 190 { 191 try 192 { 193 Any aBegin( xNode->getBegin() ); 194 Any aEmpty; 195 xNode->setBegin( aEmpty ); 196 197 Reference< XEnumerationAccess > xEA( xNode, UNO_QUERY_THROW ); 198 Reference< XEnumeration > xE( xEA->createEnumeration(), UNO_QUERY_THROW ); 199 while( xE->hasMoreElements() ) 200 { 201 // click node 202 Reference< XAnimationNode > xClickNode( xE->nextElement(), UNO_QUERY ); 203 xClickNode->setBegin( aBegin ); 204 } 205 } 206 catch( Exception& e ) 207 { 208 (void)e; 209 OSL_TRACE("fixInteractiveSequenceTiming(), exception caught!" ); 210 } 211 } 212 213 // END CUT&PASTE 214 215 void TimeNode::addNode( const XmlFilterBase& rFilter, const Reference< XAnimationNode >& rxNode, const SlidePersistPtr & pSlide ) 216 { 217 try { 218 OUString sServiceName = getServiceName( mnNodeType ); 219 Reference< XAnimationNode > xNode = createAndInsert( rFilter, sServiceName, rxNode ); 220 setNode( rFilter, xNode, pSlide ); 221 } 222 catch( const Exception& e ) 223 { 224 OSL_TRACE( "OOX: exception raised in TimeNode::addNode() - %s", 225 OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() ); 226 } 227 } 228 229 void TimeNode::setNode( const XmlFilterBase& rFilter, const Reference< XAnimationNode >& xNode, const SlidePersistPtr & pSlide ) 230 { 231 OSL_ENSURE( xNode.is(), "null node passed" ); 232 233 try { 234 if( msId.getLength() ) 235 { 236 pSlide->getAnimNodesMap()[ msId ] = xNode; 237 } 238 239 if( mpTarget ) 240 { 241 sal_Int16 nSubType; 242 maNodeProperties[ NP_TARGET ] = mpTarget->convert( pSlide, nSubType ); 243 if( mpTarget->mnType == XML_spTgt ) 244 { 245 maNodeProperties[ NP_SUBITEM ] <<= nSubType; 246 } 247 } 248 249 if( !maStCondList.empty() ) 250 { 251 Any aAny = AnimationCondition::convertList( pSlide, maStCondList ); 252 if( aAny.hasValue() ) 253 { 254 xNode->setBegin( aAny ); 255 } 256 257 } 258 if( !maEndCondList.empty() ) 259 { 260 Any aAny = AnimationCondition::convertList( pSlide, maEndCondList ); 261 if( aAny.hasValue() ) 262 { 263 xNode->setEnd( aAny ); 264 } 265 } 266 #if 0 // FIXME even the binary filter has this disabled. 267 if( !maNextCondList.empty() ) 268 { 269 Any aAny = AnimationCondition::convertList( pSlide, maNextCondList ); 270 if( aAny.hasValue() ) 271 { 272 xNode->setNext( aAny ); 273 } 274 } 275 if( !maPrevCondList.empty() ) 276 { 277 Any aAny = AnimationCondition::convertList( pSlide, maPrevCondList ); 278 if( aAny.hasValue() ) 279 { 280 xNode->setPrev( aAny ); 281 } 282 } 283 #endif 284 if( mbHasEndSyncValue ) 285 { 286 Any aValue = maEndSyncValue.convert( pSlide ); 287 xNode->setEndSync(aValue); 288 } 289 290 if( !maUserData.empty() ) 291 { 292 Sequence< NamedValue > aUserDataSeq( static_cast< sal_Int32 >( maUserData.size() ) ); 293 NamedValue* pValues = aUserDataSeq.getArray(); 294 for( UserDataMap::const_iterator aIt = maUserData.begin(), aEnd = maUserData.end(); aIt != aEnd; ++aIt, ++pValues ) 295 { 296 pValues->Name = aIt->first; 297 pValues->Value = aIt->second; 298 } 299 maNodeProperties[ NP_USERDATA ] <<= aUserDataSeq; 300 } 301 302 Reference< XAnimate > xAnimate( xNode, UNO_QUERY ); 303 Reference< XAnimateColor > xAnimateColor( xNode, UNO_QUERY ); 304 Reference< XAnimateMotion > xAnimateMotion( xNode, UNO_QUERY ); 305 Reference< XAnimateTransform > xAnimateTransform( xNode, UNO_QUERY ); 306 Reference< XCommand > xCommand( xNode, UNO_QUERY ); 307 Reference< XIterateContainer > xIterateContainer( xNode, UNO_QUERY ); 308 sal_Int16 nInt16 = 0; 309 sal_Bool bBool = sal_False; 310 double fDouble = 0; 311 OUString sString; 312 Sequence< NamedValue > aSeq; 313 314 for( int i = 0; i < _NP_SIZE; i++) 315 { 316 Any & aValue( maNodeProperties[ i ] ); 317 if( aValue.hasValue() ) 318 { 319 switch( i ) 320 { 321 case NP_TO: 322 if( xAnimate.is() ) 323 xAnimate->setTo( aValue ); 324 break; 325 case NP_FROM: 326 if( xAnimate.is() ) 327 xAnimate->setFrom( aValue ); 328 break; 329 case NP_BY: 330 if( xAnimate.is() ) 331 xAnimate->setBy( aValue ); 332 break; 333 case NP_TARGET: 334 if( xAnimate.is() ) 335 xAnimate->setTarget( aValue ); 336 break; 337 case NP_SUBITEM: 338 if( xAnimate.is() ) 339 { 340 if( aValue >>= nInt16 ) 341 xAnimate->setSubItem( nInt16 ); 342 else 343 { 344 OSL_TRACE( "any >>= failed %d", __LINE__ ); 345 } 346 } 347 break; 348 case NP_ATTRIBUTENAME: 349 if( xAnimate.is() ) 350 { 351 if( aValue >>= sString ) 352 xAnimate->setAttributeName( sString ); 353 else 354 { 355 OSL_TRACE( "any >>= failed %d", __LINE__ ); 356 } 357 } 358 break; 359 case NP_CALCMODE: 360 if( xAnimate.is() ) 361 { 362 if( aValue >>= nInt16 ) 363 xAnimate->setCalcMode( nInt16 ); 364 else 365 { 366 OSL_TRACE( "any >>= failed %d", __LINE__ ); 367 } 368 } 369 break; 370 case NP_KEYTIMES: 371 if( xAnimate.is() ) 372 { 373 Sequence<double> aKeyTimes; 374 if( aValue >>= aKeyTimes ) 375 xAnimate->setKeyTimes(aKeyTimes); 376 else 377 { 378 OSL_TRACE( "any >>= failed %d", __LINE__ ); 379 } 380 } 381 break; 382 case NP_VALUES: 383 if( xAnimate.is() ) 384 { 385 Sequence<Any> aValues; 386 if( aValue >>= aValues ) 387 xAnimate->setValues(aValues); 388 else 389 { 390 OSL_TRACE( "any >>= failed %d", __LINE__ ); 391 } 392 } 393 break; 394 case NP_FORMULA: 395 if( xAnimate.is() ) 396 { 397 if( aValue >>= sString ) 398 xAnimate->setFormula(sString); 399 else 400 { 401 OSL_TRACE( "any >>= failed %d", __LINE__ ); 402 } 403 } 404 break; 405 case NP_COLORINTERPOLATION: 406 if( xAnimateColor.is() ) 407 { 408 if( aValue >>= nInt16 ) 409 xAnimateColor->setColorInterpolation( nInt16 ); 410 else 411 { 412 OSL_TRACE( "any >>= failed %d", __LINE__ ); 413 } 414 } 415 break; 416 case NP_DIRECTION: 417 if( xAnimateColor.is() ) 418 { 419 if( aValue >>= bBool ) 420 xAnimateColor->setDirection( bBool ); 421 else 422 { 423 OSL_TRACE( "any >>= failed %d", __LINE__ ); 424 } 425 } 426 break; 427 case NP_PATH: 428 if( xAnimateMotion.is() ) 429 xAnimateMotion->setPath( aValue ); 430 break; 431 case NP_TRANSFORMTYPE: 432 if( xAnimateTransform.is() ) 433 { 434 if( aValue >>= nInt16 ) 435 xAnimateTransform->setTransformType( nInt16 ); 436 else 437 { 438 OSL_TRACE( "any >>= failed %d", __LINE__ ); 439 } 440 } 441 break; 442 case NP_USERDATA: 443 if( aValue >>= aSeq ) 444 xNode->setUserData( aSeq ); 445 else 446 { 447 OSL_TRACE( "any >>= failed %d", __LINE__ ); 448 } 449 break; 450 case NP_ACCELERATION: 451 if( aValue >>= fDouble ) 452 xNode->setAcceleration( fDouble ); 453 else 454 { 455 OSL_TRACE( "any >>= failed %d", __LINE__ ); 456 } 457 break; 458 case NP_DECELERATE: 459 if( aValue >>= fDouble ) 460 xNode->setDecelerate( fDouble ); 461 else 462 { 463 OSL_TRACE( "any >>= failed %d", __LINE__ ); 464 } 465 break; 466 case NP_AUTOREVERSE: 467 if( aValue >>= bBool ) 468 xNode->setAutoReverse( bBool ); 469 else 470 { 471 OSL_TRACE( "any >>= failed %d", __LINE__ ); 472 } 473 break; 474 case NP_DURATION: 475 xNode->setDuration( aValue ); 476 break; 477 case NP_FILL: 478 if( aValue >>= nInt16 ) 479 xNode->setFill( nInt16 ); 480 else 481 { 482 OSL_TRACE( "any >>= failed %d", __LINE__ ); 483 } 484 break; 485 case NP_REPEATCOUNT: 486 xNode->setRepeatCount( aValue ); 487 break; 488 case NP_REPEATDURATION: 489 xNode->setRepeatDuration( aValue ); 490 break; 491 case NP_RESTART: 492 if( aValue >>= nInt16 ) 493 xNode->setRestart( nInt16 ); 494 else 495 { 496 OSL_TRACE( "any >>= failed %d", __LINE__ ); 497 } 498 break; 499 case NP_COMMAND: 500 if( xCommand.is() ) 501 { 502 if( aValue >>= nInt16 ) 503 xCommand->setCommand( nInt16 ); 504 else 505 { 506 OSL_TRACE( "any >>= failed %d", __LINE__ ); 507 } 508 } 509 break; 510 case NP_PARAMETER: 511 if( xCommand.is() ) 512 xCommand->setParameter( aValue ); 513 break; 514 case NP_ITERATETYPE: 515 if( xIterateContainer.is() ) 516 { 517 if( aValue >>= nInt16 ) 518 xIterateContainer->setIterateType( nInt16 ); 519 else 520 { 521 OSL_TRACE( "any >>= failed %d", __LINE__ ); 522 } 523 } 524 break; 525 case NP_ITERATEINTERVAL: 526 if( xIterateContainer.is() ) 527 { 528 if( aValue >>= fDouble ) 529 xIterateContainer->setIterateInterval( fDouble ); 530 else 531 { 532 OSL_TRACE( "any >>= failed %d", __LINE__ ); 533 } 534 } 535 break; 536 default: 537 OSL_TRACE( "ERR-OOX: unknown prop index %d", i ); 538 break; 539 } 540 } 541 } 542 543 if( mnNodeType == AnimationNodeType::TRANSITIONFILTER ) 544 { 545 546 Reference< XTransitionFilter > xFilter( xNode, UNO_QUERY ); 547 maTransitionFilter.setTransitionFilterProperties( xFilter ); 548 } 549 550 std::for_each( maChildren.begin(), maChildren.end(), 551 boost::bind(&TimeNode::addNode, _1, boost::cref(rFilter), boost::ref(xNode), 552 boost::ref(pSlide) ) ); 553 554 switch( mnNodeType ) 555 { 556 case AnimationNodeType::SEQ: 557 { 558 sal_Int16 nEnum = 0; 559 if( maUserData[ CREATE_OUSTRING( "node-type" ) ] >>= nEnum ) 560 { 561 if( nEnum == EffectNodeType::MAIN_SEQUENCE ) 562 { 563 fixMainSequenceTiming( xNode ); 564 } 565 else if( nEnum == EffectNodeType::INTERACTIVE_SEQUENCE ) 566 { 567 fixInteractiveSequenceTiming( xNode ); 568 } 569 } 570 break; 571 } 572 case AnimationNodeType::PAR: 573 // some other cut&paste... from AnimationImporter::importAnimationContainer() 574 break; 575 } 576 } 577 catch( const Exception& e ) 578 { 579 OSL_TRACE( "OOX: exception raised in TimeNode::setNode() - %s", 580 OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() ); 581 } 582 } 583 584 585 Reference< XAnimationNode > TimeNode::createAndInsert( 586 const XmlFilterBase& rFilter, 587 const OUString& rServiceName, 588 const Reference< XAnimationNode >& rxNode ) 589 { 590 try { 591 Reference< XAnimationNode > xNode ( rFilter.getServiceFactory()->createInstance( rServiceName ), UNO_QUERY_THROW ); 592 Reference< XTimeContainer > xParentContainer( rxNode, UNO_QUERY_THROW ); 593 594 xParentContainer->appendChild( xNode ); 595 return xNode; 596 } 597 catch( const Exception& e ) 598 { 599 OSL_TRACE( "OOX: exception raised in TimeNode::createAndInsert() trying to create a service %s = %s", 600 OUStringToOString( rServiceName, RTL_TEXTENCODING_ASCII_US ).getStr(), 601 OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() ); 602 } 603 604 return Reference< XAnimationNode >(); 605 } 606 607 608 void TimeNode::setId( sal_Int32 nId ) 609 { 610 msId = OUString::valueOf(nId); 611 } 612 613 void TimeNode::setTo( const Any & aTo ) 614 { 615 maNodeProperties[ NP_TO ] = aTo; 616 } 617 618 619 void TimeNode::setFrom( const Any & aFrom ) 620 { 621 maNodeProperties[ NP_FROM ] = aFrom; 622 } 623 624 void TimeNode::setBy( const Any & aBy ) 625 { 626 maNodeProperties[ NP_BY ] = aBy; 627 } 628 629 630 } } 631