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