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