1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sd.hxx" 26 #include <tools/debug.hxx> 27 #include <com/sun/star/util/XCloneable.hpp> 28 #include <com/sun/star/animations/AnimationFill.hpp> 29 #include <com/sun/star/container/XEnumerationAccess.hpp> 30 #include <com/sun/star/presentation/EffectNodeType.hpp> 31 #include <com/sun/star/presentation/EffectCommands.hpp> 32 #include <com/sun/star/presentation/EffectPresetClass.hpp> 33 #include <com/sun/star/presentation/ParagraphTarget.hpp> 34 #include <com/sun/star/lang/XInitialization.hpp> 35 #include <com/sun/star/presentation/ShapeAnimationSubType.hpp> 36 #include <com/sun/star/animations/AnimationNodeType.hpp> 37 #include <com/sun/star/animations/XCommand.hpp> 38 #include <com/sun/star/animations/AnimationTransformType.hpp> 39 #include <com/sun/star/animations/XIterateContainer.hpp> 40 #include <com/sun/star/animations/XAnimateTransform.hpp> 41 #include <com/sun/star/animations/Event.hpp> 42 #include <com/sun/star/animations/EventTrigger.hpp> 43 #include <com/sun/star/animations/Timing.hpp> 44 #include <com/sun/star/drawing/XDrawPage.hpp> 45 #include <com/sun/star/text/XText.hpp> 46 #include <com/sun/star/animations/XAnimate.hpp> 47 #include <com/sun/star/beans/NamedValue.hpp> 48 #include <com/sun/star/beans/XPropertySet.hpp> 49 #include <com/sun/star/util/XChangesNotifier.hpp> 50 #include <com/sun/star/animations/XAnimateMotion.hpp> 51 #include <comphelper/processfactory.hxx> 52 #include <comphelper/sequence.hxx> 53 #include <com/sun/star/lang/Locale.hpp> 54 #include <com/sun/star/i18n/XBreakIterator.hpp> 55 #include <com/sun/star/i18n/CharacterIteratorMode.hpp> 56 #ifndef _COM_SUN_STAR_TEXT_WORDTYPE_HPP_ 57 #include <com/sun/star/i18n/WordType.hpp> 58 #endif 59 #include <com/sun/star/presentation/TextAnimationType.hpp> 60 61 #include <basegfx/polygon/b2dpolypolygon.hxx> 62 #include <basegfx/polygon/b2dpolypolygontools.hxx> 63 #include <basegfx/matrix/b2dhommatrix.hxx> 64 #include <basegfx/range/b2drange.hxx> 65 #include <basegfx/matrix/b2dhommatrixtools.hxx> 66 67 #include <algorithm> 68 69 #include <cppuhelper/implbase1.hxx> 70 71 #include <drawinglayer/geometry/viewinformation2d.hxx> 72 #include <svx/sdr/contact/viewcontact.hxx> 73 #include <svx/svdopath.hxx> 74 #include <svx/svdpage.hxx> 75 #include <svx/unoapi.hxx> 76 #include "CustomAnimationEffect.hxx" 77 #include <CustomAnimationPreset.hxx> 78 #include "animations.hxx" 79 80 using namespace ::com::sun::star; 81 using namespace ::com::sun::star::presentation; 82 using namespace ::com::sun::star::animations; 83 84 using ::rtl::OUString; 85 using ::com::sun::star::uno::Reference; 86 using ::com::sun::star::uno::Sequence; 87 using ::com::sun::star::uno::XInterface; 88 using ::com::sun::star::uno::UNO_QUERY; 89 using ::com::sun::star::uno::UNO_QUERY_THROW; 90 using ::com::sun::star::uno::Any; 91 using ::com::sun::star::uno::makeAny; 92 using ::com::sun::star::uno::Exception; 93 using ::com::sun::star::uno::RuntimeException; 94 using ::com::sun::star::container::XEnumerationAccess; 95 using ::com::sun::star::container::XEnumeration; 96 using ::com::sun::star::beans::NamedValue; 97 using ::com::sun::star::container::XChild; 98 using ::com::sun::star::container::XElementAccess; 99 using ::com::sun::star::drawing::XShape; 100 using ::com::sun::star::lang::XInitialization; 101 using ::com::sun::star::drawing::XShapes; 102 using ::com::sun::star::drawing::XDrawPage; 103 using ::com::sun::star::text::XText; 104 using ::com::sun::star::text::XTextRange; 105 using ::com::sun::star::beans::XPropertySet; 106 using ::com::sun::star::lang::XMultiServiceFactory; 107 using ::com::sun::star::util::XCloneable; 108 using ::com::sun::star::lang::Locale; 109 using ::com::sun::star::util::XChangesNotifier; 110 using ::com::sun::star::util::XChangesListener; 111 112 namespace sd 113 { 114 class MainSequenceChangeGuard 115 { 116 public: 117 MainSequenceChangeGuard( EffectSequenceHelper* pSequence ) 118 { 119 mpMainSequence = dynamic_cast< MainSequence* >( pSequence ); 120 if( mpMainSequence == 0 ) 121 { 122 InteractiveSequence* pI = dynamic_cast< InteractiveSequence* >( pSequence ); 123 if( pI ) 124 mpMainSequence = pI->mpMainSequence; 125 } 126 DBG_ASSERT( mpMainSequence, "sd::MainSequenceChangeGuard::MainSequenceChangeGuard(), no main sequence to guard!" ); 127 128 if( mpMainSequence ) 129 mpMainSequence->mbIgnoreChanges++; 130 } 131 132 ~MainSequenceChangeGuard() 133 { 134 if( mpMainSequence ) 135 mpMainSequence->mbIgnoreChanges++; 136 } 137 138 private: 139 MainSequence* mpMainSequence; 140 }; 141 142 CustomAnimationEffect::CustomAnimationEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) 143 : mnNodeType(-1), 144 mnPresetClass(-1), 145 mfBegin(-1.0), 146 mfDuration(-1.0), 147 mfAbsoluteDuration(-1.0), 148 mnGroupId(-1), 149 mnIterateType(0), 150 mfIterateInterval(0.0), 151 mnParaDepth( -1 ), 152 mbHasText(sal_False), 153 mfAcceleration( 1.0 ), 154 mfDecelerate( 1.0 ), 155 mbAutoReverse(false), 156 mnTargetSubItem(0), 157 mnCommand(0), 158 mpEffectSequence( 0 ), 159 mbHasAfterEffect(false), 160 mbAfterEffectOnNextEffect(false) 161 { 162 setNode( xNode ); 163 } 164 165 // -------------------------------------------------------------------- 166 167 void CustomAnimationEffect::setNode( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) 168 { 169 mxNode = xNode; 170 mxAudio.clear(); 171 172 Sequence< NamedValue > aUserData( mxNode->getUserData() ); 173 sal_Int32 nLength = aUserData.getLength(); 174 const NamedValue* p = aUserData.getConstArray(); 175 176 while( nLength-- ) 177 { 178 if( p->Name.equalsAscii( "node-type" ) ) 179 { 180 p->Value >>= mnNodeType; 181 } 182 else if( p->Name.equalsAscii( "preset-id" ) ) 183 { 184 p->Value >>= maPresetId; 185 } 186 else if( p->Name.equalsAscii( "preset-sub-type" ) ) 187 { 188 p->Value >>= maPresetSubType; 189 } 190 else if( p->Name.equalsAscii( "preset-class" ) ) 191 { 192 p->Value >>= mnPresetClass; 193 } 194 else if( p->Name.equalsAscii( "preset-property" ) ) 195 { 196 p->Value >>= maProperty; 197 } 198 else if( p->Name.equalsAscii( "group-id" ) ) 199 { 200 p->Value >>= mnGroupId; 201 } 202 203 p++; 204 } 205 206 // get effect start time 207 mxNode->getBegin() >>= mfBegin; 208 209 mfAcceleration = mxNode->getAcceleration(); 210 mfDecelerate = mxNode->getDecelerate(); 211 mbAutoReverse = mxNode->getAutoReverse(); 212 213 // get iteration data 214 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY ); 215 if( xIter.is() ) 216 { 217 mfIterateInterval = xIter->getIterateInterval(); 218 mnIterateType = xIter->getIterateType(); 219 maTarget = xIter->getTarget(); 220 mnTargetSubItem = xIter->getSubItem(); 221 } 222 else 223 { 224 mfIterateInterval = 0.0f; 225 mnIterateType = 0; 226 } 227 228 // calculate effect duration and get target shape 229 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY ); 230 if( xEnumerationAccess.is() ) 231 { 232 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY ); 233 if( xEnumeration.is() ) 234 { 235 while( xEnumeration->hasMoreElements() ) 236 { 237 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY ); 238 if( !xChildNode.is() ) 239 continue; 240 241 if( xChildNode->getType() == AnimationNodeType::AUDIO ) 242 { 243 mxAudio.set( xChildNode, UNO_QUERY ); 244 } 245 else if( xChildNode->getType() == AnimationNodeType::COMMAND ) 246 { 247 Reference< XCommand > xCommand( xChildNode, UNO_QUERY ); 248 if( xCommand.is() ) 249 { 250 mnCommand = xCommand->getCommand(); 251 if( !maTarget.hasValue() ) 252 maTarget = xCommand->getTarget(); 253 } 254 } 255 else 256 { 257 double fBegin = 0.0; 258 double fDuration = 0.0; 259 xChildNode->getBegin() >>= fBegin; 260 xChildNode->getDuration() >>= fDuration; 261 262 fDuration += fBegin; 263 if( fDuration > mfDuration ) 264 mfDuration = fDuration; 265 266 // no target shape yet? 267 if( !maTarget.hasValue() ) 268 { 269 // go get it boys! 270 Reference< XAnimate > xAnimate( xChildNode, UNO_QUERY ); 271 if( xAnimate.is() ) 272 { 273 maTarget = xAnimate->getTarget(); 274 mnTargetSubItem = xAnimate->getSubItem(); 275 } 276 } 277 } 278 } 279 } 280 } 281 282 mfAbsoluteDuration = mfDuration; 283 checkForText(); 284 } 285 286 // -------------------------------------------------------------------- 287 288 sal_Int32 CustomAnimationEffect::getNumberOfSubitems( const Any& aTarget, sal_Int16 nIterateType ) 289 { 290 sal_Int32 nSubItems = 0; 291 292 try 293 { 294 // first get target text 295 sal_Int32 nOnlyPara = -1; 296 297 Reference< XText > xShape; 298 aTarget >>= xShape; 299 if( !xShape.is() ) 300 { 301 ParagraphTarget aParaTarget; 302 if( aTarget >>= aParaTarget ) 303 { 304 xShape.set( aParaTarget.Shape, UNO_QUERY ); 305 nOnlyPara = aParaTarget.Paragraph; 306 } 307 } 308 309 // now use the break iterator to iterate over the given text 310 // and count the sub items 311 312 if( xShape.is() ) 313 { 314 // TODO/LATER: Optimize this, don't create a break iterator each time 315 Reference< lang::XMultiServiceFactory > xMSF( ::comphelper::getProcessServiceFactory() ); 316 Reference < i18n::XBreakIterator > xBI( xMSF->createInstance( OUString::createFromAscii( "com.sun.star.i18n.BreakIterator" ) ), UNO_QUERY ); 317 DBG_ASSERT( xBI.is(), "sd::CustomAnimationEffect::getNumberOfSubitems(), could not create a 'com.sun.star.i18n.BreakIterator'!" ); 318 319 if( xBI.is() ) 320 { 321 Reference< XEnumerationAccess > xEA( xShape, UNO_QUERY_THROW ); 322 Reference< XEnumeration > xEnumeration( xEA->createEnumeration(), UNO_QUERY_THROW ); 323 Locale aLocale; 324 const OUString aStrLocaleName( RTL_CONSTASCII_USTRINGPARAM("CharLocale") ); 325 Reference< XTextRange > xParagraph; 326 327 sal_Int32 nPara = 0; 328 while( xEnumeration->hasMoreElements() ) 329 { 330 xEnumeration->nextElement() >>= xParagraph; 331 332 // skip this if its not the only paragraph we want to count 333 if( (nOnlyPara != -1) && (nOnlyPara != nPara ) ) 334 continue; 335 336 if( nIterateType == TextAnimationType::BY_PARAGRAPH ) 337 { 338 nSubItems++; 339 } 340 else 341 { 342 const OUString aText( xParagraph->getString() ); 343 Reference< XPropertySet > xSet( xParagraph, UNO_QUERY_THROW ); 344 xSet->getPropertyValue( aStrLocaleName ) >>= aLocale; 345 346 sal_Int32 nPos; 347 const sal_Int32 nEndPos = aText.getLength(); 348 349 if( nIterateType == TextAnimationType::BY_WORD ) 350 { 351 for( nPos = 0; nPos < nEndPos; nPos++ ) 352 { 353 nPos = xBI->getWordBoundary(aText, nPos, aLocale, i18n::WordType::ANY_WORD, sal_True).endPos; 354 nSubItems++; 355 } 356 break; 357 } 358 else 359 { 360 sal_Int32 nDone; 361 for( nPos = 0; nPos < nEndPos; nPos++ ) 362 { 363 nPos = xBI->nextCharacters(aText, nPos, aLocale, i18n::CharacterIteratorMode::SKIPCELL, 0, nDone); 364 nSubItems++; 365 } 366 } 367 } 368 369 if( nPara == nOnlyPara ) 370 break; 371 372 nPara++; 373 } 374 } 375 } 376 } 377 catch( Exception& e ) 378 { 379 (void)e; 380 nSubItems = 0; 381 DBG_ERROR( "sd::CustomAnimationEffect::getNumberOfSubitems(), exception cought!" ); 382 } 383 384 return nSubItems; 385 } 386 387 // -------------------------------------------------------------------- 388 389 CustomAnimationEffect::~CustomAnimationEffect() 390 { 391 } 392 393 // -------------------------------------------------------------------- 394 395 CustomAnimationEffectPtr CustomAnimationEffect::clone() const 396 { 397 Reference< XCloneable > xCloneable( mxNode, UNO_QUERY_THROW ); 398 Reference< XAnimationNode > xNode( xCloneable->createClone(), UNO_QUERY_THROW ); 399 CustomAnimationEffectPtr pEffect( new CustomAnimationEffect( xNode ) ); 400 pEffect->setEffectSequence( getEffectSequence() ); 401 return pEffect; 402 } 403 404 // -------------------------------------------------------------------- 405 406 sal_Int32 CustomAnimationEffect::get_node_type( const Reference< XAnimationNode >& xNode ) 407 { 408 sal_Int16 nNodeType = -1; 409 410 if( xNode.is() ) 411 { 412 Sequence< NamedValue > aUserData( xNode->getUserData() ); 413 sal_Int32 nLength = aUserData.getLength(); 414 if( nLength ) 415 { 416 const NamedValue* p = aUserData.getConstArray(); 417 while( nLength-- ) 418 { 419 if( p->Name.equalsAscii( "node-type" ) ) 420 { 421 p->Value >>= nNodeType; 422 break; 423 } 424 p++; 425 } 426 } 427 } 428 429 return nNodeType; 430 } 431 432 // -------------------------------------------------------------------- 433 434 void CustomAnimationEffect::setPresetClass( sal_Int16 nPresetClass ) 435 { 436 if( mnPresetClass != nPresetClass ) 437 { 438 mnPresetClass = nPresetClass; 439 if( mxNode.is() ) 440 { 441 // first try to find a "preset-class" entry in the user data 442 // and change it 443 Sequence< NamedValue > aUserData( mxNode->getUserData() ); 444 sal_Int32 nLength = aUserData.getLength(); 445 bool bFound = false; 446 if( nLength ) 447 { 448 NamedValue* p = aUserData.getArray(); 449 while( nLength-- ) 450 { 451 if( p->Name.equalsAscii( "preset-class" ) ) 452 { 453 p->Value <<= mnPresetClass; 454 bFound = true; 455 break; 456 } 457 p++; 458 } 459 } 460 461 // no "node-type" entry inside user data, so add it 462 if( !bFound ) 463 { 464 nLength = aUserData.getLength(); 465 aUserData.realloc( nLength + 1); 466 aUserData[nLength].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "preset-class" ) ); 467 aUserData[nLength].Value <<= mnPresetClass; 468 } 469 470 mxNode->setUserData( aUserData ); 471 } 472 } 473 } 474 475 void CustomAnimationEffect::setNodeType( sal_Int16 nNodeType ) 476 { 477 if( mnNodeType != nNodeType ) 478 { 479 mnNodeType = nNodeType; 480 if( mxNode.is() ) 481 { 482 // first try to find a "node-type" entry in the user data 483 // and change it 484 Sequence< NamedValue > aUserData( mxNode->getUserData() ); 485 sal_Int32 nLength = aUserData.getLength(); 486 bool bFound = false; 487 if( nLength ) 488 { 489 NamedValue* p = aUserData.getArray(); 490 while( nLength-- ) 491 { 492 if( p->Name.equalsAscii( "node-type" ) ) 493 { 494 p->Value <<= mnNodeType; 495 bFound = true; 496 break; 497 } 498 p++; 499 } 500 } 501 502 // no "node-type" entry inside user data, so add it 503 if( !bFound ) 504 { 505 nLength = aUserData.getLength(); 506 aUserData.realloc( nLength + 1); 507 aUserData[nLength].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) ); 508 aUserData[nLength].Value <<= mnNodeType; 509 } 510 511 mxNode->setUserData( aUserData ); 512 } 513 } 514 } 515 516 // -------------------------------------------------------------------- 517 518 void CustomAnimationEffect::setGroupId( sal_Int32 nGroupId ) 519 { 520 mnGroupId = nGroupId; 521 if( mxNode.is() ) 522 { 523 // first try to find a "group-id" entry in the user data 524 // and change it 525 Sequence< NamedValue > aUserData( mxNode->getUserData() ); 526 sal_Int32 nLength = aUserData.getLength(); 527 bool bFound = false; 528 if( nLength ) 529 { 530 NamedValue* p = aUserData.getArray(); 531 while( nLength-- ) 532 { 533 if( p->Name.equalsAscii( "group-id" ) ) 534 { 535 p->Value <<= mnGroupId; 536 bFound = true; 537 break; 538 } 539 p++; 540 } 541 } 542 543 // no "node-type" entry inside user data, so add it 544 if( !bFound ) 545 { 546 nLength = aUserData.getLength(); 547 aUserData.realloc( nLength + 1); 548 aUserData[nLength].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "group-id" ) ); 549 aUserData[nLength].Value <<= mnGroupId; 550 } 551 552 mxNode->setUserData( aUserData ); 553 } 554 } 555 556 // -------------------------------------------------------------------- 557 558 /** checks if the text for this effect has changed and updates internal flags. 559 returns true if something changed. 560 */ 561 bool CustomAnimationEffect::checkForText() 562 { 563 bool bChange = false; 564 565 Reference< XText > xText; 566 567 if( maTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) ) 568 { 569 // calc para depth 570 ParagraphTarget aParaTarget; 571 maTarget >>= aParaTarget; 572 573 xText = Reference< XText >::query( aParaTarget.Shape ); 574 575 // get paragraph 576 if( xText.is() ) 577 { 578 Reference< XEnumerationAccess > xEA( xText, UNO_QUERY ); 579 if( xEA.is() ) 580 { 581 Reference< XEnumeration > xEnumeration( xEA->createEnumeration(), UNO_QUERY ); 582 if( xEnumeration.is() ) 583 { 584 sal_Bool bHasText = xEnumeration->hasMoreElements(); 585 bChange |= bHasText != mbHasText; 586 mbHasText = bHasText; 587 588 sal_Int32 nPara = aParaTarget.Paragraph; 589 590 while( xEnumeration->hasMoreElements() && nPara-- ) 591 xEnumeration->nextElement(); 592 593 if( xEnumeration->hasMoreElements() ) 594 { 595 Reference< XPropertySet > xParaSet; 596 xEnumeration->nextElement() >>= xParaSet; 597 if( xParaSet.is() ) 598 { 599 sal_Int32 nParaDepth = 0; 600 const OUString strNumberingLevel( RTL_CONSTASCII_USTRINGPARAM("NumberingLevel") ); 601 xParaSet->getPropertyValue( strNumberingLevel ) >>= nParaDepth; 602 bChange |= nParaDepth != mnParaDepth; 603 mnParaDepth = nParaDepth; 604 } 605 } 606 } 607 } 608 } 609 } 610 else 611 { 612 maTarget >>= xText; 613 sal_Bool bHasText = xText.is() && xText->getString().getLength(); 614 bChange |= bHasText != mbHasText; 615 mbHasText = bHasText; 616 } 617 618 bChange |= calculateIterateDuration(); 619 return bChange; 620 } 621 622 bool CustomAnimationEffect::calculateIterateDuration() 623 { 624 bool bChange = false; 625 626 // if we have an iteration, we must also calculate the 627 // 'true' container duration, that is 628 // ( ( is form animated ) ? [contained effects duration] : 0 ) + 629 // ( [number of animated children] - 1 ) * [interval-delay] + [contained effects duration] 630 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY ); 631 if( xIter.is() ) 632 { 633 double fDuration = mfDuration; 634 const double fSubEffectDuration = mfDuration; 635 636 if( mnTargetSubItem != ShapeAnimationSubType::ONLY_BACKGROUND ) // does not make sense for iterate container but better check 637 { 638 const sal_Int32 nSubItems = getNumberOfSubitems( maTarget, mnIterateType ); 639 if( nSubItems ) 640 { 641 const double f = (nSubItems-1) * mfIterateInterval; 642 fDuration += f; 643 } 644 } 645 646 // if we also animate the form first, we have to add the 647 // sub effect duration to the whole effect duration 648 if( mnTargetSubItem == ShapeAnimationSubType::AS_WHOLE ) 649 fDuration += fSubEffectDuration; 650 651 bChange |= fDuration != mfAbsoluteDuration; 652 mfAbsoluteDuration = fDuration; 653 } 654 655 return bChange; 656 } 657 658 // -------------------------------------------------------------------- 659 660 void CustomAnimationEffect::setTarget( const ::com::sun::star::uno::Any& rTarget ) 661 { 662 try 663 { 664 maTarget = rTarget; 665 666 // first, check special case for random node 667 Reference< XInitialization > xInit( mxNode, UNO_QUERY ); 668 if( xInit.is() ) 669 { 670 const Sequence< Any > aArgs( &maTarget, 1 ); 671 xInit->initialize( aArgs ); 672 } 673 else 674 { 675 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY ); 676 if( xIter.is() ) 677 { 678 xIter->setTarget(maTarget); 679 } 680 else 681 { 682 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY ); 683 if( xEnumerationAccess.is() ) 684 { 685 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY ); 686 if( xEnumeration.is() ) 687 { 688 while( xEnumeration->hasMoreElements() ) 689 { 690 const Any aElem( xEnumeration->nextElement() ); 691 Reference< XAnimate > xAnimate( aElem, UNO_QUERY ); 692 if( xAnimate.is() ) 693 xAnimate->setTarget( rTarget ); 694 else 695 { 696 Reference< XCommand > xCommand( aElem, UNO_QUERY ); 697 if( xCommand.is() ) 698 xCommand->setTarget( rTarget ); 699 } 700 } 701 } 702 } 703 } 704 } 705 checkForText(); 706 } 707 catch( Exception& ) 708 { 709 DBG_ERROR( "sd::CustomAnimationEffect::setTarget(), exception cought!" ); 710 } 711 } 712 713 // -------------------------------------------------------------------- 714 715 void CustomAnimationEffect::setTargetSubItem( sal_Int16 nSubItem ) 716 { 717 try 718 { 719 mnTargetSubItem = nSubItem; 720 721 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY ); 722 if( xIter.is() ) 723 { 724 xIter->setSubItem(mnTargetSubItem); 725 } 726 else 727 { 728 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY ); 729 if( xEnumerationAccess.is() ) 730 { 731 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY ); 732 if( xEnumeration.is() ) 733 { 734 while( xEnumeration->hasMoreElements() ) 735 { 736 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY ); 737 if( xAnimate.is() ) 738 xAnimate->setSubItem( mnTargetSubItem ); 739 } 740 } 741 } 742 } 743 } 744 catch( Exception& ) 745 { 746 DBG_ERROR( "sd::CustomAnimationEffect::setTargetSubItem(), exception cought!" ); 747 } 748 } 749 750 // -------------------------------------------------------------------- 751 752 void CustomAnimationEffect::setDuration( double fDuration ) 753 { 754 if( (mfDuration != -1.0) && (mfDuration != fDuration) ) try 755 { 756 double fScale = fDuration / mfDuration; 757 mfDuration = fDuration; 758 mfAbsoluteDuration = mfDuration; 759 760 // calculate effect duration and get target shape 761 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY ); 762 if( xEnumerationAccess.is() ) 763 { 764 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY ); 765 if( xEnumeration.is() ) 766 { 767 while( xEnumeration->hasMoreElements() ) 768 { 769 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY ); 770 if( !xChildNode.is() ) 771 continue; 772 773 774 double fChildBegin = 0.0; 775 xChildNode->getBegin() >>= fChildBegin; 776 if( fChildBegin != 0.0 ) 777 { 778 fChildBegin *= fScale; 779 xChildNode->setBegin( makeAny( fChildBegin ) ); 780 } 781 782 double fChildDuration = 0.0; 783 xChildNode->getDuration() >>= fChildDuration; 784 if( fChildDuration != 0.0 ) 785 { 786 fChildDuration *= fScale; 787 xChildNode->setDuration( makeAny( fChildDuration ) ); 788 } 789 } 790 } 791 } 792 calculateIterateDuration(); 793 } 794 catch( Exception& ) 795 { 796 DBG_ERROR( "sd::CustomAnimationEffect::setDuration(), exception cought!" ); 797 } 798 } 799 800 // -------------------------------------------------------------------- 801 802 void CustomAnimationEffect::setBegin( double fBegin ) 803 { 804 if( mxNode.is() ) try 805 { 806 mfBegin = fBegin; 807 mxNode->setBegin( makeAny( fBegin ) ); 808 } 809 catch( Exception& ) 810 { 811 DBG_ERROR( "sd::CustomAnimationEffect::setBegin(), exception cought!" ); 812 } 813 } 814 815 // -------------------------------------------------------------------- 816 817 void CustomAnimationEffect::setAcceleration( double fAcceleration ) 818 { 819 if( mxNode.is() ) try 820 { 821 mfAcceleration = fAcceleration; 822 mxNode->setAcceleration( fAcceleration ); 823 } 824 catch( Exception& ) 825 { 826 DBG_ERROR( "sd::CustomAnimationEffect::setAcceleration(), exception cought!" ); 827 } 828 } 829 // -------------------------------------------------------------------- 830 831 void CustomAnimationEffect::setDecelerate( double fDecelerate ) 832 { 833 if( mxNode.is() ) try 834 { 835 mfDecelerate = fDecelerate; 836 mxNode->setDecelerate( fDecelerate ); 837 } 838 catch( Exception& ) 839 { 840 DBG_ERROR( "sd::CustomAnimationEffect::setDecelerate(), exception cought!" ); 841 } 842 } 843 844 // -------------------------------------------------------------------- 845 846 void CustomAnimationEffect::setAutoReverse( sal_Bool bAutoReverse ) 847 { 848 if( mxNode.is() ) try 849 { 850 mbAutoReverse = bAutoReverse; 851 mxNode->setAutoReverse( bAutoReverse ); 852 } 853 catch( Exception& ) 854 { 855 DBG_ERROR( "sd::CustomAnimationEffect::setAutoReverse(), exception cought!" ); 856 } 857 } 858 859 // -------------------------------------------------------------------- 860 861 void CustomAnimationEffect::replaceNode( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) 862 { 863 sal_Int16 nNodeType = mnNodeType; 864 Any aTarget = maTarget; 865 866 double fBegin = mfBegin; 867 double fDuration = mfDuration; 868 double fAcceleration = mfAcceleration; 869 double fDecelerate = mfDecelerate ; 870 sal_Bool bAutoReverse = mbAutoReverse; 871 Reference< XAudio > xAudio( mxAudio ); 872 sal_Int16 nIterateType = mnIterateType; 873 double fIterateInterval = mfIterateInterval; 874 sal_Int16 nSubItem = mnTargetSubItem; 875 876 setNode( xNode ); 877 878 setAudio( xAudio ); 879 setNodeType( nNodeType ); 880 setTarget( aTarget ); 881 setTargetSubItem( nSubItem ); 882 setDuration( fDuration ); 883 setBegin( fBegin ); 884 885 setAcceleration( fAcceleration ); 886 setDecelerate( fDecelerate ); 887 setAutoReverse( bAutoReverse ); 888 889 if( nIterateType != mnIterateType ) 890 setIterateType( nIterateType ); 891 892 if( mnIterateType && ( fIterateInterval != mfIterateInterval ) ) 893 setIterateInterval( fIterateInterval ); 894 } 895 896 // -------------------------------------------------------------------- 897 898 Reference< XShape > CustomAnimationEffect::getTargetShape() const 899 { 900 Reference< XShape > xShape; 901 maTarget >>= xShape; 902 if( !xShape.is() ) 903 { 904 ParagraphTarget aParaTarget; 905 if( maTarget >>= aParaTarget ) 906 xShape = aParaTarget.Shape; 907 } 908 909 return xShape; 910 } 911 912 // -------------------------------------------------------------------- 913 914 Any CustomAnimationEffect::getRepeatCount() const 915 { 916 if( mxNode.is() ) 917 { 918 return mxNode->getRepeatCount(); 919 } 920 else 921 { 922 Any aAny; 923 return aAny; 924 } 925 } 926 927 // -------------------------------------------------------------------- 928 929 Any CustomAnimationEffect::getEnd() const 930 { 931 if( mxNode.is() ) 932 { 933 return mxNode->getEnd(); 934 } 935 else 936 { 937 Any aAny; 938 return aAny; 939 } 940 } 941 942 // -------------------------------------------------------------------- 943 944 sal_Int16 CustomAnimationEffect::getFill() const 945 { 946 if( mxNode.is() ) 947 return mxNode->getFill(); 948 else 949 return 0; 950 } 951 952 // -------------------------------------------------------------------- 953 954 void CustomAnimationEffect::setRepeatCount( const Any& rRepeatCount ) 955 { 956 if( mxNode.is() ) 957 mxNode->setRepeatCount( rRepeatCount ); 958 } 959 960 // -------------------------------------------------------------------- 961 962 void CustomAnimationEffect::setEnd( const Any& rEnd ) 963 { 964 if( mxNode.is() ) 965 mxNode->setEnd( rEnd ); 966 } 967 968 // -------------------------------------------------------------------- 969 970 void CustomAnimationEffect::setFill( sal_Int16 nFill ) 971 { 972 if( mxNode.is() ) 973 mxNode->setFill( nFill ); 974 } 975 976 // -------------------------------------------------------------------- 977 978 Reference< XAnimationNode > CustomAnimationEffect::createAfterEffectNode() const throw (Exception) 979 { 980 DBG_ASSERT( mbHasAfterEffect, "sd::CustomAnimationEffect::createAfterEffectNode(), this node has no after effect!" ); 981 982 Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() ); 983 984 const char* pServiceName = maDimColor.hasValue() ? 985 "com.sun.star.animations.AnimateColor" : "com.sun.star.animations.AnimateSet"; 986 987 Reference< XAnimate > xAnimate( xMsf->createInstance(OUString::createFromAscii(pServiceName) ), UNO_QUERY_THROW ); 988 989 Any aTo; 990 OUString aAttributeName; 991 992 if( maDimColor.hasValue() ) 993 { 994 aTo = maDimColor; 995 aAttributeName = OUString( RTL_CONSTASCII_USTRINGPARAM( "DimColor" ) ); 996 } 997 else 998 { 999 aTo = makeAny( (sal_Bool)sal_False ); 1000 aAttributeName = OUString( RTL_CONSTASCII_USTRINGPARAM( "Visibility" ) ); 1001 } 1002 1003 Any aBegin; 1004 if( !mbAfterEffectOnNextEffect ) // sameClick 1005 { 1006 Event aEvent; 1007 1008 aEvent.Source <<= getNode(); 1009 aEvent.Trigger = EventTrigger::END_EVENT; 1010 aEvent.Repeat = 0; 1011 1012 aBegin <<= aEvent; 1013 } 1014 else 1015 { 1016 aBegin <<= (double)0.0; 1017 } 1018 1019 xAnimate->setBegin( aBegin ); 1020 xAnimate->setTo( aTo ); 1021 xAnimate->setAttributeName( aAttributeName ); 1022 1023 xAnimate->setDuration( makeAny( (double)0.001 ) ); 1024 xAnimate->setFill( AnimationFill::HOLD ); 1025 xAnimate->setTarget( maTarget ); 1026 1027 return Reference< XAnimationNode >( xAnimate, UNO_QUERY_THROW ); 1028 } 1029 1030 // -------------------------------------------------------------------- 1031 1032 void CustomAnimationEffect::setIterateType( sal_Int16 nIterateType ) 1033 { 1034 if( mnIterateType != nIterateType ) try 1035 { 1036 // do we need to exchange the container node? 1037 if( (mnIterateType == 0) || (nIterateType == 0) ) 1038 { 1039 sal_Int16 nTargetSubItem = mnTargetSubItem; 1040 1041 Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() ); 1042 const char * pServiceName = 1043 nIterateType ? "com.sun.star.animations.IterateContainer" : "com.sun.star.animations.ParallelTimeContainer"; 1044 Reference< XTimeContainer > xNewContainer( 1045 xMsf->createInstance( OUString::createFromAscii(pServiceName) ), UNO_QUERY_THROW ); 1046 1047 Reference< XTimeContainer > xOldContainer( mxNode, UNO_QUERY_THROW ); 1048 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW ); 1049 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW ); 1050 while( xEnumeration->hasMoreElements() ) 1051 { 1052 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW ); 1053 xOldContainer->removeChild( xChildNode ); 1054 xNewContainer->appendChild( xChildNode ); 1055 } 1056 1057 Reference< XAnimationNode > xNewNode( xNewContainer, UNO_QUERY_THROW ); 1058 1059 xNewNode->setBegin( mxNode->getBegin() ); 1060 xNewNode->setDuration( mxNode->getDuration() ); 1061 xNewNode->setEnd( mxNode->getEnd() ); 1062 xNewNode->setEndSync( mxNode->getEndSync() ); 1063 xNewNode->setRepeatCount( mxNode->getRepeatCount() ); 1064 xNewNode->setFill( mxNode->getFill() ); 1065 xNewNode->setFillDefault( mxNode->getFillDefault() ); 1066 xNewNode->setRestart( mxNode->getRestart() ); 1067 xNewNode->setRestartDefault( mxNode->getRestartDefault() ); 1068 xNewNode->setAcceleration( mxNode->getAcceleration() ); 1069 xNewNode->setDecelerate( mxNode->getDecelerate() ); 1070 xNewNode->setAutoReverse( mxNode->getAutoReverse() ); 1071 xNewNode->setRepeatDuration( mxNode->getRepeatDuration() ); 1072 xNewNode->setEndSync( mxNode->getEndSync() ); 1073 xNewNode->setRepeatCount( mxNode->getRepeatCount() ); 1074 xNewNode->setUserData( mxNode->getUserData() ); 1075 1076 mxNode = xNewNode; 1077 1078 Any aTarget; 1079 if( nIterateType ) 1080 { 1081 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY_THROW ); 1082 xIter->setTarget(maTarget); 1083 xIter->setSubItem( nTargetSubItem ); 1084 } 1085 else 1086 { 1087 aTarget = maTarget; 1088 } 1089 1090 Reference< XEnumerationAccess > xEA( mxNode, UNO_QUERY_THROW ); 1091 Reference< XEnumeration > xE( xEA->createEnumeration(), UNO_QUERY_THROW ); 1092 while( xE->hasMoreElements() ) 1093 { 1094 Reference< XAnimate > xAnimate( xE->nextElement(), UNO_QUERY ); 1095 if( xAnimate.is() ) 1096 { 1097 xAnimate->setTarget( aTarget ); 1098 xAnimate->setSubItem( nTargetSubItem ); 1099 } 1100 } 1101 } 1102 1103 mnIterateType = nIterateType; 1104 1105 // if we have an iteration container, we must set its type 1106 if( mnIterateType ) 1107 { 1108 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY_THROW ); 1109 xIter->setIterateType( nIterateType ); 1110 } 1111 1112 checkForText(); 1113 } 1114 catch( Exception& e ) 1115 { 1116 (void)e; 1117 DBG_ERROR( "sd::CustomAnimationEffect::setIterateType(), Exception cought!" ); 1118 } 1119 } 1120 1121 // -------------------------------------------------------------------- 1122 1123 void CustomAnimationEffect::setIterateInterval( double fIterateInterval ) 1124 { 1125 if( mfIterateInterval != fIterateInterval ) 1126 { 1127 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY ); 1128 1129 DBG_ASSERT( xIter.is(), "sd::CustomAnimationEffect::setIterateInterval(), not an iteration node" ); 1130 if( xIter.is() ) 1131 { 1132 mfIterateInterval = fIterateInterval; 1133 xIter->setIterateInterval( fIterateInterval ); 1134 } 1135 1136 calculateIterateDuration(); 1137 } 1138 } 1139 1140 // -------------------------------------------------------------------- 1141 1142 ::rtl::OUString CustomAnimationEffect::getPath() const 1143 { 1144 ::rtl::OUString aPath; 1145 1146 if( mxNode.is() ) try 1147 { 1148 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW ); 1149 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW ); 1150 while( xEnumeration->hasMoreElements() ) 1151 { 1152 Reference< XAnimateMotion > xMotion( xEnumeration->nextElement(), UNO_QUERY ); 1153 if( xMotion.is() ) 1154 { 1155 xMotion->getPath() >>= aPath; 1156 break; 1157 } 1158 } 1159 } 1160 catch( Exception& e ) 1161 { 1162 (void)e; 1163 DBG_ERROR("sd::CustomAnimationEffect::getPath(), exception cought!" ); 1164 } 1165 1166 return aPath; 1167 } 1168 1169 // -------------------------------------------------------------------- 1170 1171 void CustomAnimationEffect::setPath( const ::rtl::OUString& rPath ) 1172 { 1173 if( mxNode.is() ) try 1174 { 1175 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW ); 1176 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW ); 1177 while( xEnumeration->hasMoreElements() ) 1178 { 1179 Reference< XAnimateMotion > xMotion( xEnumeration->nextElement(), UNO_QUERY ); 1180 if( xMotion.is() ) 1181 { 1182 1183 MainSequenceChangeGuard aGuard( mpEffectSequence ); 1184 xMotion->setPath( Any( rPath ) ); 1185 break; 1186 } 1187 } 1188 } 1189 catch( Exception& e ) 1190 { 1191 (void)e; 1192 DBG_ERROR("sd::CustomAnimationEffect::setPath(), exception cought!" ); 1193 } 1194 } 1195 1196 // -------------------------------------------------------------------- 1197 1198 Any CustomAnimationEffect::getProperty( sal_Int32 nNodeType, const OUString& rAttributeName, EValue eValue ) 1199 { 1200 Any aProperty; 1201 if( mxNode.is() ) try 1202 { 1203 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY ); 1204 if( xEnumerationAccess.is() ) 1205 { 1206 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY ); 1207 if( xEnumeration.is() ) 1208 { 1209 while( xEnumeration->hasMoreElements() && !aProperty.hasValue() ) 1210 { 1211 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY ); 1212 if( !xAnimate.is() ) 1213 continue; 1214 1215 if( xAnimate->getType() == nNodeType ) 1216 { 1217 if( xAnimate->getAttributeName() == rAttributeName ) 1218 { 1219 switch( eValue ) 1220 { 1221 case VALUE_FROM: aProperty = xAnimate->getFrom(); break; 1222 case VALUE_TO: aProperty = xAnimate->getTo(); break; 1223 case VALUE_BY: aProperty = xAnimate->getBy(); break; 1224 case VALUE_FIRST: 1225 case VALUE_LAST: 1226 { 1227 Sequence<Any> aValues( xAnimate->getValues() ); 1228 if( aValues.hasElements() ) 1229 aProperty = aValues[ eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1 ]; 1230 } 1231 break; 1232 } 1233 } 1234 } 1235 } 1236 } 1237 } 1238 } 1239 catch( Exception& e ) 1240 { 1241 (void)e; 1242 DBG_ERROR("sd::CustomAnimationEffect::getProperty(), exception cought!" ); 1243 } 1244 1245 return aProperty; 1246 } 1247 1248 // -------------------------------------------------------------------- 1249 1250 bool CustomAnimationEffect::setProperty( sal_Int32 nNodeType, const OUString& rAttributeName, EValue eValue, const Any& rValue ) 1251 { 1252 bool bChanged = false; 1253 if( mxNode.is() ) try 1254 { 1255 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY ); 1256 if( xEnumerationAccess.is() ) 1257 { 1258 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY ); 1259 if( xEnumeration.is() ) 1260 { 1261 while( xEnumeration->hasMoreElements() ) 1262 { 1263 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY ); 1264 if( !xAnimate.is() ) 1265 continue; 1266 1267 if( xAnimate->getType() == nNodeType ) 1268 { 1269 if( xAnimate->getAttributeName() == rAttributeName ) 1270 { 1271 switch( eValue ) 1272 { 1273 case VALUE_FROM: 1274 if( xAnimate->getFrom() != rValue ) 1275 { 1276 xAnimate->setFrom( rValue ); 1277 bChanged = true; 1278 } 1279 break; 1280 case VALUE_TO: 1281 if( xAnimate->getTo() != rValue ) 1282 { 1283 xAnimate->setTo( rValue ); 1284 bChanged = true; 1285 } 1286 break; 1287 case VALUE_BY: 1288 if( xAnimate->getTo() != rValue ) 1289 { 1290 xAnimate->setBy( rValue ); 1291 bChanged = true; 1292 } 1293 break; 1294 case VALUE_FIRST: 1295 case VALUE_LAST: 1296 { 1297 Sequence<Any> aValues( xAnimate->getValues() ); 1298 if( !aValues.hasElements() ) 1299 aValues.realloc(1); 1300 1301 sal_Int32 nIndex = eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1; 1302 1303 if( aValues[ nIndex ] != rValue ) 1304 { 1305 aValues[ nIndex ] = rValue; 1306 xAnimate->setValues( aValues ); 1307 bChanged = true; 1308 } 1309 } 1310 } 1311 } 1312 } 1313 } 1314 } 1315 } 1316 } 1317 catch( Exception& e ) 1318 { 1319 (void)e; 1320 DBG_ERROR("sd::CustomAnimationEffect::setProperty(), exception cought!" ); 1321 } 1322 1323 return bChanged; 1324 } 1325 1326 // -------------------------------------------------------------------- 1327 1328 static bool implIsColorAttribute( const OUString& rAttributeName ) 1329 { 1330 return rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("FillColor") ) || 1331 rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("LineColor") ) || 1332 rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("CharColor") ); 1333 } 1334 1335 // -------------------------------------------------------------------- 1336 1337 Any CustomAnimationEffect::getColor( sal_Int32 nIndex ) 1338 { 1339 Any aColor; 1340 if( mxNode.is() ) try 1341 { 1342 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY ); 1343 if( xEnumerationAccess.is() ) 1344 { 1345 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY ); 1346 if( xEnumeration.is() ) 1347 { 1348 while( xEnumeration->hasMoreElements() && !aColor.hasValue() ) 1349 { 1350 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY ); 1351 if( !xAnimate.is() ) 1352 continue; 1353 1354 switch( xAnimate->getType() ) 1355 { 1356 case AnimationNodeType::SET: 1357 case AnimationNodeType::ANIMATE: 1358 if( !implIsColorAttribute( xAnimate->getAttributeName() ) ) 1359 break; 1360 case AnimationNodeType::ANIMATECOLOR: 1361 Sequence<Any> aValues( xAnimate->getValues() ); 1362 if( aValues.hasElements() ) 1363 { 1364 if( aValues.getLength() > nIndex ) 1365 aColor = aValues[nIndex]; 1366 } 1367 else if( nIndex == 0 ) 1368 aColor = xAnimate->getFrom(); 1369 else 1370 aColor = xAnimate->getTo(); 1371 } 1372 } 1373 } 1374 } 1375 } 1376 catch( Exception& e ) 1377 { 1378 (void)e; 1379 DBG_ERROR("sd::CustomAnimationEffect::getColor(), exception cought!" ); 1380 } 1381 1382 return aColor; 1383 } 1384 1385 // -------------------------------------------------------------------- 1386 1387 void CustomAnimationEffect::setColor( sal_Int32 nIndex, const Any& rColor ) 1388 { 1389 if( mxNode.is() ) try 1390 { 1391 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY ); 1392 if( xEnumerationAccess.is() ) 1393 { 1394 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY ); 1395 if( xEnumeration.is() ) 1396 { 1397 while( xEnumeration->hasMoreElements() ) 1398 { 1399 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY ); 1400 if( !xAnimate.is() ) 1401 continue; 1402 1403 switch( xAnimate->getType() ) 1404 { 1405 case AnimationNodeType::SET: 1406 case AnimationNodeType::ANIMATE: 1407 if( !implIsColorAttribute( xAnimate->getAttributeName() ) ) 1408 break; 1409 case AnimationNodeType::ANIMATECOLOR: 1410 { 1411 Sequence<Any> aValues( xAnimate->getValues() ); 1412 if( aValues.hasElements() ) 1413 { 1414 if( aValues.getLength() > nIndex ) 1415 { 1416 aValues[nIndex] = rColor; 1417 xAnimate->setValues( aValues ); 1418 } 1419 } 1420 else if( (nIndex == 0) && xAnimate->getFrom().hasValue() ) 1421 xAnimate->setFrom(rColor); 1422 else if( (nIndex == 1) && xAnimate->getTo().hasValue() ) 1423 xAnimate->setTo(rColor); 1424 } 1425 break; 1426 1427 } 1428 } 1429 } 1430 } 1431 } 1432 catch( Exception& e ) 1433 { 1434 (void)e; 1435 DBG_ERROR("sd::CustomAnimationEffect::setColor(), exception cought!" ); 1436 } 1437 } 1438 1439 // -------------------------------------------------------------------- 1440 1441 Any CustomAnimationEffect::getTransformationProperty( sal_Int32 nTransformType, EValue eValue ) 1442 { 1443 Any aProperty; 1444 if( mxNode.is() ) try 1445 { 1446 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY ); 1447 if( xEnumerationAccess.is() ) 1448 { 1449 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY ); 1450 if( xEnumeration.is() ) 1451 { 1452 while( xEnumeration->hasMoreElements() && !aProperty.hasValue() ) 1453 { 1454 Reference< XAnimateTransform > xTransform( xEnumeration->nextElement(), UNO_QUERY ); 1455 if( !xTransform.is() ) 1456 continue; 1457 1458 if( xTransform->getTransformType() == nTransformType ) 1459 { 1460 switch( eValue ) 1461 { 1462 case VALUE_FROM: aProperty = xTransform->getFrom(); break; 1463 case VALUE_TO: aProperty = xTransform->getTo(); break; 1464 case VALUE_BY: aProperty = xTransform->getBy(); break; 1465 case VALUE_FIRST: 1466 case VALUE_LAST: 1467 { 1468 Sequence<Any> aValues( xTransform->getValues() ); 1469 if( aValues.hasElements() ) 1470 aProperty = aValues[ eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1 ]; 1471 } 1472 break; 1473 } 1474 } 1475 } 1476 } 1477 } 1478 } 1479 catch( Exception& e ) 1480 { 1481 (void)e; 1482 DBG_ERROR("sd::CustomAnimationEffect::getTransformationProperty(), exception cought!" ); 1483 } 1484 1485 return aProperty; 1486 } 1487 1488 // -------------------------------------------------------------------- 1489 1490 bool CustomAnimationEffect::setTransformationProperty( sal_Int32 nTransformType, EValue eValue, const Any& rValue ) 1491 { 1492 bool bChanged = false; 1493 if( mxNode.is() ) try 1494 { 1495 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY ); 1496 if( xEnumerationAccess.is() ) 1497 { 1498 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY ); 1499 if( xEnumeration.is() ) 1500 { 1501 while( xEnumeration->hasMoreElements() ) 1502 { 1503 Reference< XAnimateTransform > xTransform( xEnumeration->nextElement(), UNO_QUERY ); 1504 if( !xTransform.is() ) 1505 continue; 1506 1507 if( xTransform->getTransformType() == nTransformType ) 1508 { 1509 switch( eValue ) 1510 { 1511 case VALUE_FROM: 1512 if( xTransform->getFrom() != rValue ) 1513 { 1514 xTransform->setFrom( rValue ); 1515 bChanged = true; 1516 } 1517 break; 1518 case VALUE_TO: 1519 if( xTransform->getTo() != rValue ) 1520 { 1521 xTransform->setTo( rValue ); 1522 bChanged = true; 1523 } 1524 break; 1525 case VALUE_BY: 1526 if( xTransform->getBy() != rValue ) 1527 { 1528 xTransform->setBy( rValue ); 1529 bChanged = true; 1530 } 1531 break; 1532 case VALUE_FIRST: 1533 case VALUE_LAST: 1534 { 1535 Sequence<Any> aValues( xTransform->getValues() ); 1536 if( !aValues.hasElements() ) 1537 aValues.realloc(1); 1538 1539 sal_Int32 nIndex = eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1; 1540 if( aValues[nIndex] != rValue ) 1541 { 1542 aValues[nIndex] = rValue; 1543 xTransform->setValues( aValues ); 1544 bChanged = true; 1545 } 1546 } 1547 } 1548 } 1549 } 1550 } 1551 } 1552 } 1553 catch( Exception& e ) 1554 { 1555 (void)e; 1556 DBG_ERROR("sd::CustomAnimationEffect::setTransformationProperty(), exception cought!" ); 1557 } 1558 1559 return bChanged; 1560 } 1561 1562 // -------------------------------------------------------------------- 1563 1564 void CustomAnimationEffect::createAudio( const ::com::sun::star::uno::Any& rSource, double fVolume /* = 1.0 */ ) 1565 { 1566 DBG_ASSERT( !mxAudio.is(), "sd::CustomAnimationEffect::createAudio(), node already has an audio!" ); 1567 1568 if( !mxAudio.is() ) try 1569 { 1570 Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() ); 1571 Reference< XAudio > xAudio( xMsf->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.Audio") ) ), UNO_QUERY_THROW ); 1572 xAudio->setSource( rSource ); 1573 xAudio->setVolume( fVolume ); 1574 setAudio( xAudio ); 1575 } 1576 catch( Exception& e ) 1577 { 1578 (void)e; 1579 DBG_ERROR("sd::CustomAnimationEffect::createAudio(), exception cought!" ); 1580 } 1581 } 1582 1583 // -------------------------------------------------------------------- 1584 1585 static Reference< XCommand > findCommandNode( const Reference< XAnimationNode >& xRootNode ) 1586 { 1587 Reference< XCommand > xCommand; 1588 1589 if( xRootNode.is() ) try 1590 { 1591 Reference< XEnumerationAccess > xEnumerationAccess( xRootNode, UNO_QUERY_THROW ); 1592 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW ); 1593 while( !xCommand.is() && xEnumeration->hasMoreElements() ) 1594 { 1595 Reference< XAnimationNode > xNode( xEnumeration->nextElement(), UNO_QUERY ); 1596 if( xNode.is() && (xNode->getType() == AnimationNodeType::COMMAND) ) 1597 xCommand.set( xNode, UNO_QUERY_THROW ); 1598 } 1599 } 1600 catch( Exception& e ) 1601 { 1602 (void)e; 1603 DBG_ERROR("sd::findCommandNode(), exception caught!" ); 1604 } 1605 1606 return xCommand; 1607 } 1608 1609 void CustomAnimationEffect::removeAudio() 1610 { 1611 try 1612 { 1613 Reference< XAnimationNode > xChild; 1614 1615 if( mxAudio.is() ) 1616 { 1617 xChild.set( mxAudio, UNO_QUERY ); 1618 mxAudio.clear(); 1619 } 1620 else if( mnCommand == EffectCommands::STOPAUDIO ) 1621 { 1622 xChild.set( findCommandNode( mxNode ), UNO_QUERY ); 1623 mnCommand = 0; 1624 } 1625 1626 if( xChild.is() ) 1627 { 1628 Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY ); 1629 if( xContainer.is() ) 1630 xContainer->removeChild( xChild ); 1631 } 1632 } 1633 catch( Exception& e ) 1634 { 1635 (void)e; 1636 DBG_ERROR("sd::CustomAnimationEffect::removeAudio(), exception caught!" ); 1637 } 1638 1639 } 1640 1641 // -------------------------------------------------------------------- 1642 1643 void CustomAnimationEffect::setAudio( const Reference< ::com::sun::star::animations::XAudio >& xAudio ) 1644 { 1645 if( mxAudio != xAudio ) try 1646 { 1647 removeAudio(); 1648 mxAudio = xAudio; 1649 Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY ); 1650 Reference< XAnimationNode > xChild( mxAudio, UNO_QUERY ); 1651 if( xContainer.is() && xChild.is() ) 1652 xContainer->appendChild( xChild ); 1653 } 1654 catch( Exception& e ) 1655 { 1656 (void)e; 1657 DBG_ERROR("sd::CustomAnimationEffect::setAudio(), exception caught!" ); 1658 } 1659 } 1660 1661 // -------------------------------------------------------------------- 1662 1663 void CustomAnimationEffect::setStopAudio() 1664 { 1665 if( mnCommand != EffectCommands::STOPAUDIO ) try 1666 { 1667 if( mxAudio.is() ) 1668 removeAudio(); 1669 1670 Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() ); 1671 Reference< XCommand > xCommand( xMsf->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.Command") ) ), UNO_QUERY_THROW ); 1672 1673 xCommand->setCommand( EffectCommands::STOPAUDIO ); 1674 1675 Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY_THROW ); 1676 Reference< XAnimationNode > xChild( xCommand, UNO_QUERY_THROW ); 1677 xContainer->appendChild( xChild ); 1678 1679 mnCommand = EffectCommands::STOPAUDIO; 1680 } 1681 catch( Exception& e ) 1682 { 1683 (void)e; 1684 DBG_ERROR("sd::CustomAnimationEffect::setStopAudio(), exception caught!" ); 1685 } 1686 } 1687 1688 // -------------------------------------------------------------------- 1689 1690 bool CustomAnimationEffect::getStopAudio() const 1691 { 1692 return mnCommand == EffectCommands::STOPAUDIO; 1693 } 1694 1695 // -------------------------------------------------------------------- 1696 1697 SdrPathObj* CustomAnimationEffect::createSdrPathObjFromPath() 1698 { 1699 SdrPathObj * pPathObj = new SdrPathObj( OBJ_PATHLINE ); 1700 updateSdrPathObjFromPath( *pPathObj ); 1701 return pPathObj; 1702 } 1703 1704 // -------------------------------------------------------------------- 1705 1706 void CustomAnimationEffect::updateSdrPathObjFromPath( SdrPathObj& rPathObj ) 1707 { 1708 ::basegfx::B2DPolyPolygon xPolyPoly; 1709 if( ::basegfx::tools::importFromSvgD( xPolyPoly, getPath(), true, 0 ) ) 1710 { 1711 SdrObject* pObj = GetSdrObjectFromXShape( getTargetShape() ); 1712 if( pObj ) 1713 { 1714 SdrPage* pPage = pObj->GetPage(); 1715 if( pPage ) 1716 { 1717 const Size aPageSize( pPage->GetSize() ); 1718 xPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix((double)aPageSize.Width(), (double)aPageSize.Height())); 1719 } 1720 1721 const Rectangle aBoundRect( pObj->GetCurrentBoundRect() ); 1722 const Point aCenter( aBoundRect.Center() ); 1723 xPolyPoly.transform(basegfx::tools::createTranslateB2DHomMatrix(aCenter.X(), aCenter.Y())); 1724 } 1725 } 1726 1727 rPathObj.SetPathPoly( xPolyPoly ); 1728 } 1729 1730 // -------------------------------------------------------------------- 1731 1732 void CustomAnimationEffect::updatePathFromSdrPathObj( const SdrPathObj& rPathObj ) 1733 { 1734 ::basegfx::B2DPolyPolygon xPolyPoly( rPathObj.GetPathPoly() ); 1735 1736 SdrObject* pObj = GetSdrObjectFromXShape( getTargetShape() ); 1737 if( pObj ) 1738 { 1739 Rectangle aBoundRect(0,0,0,0); 1740 1741 const drawinglayer::primitive2d::Primitive2DSequence xPrimitives(pObj->GetViewContact().getViewIndependentPrimitive2DSequence()); 1742 const drawinglayer::geometry::ViewInformation2D aViewInformation2D; 1743 const basegfx::B2DRange aRange(drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(xPrimitives, aViewInformation2D)); 1744 1745 if(!aRange.isEmpty()) 1746 { 1747 aBoundRect = Rectangle( 1748 (sal_Int32)floor(aRange.getMinX()), (sal_Int32)floor(aRange.getMinY()), 1749 (sal_Int32)ceil(aRange.getMaxX()), (sal_Int32)ceil(aRange.getMaxY())); 1750 } 1751 1752 const Point aCenter( aBoundRect.Center() ); 1753 1754 xPolyPoly.transform(basegfx::tools::createTranslateB2DHomMatrix(-aCenter.X(), -aCenter.Y())); 1755 1756 SdrPage* pPage = pObj->GetPage(); 1757 if( pPage ) 1758 { 1759 const Size aPageSize( pPage->GetSize() ); 1760 xPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix( 1761 1.0 / (double)aPageSize.Width(), 1.0 / (double)aPageSize.Height())); 1762 } 1763 } 1764 1765 setPath( ::basegfx::tools::exportToSvgD( xPolyPoly, true, true, true) ); 1766 } 1767 1768 // ==================================================================== 1769 1770 EffectSequenceHelper::EffectSequenceHelper() 1771 : mnSequenceType( EffectNodeType::DEFAULT ) 1772 { 1773 } 1774 1775 // -------------------------------------------------------------------- 1776 1777 EffectSequenceHelper::EffectSequenceHelper( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XTimeContainer >& xSequenceRoot ) 1778 : mxSequenceRoot( xSequenceRoot ), mnSequenceType( EffectNodeType::DEFAULT ) 1779 { 1780 Reference< XAnimationNode > xNode( mxSequenceRoot, UNO_QUERY_THROW ); 1781 create( xNode ); 1782 } 1783 1784 // -------------------------------------------------------------------- 1785 1786 EffectSequenceHelper::~EffectSequenceHelper() 1787 { 1788 reset(); 1789 } 1790 1791 // -------------------------------------------------------------------- 1792 1793 void EffectSequenceHelper::reset() 1794 { 1795 EffectSequence::iterator aIter( maEffects.begin() ); 1796 EffectSequence::iterator aEnd( maEffects.end() ); 1797 if( aIter != aEnd ) 1798 { 1799 CustomAnimationEffectPtr pEffect = (*aIter++); 1800 pEffect->setEffectSequence(0); 1801 } 1802 maEffects.clear(); 1803 } 1804 1805 Reference< XAnimationNode > EffectSequenceHelper::getRootNode() 1806 { 1807 Reference< XAnimationNode > xRoot( mxSequenceRoot, UNO_QUERY ); 1808 return xRoot; 1809 } 1810 1811 // -------------------------------------------------------------------- 1812 1813 void EffectSequenceHelper::append( const CustomAnimationEffectPtr& pEffect ) 1814 { 1815 pEffect->setEffectSequence( this ); 1816 maEffects.push_back(pEffect); 1817 rebuild(); 1818 } 1819 1820 // -------------------------------------------------------------------- 1821 1822 CustomAnimationEffectPtr EffectSequenceHelper::append( const CustomAnimationPresetPtr& pPreset, const Any& rTarget, double fDuration /* = -1.0 */ ) 1823 { 1824 CustomAnimationEffectPtr pEffect; 1825 1826 if( pPreset.get() ) 1827 { 1828 OUString strEmpty; 1829 Reference< XAnimationNode > xNode( pPreset->create( strEmpty ) ); 1830 if( xNode.is() ) 1831 { 1832 // first, filter all only ui relevant user data 1833 std::vector< NamedValue > aNewUserData; 1834 Sequence< NamedValue > aUserData( xNode->getUserData() ); 1835 sal_Int32 nLength = aUserData.getLength(); 1836 const NamedValue* p = aUserData.getConstArray(); 1837 bool bFilter = false; 1838 1839 while( nLength-- ) 1840 { 1841 if( !p->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "text-only" ) ) && 1842 !p->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "preset-property" ) ) ) 1843 { 1844 aNewUserData.push_back( *p ); 1845 bFilter = true; 1846 } 1847 p++; 1848 } 1849 1850 if( bFilter ) 1851 { 1852 aUserData = ::comphelper::containerToSequence< NamedValue, std::vector< NamedValue > >( aNewUserData ); 1853 xNode->setUserData( aUserData ); 1854 } 1855 1856 // check target, maybe we need to force it to text 1857 Any aTarget( rTarget ); 1858 sal_Int16 nSubItem = ShapeAnimationSubType::AS_WHOLE; 1859 1860 if( aTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) ) 1861 { 1862 nSubItem = ShapeAnimationSubType::ONLY_TEXT; 1863 } 1864 else if( pPreset->isTextOnly() ) 1865 { 1866 Reference< XShape > xShape; 1867 aTarget >>= xShape; 1868 if( xShape.is() ) 1869 { 1870 // thats bad, we target a shape here but the effect is only for text 1871 // so change subitem 1872 nSubItem = ShapeAnimationSubType::ONLY_TEXT; 1873 } 1874 } 1875 1876 // now create effect from preset 1877 pEffect.reset( new CustomAnimationEffect( xNode ) ); 1878 pEffect->setEffectSequence( this ); 1879 pEffect->setTarget( aTarget ); 1880 pEffect->setTargetSubItem( nSubItem ); 1881 if( fDuration != -1.0 ) 1882 pEffect->setDuration( fDuration ); 1883 1884 maEffects.push_back(pEffect); 1885 1886 rebuild(); 1887 } 1888 } 1889 1890 DBG_ASSERT( pEffect.get(), "sd::EffectSequenceHelper::append(), failed!" ); 1891 return pEffect; 1892 } 1893 1894 // -------------------------------------------------------------------- 1895 1896 CustomAnimationEffectPtr EffectSequenceHelper::append( const SdrPathObj& rPathObj, const Any& rTarget, double fDuration /* = -1.0 */ ) 1897 { 1898 CustomAnimationEffectPtr pEffect; 1899 1900 if( fDuration <= 0.0 ) 1901 fDuration = 2.0; 1902 1903 try 1904 { 1905 Reference< XTimeContainer > xEffectContainer( createParallelTimeContainer() ); 1906 const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.animations.AnimateMotion" ) ); 1907 Reference< XAnimationNode > xAnimateMotion( ::comphelper::getProcessServiceFactory()->createInstance(aServiceName), UNO_QUERY_THROW ); 1908 1909 xAnimateMotion->setDuration( Any( fDuration ) ); 1910 xAnimateMotion->setFill( AnimationFill::HOLD ); 1911 xEffectContainer->appendChild( xAnimateMotion ); 1912 1913 sal_Int16 nSubItem = ShapeAnimationSubType::AS_WHOLE; 1914 1915 if( rTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) ) 1916 nSubItem = ShapeAnimationSubType::ONLY_TEXT; 1917 1918 Reference< XAnimationNode > xEffectNode( xEffectContainer, UNO_QUERY_THROW ); 1919 pEffect.reset( new CustomAnimationEffect( xEffectNode ) ); 1920 pEffect->setEffectSequence( this ); 1921 pEffect->setTarget( rTarget ); 1922 pEffect->setTargetSubItem( nSubItem ); 1923 pEffect->setNodeType( ::com::sun::star::presentation::EffectNodeType::ON_CLICK ); 1924 pEffect->setPresetClass( ::com::sun::star::presentation::EffectPresetClass::MOTIONPATH ); 1925 pEffect->setAcceleration( 0.5 ); 1926 pEffect->setDecelerate( 0.5 ); 1927 pEffect->setFill( AnimationFill::HOLD ); 1928 pEffect->setBegin( 0.0 ); 1929 pEffect->updatePathFromSdrPathObj( rPathObj ); 1930 if( fDuration != -1.0 ) 1931 pEffect->setDuration( fDuration ); 1932 1933 maEffects.push_back(pEffect); 1934 1935 rebuild(); 1936 } 1937 catch( Exception& ) 1938 { 1939 DBG_ERROR( "sd::EffectSequenceHelper::append(), exception cought!" ); 1940 } 1941 1942 return pEffect; 1943 } 1944 1945 // -------------------------------------------------------------------- 1946 1947 void EffectSequenceHelper::replace( const CustomAnimationEffectPtr& pEffect, const CustomAnimationPresetPtr& pPreset, const OUString& rPresetSubType, double fDuration /* = -1.0 */ ) 1948 { 1949 if( pEffect.get() && pPreset.get() ) try 1950 { 1951 Reference< XAnimationNode > xNewNode( pPreset->create( rPresetSubType ) ); 1952 if( xNewNode.is() ) 1953 { 1954 pEffect->replaceNode( xNewNode ); 1955 if( fDuration != -1.0 ) 1956 pEffect->setDuration( fDuration ); 1957 } 1958 1959 rebuild(); 1960 } 1961 catch( Exception& e ) 1962 { 1963 (void)e; 1964 DBG_ERROR( "sd::EffectSequenceHelper::replace(), exception cought!" ); 1965 } 1966 } 1967 1968 // -------------------------------------------------------------------- 1969 1970 void EffectSequenceHelper::replace( const CustomAnimationEffectPtr& pEffect, const CustomAnimationPresetPtr& pPreset, double fDuration /* = -1.0 */ ) 1971 { 1972 OUString strEmpty; 1973 replace( pEffect, pPreset, strEmpty, fDuration ); 1974 } 1975 1976 // -------------------------------------------------------------------- 1977 1978 void EffectSequenceHelper::remove( const CustomAnimationEffectPtr& pEffect ) 1979 { 1980 if( pEffect.get() ) 1981 { 1982 pEffect->setEffectSequence( 0 ); 1983 maEffects.remove( pEffect ); 1984 } 1985 1986 rebuild(); 1987 } 1988 1989 // -------------------------------------------------------------------- 1990 1991 void EffectSequenceHelper::rebuild() 1992 { 1993 implRebuild(); 1994 } 1995 1996 // -------------------------------------------------------------------- 1997 1998 void EffectSequenceHelper::implRebuild() 1999 { 2000 try 2001 { 2002 // first we delete all time containers on the first two levels 2003 Reference< XEnumerationAccess > xEnumerationAccess( mxSequenceRoot, UNO_QUERY_THROW ); 2004 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW ); 2005 while( xEnumeration->hasMoreElements() ) 2006 { 2007 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW ); 2008 Reference< XTimeContainer > xChildContainer( xChildNode, UNO_QUERY_THROW ); 2009 2010 Reference< XEnumerationAccess > xChildEnumerationAccess( xChildNode, UNO_QUERY_THROW ); 2011 Reference< XEnumeration > xChildEnumeration( xChildEnumerationAccess->createEnumeration(), UNO_QUERY_THROW ); 2012 while( xChildEnumeration->hasMoreElements() ) 2013 { 2014 Reference< XAnimationNode > xNode( xChildEnumeration->nextElement(), UNO_QUERY_THROW ); 2015 xChildContainer->removeChild( xNode ); 2016 } 2017 2018 mxSequenceRoot->removeChild( xChildNode ); 2019 } 2020 2021 // second, rebuild main sequence 2022 EffectSequence::iterator aIter( maEffects.begin() ); 2023 EffectSequence::iterator aEnd( maEffects.end() ); 2024 if( aIter != aEnd ) 2025 { 2026 AfterEffectNodeList aAfterEffects; 2027 2028 CustomAnimationEffectPtr pEffect = (*aIter++); 2029 2030 bool bFirst = true; 2031 do 2032 { 2033 // create a par container for the next click node and all following with and after effects 2034 Reference< XTimeContainer > xOnClickContainer( createParallelTimeContainer() ); 2035 2036 Event aEvent; 2037 if( mxEventSource.is() ) 2038 { 2039 aEvent.Source <<= mxEventSource; 2040 aEvent.Trigger = EventTrigger::ON_CLICK; 2041 } 2042 else 2043 { 2044 aEvent.Trigger = EventTrigger::ON_NEXT; 2045 } 2046 aEvent.Repeat = 0; 2047 2048 Any aBegin( makeAny( aEvent ) ); 2049 if( bFirst ) 2050 { 2051 // if the first node is not a click action, this click container 2052 // must not have INDEFINITE begin but start at 0s 2053 bFirst = false; 2054 if( pEffect->getNodeType() != EffectNodeType::ON_CLICK ) 2055 aBegin <<= (double)0.0; 2056 } 2057 2058 xOnClickContainer->setBegin( aBegin ); 2059 2060 Reference< XAnimationNode > xOnClickContainerNode( xOnClickContainer, UNO_QUERY_THROW ); 2061 mxSequenceRoot->appendChild( xOnClickContainerNode ); 2062 2063 double fBegin = 0.0; 2064 2065 do 2066 { 2067 // create a par container for the current click or after effect node and all following with effects 2068 Reference< XTimeContainer > xWithContainer( createParallelTimeContainer() ); 2069 Reference< XAnimationNode > xWithContainerNode( xWithContainer, UNO_QUERY_THROW ); 2070 xWithContainer->setBegin( makeAny( fBegin ) ); 2071 xOnClickContainer->appendChild( xWithContainerNode ); 2072 2073 double fDuration = 0.0; 2074 do 2075 { 2076 Reference< XAnimationNode > xEffectNode( pEffect->getNode() ); 2077 xWithContainer->appendChild( xEffectNode ); 2078 2079 if( pEffect->hasAfterEffect() ) 2080 { 2081 Reference< XAnimationNode > xAfterEffect( pEffect->createAfterEffectNode() ); 2082 AfterEffectNode a( xAfterEffect, xEffectNode, pEffect->IsAfterEffectOnNext() ); 2083 aAfterEffects.push_back( a ); 2084 } 2085 2086 double fTemp = pEffect->getBegin() + pEffect->getAbsoluteDuration(); 2087 if( fTemp > fDuration ) 2088 fDuration = fTemp; 2089 2090 if( aIter != aEnd ) 2091 pEffect = (*aIter++); 2092 else 2093 pEffect.reset(); 2094 } 2095 while( pEffect.get() && (pEffect->getNodeType() == EffectNodeType::WITH_PREVIOUS) ); 2096 2097 fBegin += fDuration; 2098 } 2099 while( pEffect.get() && (pEffect->getNodeType() != EffectNodeType::ON_CLICK) ); 2100 } 2101 while( pEffect.get() ); 2102 2103 // process after effect nodes 2104 std::for_each( aAfterEffects.begin(), aAfterEffects.end(), stl_process_after_effect_node_func ); 2105 2106 updateTextGroups(); 2107 2108 // reset duration, might have been altered (see below) 2109 mxSequenceRoot->setDuration( Any() ); 2110 } 2111 else 2112 { 2113 // empty sequence, set duration to 0.0 explicitely 2114 // (otherwise, this sequence will never end) 2115 mxSequenceRoot->setDuration( makeAny((double)0.0) ); 2116 } 2117 } 2118 catch( Exception& e ) 2119 { 2120 (void)e; 2121 DBG_ERROR( "sd::EffectSequenceHelper::rebuild(), exception cought!" ); 2122 } 2123 } 2124 2125 // -------------------------------------------------------------------- 2126 2127 Reference< XTimeContainer > EffectSequenceHelper::createParallelTimeContainer() const 2128 { 2129 const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.animations.ParallelTimeContainer" ) ); 2130 return Reference< XTimeContainer >( ::comphelper::getProcessServiceFactory()->createInstance(aServiceName), UNO_QUERY ); 2131 } 2132 2133 // -------------------------------------------------------------------- 2134 2135 stl_CustomAnimationEffect_search_node_predict::stl_CustomAnimationEffect_search_node_predict( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xSearchNode ) 2136 : mxSearchNode( xSearchNode ) 2137 { 2138 } 2139 2140 // -------------------------------------------------------------------- 2141 2142 bool stl_CustomAnimationEffect_search_node_predict::operator()( CustomAnimationEffectPtr pEffect ) const 2143 { 2144 return pEffect->getNode() == mxSearchNode; 2145 } 2146 2147 // -------------------------------------------------------------------- 2148 2149 static bool implFindNextContainer( Reference< XTimeContainer >& xParent, Reference< XTimeContainer >& xCurrent, Reference< XTimeContainer >& xNext ) 2150 throw(Exception) 2151 { 2152 Reference< XEnumerationAccess > xEnumerationAccess( xParent, UNO_QUERY_THROW ); 2153 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration() ); 2154 if( xEnumeration.is() ) 2155 { 2156 Reference< XInterface > x; 2157 while( xEnumeration->hasMoreElements() && !xNext.is() ) 2158 { 2159 if( (xEnumeration->nextElement() >>= x) && (x == xCurrent) ) 2160 { 2161 if( xEnumeration->hasMoreElements() ) 2162 xEnumeration->nextElement() >>= xNext; 2163 } 2164 } 2165 } 2166 return xNext.is(); 2167 } 2168 2169 // -------------------------------------------------------------------- 2170 2171 void stl_process_after_effect_node_func(AfterEffectNode& rNode) 2172 { 2173 try 2174 { 2175 if( rNode.mxNode.is() && rNode.mxMaster.is() ) 2176 { 2177 // set master node 2178 Reference< XAnimationNode > xMasterNode( rNode.mxMaster, UNO_QUERY_THROW ); 2179 Sequence< NamedValue > aUserData( rNode.mxNode->getUserData() ); 2180 sal_Int32 nSize = aUserData.getLength(); 2181 aUserData.realloc(nSize+1); 2182 aUserData[nSize].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "master-element" ) ); 2183 aUserData[nSize].Value <<= xMasterNode; 2184 rNode.mxNode->setUserData( aUserData ); 2185 2186 // insert after effect node into timeline 2187 Reference< XTimeContainer > xContainer( rNode.mxMaster->getParent(), UNO_QUERY_THROW ); 2188 2189 if( !rNode.mbOnNextEffect ) // sameClick 2190 { 2191 // insert the aftereffect after its effect is animated 2192 xContainer->insertAfter( rNode.mxNode, rNode.mxMaster ); 2193 } 2194 else // nextClick 2195 { 2196 Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() ); 2197 // insert the aftereffect in the next group 2198 2199 Reference< XTimeContainer > xClickContainer( xContainer->getParent(), UNO_QUERY_THROW ); 2200 Reference< XTimeContainer > xSequenceContainer( xClickContainer->getParent(), UNO_QUERY_THROW ); 2201 2202 Reference< XTimeContainer > xNextContainer; 2203 2204 // first try if we have an after effect container 2205 if( !implFindNextContainer( xClickContainer, xContainer, xNextContainer ) ) 2206 { 2207 Reference< XTimeContainer > xNextClickContainer; 2208 // if not, try to find the next click effect container 2209 if( implFindNextContainer( xSequenceContainer, xClickContainer, xNextClickContainer ) ) 2210 { 2211 Reference< XEnumerationAccess > xEnumerationAccess( xNextClickContainer, UNO_QUERY_THROW ); 2212 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW ); 2213 if( xEnumeration->hasMoreElements() ) 2214 { 2215 // the next container is the first child container 2216 xEnumeration->nextElement() >>= xNextContainer; 2217 } 2218 else 2219 { 2220 // this does not yet have a child container, create one 2221 const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.ParallelTimeContainer") ); 2222 xNextContainer = Reference< XTimeContainer >::query( xMsf->createInstance(aServiceName) ); 2223 2224 if( xNextContainer.is() ) 2225 { 2226 Reference< XAnimationNode > xNode( xNextContainer, UNO_QUERY_THROW ); 2227 xNode->setBegin( makeAny( (double)0.0 ) ); 2228 // xNode->setFill( AnimationFill::HOLD ); 2229 xNextClickContainer->appendChild( xNode ); 2230 } 2231 } 2232 DBG_ASSERT( xNextContainer.is(), "ppt::stl_process_after_effect_node_func::operator(), could not find/create container!" ); 2233 } 2234 } 2235 2236 // if we don't have a next container, we add one to the sequence container 2237 if( !xNextContainer.is() ) 2238 { 2239 const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.ParallelTimeContainer") ); 2240 Reference< XTimeContainer > xNewClickContainer( xMsf->createInstance(aServiceName), UNO_QUERY_THROW ); 2241 2242 Reference< XAnimationNode > xNewClickNode( xNewClickContainer, UNO_QUERY_THROW ); 2243 2244 Event aEvent; 2245 aEvent.Trigger = EventTrigger::ON_NEXT; 2246 aEvent.Repeat = 0; 2247 xNewClickNode->setBegin( makeAny( aEvent ) ); 2248 2249 Reference< XAnimationNode > xRefNode( xClickContainer, UNO_QUERY_THROW ); 2250 xSequenceContainer->insertAfter( xNewClickNode, xRefNode ); 2251 2252 xNextContainer = Reference< XTimeContainer >::query( xMsf->createInstance(aServiceName) ); 2253 2254 DBG_ASSERT( xNextContainer.is(), "ppt::stl_process_after_effect_node_func::operator(), could not create container!" ); 2255 if( xNextContainer.is() ) 2256 { 2257 Reference< XAnimationNode > xNode( xNextContainer, UNO_QUERY_THROW ); 2258 xNode->setBegin( makeAny( (double)0.0 ) ); 2259 // xNode->setFill( AnimationFill::HOLD ); 2260 xNewClickContainer->appendChild( xNode ); 2261 } 2262 } 2263 2264 if( xNextContainer.is() ) 2265 { 2266 // find begin time of first element 2267 Reference< XEnumerationAccess > xEnumerationAccess( xNextContainer, UNO_QUERY_THROW ); 2268 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW ); 2269 if( xEnumeration->hasMoreElements() ) 2270 { 2271 Reference< XAnimationNode > xChild; 2272 // the next container is the first child container 2273 xEnumeration->nextElement() >>= xChild; 2274 if( xChild.is() ) 2275 { 2276 Any aBegin( xChild->getBegin() ); 2277 double fBegin = 0.0; 2278 if( (aBegin >>= fBegin) && (fBegin >= 0.0)) 2279 rNode.mxNode->setBegin( aBegin ); 2280 } 2281 } 2282 2283 xNextContainer->appendChild( rNode.mxNode ); 2284 } 2285 } 2286 } 2287 } 2288 catch( Exception& e ) 2289 { 2290 (void)e; 2291 DBG_ERROR( "ppt::stl_process_after_effect_node_func::operator(), exception cought!" ); 2292 } 2293 } 2294 2295 // -------------------------------------------------------------------- 2296 2297 EffectSequence::iterator EffectSequenceHelper::find( const CustomAnimationEffectPtr& pEffect ) 2298 { 2299 return std::find( maEffects.begin(), maEffects.end(), pEffect ); 2300 } 2301 2302 // -------------------------------------------------------------------- 2303 2304 CustomAnimationEffectPtr EffectSequenceHelper::findEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) const 2305 { 2306 CustomAnimationEffectPtr pEffect; 2307 2308 EffectSequence::const_iterator aIter( maEffects.begin() ); 2309 for( ; aIter != maEffects.end(); aIter++ ) 2310 { 2311 if( (*aIter)->getNode() == xNode ) 2312 { 2313 pEffect = (*aIter); 2314 break; 2315 } 2316 } 2317 2318 return pEffect; 2319 } 2320 2321 // -------------------------------------------------------------------- 2322 2323 sal_Int32 EffectSequenceHelper::getOffsetFromEffect( const CustomAnimationEffectPtr& xEffect ) const 2324 { 2325 sal_Int32 nOffset = 0; 2326 2327 EffectSequence::const_iterator aIter( maEffects.begin() ); 2328 for( ; aIter != maEffects.end(); aIter++, nOffset++ ) 2329 { 2330 if( (*aIter) == xEffect ) 2331 return nOffset; 2332 } 2333 2334 return -1; 2335 } 2336 2337 // -------------------------------------------------------------------- 2338 2339 CustomAnimationEffectPtr EffectSequenceHelper::getEffectFromOffset( sal_Int32 nOffset ) const 2340 { 2341 EffectSequence::const_iterator aIter( maEffects.begin() ); 2342 while( nOffset-- && aIter != maEffects.end() ) 2343 aIter++; 2344 2345 CustomAnimationEffectPtr pEffect; 2346 if( aIter != maEffects.end() ) 2347 pEffect = (*aIter); 2348 2349 return pEffect; 2350 } 2351 2352 // -------------------------------------------------------------------- 2353 2354 bool EffectSequenceHelper::disposeShape( const Reference< XShape >& xShape ) 2355 { 2356 bool bChanges = false; 2357 2358 EffectSequence::iterator aIter( maEffects.begin() ); 2359 while( aIter != maEffects.end() ) 2360 { 2361 if( (*aIter)->getTargetShape() == xShape ) 2362 { 2363 (*aIter)->setEffectSequence( 0 ); 2364 bChanges = true; 2365 aIter = maEffects.erase( aIter ); 2366 } 2367 else 2368 { 2369 aIter++; 2370 } 2371 } 2372 2373 return bChanges; 2374 } 2375 2376 // -------------------------------------------------------------------- 2377 2378 bool EffectSequenceHelper::hasEffect( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape ) 2379 { 2380 EffectSequence::iterator aIter( maEffects.begin() ); 2381 while( aIter != maEffects.end() ) 2382 { 2383 if( (*aIter)->getTargetShape() == xShape ) 2384 return true; 2385 aIter++; 2386 } 2387 2388 return false; 2389 } 2390 2391 // -------------------------------------------------------------------- 2392 2393 void EffectSequenceHelper::insertTextRange( const com::sun::star::uno::Any& aTarget ) 2394 { 2395 bool bChanges = false; 2396 2397 ParagraphTarget aParaTarget; 2398 if( !(aTarget >>= aParaTarget ) ) 2399 return; 2400 2401 EffectSequence::iterator aIter( maEffects.begin() ); 2402 while( aIter != maEffects.end() ) 2403 { 2404 if( (*aIter)->getTargetShape() == aParaTarget.Shape ) 2405 bChanges |= (*aIter)->checkForText(); 2406 aIter++; 2407 } 2408 2409 if( bChanges ) 2410 rebuild(); 2411 } 2412 2413 // -------------------------------------------------------------------- 2414 2415 void EffectSequenceHelper::disposeTextRange( const com::sun::star::uno::Any& aTarget ) 2416 { 2417 ParagraphTarget aParaTarget; 2418 if( !(aTarget >>= aParaTarget ) ) 2419 return; 2420 2421 bool bChanges = false; 2422 bool bErased = false; 2423 2424 EffectSequence::iterator aIter( maEffects.begin() ); 2425 while( aIter != maEffects.end() ) 2426 { 2427 Any aIterTarget( (*aIter)->getTarget() ); 2428 if( aIterTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) ) 2429 { 2430 ParagraphTarget aIterParaTarget; 2431 if( (aIterTarget >>= aIterParaTarget) && (aIterParaTarget.Shape == aParaTarget.Shape) ) 2432 { 2433 if( aIterParaTarget.Paragraph == aParaTarget.Paragraph ) 2434 { 2435 // delete this effect if it targets the disposed paragraph directly 2436 (*aIter)->setEffectSequence( 0 ); 2437 aIter = maEffects.erase( aIter ); 2438 bChanges = true; 2439 bErased = true; 2440 } 2441 else 2442 { 2443 if( aIterParaTarget.Paragraph > aParaTarget.Paragraph ) 2444 { 2445 // shift all paragraphs after disposed paragraph 2446 aIterParaTarget.Paragraph--; 2447 (*aIter)->setTarget( makeAny( aIterParaTarget ) ); 2448 } 2449 } 2450 } 2451 } 2452 else if( (*aIter)->getTargetShape() == aParaTarget.Shape ) 2453 { 2454 bChanges |= (*aIter)->checkForText(); 2455 } 2456 2457 if( bErased ) 2458 bErased = false; 2459 else 2460 aIter++; 2461 } 2462 2463 if( bChanges ) 2464 rebuild(); 2465 } 2466 2467 // -------------------------------------------------------------------- 2468 2469 CustomAnimationTextGroup::CustomAnimationTextGroup( const Reference< XShape >& rTarget, sal_Int32 nGroupId ) 2470 : maTarget( rTarget ), 2471 mnGroupId( nGroupId ) 2472 { 2473 reset(); 2474 } 2475 2476 // -------------------------------------------------------------------- 2477 2478 void CustomAnimationTextGroup::reset() 2479 { 2480 mnTextGrouping = -1; 2481 mbAnimateForm = false; 2482 mbTextReverse = false; 2483 mfGroupingAuto = -1.0; 2484 mnLastPara = -1; // used to check for TextReverse 2485 2486 int i = 5; 2487 while( i-- ) mnDepthFlags[i] = 0; 2488 2489 maEffects.clear(); 2490 } 2491 2492 // -------------------------------------------------------------------- 2493 2494 void CustomAnimationTextGroup::addEffect( CustomAnimationEffectPtr& pEffect ) 2495 { 2496 maEffects.push_back( pEffect ); 2497 2498 Any aTarget( pEffect->getTarget() ); 2499 if( aTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) ) 2500 { 2501 // now look at the paragraph 2502 ParagraphTarget aParaTarget; 2503 aTarget >>= aParaTarget; 2504 2505 if( mnLastPara != -1 ) 2506 mbTextReverse = mnLastPara > aParaTarget.Paragraph; 2507 2508 mnLastPara = aParaTarget.Paragraph; 2509 2510 const sal_Int32 nParaDepth = pEffect->getParaDepth(); 2511 2512 // only look at the first 5 levels 2513 if( nParaDepth < 5 ) 2514 { 2515 // our first paragraph with this level? 2516 if( mnDepthFlags[nParaDepth] == 0 ) 2517 { 2518 // so set it to the first found 2519 mnDepthFlags[nParaDepth] = (sal_Int8)pEffect->getNodeType(); 2520 } 2521 else if( mnDepthFlags[nParaDepth] != pEffect->getNodeType() ) 2522 { 2523 mnDepthFlags[nParaDepth] = -1; 2524 } 2525 2526 if( pEffect->getNodeType() == EffectNodeType::AFTER_PREVIOUS ) 2527 mfGroupingAuto = pEffect->getBegin(); 2528 2529 mnTextGrouping = 0; 2530 while( (mnTextGrouping < 5) && (mnDepthFlags[mnTextGrouping] > 0) ) 2531 mnTextGrouping++; 2532 } 2533 } 2534 else 2535 { 2536 // if we have an effect with the shape as a target, we animate the background 2537 mbAnimateForm = pEffect->getTargetSubItem() != ShapeAnimationSubType::ONLY_TEXT; 2538 } 2539 } 2540 2541 // -------------------------------------------------------------------- 2542 2543 class TextGroupMapImpl : public std::map< sal_Int32, CustomAnimationTextGroup* > 2544 { 2545 public: 2546 CustomAnimationTextGroup* findGroup( sal_Int32 nGroupId ); 2547 }; 2548 2549 // -------------------------------------------------------------------- 2550 2551 CustomAnimationTextGroupPtr EffectSequenceHelper::findGroup( sal_Int32 nGroupId ) 2552 { 2553 CustomAnimationTextGroupPtr aPtr; 2554 2555 CustomAnimationTextGroupMap::iterator aIter( maGroupMap.find( nGroupId ) ); 2556 if( aIter != maGroupMap.end() ) 2557 aPtr = (*aIter).second; 2558 2559 return aPtr; 2560 } 2561 2562 // -------------------------------------------------------------------- 2563 2564 void EffectSequenceHelper::updateTextGroups() 2565 { 2566 maGroupMap.clear(); 2567 2568 // first create all the groups 2569 EffectSequence::iterator aIter( maEffects.begin() ); 2570 const EffectSequence::iterator aEnd( maEffects.end() ); 2571 while( aIter != aEnd ) 2572 { 2573 CustomAnimationEffectPtr pEffect( (*aIter++) ); 2574 2575 const sal_Int32 nGroupId = pEffect->getGroupId(); 2576 2577 if( nGroupId == -1 ) 2578 continue; // trivial case, no group 2579 2580 CustomAnimationTextGroupPtr pGroup = findGroup( nGroupId ); 2581 if( !pGroup.get() ) 2582 { 2583 pGroup.reset( new CustomAnimationTextGroup( pEffect->getTargetShape(), nGroupId ) ); 2584 maGroupMap[nGroupId] = pGroup; 2585 } 2586 2587 pGroup->addEffect( pEffect ); 2588 } 2589 } 2590 2591 // -------------------------------------------------------------------- 2592 2593 CustomAnimationTextGroupPtr EffectSequenceHelper::createTextGroup( CustomAnimationEffectPtr pEffect, sal_Int32 nTextGrouping, double fTextGroupingAuto, sal_Bool bAnimateForm, sal_Bool bTextReverse ) 2594 { 2595 // first finde a free group-id 2596 sal_Int32 nGroupId = 0; 2597 2598 CustomAnimationTextGroupMap::iterator aIter( maGroupMap.begin() ); 2599 const CustomAnimationTextGroupMap::iterator aEnd( maGroupMap.end() ); 2600 while( aIter != aEnd ) 2601 { 2602 if( (*aIter).first == nGroupId ) 2603 { 2604 nGroupId++; 2605 aIter = maGroupMap.begin(); 2606 } 2607 else 2608 { 2609 aIter++; 2610 } 2611 } 2612 2613 Reference< XShape > xTarget( pEffect->getTargetShape() ); 2614 2615 CustomAnimationTextGroupPtr pTextGroup( new CustomAnimationTextGroup( xTarget, nGroupId ) ); 2616 maGroupMap[nGroupId] = pTextGroup; 2617 2618 bool bUsed = false; 2619 2620 // do we need to target the shape? 2621 if( (nTextGrouping == 0) || bAnimateForm ) 2622 { 2623 sal_Int16 nSubItem; 2624 if( nTextGrouping == 0) 2625 nSubItem = bAnimateForm ? ShapeAnimationSubType::AS_WHOLE : ShapeAnimationSubType::ONLY_TEXT; 2626 else 2627 nSubItem = ShapeAnimationSubType::ONLY_BACKGROUND; 2628 2629 pEffect->setTarget( makeAny( xTarget ) ); 2630 pEffect->setTargetSubItem( nSubItem ); 2631 pEffect->setEffectSequence( this ); 2632 pEffect->setGroupId( nGroupId ); 2633 2634 pTextGroup->addEffect( pEffect ); 2635 bUsed = true; 2636 } 2637 2638 pTextGroup->mnTextGrouping = nTextGrouping; 2639 pTextGroup->mfGroupingAuto = fTextGroupingAuto; 2640 pTextGroup->mbTextReverse = bTextReverse; 2641 2642 // now add an effect for each paragraph 2643 createTextGroupParagraphEffects( pTextGroup, pEffect, bUsed ); 2644 2645 notify_listeners(); 2646 2647 return pTextGroup; 2648 } 2649 2650 // -------------------------------------------------------------------- 2651 2652 void EffectSequenceHelper::createTextGroupParagraphEffects( CustomAnimationTextGroupPtr pTextGroup, CustomAnimationEffectPtr pEffect, bool bUsed ) 2653 { 2654 Reference< XShape > xTarget( pTextGroup->maTarget ); 2655 2656 sal_Int32 nTextGrouping = pTextGroup->mnTextGrouping; 2657 double fTextGroupingAuto = pTextGroup->mfGroupingAuto; 2658 sal_Bool bTextReverse = pTextGroup->mbTextReverse; 2659 2660 // now add an effect for each paragraph 2661 if( nTextGrouping >= 0 ) try 2662 { 2663 EffectSequence::iterator aInsertIter( find( pEffect ) ); 2664 2665 const OUString strNumberingLevel( RTL_CONSTASCII_USTRINGPARAM("NumberingLevel") ); 2666 Reference< XEnumerationAccess > xText( xTarget, UNO_QUERY_THROW ); 2667 Reference< XEnumeration > xEnumeration( xText->createEnumeration(), UNO_QUERY_THROW ); 2668 2669 std::list< sal_Int16 > aParaList; 2670 sal_Int16 nPara; 2671 2672 // fill the list with all valid paragraphs 2673 for( nPara = 0; xEnumeration->hasMoreElements(); nPara++ ) 2674 { 2675 Reference< XTextRange > xRange( xEnumeration->nextElement(), UNO_QUERY ); 2676 if( xRange.is() && xRange->getString().getLength() ) 2677 { 2678 if( bTextReverse ) // sort them 2679 aParaList.push_front( nPara ); 2680 else 2681 aParaList.push_back( nPara ); 2682 } 2683 } 2684 2685 ParagraphTarget aTarget; 2686 aTarget.Shape = xTarget; 2687 2688 std::list< sal_Int16 >::iterator aIter( aParaList.begin() ); 2689 std::list< sal_Int16 >::iterator aEnd( aParaList.end() ); 2690 while( aIter != aEnd ) 2691 { 2692 aTarget.Paragraph = (*aIter++); 2693 2694 CustomAnimationEffectPtr pNewEffect; 2695 if( bUsed ) 2696 { 2697 // clone a new effect from first effect 2698 pNewEffect = pEffect->clone(); 2699 ++aInsertIter; 2700 aInsertIter = maEffects.insert( aInsertIter, pNewEffect ); 2701 } 2702 else 2703 { 2704 // reuse first effect if its not yet used 2705 pNewEffect = pEffect; 2706 bUsed = true; 2707 aInsertIter = find( pNewEffect ); 2708 } 2709 2710 // set target and group-id 2711 pNewEffect->setTarget( makeAny( aTarget ) ); 2712 pNewEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT ); 2713 pNewEffect->setGroupId( pTextGroup->mnGroupId ); 2714 pNewEffect->setEffectSequence( this ); 2715 2716 // set correct node type 2717 if( pNewEffect->getParaDepth() < nTextGrouping ) 2718 { 2719 if( fTextGroupingAuto == -1.0 ) 2720 { 2721 pNewEffect->setNodeType( EffectNodeType::ON_CLICK ); 2722 pNewEffect->setBegin( 0.0 ); 2723 } 2724 else 2725 { 2726 pNewEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS ); 2727 pNewEffect->setBegin( fTextGroupingAuto ); 2728 } 2729 } 2730 else 2731 { 2732 pNewEffect->setNodeType( EffectNodeType::WITH_PREVIOUS ); 2733 pNewEffect->setBegin( 0.0 ); 2734 } 2735 2736 pTextGroup->addEffect( pNewEffect ); 2737 } 2738 notify_listeners(); 2739 } 2740 catch( Exception& e ) 2741 { 2742 (void)e; 2743 DBG_ERROR("sd::EffectSequenceHelper::createTextGroup(), exception cought!" ); 2744 } 2745 } 2746 2747 // -------------------------------------------------------------------- 2748 2749 void EffectSequenceHelper::setTextGrouping( CustomAnimationTextGroupPtr pTextGroup, sal_Int32 nTextGrouping ) 2750 { 2751 if( pTextGroup->mnTextGrouping == nTextGrouping ) 2752 { 2753 // first case, trivial case, do nothing 2754 } 2755 else if( (pTextGroup->mnTextGrouping == -1) && (nTextGrouping >= 0) ) 2756 { 2757 // second case, we need to add new effects for each paragraph 2758 2759 CustomAnimationEffectPtr pEffect( pTextGroup->maEffects.front() ); 2760 2761 pTextGroup->mnTextGrouping = nTextGrouping; 2762 createTextGroupParagraphEffects( pTextGroup, pEffect, true ); 2763 notify_listeners(); 2764 } 2765 else if( (pTextGroup->mnTextGrouping >= 0) && (nTextGrouping == -1 ) ) 2766 { 2767 // third case, we need to remove effects for each paragraph 2768 2769 EffectSequence aEffects( pTextGroup->maEffects ); 2770 pTextGroup->reset(); 2771 2772 EffectSequence::iterator aIter( aEffects.begin() ); 2773 const EffectSequence::iterator aEnd( aEffects.end() ); 2774 while( aIter != aEnd ) 2775 { 2776 CustomAnimationEffectPtr pEffect( (*aIter++) ); 2777 2778 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) ) 2779 remove( pEffect ); 2780 else 2781 pTextGroup->addEffect( pEffect ); 2782 } 2783 notify_listeners(); 2784 } 2785 else 2786 { 2787 // fourth case, we need to change the node types for the text nodes 2788 double fTextGroupingAuto = pTextGroup->mfGroupingAuto; 2789 2790 EffectSequence aEffects( pTextGroup->maEffects ); 2791 pTextGroup->reset(); 2792 2793 EffectSequence::iterator aIter( aEffects.begin() ); 2794 const EffectSequence::iterator aEnd( aEffects.end() ); 2795 while( aIter != aEnd ) 2796 { 2797 CustomAnimationEffectPtr pEffect( (*aIter++) ); 2798 2799 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) ) 2800 { 2801 // set correct node type 2802 if( pEffect->getParaDepth() < nTextGrouping ) 2803 { 2804 if( fTextGroupingAuto == -1.0 ) 2805 { 2806 pEffect->setNodeType( EffectNodeType::ON_CLICK ); 2807 pEffect->setBegin( 0.0 ); 2808 } 2809 else 2810 { 2811 pEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS ); 2812 pEffect->setBegin( fTextGroupingAuto ); 2813 } 2814 } 2815 else 2816 { 2817 pEffect->setNodeType( EffectNodeType::WITH_PREVIOUS ); 2818 pEffect->setBegin( 0.0 ); 2819 } 2820 } 2821 2822 pTextGroup->addEffect( pEffect ); 2823 2824 } 2825 notify_listeners(); 2826 } 2827 } 2828 2829 // -------------------------------------------------------------------- 2830 2831 void EffectSequenceHelper::setAnimateForm( CustomAnimationTextGroupPtr pTextGroup, sal_Bool bAnimateForm ) 2832 { 2833 if( pTextGroup->mbAnimateForm == bAnimateForm ) 2834 { 2835 // trivial case, do nothing 2836 } 2837 else 2838 { 2839 EffectSequence aEffects( pTextGroup->maEffects ); 2840 pTextGroup->reset(); 2841 2842 EffectSequence::iterator aIter( aEffects.begin() ); 2843 const EffectSequence::iterator aEnd( aEffects.end() ); 2844 2845 // first insert if we have to 2846 if( bAnimateForm ) 2847 { 2848 EffectSequence::iterator aInsertIter( find( (*aIter) ) ); 2849 2850 CustomAnimationEffectPtr pEffect; 2851 if( (aEffects.size() == 1) && ((*aIter)->getTarget().getValueType() != ::getCppuType((const ParagraphTarget*)0) ) ) 2852 { 2853 // special case, only one effect and that targets whole text, 2854 // convert this to target whole shape 2855 pEffect = (*aIter++); 2856 pEffect->setTargetSubItem( ShapeAnimationSubType::AS_WHOLE ); 2857 } 2858 else 2859 { 2860 pEffect = (*aIter)->clone(); 2861 pEffect->setTarget( makeAny( (*aIter)->getTargetShape() ) ); 2862 pEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_BACKGROUND ); 2863 maEffects.insert( aInsertIter, pEffect ); 2864 } 2865 2866 pTextGroup->addEffect( pEffect ); 2867 } 2868 2869 if( !bAnimateForm && (aEffects.size() == 1) ) 2870 { 2871 CustomAnimationEffectPtr pEffect( (*aIter) ); 2872 pEffect->setTarget( makeAny( (*aIter)->getTargetShape() ) ); 2873 pEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT ); 2874 pTextGroup->addEffect( pEffect ); 2875 } 2876 else 2877 { 2878 // readd the rest to the group again 2879 while( aIter != aEnd ) 2880 { 2881 CustomAnimationEffectPtr pEffect( (*aIter++) ); 2882 2883 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) ) 2884 { 2885 pTextGroup->addEffect( pEffect ); 2886 } 2887 else 2888 { 2889 DBG_ASSERT( !bAnimateForm, "sd::EffectSequenceHelper::setAnimateForm(), something is wrong here!" ); 2890 remove( pEffect ); 2891 } 2892 } 2893 } 2894 notify_listeners(); 2895 } 2896 } 2897 2898 // -------------------------------------------------------------------- 2899 2900 void EffectSequenceHelper::setTextGroupingAuto( CustomAnimationTextGroupPtr pTextGroup, double fTextGroupingAuto ) 2901 { 2902 sal_Int32 nTextGrouping = pTextGroup->mnTextGrouping; 2903 2904 EffectSequence aEffects( pTextGroup->maEffects ); 2905 pTextGroup->reset(); 2906 2907 EffectSequence::iterator aIter( aEffects.begin() ); 2908 const EffectSequence::iterator aEnd( aEffects.end() ); 2909 while( aIter != aEnd ) 2910 { 2911 CustomAnimationEffectPtr pEffect( (*aIter++) ); 2912 2913 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) ) 2914 { 2915 // set correct node type 2916 if( pEffect->getParaDepth() < nTextGrouping ) 2917 { 2918 if( fTextGroupingAuto == -1.0 ) 2919 { 2920 pEffect->setNodeType( EffectNodeType::ON_CLICK ); 2921 pEffect->setBegin( 0.0 ); 2922 } 2923 else 2924 { 2925 pEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS ); 2926 pEffect->setBegin( fTextGroupingAuto ); 2927 } 2928 } 2929 else 2930 { 2931 pEffect->setNodeType( EffectNodeType::WITH_PREVIOUS ); 2932 pEffect->setBegin( 0.0 ); 2933 } 2934 } 2935 2936 pTextGroup->addEffect( pEffect ); 2937 2938 } 2939 notify_listeners(); 2940 } 2941 2942 // -------------------------------------------------------------------- 2943 2944 struct ImplStlTextGroupSortHelper 2945 { 2946 ImplStlTextGroupSortHelper( bool bReverse ) : mbReverse( bReverse ) {}; 2947 bool operator()( const CustomAnimationEffectPtr& p1, const CustomAnimationEffectPtr& p2 ); 2948 bool mbReverse; 2949 sal_Int32 getTargetParagraph( const CustomAnimationEffectPtr& p1 ); 2950 }; 2951 2952 // -------------------------------------------------------------------- 2953 2954 sal_Int32 ImplStlTextGroupSortHelper::getTargetParagraph( const CustomAnimationEffectPtr& p1 ) 2955 { 2956 const Any aTarget(p1->getTarget()); 2957 if( aTarget.hasValue() && aTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) ) 2958 { 2959 ParagraphTarget aParaTarget; 2960 aTarget >>= aParaTarget; 2961 return aParaTarget.Paragraph; 2962 } 2963 else 2964 { 2965 return mbReverse ? 0x7fffffff : -1; 2966 } 2967 } 2968 2969 // -------------------------------------------------------------------- 2970 2971 bool ImplStlTextGroupSortHelper::operator()( const CustomAnimationEffectPtr& p1, const CustomAnimationEffectPtr& p2 ) 2972 { 2973 if( mbReverse ) 2974 { 2975 return getTargetParagraph( p2 ) < getTargetParagraph( p1 ); 2976 } 2977 else 2978 { 2979 return getTargetParagraph( p1 ) < getTargetParagraph( p2 ); 2980 } 2981 } 2982 2983 // -------------------------------------------------------------------- 2984 2985 void EffectSequenceHelper::setTextReverse( CustomAnimationTextGroupPtr pTextGroup, sal_Bool bTextReverse ) 2986 { 2987 if( pTextGroup->mbTextReverse == bTextReverse ) 2988 { 2989 // do nothing 2990 } 2991 else 2992 { 2993 std::vector< CustomAnimationEffectPtr > aSortedVector(pTextGroup->maEffects.size()); 2994 std::copy( pTextGroup->maEffects.begin(), pTextGroup->maEffects.end(), aSortedVector.begin() ); 2995 ImplStlTextGroupSortHelper aSortHelper( bTextReverse ); 2996 std::sort( aSortedVector.begin(), aSortedVector.end(), aSortHelper ); 2997 2998 pTextGroup->reset(); 2999 3000 std::vector< CustomAnimationEffectPtr >::iterator aIter( aSortedVector.begin() ); 3001 const std::vector< CustomAnimationEffectPtr >::iterator aEnd( aSortedVector.end() ); 3002 3003 if( aIter != aEnd ) 3004 { 3005 pTextGroup->addEffect( (*aIter ) ); 3006 EffectSequence::iterator aInsertIter( find( (*aIter++) ) ); 3007 while( aIter != aEnd ) 3008 { 3009 CustomAnimationEffectPtr pEffect( (*aIter++) ); 3010 maEffects.erase( find( pEffect ) ); 3011 aInsertIter = maEffects.insert( ++aInsertIter, pEffect ); 3012 pTextGroup->addEffect( pEffect ); 3013 } 3014 } 3015 notify_listeners(); 3016 } 3017 } 3018 3019 // -------------------------------------------------------------------- 3020 3021 void EffectSequenceHelper::addListener( ISequenceListener* pListener ) 3022 { 3023 if( std::find( maListeners.begin(), maListeners.end(), pListener ) == maListeners.end() ) 3024 maListeners.push_back( pListener ); 3025 } 3026 3027 // -------------------------------------------------------------------- 3028 3029 void EffectSequenceHelper::removeListener( ISequenceListener* pListener ) 3030 { 3031 maListeners.remove( pListener ); 3032 } 3033 3034 // -------------------------------------------------------------------- 3035 3036 struct stl_notify_listeners_func : public std::unary_function<ISequenceListener*, void> 3037 { 3038 stl_notify_listeners_func() {} 3039 void operator()(ISequenceListener* pListener) { pListener->notify_change(); } 3040 }; 3041 3042 // -------------------------------------------------------------------- 3043 3044 void EffectSequenceHelper::notify_listeners() 3045 { 3046 stl_notify_listeners_func aFunc; 3047 std::for_each( maListeners.begin(), maListeners.end(), aFunc ); 3048 } 3049 3050 // -------------------------------------------------------------------- 3051 3052 void EffectSequenceHelper::create( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) 3053 { 3054 DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::create(), illegal argument" ); 3055 3056 if( xNode.is() ) try 3057 { 3058 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW ); 3059 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW ); 3060 while( xEnumeration->hasMoreElements() ) 3061 { 3062 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW ); 3063 createEffectsequence( xChildNode ); 3064 } 3065 } 3066 catch( Exception& ) 3067 { 3068 DBG_ERROR( "sd::EffectSequenceHelper::create(), exception cought!" ); 3069 } 3070 } 3071 3072 // -------------------------------------------------------------------- 3073 3074 void EffectSequenceHelper::createEffectsequence( const Reference< XAnimationNode >& xNode ) 3075 { 3076 DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::createEffectsequence(), illegal argument" ); 3077 3078 if( xNode.is() ) try 3079 { 3080 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW ); 3081 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW ); 3082 while( xEnumeration->hasMoreElements() ) 3083 { 3084 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW ); 3085 3086 createEffects( xChildNode ); 3087 } 3088 } 3089 catch( Exception& ) 3090 { 3091 DBG_ERROR( "sd::EffectSequenceHelper::createEffectsequence(), exception cought!" ); 3092 } 3093 } 3094 3095 // -------------------------------------------------------------------- 3096 3097 void EffectSequenceHelper::createEffects( const Reference< XAnimationNode >& xNode ) 3098 { 3099 DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::createEffects(), illegal argument" ); 3100 3101 if( xNode.is() ) try 3102 { 3103 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW ); 3104 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW ); 3105 while( xEnumeration->hasMoreElements() ) 3106 { 3107 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW ); 3108 3109 switch( xChildNode->getType() ) 3110 { 3111 // found an effect 3112 case AnimationNodeType::PAR: 3113 case AnimationNodeType::ITERATE: 3114 { 3115 CustomAnimationEffectPtr pEffect( new CustomAnimationEffect( xChildNode ) ); 3116 3117 if( pEffect->mnNodeType != -1 ) 3118 { 3119 pEffect->setEffectSequence( this ); 3120 maEffects.push_back(pEffect); 3121 } 3122 } 3123 break; 3124 3125 // found an after effect 3126 case AnimationNodeType::SET: 3127 case AnimationNodeType::ANIMATECOLOR: 3128 { 3129 processAfterEffect( xChildNode ); 3130 } 3131 break; 3132 } 3133 } 3134 } 3135 catch( Exception& e ) 3136 { 3137 (void)e; 3138 DBG_ERROR( "sd::EffectSequenceHelper::createEffects(), exception cought!" ); 3139 } 3140 } 3141 3142 // -------------------------------------------------------------------- 3143 3144 void EffectSequenceHelper::processAfterEffect( const Reference< XAnimationNode >& xNode ) 3145 { 3146 try 3147 { 3148 Reference< XAnimationNode > xMaster; 3149 3150 Sequence< NamedValue > aUserData( xNode->getUserData() ); 3151 sal_Int32 nLength = aUserData.getLength(); 3152 const NamedValue* p = aUserData.getConstArray(); 3153 3154 while( nLength-- ) 3155 { 3156 if( p->Name.equalsAscii( "master-element" ) ) 3157 { 3158 p->Value >>= xMaster; 3159 break; 3160 } 3161 p++; 3162 } 3163 3164 // only process if this is a valid after effect 3165 if( xMaster.is() ) 3166 { 3167 CustomAnimationEffectPtr pMasterEffect; 3168 3169 // find the master effect 3170 stl_CustomAnimationEffect_search_node_predict aSearchPredict( xMaster ); 3171 EffectSequence::iterator aIter( std::find_if( maEffects.begin(), maEffects.end(), aSearchPredict ) ); 3172 if( aIter != maEffects.end() ) 3173 pMasterEffect = (*aIter ); 3174 3175 if( pMasterEffect.get() ) 3176 { 3177 pMasterEffect->setHasAfterEffect( true ); 3178 3179 // find out what kind of after effect this is 3180 if( xNode->getType() == AnimationNodeType::ANIMATECOLOR ) 3181 { 3182 // its a dim 3183 Reference< XAnimate > xAnimate( xNode, UNO_QUERY_THROW ); 3184 pMasterEffect->setDimColor( xAnimate->getTo() ); 3185 pMasterEffect->setAfterEffectOnNext( true ); 3186 } 3187 else 3188 { 3189 // its a hide 3190 Reference< XChild > xNodeChild( xNode, UNO_QUERY_THROW ); 3191 Reference< XChild > xMasterChild( xMaster, UNO_QUERY_THROW ); 3192 pMasterEffect->setAfterEffectOnNext( xNodeChild->getParent() != xMasterChild->getParent() ); 3193 } 3194 } 3195 } 3196 } 3197 catch( Exception& e ) 3198 { 3199 (void)e; 3200 DBG_ERROR( "sd::EffectSequenceHelper::processAfterEffect(), exception cought!" ); 3201 } 3202 } 3203 3204 /* 3205 double EffectSequenceHelper::calculateIterateNodeDuration( 3206 { 3207 Reference< i18n::XBreakIterator > xBI( ImplGetBreakIterator() ); 3208 3209 sal_Int32 nDone; 3210 sal_Int32 nNextCellBreak( xBI->nextCharacters(rTxt, nIdx, rLocale, i18n::CharacterIteratorMode::SKIPCELL, 0, nDone) ); 3211 i18n::Boundary nNextWordBoundary( xBI->getWordBoundary(rTxt, nIdx, rLocale, i18n::WordType::ANY_WORD, sal_True) ); 3212 sal_Int32 nNextSentenceBreak( xBI->endOfSentence(rTxt, nIdx, rLocale) ); 3213 3214 const sal_Int32 nEndPos( nIdx + nLen ); 3215 sal_Int32 i, currOffset(0); 3216 for( i=nIdx; i<nEndPos; ++i ) 3217 { 3218 // TODO: Check whether position update is valid for CTL/BiDi 3219 rOutDev.DrawText( rPos + Point(currOffset,0), rTxt, i, 1 ); 3220 currOffset = *pDXArray++; 3221 3222 // issue the comments at the respective break positions 3223 if( i == nNextCellBreak ) 3224 { 3225 rMtf.AddAction( new MetaCommentAction( "XTEXT_EOC" ) ); 3226 nNextCellBreak = xBI->nextCharacters(rTxt, i, rLocale, i18n::CharacterIteratorMode::SKIPCELL, 1, nDone); 3227 } 3228 if( i == nNextWordBoundary.endPos ) 3229 { 3230 rMtf.AddAction( new MetaCommentAction( "XTEXT_EOW" ) ); 3231 nNextWordBoundary = xBI->getWordBoundary(rTxt, i+1, rLocale, i18n::WordType::ANY_WORD, sal_True); 3232 } 3233 if( i == nNextSentenceBreak ) 3234 { 3235 rMtf.AddAction( new MetaCommentAction( "XTEXT_EOS" ) ); 3236 nNextSentenceBreak = xBI->endOfSentence(rTxt, i+1, rLocale); 3237 } 3238 } 3239 } 3240 3241 */ 3242 // ==================================================================== 3243 3244 class AnimationChangeListener : public cppu::WeakImplHelper1< XChangesListener > 3245 { 3246 public: 3247 AnimationChangeListener( MainSequence* pMainSequence ) : mpMainSequence( pMainSequence ) {} 3248 3249 virtual void SAL_CALL changesOccurred( const ::com::sun::star::util::ChangesEvent& Event ) throw (RuntimeException); 3250 virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (RuntimeException); 3251 private: 3252 MainSequence* mpMainSequence; 3253 }; 3254 3255 void SAL_CALL AnimationChangeListener::changesOccurred( const ::com::sun::star::util::ChangesEvent& ) throw (RuntimeException) 3256 { 3257 if( mpMainSequence ) 3258 mpMainSequence->startRecreateTimer(); 3259 } 3260 3261 void SAL_CALL AnimationChangeListener::disposing( const ::com::sun::star::lang::EventObject& ) throw (RuntimeException) 3262 { 3263 } 3264 3265 // ==================================================================== 3266 3267 MainSequence::MainSequence() 3268 : mxTimingRootNode( ::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.SequenceTimeContainer"))), UNO_QUERY ) 3269 , mbRebuilding( false ) 3270 , mnRebuildLockGuard( 0 ) 3271 , mbPendingRebuildRequest( false ) 3272 { 3273 if( mxTimingRootNode.is() ) 3274 { 3275 Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 ); 3276 aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) ); 3277 aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::MAIN_SEQUENCE; 3278 mxTimingRootNode->setUserData( aUserData ); 3279 } 3280 init(); 3281 } 3282 3283 // -------------------------------------------------------------------- 3284 3285 MainSequence::MainSequence( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) 3286 : mxTimingRootNode( xNode, UNO_QUERY ) 3287 , mbRebuilding( false ) 3288 , mnRebuildLockGuard( 0 ) 3289 , mbPendingRebuildRequest( false ) 3290 , mbIgnoreChanges( 0 ) 3291 { 3292 init(); 3293 } 3294 3295 // -------------------------------------------------------------------- 3296 3297 MainSequence::~MainSequence() 3298 { 3299 reset(); 3300 } 3301 3302 // -------------------------------------------------------------------- 3303 3304 void MainSequence::init() 3305 { 3306 mnSequenceType = EffectNodeType::MAIN_SEQUENCE; 3307 3308 maTimer.SetTimeoutHdl( LINK(this, MainSequence, onTimerHdl) ); 3309 maTimer.SetTimeout(500); 3310 3311 mxChangesListener.set( new AnimationChangeListener( this ) ); 3312 3313 createMainSequence(); 3314 } 3315 3316 // -------------------------------------------------------------------- 3317 3318 void MainSequence::reset( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xTimingRootNode ) 3319 { 3320 reset(); 3321 3322 mxTimingRootNode.set( xTimingRootNode, UNO_QUERY ); 3323 3324 createMainSequence(); 3325 } 3326 3327 // -------------------------------------------------------------------- 3328 3329 Reference< ::com::sun::star::animations::XAnimationNode > MainSequence::getRootNode() 3330 { 3331 DBG_ASSERT( mnRebuildLockGuard == 0, "MainSequence::getRootNode(), rebuild is locked, ist this really what you want?" ); 3332 3333 if( maTimer.IsActive() && mbTimerMode ) 3334 { 3335 // force a rebuild NOW if one is pending 3336 maTimer.Stop(); 3337 implRebuild(); 3338 } 3339 3340 return EffectSequenceHelper::getRootNode(); 3341 } 3342 3343 // -------------------------------------------------------------------- 3344 3345 void MainSequence::createMainSequence() 3346 { 3347 if( mxTimingRootNode.is() ) try 3348 { 3349 Reference< XEnumerationAccess > xEnumerationAccess( mxTimingRootNode, UNO_QUERY_THROW ); 3350 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW ); 3351 while( xEnumeration->hasMoreElements() ) 3352 { 3353 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW ); 3354 sal_Int32 nNodeType = CustomAnimationEffect::get_node_type( xChildNode ); 3355 if( nNodeType == EffectNodeType::MAIN_SEQUENCE ) 3356 { 3357 mxSequenceRoot.set( xChildNode, UNO_QUERY ); 3358 EffectSequenceHelper::create( xChildNode ); 3359 } 3360 else if( nNodeType == EffectNodeType::INTERACTIVE_SEQUENCE ) 3361 { 3362 Reference< XTimeContainer > xInteractiveRoot( xChildNode, UNO_QUERY_THROW ); 3363 InteractiveSequencePtr pIS( new InteractiveSequence( xInteractiveRoot, this ) ); 3364 pIS->addListener( this ); 3365 maInteractiveSequenceList.push_back( pIS ); 3366 } 3367 } 3368 3369 // see if we have a mainsequence at all. if not, create one... 3370 if( !mxSequenceRoot.is() ) 3371 { 3372 mxSequenceRoot = Reference< XTimeContainer >::query(::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.SequenceTimeContainer")))); 3373 if( mxSequenceRoot.is() ) 3374 { 3375 uno::Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 ); 3376 aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) ); 3377 aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::MAIN_SEQUENCE; 3378 mxSequenceRoot->setUserData( aUserData ); 3379 3380 // empty sequence until now, set duration to 0.0 3381 // explicitely (otherwise, this sequence will never 3382 // end) 3383 mxSequenceRoot->setDuration( makeAny((double)0.0) ); 3384 3385 Reference< XAnimationNode > xMainSequenceNode( mxSequenceRoot, UNO_QUERY_THROW ); 3386 mxTimingRootNode->appendChild( xMainSequenceNode ); 3387 } 3388 } 3389 3390 updateTextGroups(); 3391 3392 notify_listeners(); 3393 3394 Reference< XChangesNotifier > xNotifier( mxTimingRootNode, UNO_QUERY ); 3395 if( xNotifier.is() ) 3396 xNotifier->addChangesListener( mxChangesListener ); 3397 } 3398 catch( Exception& e ) 3399 { 3400 (void)e; 3401 DBG_ERROR( "sd::MainSequence::create(), exception cought!" ); 3402 return; 3403 } 3404 3405 DBG_ASSERT( mxSequenceRoot.is(), "sd::MainSequence::create(), found no main sequence!" ); 3406 } 3407 3408 // -------------------------------------------------------------------- 3409 3410 void MainSequence::reset() 3411 { 3412 EffectSequenceHelper::reset(); 3413 3414 InteractiveSequenceList::iterator aIter; 3415 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ ) 3416 (*aIter)->reset(); 3417 maInteractiveSequenceList.clear(); 3418 3419 try 3420 { 3421 Reference< XChangesNotifier > xNotifier( mxTimingRootNode, UNO_QUERY ); 3422 if( xNotifier.is() ) 3423 xNotifier->removeChangesListener( mxChangesListener ); 3424 } 3425 catch( Exception& ) 3426 { 3427 // ... 3428 } 3429 } 3430 3431 // -------------------------------------------------------------------- 3432 3433 InteractiveSequencePtr MainSequence::createInteractiveSequence( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xShape ) 3434 { 3435 InteractiveSequencePtr pIS; 3436 3437 // create a new interactive sequence container 3438 Reference< XTimeContainer > xISRoot( ::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.SequenceTimeContainer"))), UNO_QUERY ); 3439 DBG_ASSERT( xISRoot.is(), "sd::MainSequence::createInteractiveSequence(), could not create \"com.sun.star.animations.SequenceTimeContainer\"!"); 3440 if( xISRoot.is() ) 3441 { 3442 uno::Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 ); 3443 aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) ); 3444 aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::INTERACTIVE_SEQUENCE ; 3445 xISRoot->setUserData( aUserData ); 3446 3447 Reference< XChild > xChild( mxSequenceRoot, UNO_QUERY_THROW ); 3448 Reference< XAnimationNode > xISNode( xISRoot, UNO_QUERY_THROW ); 3449 Reference< XTimeContainer > xParent( xChild->getParent(), UNO_QUERY_THROW ); 3450 xParent->appendChild( xISNode ); 3451 } 3452 pIS.reset( new InteractiveSequence( xISRoot, this) ); 3453 pIS->setTriggerShape( xShape ); 3454 pIS->addListener( this ); 3455 maInteractiveSequenceList.push_back( pIS ); 3456 return pIS; 3457 } 3458 3459 // -------------------------------------------------------------------- 3460 3461 CustomAnimationEffectPtr MainSequence::findEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) const 3462 { 3463 CustomAnimationEffectPtr pEffect = EffectSequenceHelper::findEffect( xNode ); 3464 3465 if( pEffect.get() == 0 ) 3466 { 3467 InteractiveSequenceList::const_iterator aIter; 3468 for( aIter = maInteractiveSequenceList.begin(); (aIter != maInteractiveSequenceList.end()) && (pEffect.get() == 0); aIter++ ) 3469 { 3470 pEffect = (*aIter)->findEffect( xNode ); 3471 } 3472 } 3473 return pEffect; 3474 } 3475 3476 // -------------------------------------------------------------------- 3477 3478 sal_Int32 MainSequence::getOffsetFromEffect( const CustomAnimationEffectPtr& pEffect ) const 3479 { 3480 sal_Int32 nOffset = EffectSequenceHelper::getOffsetFromEffect( pEffect ); 3481 3482 if( nOffset != -1 ) 3483 return nOffset; 3484 3485 nOffset = EffectSequenceHelper::getCount(); 3486 3487 InteractiveSequenceList::const_iterator aIter; 3488 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ ) 3489 { 3490 sal_Int32 nTemp = (*aIter)->getOffsetFromEffect( pEffect ); 3491 if( nTemp != -1 ) 3492 return nOffset + nTemp; 3493 3494 nOffset += (*aIter)->getCount(); 3495 } 3496 3497 return -1; 3498 } 3499 3500 // -------------------------------------------------------------------- 3501 3502 CustomAnimationEffectPtr MainSequence::getEffectFromOffset( sal_Int32 nOffset ) const 3503 { 3504 if( nOffset >= 0 ) 3505 { 3506 if( nOffset < getCount() ) 3507 return EffectSequenceHelper::getEffectFromOffset( nOffset ); 3508 3509 nOffset -= getCount(); 3510 3511 InteractiveSequenceList::const_iterator aIter( maInteractiveSequenceList.begin() ); 3512 3513 while( (aIter != maInteractiveSequenceList.end()) && (nOffset > (*aIter)->getCount()) ) 3514 nOffset -= (*aIter++)->getCount(); 3515 3516 if( (aIter != maInteractiveSequenceList.end()) && (nOffset >= 0) ) 3517 return (*aIter)->getEffectFromOffset( nOffset ); 3518 } 3519 3520 CustomAnimationEffectPtr pEffect; 3521 return pEffect; 3522 } 3523 3524 // -------------------------------------------------------------------- 3525 3526 bool MainSequence::disposeShape( const Reference< XShape >& xShape ) 3527 { 3528 bool bChanges = EffectSequenceHelper::disposeShape( xShape ); 3529 3530 InteractiveSequenceList::iterator aIter; 3531 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); ) 3532 { 3533 bChanges |= (*aIter++)->disposeShape( xShape ); 3534 } 3535 3536 if( bChanges ) 3537 startRebuildTimer(); 3538 3539 return bChanges; 3540 } 3541 3542 // -------------------------------------------------------------------- 3543 3544 bool MainSequence::hasEffect( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape ) 3545 { 3546 if( EffectSequenceHelper::hasEffect( xShape ) ) 3547 return true; 3548 3549 InteractiveSequenceList::iterator aIter; 3550 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); ) 3551 { 3552 if( (*aIter)->getTriggerShape() == xShape ) 3553 return true; 3554 3555 if( (*aIter++)->hasEffect( xShape ) ) 3556 return true; 3557 } 3558 3559 return false; 3560 } 3561 3562 // -------------------------------------------------------------------- 3563 3564 void MainSequence::insertTextRange( const com::sun::star::uno::Any& aTarget ) 3565 { 3566 EffectSequenceHelper::insertTextRange( aTarget ); 3567 3568 InteractiveSequenceList::iterator aIter; 3569 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ ) 3570 { 3571 (*aIter)->insertTextRange( aTarget ); 3572 } 3573 } 3574 // -------------------------------------------------------------------- 3575 3576 void MainSequence::disposeTextRange( const com::sun::star::uno::Any& aTarget ) 3577 { 3578 EffectSequenceHelper::disposeTextRange( aTarget ); 3579 3580 InteractiveSequenceList::iterator aIter; 3581 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ ) 3582 { 3583 (*aIter)->disposeTextRange( aTarget ); 3584 } 3585 } 3586 3587 // -------------------------------------------------------------------- 3588 3589 /** callback from the sd::View when an object just left text edit mode */ 3590 void MainSequence::onTextChanged( const Reference< XShape >& xShape ) 3591 { 3592 EffectSequenceHelper::onTextChanged( xShape ); 3593 3594 InteractiveSequenceList::iterator aIter; 3595 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ ) 3596 { 3597 (*aIter)->onTextChanged( xShape ); 3598 } 3599 } 3600 3601 // -------------------------------------------------------------------- 3602 3603 void EffectSequenceHelper::onTextChanged( const Reference< XShape >& xShape ) 3604 { 3605 bool bChanges = false; 3606 3607 EffectSequence::iterator aIter; 3608 for( aIter = maEffects.begin(); aIter != maEffects.end(); aIter++ ) 3609 { 3610 if( (*aIter)->getTargetShape() == xShape ) 3611 bChanges |= (*aIter)->checkForText(); 3612 } 3613 3614 if( bChanges ) 3615 EffectSequenceHelper::implRebuild(); 3616 } 3617 3618 // -------------------------------------------------------------------- 3619 3620 void MainSequence::rebuild() 3621 { 3622 startRebuildTimer(); 3623 } 3624 3625 // -------------------------------------------------------------------- 3626 3627 void MainSequence::lockRebuilds() 3628 { 3629 mnRebuildLockGuard++; 3630 } 3631 3632 // -------------------------------------------------------------------- 3633 3634 void MainSequence::unlockRebuilds() 3635 { 3636 DBG_ASSERT( mnRebuildLockGuard, "sd::MainSequence::unlockRebuilds(), no corresponding lockRebuilds() call!" ); 3637 if( mnRebuildLockGuard ) 3638 mnRebuildLockGuard--; 3639 3640 if( (mnRebuildLockGuard == 0) && mbPendingRebuildRequest ) 3641 { 3642 mbPendingRebuildRequest = false; 3643 startRebuildTimer(); 3644 } 3645 } 3646 3647 // -------------------------------------------------------------------- 3648 3649 void MainSequence::implRebuild() 3650 { 3651 if( mnRebuildLockGuard ) 3652 { 3653 mbPendingRebuildRequest = true; 3654 return; 3655 } 3656 3657 mbRebuilding = true; 3658 3659 EffectSequenceHelper::implRebuild(); 3660 3661 InteractiveSequenceList::iterator aIter( maInteractiveSequenceList.begin() ); 3662 const InteractiveSequenceList::iterator aEnd( maInteractiveSequenceList.end() ); 3663 while( aIter != aEnd ) 3664 { 3665 InteractiveSequencePtr pIS( (*aIter) ); 3666 if( pIS->maEffects.empty() ) 3667 { 3668 // remove empty interactive sequences 3669 aIter = maInteractiveSequenceList.erase( aIter ); 3670 3671 Reference< XChild > xChild( mxSequenceRoot, UNO_QUERY_THROW ); 3672 Reference< XTimeContainer > xParent( xChild->getParent(), UNO_QUERY_THROW ); 3673 Reference< XAnimationNode > xISNode( pIS->mxSequenceRoot, UNO_QUERY_THROW ); 3674 xParent->removeChild( xISNode ); 3675 } 3676 else 3677 { 3678 pIS->implRebuild(); 3679 aIter++; 3680 } 3681 } 3682 3683 notify_listeners(); 3684 mbRebuilding = false; 3685 } 3686 3687 // -------------------------------------------------------------------- 3688 3689 void MainSequence::notify_change() 3690 { 3691 notify_listeners(); 3692 } 3693 3694 // -------------------------------------------------------------------- 3695 3696 bool MainSequence::setTrigger( const CustomAnimationEffectPtr& pEffect, const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xTriggerShape ) 3697 { 3698 EffectSequenceHelper* pOldSequence = pEffect->getEffectSequence(); 3699 3700 EffectSequenceHelper* pNewSequence = 0; 3701 if( xTriggerShape.is() ) 3702 { 3703 InteractiveSequenceList::iterator aIter( maInteractiveSequenceList.begin() ); 3704 const InteractiveSequenceList::iterator aEnd( maInteractiveSequenceList.end() ); 3705 while( aIter != aEnd ) 3706 { 3707 InteractiveSequencePtr pIS( (*aIter++) ); 3708 if( pIS->getTriggerShape() == xTriggerShape ) 3709 { 3710 pNewSequence = pIS.get(); 3711 break; 3712 } 3713 } 3714 3715 if( !pNewSequence ) 3716 pNewSequence = createInteractiveSequence( xTriggerShape ).get(); 3717 } 3718 else 3719 { 3720 pNewSequence = this; 3721 } 3722 3723 if( pOldSequence != pNewSequence ) 3724 { 3725 if( pOldSequence ) 3726 pOldSequence->maEffects.remove( pEffect ); 3727 if( pNewSequence ) 3728 pNewSequence->maEffects.push_back( pEffect ); 3729 pEffect->setEffectSequence( pNewSequence ); 3730 return true; 3731 } 3732 else 3733 { 3734 return false; 3735 } 3736 3737 } 3738 3739 // -------------------------------------------------------------------- 3740 3741 IMPL_LINK( MainSequence, onTimerHdl, Timer *, EMPTYARG ) 3742 { 3743 if( mbTimerMode ) 3744 { 3745 implRebuild(); 3746 } 3747 else 3748 { 3749 reset(); 3750 createMainSequence(); 3751 } 3752 3753 return 0; 3754 } 3755 3756 // -------------------------------------------------------------------- 3757 3758 /** starts a timer that recreates the internal structure from the API core after 1 second */ 3759 void MainSequence::startRecreateTimer() 3760 { 3761 if( !mbRebuilding && (mbIgnoreChanges == 0) ) 3762 { 3763 mbTimerMode = false; 3764 maTimer.Start(); 3765 } 3766 } 3767 3768 // -------------------------------------------------------------------- 3769 3770 /** starts a timer that rebuilds the API core from the internal structure after 1 second */ 3771 void MainSequence::startRebuildTimer() 3772 { 3773 mbTimerMode = true; 3774 maTimer.Start(); 3775 } 3776 3777 // ==================================================================== 3778 3779 InteractiveSequence::InteractiveSequence( const Reference< XTimeContainer >& xSequenceRoot, MainSequence* pMainSequence ) 3780 : EffectSequenceHelper( xSequenceRoot ), mpMainSequence( pMainSequence ) 3781 { 3782 mnSequenceType = EffectNodeType::INTERACTIVE_SEQUENCE; 3783 3784 try 3785 { 3786 if( mxSequenceRoot.is() ) 3787 { 3788 Reference< XEnumerationAccess > xEnumerationAccess( mxSequenceRoot, UNO_QUERY_THROW ); 3789 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW ); 3790 while( !mxEventSource.is() && xEnumeration->hasMoreElements() ) 3791 { 3792 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW ); 3793 3794 Event aEvent; 3795 if( (xChildNode->getBegin() >>= aEvent) && (aEvent.Trigger == EventTrigger::ON_CLICK) ) 3796 aEvent.Source >>= mxEventSource; 3797 } 3798 } 3799 } 3800 catch( Exception& e ) 3801 { 3802 (void)e; 3803 DBG_ERROR( "sd::InteractiveSequence::InteractiveSequence(), exception cought!" ); 3804 return; 3805 } 3806 } 3807 3808 // -------------------------------------------------------------------- 3809 3810 void InteractiveSequence::rebuild() 3811 { 3812 mpMainSequence->rebuild(); 3813 } 3814 3815 void InteractiveSequence::implRebuild() 3816 { 3817 EffectSequenceHelper::implRebuild(); 3818 } 3819 3820 // -------------------------------------------------------------------- 3821 3822 MainSequenceRebuildGuard::MainSequenceRebuildGuard( const MainSequencePtr& pMainSequence ) 3823 : mpMainSequence( pMainSequence ) 3824 { 3825 if( mpMainSequence.get() ) 3826 mpMainSequence->lockRebuilds(); 3827 } 3828 3829 MainSequenceRebuildGuard::~MainSequenceRebuildGuard() 3830 { 3831 if( mpMainSequence.get() ) 3832 mpMainSequence->unlockRebuilds(); 3833 } 3834 3835 3836 } 3837