update credits
[LibreOffice.git] / sd / source / core / CustomAnimationEffect.cxx
blob827bed2af29f4f4e7e2647c577e8a2822e67efbb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <tools/debug.hxx>
21 #include <com/sun/star/animations/AnimationNodeType.hpp>
22 #include <com/sun/star/animations/AnimateColor.hpp>
23 #include <com/sun/star/animations/AnimateMotion.hpp>
24 #include <com/sun/star/animations/AnimateSet.hpp>
25 #include <com/sun/star/animations/AnimationFill.hpp>
26 #include <com/sun/star/animations/AnimationTransformType.hpp>
27 #include <com/sun/star/animations/Audio.hpp>
28 #include <com/sun/star/animations/Command.hpp>
29 #include <com/sun/star/animations/Event.hpp>
30 #include <com/sun/star/animations/EventTrigger.hpp>
31 #include <com/sun/star/animations/IterateContainer.hpp>
32 #include <com/sun/star/animations/ParallelTimeContainer.hpp>
33 #include <com/sun/star/animations/SequenceTimeContainer.hpp>
34 #include <com/sun/star/animations/Timing.hpp>
35 #include <com/sun/star/animations/XCommand.hpp>
36 #include <com/sun/star/animations/XIterateContainer.hpp>
37 #include <com/sun/star/animations/XAnimateTransform.hpp>
38 #include <com/sun/star/animations/XAnimateMotion.hpp>
39 #include <com/sun/star/animations/XAnimate.hpp>
40 #include <com/sun/star/beans/NamedValue.hpp>
41 #include <com/sun/star/beans/XPropertySet.hpp>
42 #include <com/sun/star/container/XEnumerationAccess.hpp>
43 #include <com/sun/star/drawing/XDrawPage.hpp>
44 #include <com/sun/star/lang/XInitialization.hpp>
45 #include <com/sun/star/presentation/EffectNodeType.hpp>
46 #include <com/sun/star/presentation/EffectCommands.hpp>
47 #include <com/sun/star/presentation/EffectPresetClass.hpp>
48 #include <com/sun/star/presentation/ParagraphTarget.hpp>
49 #include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
50 #include <com/sun/star/text/XText.hpp>
51 #include <com/sun/star/util/XCloneable.hpp>
52 #include <com/sun/star/util/XChangesNotifier.hpp>
53 #include <comphelper/processfactory.hxx>
54 #include <comphelper/sequence.hxx>
55 #include <com/sun/star/lang/Locale.hpp>
56 #include <com/sun/star/i18n/BreakIterator.hpp>
57 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
58 #include <com/sun/star/i18n/WordType.hpp>
59 #include <com/sun/star/presentation/TextAnimationType.hpp>
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>
67 #include <algorithm>
69 #include <cppuhelper/implbase1.hxx>
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"
80 using namespace ::com::sun::star;
81 using namespace ::com::sun::star::uno;
82 using namespace ::com::sun::star::presentation;
83 using namespace ::com::sun::star::animations;
85 using ::com::sun::star::container::XEnumerationAccess;
86 using ::com::sun::star::container::XEnumeration;
87 using ::com::sun::star::beans::NamedValue;
88 using ::com::sun::star::container::XChild;
89 using ::com::sun::star::container::XElementAccess;
90 using ::com::sun::star::drawing::XShape;
91 using ::com::sun::star::lang::XInitialization;
92 using ::com::sun::star::drawing::XShapes;
93 using ::com::sun::star::drawing::XDrawPage;
94 using ::com::sun::star::text::XText;
95 using ::com::sun::star::text::XTextRange;
96 using ::com::sun::star::beans::XPropertySet;
97 using ::com::sun::star::lang::XMultiServiceFactory;
98 using ::com::sun::star::util::XCloneable;
99 using ::com::sun::star::lang::Locale;
100 using ::com::sun::star::util::XChangesNotifier;
101 using ::com::sun::star::util::XChangesListener;
103 namespace sd
105 class MainSequenceChangeGuard
107 public:
108 MainSequenceChangeGuard( EffectSequenceHelper* pSequence )
110 mpMainSequence = dynamic_cast< MainSequence* >( pSequence );
111 if( mpMainSequence == 0 )
113 InteractiveSequence* pI = dynamic_cast< InteractiveSequence* >( pSequence );
114 if( pI )
115 mpMainSequence = pI->mpMainSequence;
117 DBG_ASSERT( mpMainSequence, "sd::MainSequenceChangeGuard::MainSequenceChangeGuard(), no main sequence to guard!" );
119 if( mpMainSequence )
120 mpMainSequence->mbIgnoreChanges++;
123 ~MainSequenceChangeGuard()
125 if( mpMainSequence )
126 mpMainSequence->mbIgnoreChanges++;
129 private:
130 MainSequence* mpMainSequence;
133 CustomAnimationEffect::CustomAnimationEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
134 : mnNodeType(-1),
135 mnPresetClass(-1),
136 mfBegin(-1.0),
137 mfDuration(-1.0),
138 mfAbsoluteDuration(-1.0),
139 mnGroupId(-1),
140 mnIterateType(0),
141 mfIterateInterval(0.0),
142 mnParaDepth( -1 ),
143 mbHasText(sal_False),
144 mfAcceleration( 1.0 ),
145 mfDecelerate( 1.0 ),
146 mbAutoReverse(false),
147 mnTargetSubItem(0),
148 mnCommand(0),
149 mpEffectSequence( 0 ),
150 mbHasAfterEffect(false),
151 mbAfterEffectOnNextEffect(false)
153 setNode( xNode );
156 // --------------------------------------------------------------------
158 void CustomAnimationEffect::setNode( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
160 mxNode = xNode;
161 mxAudio.clear();
163 Sequence< NamedValue > aUserData( mxNode->getUserData() );
164 sal_Int32 nLength = aUserData.getLength();
165 const NamedValue* p = aUserData.getConstArray();
167 while( nLength-- )
169 if ( p->Name == "node-type" )
171 p->Value >>= mnNodeType;
173 else if ( p->Name == "preset-id" )
175 p->Value >>= maPresetId;
177 else if ( p->Name == "preset-sub-type" )
179 p->Value >>= maPresetSubType;
181 else if ( p->Name == "preset-class" )
183 p->Value >>= mnPresetClass;
185 else if ( p->Name == "preset-property" )
187 p->Value >>= maProperty;
189 else if ( p->Name == "group-id" )
191 p->Value >>= mnGroupId;
194 p++;
197 // get effect start time
198 mxNode->getBegin() >>= mfBegin;
200 mfAcceleration = mxNode->getAcceleration();
201 mfDecelerate = mxNode->getDecelerate();
202 mbAutoReverse = mxNode->getAutoReverse();
204 // get iteration data
205 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
206 if( xIter.is() )
208 mfIterateInterval = xIter->getIterateInterval();
209 mnIterateType = xIter->getIterateType();
210 maTarget = xIter->getTarget();
211 mnTargetSubItem = xIter->getSubItem();
213 else
215 mfIterateInterval = 0.0f;
216 mnIterateType = 0;
219 // calculate effect duration and get target shape
220 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
221 if( xEnumerationAccess.is() )
223 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
224 if( xEnumeration.is() )
226 while( xEnumeration->hasMoreElements() )
228 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
229 if( !xChildNode.is() )
230 continue;
232 if( xChildNode->getType() == AnimationNodeType::AUDIO )
234 mxAudio.set( xChildNode, UNO_QUERY );
236 else if( xChildNode->getType() == AnimationNodeType::COMMAND )
238 Reference< XCommand > xCommand( xChildNode, UNO_QUERY );
239 if( xCommand.is() )
241 mnCommand = xCommand->getCommand();
242 if( !maTarget.hasValue() )
243 maTarget = xCommand->getTarget();
246 else
248 double fBegin = 0.0;
249 double fDuration = 0.0;
250 xChildNode->getBegin() >>= fBegin;
251 xChildNode->getDuration() >>= fDuration;
253 fDuration += fBegin;
254 if( fDuration > mfDuration )
255 mfDuration = fDuration;
257 // no target shape yet?
258 if( !maTarget.hasValue() )
260 // go get it boys!
261 Reference< XAnimate > xAnimate( xChildNode, UNO_QUERY );
262 if( xAnimate.is() )
264 maTarget = xAnimate->getTarget();
265 mnTargetSubItem = xAnimate->getSubItem();
273 mfAbsoluteDuration = mfDuration;
274 double fRepeatCount = 1.0;
275 if( (mxNode->getRepeatCount()) >>= fRepeatCount )
276 mfAbsoluteDuration *= fRepeatCount;
278 checkForText();
281 // --------------------------------------------------------------------
283 sal_Int32 CustomAnimationEffect::getNumberOfSubitems( const Any& aTarget, sal_Int16 nIterateType )
285 sal_Int32 nSubItems = 0;
289 // first get target text
290 sal_Int32 nOnlyPara = -1;
292 Reference< XText > xShape;
293 aTarget >>= xShape;
294 if( !xShape.is() )
296 ParagraphTarget aParaTarget;
297 if( aTarget >>= aParaTarget )
299 xShape.set( aParaTarget.Shape, UNO_QUERY );
300 nOnlyPara = aParaTarget.Paragraph;
304 // now use the break iterator to iterate over the given text
305 // and count the sub items
307 if( xShape.is() )
309 // TODO/LATER: Optimize this, don't create a break iterator each time
310 Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
311 Reference < i18n::XBreakIterator > xBI = i18n::BreakIterator::create(xContext);
313 Reference< XEnumerationAccess > xEA( xShape, UNO_QUERY_THROW );
314 Reference< XEnumeration > xEnumeration( xEA->createEnumeration(), UNO_QUERY_THROW );
315 Locale aLocale;
316 const OUString aStrLocaleName( "CharLocale" );
317 Reference< XTextRange > xParagraph;
319 sal_Int32 nPara = 0;
320 while( xEnumeration->hasMoreElements() )
322 xEnumeration->nextElement() >>= xParagraph;
324 // skip this if its not the only paragraph we want to count
325 if( (nOnlyPara != -1) && (nOnlyPara != nPara ) )
326 continue;
328 if( nIterateType == TextAnimationType::BY_PARAGRAPH )
330 nSubItems++;
332 else
334 const OUString aText( xParagraph->getString() );
335 Reference< XPropertySet > xSet( xParagraph, UNO_QUERY_THROW );
336 xSet->getPropertyValue( aStrLocaleName ) >>= aLocale;
338 sal_Int32 nPos;
339 const sal_Int32 nEndPos = aText.getLength();
341 if( nIterateType == TextAnimationType::BY_WORD )
343 for( nPos = 0; nPos < nEndPos; nPos++ )
345 nPos = xBI->getWordBoundary(aText, nPos, aLocale, i18n::WordType::ANY_WORD, sal_True).endPos;
346 nSubItems++;
348 break;
350 else
352 sal_Int32 nDone;
353 for( nPos = 0; nPos < nEndPos; nPos++ )
355 nPos = xBI->nextCharacters(aText, nPos, aLocale, i18n::CharacterIteratorMode::SKIPCELL, 0, nDone);
356 nSubItems++;
361 if( nPara == nOnlyPara )
362 break;
364 nPara++;
368 catch( Exception& )
370 nSubItems = 0;
371 OSL_FAIL( "sd::CustomAnimationEffect::getNumberOfSubitems(), exception caught!" );
374 return nSubItems;
377 // --------------------------------------------------------------------
379 CustomAnimationEffect::~CustomAnimationEffect()
383 // --------------------------------------------------------------------
385 CustomAnimationEffectPtr CustomAnimationEffect::clone() const
387 Reference< XCloneable > xCloneable( mxNode, UNO_QUERY_THROW );
388 Reference< XAnimationNode > xNode( xCloneable->createClone(), UNO_QUERY_THROW );
389 CustomAnimationEffectPtr pEffect( new CustomAnimationEffect( xNode ) );
390 pEffect->setEffectSequence( getEffectSequence() );
391 return pEffect;
394 // --------------------------------------------------------------------
396 sal_Int32 CustomAnimationEffect::get_node_type( const Reference< XAnimationNode >& xNode )
398 sal_Int16 nNodeType = -1;
400 if( xNode.is() )
402 Sequence< NamedValue > aUserData( xNode->getUserData() );
403 sal_Int32 nLength = aUserData.getLength();
404 if( nLength )
406 const NamedValue* p = aUserData.getConstArray();
407 while( nLength-- )
409 if ( p->Name == "node-type" )
411 p->Value >>= nNodeType;
412 break;
414 p++;
419 return nNodeType;
422 // --------------------------------------------------------------------
424 void CustomAnimationEffect::setPresetClass( sal_Int16 nPresetClass )
426 if( mnPresetClass != nPresetClass )
428 mnPresetClass = nPresetClass;
429 if( mxNode.is() )
431 // first try to find a "preset-class" entry in the user data
432 // and change it
433 Sequence< NamedValue > aUserData( mxNode->getUserData() );
434 sal_Int32 nLength = aUserData.getLength();
435 bool bFound = false;
436 if( nLength )
438 NamedValue* p = aUserData.getArray();
439 while( nLength-- )
441 if ( p->Name == "preset-class" )
443 p->Value <<= mnPresetClass;
444 bFound = true;
445 break;
447 p++;
451 // no "node-type" entry inside user data, so add it
452 if( !bFound )
454 nLength = aUserData.getLength();
455 aUserData.realloc( nLength + 1);
456 aUserData[nLength].Name = "preset-class";
457 aUserData[nLength].Value <<= mnPresetClass;
460 mxNode->setUserData( aUserData );
465 void CustomAnimationEffect::setNodeType( sal_Int16 nNodeType )
467 if( mnNodeType != nNodeType )
469 mnNodeType = nNodeType;
470 if( mxNode.is() )
472 // first try to find a "node-type" entry in the user data
473 // and change it
474 Sequence< NamedValue > aUserData( mxNode->getUserData() );
475 sal_Int32 nLength = aUserData.getLength();
476 bool bFound = false;
477 if( nLength )
479 NamedValue* p = aUserData.getArray();
480 while( nLength-- )
482 if ( p->Name == "node-type" )
484 p->Value <<= mnNodeType;
485 bFound = true;
486 break;
488 p++;
492 // no "node-type" entry inside user data, so add it
493 if( !bFound )
495 nLength = aUserData.getLength();
496 aUserData.realloc( nLength + 1);
497 aUserData[nLength].Name = "node-type";
498 aUserData[nLength].Value <<= mnNodeType;
501 mxNode->setUserData( aUserData );
506 // --------------------------------------------------------------------
508 void CustomAnimationEffect::setGroupId( sal_Int32 nGroupId )
510 mnGroupId = nGroupId;
511 if( mxNode.is() )
513 // first try to find a "group-id" entry in the user data
514 // and change it
515 Sequence< NamedValue > aUserData( mxNode->getUserData() );
516 sal_Int32 nLength = aUserData.getLength();
517 bool bFound = false;
518 if( nLength )
520 NamedValue* p = aUserData.getArray();
521 while( nLength-- )
523 if ( p->Name == "group-id" )
525 p->Value <<= mnGroupId;
526 bFound = true;
527 break;
529 p++;
533 // no "node-type" entry inside user data, so add it
534 if( !bFound )
536 nLength = aUserData.getLength();
537 aUserData.realloc( nLength + 1);
538 aUserData[nLength].Name = "group-id";
539 aUserData[nLength].Value <<= mnGroupId;
542 mxNode->setUserData( aUserData );
546 // --------------------------------------------------------------------
548 /** checks if the text for this effect has changed and updates internal flags.
549 returns true if something changed.
551 bool CustomAnimationEffect::checkForText()
553 bool bChange = false;
555 Reference< XText > xText;
557 if( maTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
559 // calc para depth
560 ParagraphTarget aParaTarget;
561 maTarget >>= aParaTarget;
563 xText = Reference< XText >::query( aParaTarget.Shape );
565 // get paragraph
566 if( xText.is() )
568 Reference< XEnumerationAccess > xEA( xText, UNO_QUERY );
569 if( xEA.is() )
571 Reference< XEnumeration > xEnumeration( xEA->createEnumeration(), UNO_QUERY );
572 if( xEnumeration.is() )
574 sal_Bool bHasText = xEnumeration->hasMoreElements();
575 bChange |= bHasText != mbHasText;
576 mbHasText = bHasText;
578 sal_Int32 nPara = aParaTarget.Paragraph;
580 while( xEnumeration->hasMoreElements() && nPara-- )
581 xEnumeration->nextElement();
583 if( xEnumeration->hasMoreElements() )
585 Reference< XPropertySet > xParaSet;
586 xEnumeration->nextElement() >>= xParaSet;
587 if( xParaSet.is() )
589 sal_Int32 nParaDepth = 0;
590 const OUString strNumberingLevel( "NumberingLevel" );
591 xParaSet->getPropertyValue( strNumberingLevel ) >>= nParaDepth;
592 bChange |= nParaDepth != mnParaDepth;
593 mnParaDepth = nParaDepth;
600 else
602 maTarget >>= xText;
603 sal_Bool bHasText = xText.is() && !xText->getString().isEmpty();
604 bChange |= bHasText != mbHasText;
605 mbHasText = bHasText;
608 bChange |= calculateIterateDuration();
609 return bChange;
612 bool CustomAnimationEffect::calculateIterateDuration()
614 bool bChange = false;
616 // if we have an iteration, we must also calculate the
617 // 'true' container duration, that is
618 // ( ( is form animated ) ? [contained effects duration] : 0 ) +
619 // ( [number of animated children] - 1 ) * [interval-delay] + [contained effects duration]
620 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
621 if( xIter.is() )
623 double fDuration = mfDuration;
624 const double fSubEffectDuration = mfDuration;
626 if( mnTargetSubItem != ShapeAnimationSubType::ONLY_BACKGROUND ) // does not make sense for iterate container but better check
628 const sal_Int32 nSubItems = getNumberOfSubitems( maTarget, mnIterateType );
629 if( nSubItems )
631 const double f = (nSubItems-1) * mfIterateInterval;
632 fDuration += f;
636 // if we also animate the form first, we have to add the
637 // sub effect duration to the whole effect duration
638 if( mnTargetSubItem == ShapeAnimationSubType::AS_WHOLE )
639 fDuration += fSubEffectDuration;
641 bChange |= fDuration != mfAbsoluteDuration;
642 mfAbsoluteDuration = fDuration;
645 return bChange;
648 // --------------------------------------------------------------------
650 void CustomAnimationEffect::setTarget( const ::com::sun::star::uno::Any& rTarget )
654 maTarget = rTarget;
656 // first, check special case for random node
657 Reference< XInitialization > xInit( mxNode, UNO_QUERY );
658 if( xInit.is() )
660 const Sequence< Any > aArgs( &maTarget, 1 );
661 xInit->initialize( aArgs );
663 else
665 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
666 if( xIter.is() )
668 xIter->setTarget(maTarget);
670 else
672 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
673 if( xEnumerationAccess.is() )
675 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
676 if( xEnumeration.is() )
678 while( xEnumeration->hasMoreElements() )
680 const Any aElem( xEnumeration->nextElement() );
681 Reference< XAnimate > xAnimate( aElem, UNO_QUERY );
682 if( xAnimate.is() )
683 xAnimate->setTarget( rTarget );
684 else
686 Reference< XCommand > xCommand( aElem, UNO_QUERY );
687 if( xCommand.is() )
688 xCommand->setTarget( rTarget );
695 checkForText();
697 catch( Exception& )
699 OSL_FAIL( "sd::CustomAnimationEffect::setTarget(), exception caught!" );
703 // --------------------------------------------------------------------
705 void CustomAnimationEffect::setTargetSubItem( sal_Int16 nSubItem )
709 mnTargetSubItem = nSubItem;
711 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
712 if( xIter.is() )
714 xIter->setSubItem(mnTargetSubItem);
716 else
718 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
719 if( xEnumerationAccess.is() )
721 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
722 if( xEnumeration.is() )
724 while( xEnumeration->hasMoreElements() )
726 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
727 if( xAnimate.is() )
728 xAnimate->setSubItem( mnTargetSubItem );
734 catch( Exception& )
736 OSL_FAIL( "sd::CustomAnimationEffect::setTargetSubItem(), exception caught!" );
740 // --------------------------------------------------------------------
742 void CustomAnimationEffect::setDuration( double fDuration )
744 if( (mfDuration != -1.0) && (mfDuration != fDuration) ) try
746 double fScale = fDuration / mfDuration;
747 mfDuration = fDuration;
748 double fRepeatCount = 1.0;
749 getRepeatCount() >>= fRepeatCount;
750 mfAbsoluteDuration = mfDuration * fRepeatCount;
752 // calculate effect duration and get target shape
753 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
754 if( xEnumerationAccess.is() )
756 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
757 if( xEnumeration.is() )
759 while( xEnumeration->hasMoreElements() )
761 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
762 if( !xChildNode.is() )
763 continue;
766 double fChildBegin = 0.0;
767 xChildNode->getBegin() >>= fChildBegin;
768 if( fChildBegin != 0.0 )
770 fChildBegin *= fScale;
771 xChildNode->setBegin( makeAny( fChildBegin ) );
774 double fChildDuration = 0.0;
775 xChildNode->getDuration() >>= fChildDuration;
776 if( fChildDuration != 0.0 )
778 fChildDuration *= fScale;
779 xChildNode->setDuration( makeAny( fChildDuration ) );
784 calculateIterateDuration();
786 catch( Exception& )
788 OSL_FAIL( "sd::CustomAnimationEffect::setDuration(), exception caught!" );
792 // --------------------------------------------------------------------
794 void CustomAnimationEffect::setBegin( double fBegin )
796 if( mxNode.is() ) try
798 mfBegin = fBegin;
799 mxNode->setBegin( makeAny( fBegin ) );
801 catch( Exception& )
803 OSL_FAIL( "sd::CustomAnimationEffect::setBegin(), exception caught!" );
807 // --------------------------------------------------------------------
809 void CustomAnimationEffect::setAcceleration( double fAcceleration )
811 if( mxNode.is() ) try
813 mfAcceleration = fAcceleration;
814 mxNode->setAcceleration( fAcceleration );
816 catch( Exception& )
818 OSL_FAIL( "sd::CustomAnimationEffect::setAcceleration(), exception caught!" );
821 // --------------------------------------------------------------------
823 void CustomAnimationEffect::setDecelerate( double fDecelerate )
825 if( mxNode.is() ) try
827 mfDecelerate = fDecelerate;
828 mxNode->setDecelerate( fDecelerate );
830 catch( Exception& )
832 OSL_FAIL( "sd::CustomAnimationEffect::setDecelerate(), exception caught!" );
836 // --------------------------------------------------------------------
838 void CustomAnimationEffect::setAutoReverse( sal_Bool bAutoReverse )
840 if( mxNode.is() ) try
842 mbAutoReverse = bAutoReverse;
843 mxNode->setAutoReverse( bAutoReverse );
845 catch( Exception& )
847 OSL_FAIL( "sd::CustomAnimationEffect::setAutoReverse(), exception caught!" );
851 // --------------------------------------------------------------------
853 void CustomAnimationEffect::replaceNode( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
855 sal_Int16 nNodeType = mnNodeType;
856 Any aTarget = maTarget;
858 double fBegin = mfBegin;
859 double fDuration = mfDuration;
860 double fAcceleration = mfAcceleration;
861 double fDecelerate = mfDecelerate ;
862 sal_Bool bAutoReverse = mbAutoReverse;
863 Reference< XAudio > xAudio( mxAudio );
864 sal_Int16 nIterateType = mnIterateType;
865 double fIterateInterval = mfIterateInterval;
866 sal_Int16 nSubItem = mnTargetSubItem;
868 setNode( xNode );
870 setAudio( xAudio );
871 setNodeType( nNodeType );
872 setTarget( aTarget );
873 setTargetSubItem( nSubItem );
874 setDuration( fDuration );
875 setBegin( fBegin );
877 setAcceleration( fAcceleration );
878 setDecelerate( fDecelerate );
879 setAutoReverse( bAutoReverse );
881 if( nIterateType != mnIterateType )
882 setIterateType( nIterateType );
884 if( mnIterateType && ( fIterateInterval != mfIterateInterval ) )
885 setIterateInterval( fIterateInterval );
888 // --------------------------------------------------------------------
890 Reference< XShape > CustomAnimationEffect::getTargetShape() const
892 Reference< XShape > xShape;
893 maTarget >>= xShape;
894 if( !xShape.is() )
896 ParagraphTarget aParaTarget;
897 if( maTarget >>= aParaTarget )
898 xShape = aParaTarget.Shape;
901 return xShape;
904 // --------------------------------------------------------------------
906 Any CustomAnimationEffect::getRepeatCount() const
908 if( mxNode.is() )
910 return mxNode->getRepeatCount();
912 else
914 Any aAny;
915 return aAny;
919 // --------------------------------------------------------------------
921 Any CustomAnimationEffect::getEnd() const
923 if( mxNode.is() )
925 return mxNode->getEnd();
927 else
929 Any aAny;
930 return aAny;
934 // --------------------------------------------------------------------
936 sal_Int16 CustomAnimationEffect::getFill() const
938 if( mxNode.is() )
939 return mxNode->getFill();
940 else
941 return 0;
944 // --------------------------------------------------------------------
946 void CustomAnimationEffect::setRepeatCount( const Any& rRepeatCount )
948 if( mxNode.is() )
950 mxNode->setRepeatCount( rRepeatCount );
951 double fRepeatCount = 1.0;
952 rRepeatCount >>= fRepeatCount;
953 mfAbsoluteDuration = mfDuration * fRepeatCount;
957 // --------------------------------------------------------------------
959 void CustomAnimationEffect::setEnd( const Any& rEnd )
961 if( mxNode.is() )
962 mxNode->setEnd( rEnd );
965 // --------------------------------------------------------------------
967 void CustomAnimationEffect::setFill( sal_Int16 nFill )
969 if( mxNode.is() )
970 mxNode->setFill( nFill );
973 // --------------------------------------------------------------------
975 Reference< XAnimationNode > CustomAnimationEffect::createAfterEffectNode() const throw (Exception)
977 DBG_ASSERT( mbHasAfterEffect, "sd::CustomAnimationEffect::createAfterEffectNode(), this node has no after effect!" );
979 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
981 Reference< XAnimate > xAnimate;
982 if( maDimColor.hasValue() )
983 xAnimate = AnimateColor::create( xContext );
984 else
985 xAnimate = AnimateSet::create( xContext );
987 Any aTo;
988 OUString aAttributeName;
990 if( maDimColor.hasValue() )
992 aTo = maDimColor;
993 aAttributeName = "DimColor";
995 else
997 aTo = makeAny( (sal_Bool)sal_False );
998 aAttributeName = "Visibility";
1001 Any aBegin;
1002 if( !mbAfterEffectOnNextEffect ) // sameClick
1004 Event aEvent;
1006 aEvent.Source <<= getNode();
1007 aEvent.Trigger = EventTrigger::END_EVENT;
1008 aEvent.Repeat = 0;
1010 aBegin <<= aEvent;
1012 else
1014 aBegin <<= (double)0.0;
1017 xAnimate->setBegin( aBegin );
1018 xAnimate->setTo( aTo );
1019 xAnimate->setAttributeName( aAttributeName );
1021 xAnimate->setDuration( makeAny( (double)0.001 ) );
1022 xAnimate->setFill( AnimationFill::HOLD );
1023 xAnimate->setTarget( maTarget );
1025 return xAnimate;
1028 // --------------------------------------------------------------------
1030 void CustomAnimationEffect::setIterateType( sal_Int16 nIterateType )
1032 if( mnIterateType != nIterateType ) try
1034 // do we need to exchange the container node?
1035 if( (mnIterateType == 0) || (nIterateType == 0) )
1037 sal_Int16 nTargetSubItem = mnTargetSubItem;
1039 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1040 Reference< XTimeContainer > xNewContainer;
1041 if(nIterateType)
1043 xNewContainer.set( IterateContainer::create( xContext ) );
1045 else
1046 xNewContainer.set( ParallelTimeContainer::create( xContext ), UNO_QUERY_THROW );
1048 Reference< XTimeContainer > xOldContainer( mxNode, UNO_QUERY_THROW );
1049 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW );
1050 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1051 while( xEnumeration->hasMoreElements() )
1053 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
1054 xOldContainer->removeChild( xChildNode );
1055 xNewContainer->appendChild( xChildNode );
1058 Reference< XAnimationNode > xNewNode( xNewContainer, UNO_QUERY_THROW );
1060 xNewNode->setBegin( mxNode->getBegin() );
1061 xNewNode->setDuration( mxNode->getDuration() );
1062 xNewNode->setEnd( mxNode->getEnd() );
1063 xNewNode->setEndSync( mxNode->getEndSync() );
1064 xNewNode->setRepeatCount( mxNode->getRepeatCount() );
1065 xNewNode->setFill( mxNode->getFill() );
1066 xNewNode->setFillDefault( mxNode->getFillDefault() );
1067 xNewNode->setRestart( mxNode->getRestart() );
1068 xNewNode->setRestartDefault( mxNode->getRestartDefault() );
1069 xNewNode->setAcceleration( mxNode->getAcceleration() );
1070 xNewNode->setDecelerate( mxNode->getDecelerate() );
1071 xNewNode->setAutoReverse( mxNode->getAutoReverse() );
1072 xNewNode->setRepeatDuration( mxNode->getRepeatDuration() );
1073 xNewNode->setEndSync( mxNode->getEndSync() );
1074 xNewNode->setRepeatCount( mxNode->getRepeatCount() );
1075 xNewNode->setUserData( mxNode->getUserData() );
1077 mxNode = xNewNode;
1079 Any aTarget;
1080 if( nIterateType )
1082 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY_THROW );
1083 xIter->setTarget(maTarget);
1084 xIter->setSubItem( nTargetSubItem );
1086 else
1088 aTarget = maTarget;
1091 Reference< XEnumerationAccess > xEA( mxNode, UNO_QUERY_THROW );
1092 Reference< XEnumeration > xE( xEA->createEnumeration(), UNO_QUERY_THROW );
1093 while( xE->hasMoreElements() )
1095 Reference< XAnimate > xAnimate( xE->nextElement(), UNO_QUERY );
1096 if( xAnimate.is() )
1098 xAnimate->setTarget( aTarget );
1099 xAnimate->setSubItem( nTargetSubItem );
1104 mnIterateType = nIterateType;
1106 // if we have an iteration container, we must set its type
1107 if( mnIterateType )
1109 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY_THROW );
1110 xIter->setIterateType( nIterateType );
1113 checkForText();
1115 catch( Exception& )
1117 OSL_FAIL( "sd::CustomAnimationEffect::setIterateType(), Exception caught!" );
1121 // --------------------------------------------------------------------
1123 void CustomAnimationEffect::setIterateInterval( double fIterateInterval )
1125 if( mfIterateInterval != fIterateInterval )
1127 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
1129 DBG_ASSERT( xIter.is(), "sd::CustomAnimationEffect::setIterateInterval(), not an iteration node" );
1130 if( xIter.is() )
1132 mfIterateInterval = fIterateInterval;
1133 xIter->setIterateInterval( fIterateInterval );
1136 calculateIterateDuration();
1140 // --------------------------------------------------------------------
1142 OUString CustomAnimationEffect::getPath() const
1144 OUString aPath;
1146 if( mxNode.is() ) try
1148 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW );
1149 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1150 while( xEnumeration->hasMoreElements() )
1152 Reference< XAnimateMotion > xMotion( xEnumeration->nextElement(), UNO_QUERY );
1153 if( xMotion.is() )
1155 xMotion->getPath() >>= aPath;
1156 break;
1160 catch( Exception& )
1162 OSL_FAIL("sd::CustomAnimationEffect::getPath(), exception caught!" );
1165 return aPath;
1168 // --------------------------------------------------------------------
1170 void CustomAnimationEffect::setPath( const OUString& rPath )
1172 if( mxNode.is() ) try
1174 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW );
1175 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1176 while( xEnumeration->hasMoreElements() )
1178 Reference< XAnimateMotion > xMotion( xEnumeration->nextElement(), UNO_QUERY );
1179 if( xMotion.is() )
1182 MainSequenceChangeGuard aGuard( mpEffectSequence );
1183 xMotion->setPath( Any( rPath ) );
1184 break;
1188 catch( Exception& )
1190 OSL_FAIL("sd::CustomAnimationEffect::setPath(), exception caught!" );
1194 // --------------------------------------------------------------------
1196 Any CustomAnimationEffect::getProperty( sal_Int32 nNodeType, const OUString& rAttributeName, EValue eValue )
1198 Any aProperty;
1199 if( mxNode.is() ) try
1201 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1202 if( xEnumerationAccess.is() )
1204 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1205 if( xEnumeration.is() )
1207 while( xEnumeration->hasMoreElements() && !aProperty.hasValue() )
1209 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1210 if( !xAnimate.is() )
1211 continue;
1213 if( xAnimate->getType() == nNodeType )
1215 if( xAnimate->getAttributeName() == rAttributeName )
1217 switch( eValue )
1219 case VALUE_FROM: aProperty = xAnimate->getFrom(); break;
1220 case VALUE_TO: aProperty = xAnimate->getTo(); break;
1221 case VALUE_BY: aProperty = xAnimate->getBy(); break;
1222 case VALUE_FIRST:
1223 case VALUE_LAST:
1225 Sequence<Any> aValues( xAnimate->getValues() );
1226 if( aValues.hasElements() )
1227 aProperty = aValues[ eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1 ];
1229 break;
1237 catch( Exception& )
1239 OSL_FAIL("sd::CustomAnimationEffect::getProperty(), exception caught!" );
1242 return aProperty;
1245 // --------------------------------------------------------------------
1247 bool CustomAnimationEffect::setProperty( sal_Int32 nNodeType, const OUString& rAttributeName, EValue eValue, const Any& rValue )
1249 bool bChanged = false;
1250 if( mxNode.is() ) try
1252 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1253 if( xEnumerationAccess.is() )
1255 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1256 if( xEnumeration.is() )
1258 while( xEnumeration->hasMoreElements() )
1260 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1261 if( !xAnimate.is() )
1262 continue;
1264 if( xAnimate->getType() == nNodeType )
1266 if( xAnimate->getAttributeName() == rAttributeName )
1268 switch( eValue )
1270 case VALUE_FROM:
1271 if( xAnimate->getFrom() != rValue )
1273 xAnimate->setFrom( rValue );
1274 bChanged = true;
1276 break;
1277 case VALUE_TO:
1278 if( xAnimate->getTo() != rValue )
1280 xAnimate->setTo( rValue );
1281 bChanged = true;
1283 break;
1284 case VALUE_BY:
1285 if( xAnimate->getTo() != rValue )
1287 xAnimate->setBy( rValue );
1288 bChanged = true;
1290 break;
1291 case VALUE_FIRST:
1292 case VALUE_LAST:
1294 Sequence<Any> aValues( xAnimate->getValues() );
1295 if( !aValues.hasElements() )
1296 aValues.realloc(1);
1298 sal_Int32 nIndex = eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1;
1300 if( aValues[ nIndex ] != rValue )
1302 aValues[ nIndex ] = rValue;
1303 xAnimate->setValues( aValues );
1304 bChanged = true;
1314 catch( Exception& )
1316 OSL_FAIL("sd::CustomAnimationEffect::setProperty(), exception caught!" );
1319 return bChanged;
1322 // --------------------------------------------------------------------
1324 static bool implIsColorAttribute( const OUString& rAttributeName )
1326 return rAttributeName == "FillColor" || rAttributeName == "LineColor" || rAttributeName == "CharColor";
1329 // --------------------------------------------------------------------
1331 Any CustomAnimationEffect::getColor( sal_Int32 nIndex )
1333 Any aColor;
1334 if( mxNode.is() ) try
1336 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1337 if( xEnumerationAccess.is() )
1339 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1340 if( xEnumeration.is() )
1342 while( xEnumeration->hasMoreElements() && !aColor.hasValue() )
1344 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1345 if( !xAnimate.is() )
1346 continue;
1348 switch( xAnimate->getType() )
1350 case AnimationNodeType::SET:
1351 case AnimationNodeType::ANIMATE:
1352 if( !implIsColorAttribute( xAnimate->getAttributeName() ) )
1353 break;
1354 case AnimationNodeType::ANIMATECOLOR:
1355 Sequence<Any> aValues( xAnimate->getValues() );
1356 if( aValues.hasElements() )
1358 if( aValues.getLength() > nIndex )
1359 aColor = aValues[nIndex];
1361 else if( nIndex == 0 )
1362 aColor = xAnimate->getFrom();
1363 else
1364 aColor = xAnimate->getTo();
1370 catch( Exception& )
1372 OSL_FAIL("sd::CustomAnimationEffect::getColor(), exception caught!" );
1375 return aColor;
1378 // --------------------------------------------------------------------
1380 void CustomAnimationEffect::setColor( sal_Int32 nIndex, const Any& rColor )
1382 if( mxNode.is() ) try
1384 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1385 if( xEnumerationAccess.is() )
1387 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1388 if( xEnumeration.is() )
1390 while( xEnumeration->hasMoreElements() )
1392 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1393 if( !xAnimate.is() )
1394 continue;
1396 switch( xAnimate->getType() )
1398 case AnimationNodeType::SET:
1399 case AnimationNodeType::ANIMATE:
1400 if( !implIsColorAttribute( xAnimate->getAttributeName() ) )
1401 break;
1402 case AnimationNodeType::ANIMATECOLOR:
1404 Sequence<Any> aValues( xAnimate->getValues() );
1405 if( aValues.hasElements() )
1407 if( aValues.getLength() > nIndex )
1409 aValues[nIndex] = rColor;
1410 xAnimate->setValues( aValues );
1413 else if( (nIndex == 0) && xAnimate->getFrom().hasValue() )
1414 xAnimate->setFrom(rColor);
1415 else if( (nIndex == 1) && xAnimate->getTo().hasValue() )
1416 xAnimate->setTo(rColor);
1418 break;
1425 catch( Exception& )
1427 OSL_FAIL("sd::CustomAnimationEffect::setColor(), exception caught!" );
1431 // --------------------------------------------------------------------
1433 Any CustomAnimationEffect::getTransformationProperty( sal_Int32 nTransformType, EValue eValue )
1435 Any aProperty;
1436 if( mxNode.is() ) try
1438 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1439 if( xEnumerationAccess.is() )
1441 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1442 if( xEnumeration.is() )
1444 while( xEnumeration->hasMoreElements() && !aProperty.hasValue() )
1446 Reference< XAnimateTransform > xTransform( xEnumeration->nextElement(), UNO_QUERY );
1447 if( !xTransform.is() )
1448 continue;
1450 if( xTransform->getTransformType() == nTransformType )
1452 switch( eValue )
1454 case VALUE_FROM: aProperty = xTransform->getFrom(); break;
1455 case VALUE_TO: aProperty = xTransform->getTo(); break;
1456 case VALUE_BY: aProperty = xTransform->getBy(); break;
1457 case VALUE_FIRST:
1458 case VALUE_LAST:
1460 Sequence<Any> aValues( xTransform->getValues() );
1461 if( aValues.hasElements() )
1462 aProperty = aValues[ eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1 ];
1464 break;
1471 catch( Exception& )
1473 OSL_FAIL("sd::CustomAnimationEffect::getTransformationProperty(), exception caught!" );
1476 return aProperty;
1479 // --------------------------------------------------------------------
1481 bool CustomAnimationEffect::setTransformationProperty( sal_Int32 nTransformType, EValue eValue, const Any& rValue )
1483 bool bChanged = false;
1484 if( mxNode.is() ) try
1486 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1487 if( xEnumerationAccess.is() )
1489 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1490 if( xEnumeration.is() )
1492 while( xEnumeration->hasMoreElements() )
1494 Reference< XAnimateTransform > xTransform( xEnumeration->nextElement(), UNO_QUERY );
1495 if( !xTransform.is() )
1496 continue;
1498 if( xTransform->getTransformType() == nTransformType )
1500 switch( eValue )
1502 case VALUE_FROM:
1503 if( xTransform->getFrom() != rValue )
1505 xTransform->setFrom( rValue );
1506 bChanged = true;
1508 break;
1509 case VALUE_TO:
1510 if( xTransform->getTo() != rValue )
1512 xTransform->setTo( rValue );
1513 bChanged = true;
1515 break;
1516 case VALUE_BY:
1517 if( xTransform->getBy() != rValue )
1519 xTransform->setBy( rValue );
1520 bChanged = true;
1522 break;
1523 case VALUE_FIRST:
1524 case VALUE_LAST:
1526 Sequence<Any> aValues( xTransform->getValues() );
1527 if( !aValues.hasElements() )
1528 aValues.realloc(1);
1530 sal_Int32 nIndex = eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1;
1531 if( aValues[nIndex] != rValue )
1533 aValues[nIndex] = rValue;
1534 xTransform->setValues( aValues );
1535 bChanged = true;
1544 catch( Exception& )
1546 OSL_FAIL("sd::CustomAnimationEffect::setTransformationProperty(), exception caught!" );
1549 return bChanged;
1552 // --------------------------------------------------------------------
1554 void CustomAnimationEffect::createAudio( const ::com::sun::star::uno::Any& rSource, double fVolume /* = 1.0 */ )
1556 DBG_ASSERT( !mxAudio.is(), "sd::CustomAnimationEffect::createAudio(), node already has an audio!" );
1558 if( !mxAudio.is() ) try
1560 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1561 Reference< XAudio > xAudio( Audio::create( xContext ) );
1562 xAudio->setSource( rSource );
1563 xAudio->setVolume( fVolume );
1564 setAudio( xAudio );
1566 catch( Exception& )
1568 OSL_FAIL("sd::CustomAnimationEffect::createAudio(), exception caught!" );
1572 // --------------------------------------------------------------------
1574 static Reference< XCommand > findCommandNode( const Reference< XAnimationNode >& xRootNode )
1576 Reference< XCommand > xCommand;
1578 if( xRootNode.is() ) try
1580 Reference< XEnumerationAccess > xEnumerationAccess( xRootNode, UNO_QUERY_THROW );
1581 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1582 while( !xCommand.is() && xEnumeration->hasMoreElements() )
1584 Reference< XAnimationNode > xNode( xEnumeration->nextElement(), UNO_QUERY );
1585 if( xNode.is() && (xNode->getType() == AnimationNodeType::COMMAND) )
1586 xCommand.set( xNode, UNO_QUERY_THROW );
1589 catch( Exception& )
1591 OSL_FAIL("sd::findCommandNode(), exception caught!" );
1594 return xCommand;
1597 void CustomAnimationEffect::removeAudio()
1601 Reference< XAnimationNode > xChild;
1603 if( mxAudio.is() )
1605 xChild.set( mxAudio, UNO_QUERY );
1606 mxAudio.clear();
1608 else if( mnCommand == EffectCommands::STOPAUDIO )
1610 xChild.set( findCommandNode( mxNode ), UNO_QUERY );
1611 mnCommand = 0;
1614 if( xChild.is() )
1616 Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY );
1617 if( xContainer.is() )
1618 xContainer->removeChild( xChild );
1621 catch( Exception& )
1623 OSL_FAIL("sd::CustomAnimationEffect::removeAudio(), exception caught!" );
1628 // --------------------------------------------------------------------
1630 void CustomAnimationEffect::setAudio( const Reference< ::com::sun::star::animations::XAudio >& xAudio )
1632 if( mxAudio != xAudio ) try
1634 removeAudio();
1635 mxAudio = xAudio;
1636 Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY );
1637 Reference< XAnimationNode > xChild( mxAudio, UNO_QUERY );
1638 if( xContainer.is() && xChild.is() )
1639 xContainer->appendChild( xChild );
1641 catch( Exception& )
1643 OSL_FAIL("sd::CustomAnimationEffect::setAudio(), exception caught!" );
1647 // --------------------------------------------------------------------
1649 void CustomAnimationEffect::setStopAudio()
1651 if( mnCommand != EffectCommands::STOPAUDIO ) try
1653 if( mxAudio.is() )
1654 removeAudio();
1656 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1657 Reference< XCommand > xCommand( Command::create( xContext ) );
1659 xCommand->setCommand( EffectCommands::STOPAUDIO );
1661 Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY_THROW );
1662 Reference< XAnimationNode > xChild( xCommand, UNO_QUERY_THROW );
1663 xContainer->appendChild( xChild );
1665 mnCommand = EffectCommands::STOPAUDIO;
1667 catch( Exception& )
1669 OSL_FAIL("sd::CustomAnimationEffect::setStopAudio(), exception caught!" );
1673 // --------------------------------------------------------------------
1675 bool CustomAnimationEffect::getStopAudio() const
1677 return mnCommand == EffectCommands::STOPAUDIO;
1680 // --------------------------------------------------------------------
1682 SdrPathObj* CustomAnimationEffect::createSdrPathObjFromPath()
1684 SdrPathObj * pPathObj = new SdrPathObj( OBJ_PATHLINE );
1685 updateSdrPathObjFromPath( *pPathObj );
1686 return pPathObj;
1689 // --------------------------------------------------------------------
1691 void CustomAnimationEffect::updateSdrPathObjFromPath( SdrPathObj& rPathObj )
1693 ::basegfx::B2DPolyPolygon xPolyPoly;
1694 if( ::basegfx::tools::importFromSvgD( xPolyPoly, getPath() ) )
1696 SdrObject* pObj = GetSdrObjectFromXShape( getTargetShape() );
1697 if( pObj )
1699 SdrPage* pPage = pObj->GetPage();
1700 if( pPage )
1702 const Size aPageSize( pPage->GetSize() );
1703 xPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix((double)aPageSize.Width(), (double)aPageSize.Height()));
1706 const Rectangle aBoundRect( pObj->GetCurrentBoundRect() );
1707 const Point aCenter( aBoundRect.Center() );
1708 xPolyPoly.transform(basegfx::tools::createTranslateB2DHomMatrix(aCenter.X(), aCenter.Y()));
1712 rPathObj.SetPathPoly( xPolyPoly );
1715 // --------------------------------------------------------------------
1717 void CustomAnimationEffect::updatePathFromSdrPathObj( const SdrPathObj& rPathObj )
1719 ::basegfx::B2DPolyPolygon xPolyPoly( rPathObj.GetPathPoly() );
1721 SdrObject* pObj = GetSdrObjectFromXShape( getTargetShape() );
1722 if( pObj )
1724 Rectangle aBoundRect(0,0,0,0);
1726 const drawinglayer::primitive2d::Primitive2DSequence xPrimitives(pObj->GetViewContact().getViewIndependentPrimitive2DSequence());
1727 const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
1728 const basegfx::B2DRange aRange(drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(xPrimitives, aViewInformation2D));
1730 if(!aRange.isEmpty())
1732 aBoundRect = Rectangle(
1733 (sal_Int32)floor(aRange.getMinX()), (sal_Int32)floor(aRange.getMinY()),
1734 (sal_Int32)ceil(aRange.getMaxX()), (sal_Int32)ceil(aRange.getMaxY()));
1737 const Point aCenter( aBoundRect.Center() );
1739 xPolyPoly.transform(basegfx::tools::createTranslateB2DHomMatrix(-aCenter.X(), -aCenter.Y()));
1741 SdrPage* pPage = pObj->GetPage();
1742 if( pPage )
1744 const Size aPageSize( pPage->GetSize() );
1745 xPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(
1746 1.0 / (double)aPageSize.Width(), 1.0 / (double)aPageSize.Height()));
1750 setPath( ::basegfx::tools::exportToSvgD( xPolyPoly ) );
1753 // ====================================================================
1755 EffectSequenceHelper::EffectSequenceHelper()
1756 : mnSequenceType( EffectNodeType::DEFAULT )
1760 // --------------------------------------------------------------------
1762 EffectSequenceHelper::EffectSequenceHelper( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XTimeContainer >& xSequenceRoot )
1763 : mxSequenceRoot( xSequenceRoot ), mnSequenceType( EffectNodeType::DEFAULT )
1765 Reference< XAnimationNode > xNode( mxSequenceRoot, UNO_QUERY_THROW );
1766 create( xNode );
1769 // --------------------------------------------------------------------
1771 EffectSequenceHelper::~EffectSequenceHelper()
1773 reset();
1776 // --------------------------------------------------------------------
1778 void EffectSequenceHelper::reset()
1780 EffectSequence::iterator aIter( maEffects.begin() );
1781 EffectSequence::iterator aEnd( maEffects.end() );
1782 if( aIter != aEnd )
1784 CustomAnimationEffectPtr pEffect = (*aIter++);
1785 pEffect->setEffectSequence(0);
1787 maEffects.clear();
1790 Reference< XAnimationNode > EffectSequenceHelper::getRootNode()
1792 Reference< XAnimationNode > xRoot( mxSequenceRoot, UNO_QUERY );
1793 return xRoot;
1796 // --------------------------------------------------------------------
1798 void EffectSequenceHelper::append( const CustomAnimationEffectPtr& pEffect )
1800 pEffect->setEffectSequence( this );
1801 maEffects.push_back(pEffect);
1802 rebuild();
1805 // --------------------------------------------------------------------
1807 CustomAnimationEffectPtr EffectSequenceHelper::append( const CustomAnimationPresetPtr& pPreset, const Any& rTarget, double fDuration /* = -1.0 */ )
1809 CustomAnimationEffectPtr pEffect;
1811 if( pPreset.get() )
1813 OUString strEmpty;
1814 Reference< XAnimationNode > xNode( pPreset->create( strEmpty ) );
1815 if( xNode.is() )
1817 // first, filter all only ui relevant user data
1818 std::vector< NamedValue > aNewUserData;
1819 Sequence< NamedValue > aUserData( xNode->getUserData() );
1820 sal_Int32 nLength = aUserData.getLength();
1821 const NamedValue* p = aUserData.getConstArray();
1822 bool bFilter = false;
1824 while( nLength-- )
1826 if( p->Name != "text-only" && p->Name != "preset-property" )
1828 aNewUserData.push_back( *p );
1829 bFilter = true;
1831 p++;
1834 if( bFilter )
1836 aUserData = ::comphelper::containerToSequence< NamedValue, std::vector< NamedValue > >( aNewUserData );
1837 xNode->setUserData( aUserData );
1840 // check target, maybe we need to force it to text
1841 Any aTarget( rTarget );
1842 sal_Int16 nSubItem = ShapeAnimationSubType::AS_WHOLE;
1844 if( aTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
1846 nSubItem = ShapeAnimationSubType::ONLY_TEXT;
1848 else if( pPreset->isTextOnly() )
1850 Reference< XShape > xShape;
1851 aTarget >>= xShape;
1852 if( xShape.is() )
1854 // thats bad, we target a shape here but the effect is only for text
1855 // so change subitem
1856 nSubItem = ShapeAnimationSubType::ONLY_TEXT;
1860 // now create effect from preset
1861 pEffect.reset( new CustomAnimationEffect( xNode ) );
1862 pEffect->setEffectSequence( this );
1863 pEffect->setTarget( aTarget );
1864 pEffect->setTargetSubItem( nSubItem );
1865 if( fDuration != -1.0 )
1866 pEffect->setDuration( fDuration );
1868 maEffects.push_back(pEffect);
1870 rebuild();
1874 DBG_ASSERT( pEffect.get(), "sd::EffectSequenceHelper::append(), failed!" );
1875 return pEffect;
1878 // --------------------------------------------------------------------
1880 CustomAnimationEffectPtr EffectSequenceHelper::append( const SdrPathObj& rPathObj, const Any& rTarget, double fDuration /* = -1.0 */ )
1882 CustomAnimationEffectPtr pEffect;
1884 if( fDuration <= 0.0 )
1885 fDuration = 2.0;
1889 Reference< XTimeContainer > xEffectContainer( ParallelTimeContainer::create( ::comphelper::getProcessComponentContext() ), UNO_QUERY_THROW );
1890 Reference< XAnimationNode > xAnimateMotion( AnimateMotion::create( ::comphelper::getProcessComponentContext() ) );
1892 xAnimateMotion->setDuration( Any( fDuration ) );
1893 xAnimateMotion->setFill( AnimationFill::HOLD );
1894 xEffectContainer->appendChild( xAnimateMotion );
1896 sal_Int16 nSubItem = ShapeAnimationSubType::AS_WHOLE;
1898 if( rTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
1899 nSubItem = ShapeAnimationSubType::ONLY_TEXT;
1901 Reference< XAnimationNode > xEffectNode( xEffectContainer, UNO_QUERY_THROW );
1902 pEffect.reset( new CustomAnimationEffect( xEffectNode ) );
1903 pEffect->setEffectSequence( this );
1904 pEffect->setTarget( rTarget );
1905 pEffect->setTargetSubItem( nSubItem );
1906 pEffect->setNodeType( ::com::sun::star::presentation::EffectNodeType::ON_CLICK );
1907 pEffect->setPresetClass( ::com::sun::star::presentation::EffectPresetClass::MOTIONPATH );
1908 pEffect->setAcceleration( 0.5 );
1909 pEffect->setDecelerate( 0.5 );
1910 pEffect->setFill( AnimationFill::HOLD );
1911 pEffect->setBegin( 0.0 );
1912 pEffect->updatePathFromSdrPathObj( rPathObj );
1913 if( fDuration != -1.0 )
1914 pEffect->setDuration( fDuration );
1916 maEffects.push_back(pEffect);
1918 rebuild();
1920 catch( Exception& )
1922 OSL_FAIL( "sd::EffectSequenceHelper::append(), exception caught!" );
1925 return pEffect;
1928 // --------------------------------------------------------------------
1930 void EffectSequenceHelper::replace( const CustomAnimationEffectPtr& pEffect, const CustomAnimationPresetPtr& pPreset, const OUString& rPresetSubType, double fDuration /* = -1.0 */ )
1932 if( pEffect.get() && pPreset.get() ) try
1934 Reference< XAnimationNode > xNewNode( pPreset->create( rPresetSubType ) );
1935 if( xNewNode.is() )
1937 pEffect->replaceNode( xNewNode );
1938 if( fDuration != -1.0 )
1939 pEffect->setDuration( fDuration );
1942 rebuild();
1944 catch( Exception& )
1946 OSL_FAIL( "sd::EffectSequenceHelper::replace(), exception caught!" );
1950 // --------------------------------------------------------------------
1952 void EffectSequenceHelper::replace( const CustomAnimationEffectPtr& pEffect, const CustomAnimationPresetPtr& pPreset, double fDuration /* = -1.0 */ )
1954 OUString strEmpty;
1955 replace( pEffect, pPreset, strEmpty, fDuration );
1958 // --------------------------------------------------------------------
1960 void EffectSequenceHelper::remove( const CustomAnimationEffectPtr& pEffect )
1962 if( pEffect.get() )
1964 pEffect->setEffectSequence( 0 );
1965 maEffects.remove( pEffect );
1968 rebuild();
1971 // --------------------------------------------------------------------
1973 void EffectSequenceHelper::rebuild()
1975 implRebuild();
1978 // --------------------------------------------------------------------
1980 void EffectSequenceHelper::implRebuild()
1984 // first we delete all time containers on the first two levels
1985 Reference< XEnumerationAccess > xEnumerationAccess( mxSequenceRoot, UNO_QUERY_THROW );
1986 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1987 while( xEnumeration->hasMoreElements() )
1989 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
1990 Reference< XTimeContainer > xChildContainer( xChildNode, UNO_QUERY_THROW );
1992 Reference< XEnumerationAccess > xChildEnumerationAccess( xChildNode, UNO_QUERY_THROW );
1993 Reference< XEnumeration > xChildEnumeration( xChildEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1994 while( xChildEnumeration->hasMoreElements() )
1996 Reference< XAnimationNode > xNode( xChildEnumeration->nextElement(), UNO_QUERY_THROW );
1997 xChildContainer->removeChild( xNode );
2000 mxSequenceRoot->removeChild( xChildNode );
2003 // second, rebuild main sequence
2004 EffectSequence::iterator aIter( maEffects.begin() );
2005 EffectSequence::iterator aEnd( maEffects.end() );
2006 if( aIter != aEnd )
2008 AfterEffectNodeList aAfterEffects;
2010 CustomAnimationEffectPtr pEffect = (*aIter++);
2012 bool bFirst = true;
2015 // create a par container for the next click node and all following with and after effects
2016 Reference< XTimeContainer > xOnClickContainer( ParallelTimeContainer::create( ::comphelper::getProcessComponentContext() ), UNO_QUERY_THROW );
2018 Event aEvent;
2019 if( mxEventSource.is() )
2021 aEvent.Source <<= mxEventSource;
2022 aEvent.Trigger = EventTrigger::ON_CLICK;
2024 else
2026 aEvent.Trigger = EventTrigger::ON_NEXT;
2028 aEvent.Repeat = 0;
2030 Any aBegin( makeAny( aEvent ) );
2031 if( bFirst )
2033 // if the first node is not a click action, this click container
2034 // must not have INDEFINITE begin but start at 0s
2035 bFirst = false;
2036 if( pEffect->getNodeType() != EffectNodeType::ON_CLICK )
2037 aBegin <<= (double)0.0;
2040 xOnClickContainer->setBegin( aBegin );
2042 Reference< XAnimationNode > xOnClickContainerNode( xOnClickContainer, UNO_QUERY_THROW );
2043 mxSequenceRoot->appendChild( xOnClickContainerNode );
2045 double fBegin = 0.0;
2049 // create a par container for the current click or after effect node and all following with effects
2050 Reference< XTimeContainer > xWithContainer( ParallelTimeContainer::create( ::comphelper::getProcessComponentContext() ), UNO_QUERY_THROW );
2051 Reference< XAnimationNode > xWithContainerNode( xWithContainer, UNO_QUERY_THROW );
2052 xWithContainer->setBegin( makeAny( fBegin ) );
2053 xOnClickContainer->appendChild( xWithContainerNode );
2055 double fDuration = 0.0;
2058 Reference< XAnimationNode > xEffectNode( pEffect->getNode() );
2059 xWithContainer->appendChild( xEffectNode );
2061 if( pEffect->hasAfterEffect() )
2063 Reference< XAnimationNode > xAfterEffect( pEffect->createAfterEffectNode() );
2064 AfterEffectNode a( xAfterEffect, xEffectNode, pEffect->IsAfterEffectOnNext() );
2065 aAfterEffects.push_back( a );
2068 double fTemp = pEffect->getBegin() + pEffect->getAbsoluteDuration();
2069 if( fTemp > fDuration )
2070 fDuration = fTemp;
2072 if( aIter != aEnd )
2073 pEffect = (*aIter++);
2074 else
2075 pEffect.reset();
2077 while( pEffect.get() && (pEffect->getNodeType() == EffectNodeType::WITH_PREVIOUS) );
2079 fBegin += fDuration;
2081 while( pEffect.get() && (pEffect->getNodeType() != EffectNodeType::ON_CLICK) );
2083 while( pEffect.get() );
2085 // process after effect nodes
2086 std::for_each( aAfterEffects.begin(), aAfterEffects.end(), stl_process_after_effect_node_func );
2088 updateTextGroups();
2090 // reset duration, might have been altered (see below)
2091 mxSequenceRoot->setDuration( Any() );
2093 else
2095 // empty sequence, set duration to 0.0 explicitly
2096 // (otherwise, this sequence will never end)
2097 mxSequenceRoot->setDuration( makeAny((double)0.0) );
2100 catch( Exception& )
2102 OSL_FAIL( "sd::EffectSequenceHelper::rebuild(), exception caught!" );
2106 // --------------------------------------------------------------------
2108 stl_CustomAnimationEffect_search_node_predict::stl_CustomAnimationEffect_search_node_predict( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xSearchNode )
2109 : mxSearchNode( xSearchNode )
2113 // --------------------------------------------------------------------
2115 bool stl_CustomAnimationEffect_search_node_predict::operator()( CustomAnimationEffectPtr pEffect ) const
2117 return pEffect->getNode() == mxSearchNode;
2120 // --------------------------------------------------------------------
2122 static bool implFindNextContainer( Reference< XTimeContainer >& xParent, Reference< XTimeContainer >& xCurrent, Reference< XTimeContainer >& xNext )
2123 throw(Exception)
2125 Reference< XEnumerationAccess > xEnumerationAccess( xParent, UNO_QUERY_THROW );
2126 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration() );
2127 if( xEnumeration.is() )
2129 Reference< XInterface > x;
2130 while( xEnumeration->hasMoreElements() && !xNext.is() )
2132 if( (xEnumeration->nextElement() >>= x) && (x == xCurrent) )
2134 if( xEnumeration->hasMoreElements() )
2135 xEnumeration->nextElement() >>= xNext;
2139 return xNext.is();
2142 // --------------------------------------------------------------------
2144 void stl_process_after_effect_node_func(AfterEffectNode& rNode)
2148 if( rNode.mxNode.is() && rNode.mxMaster.is() )
2150 // set master node
2151 Reference< XAnimationNode > xMasterNode( rNode.mxMaster, UNO_QUERY_THROW );
2152 Sequence< NamedValue > aUserData( rNode.mxNode->getUserData() );
2153 sal_Int32 nSize = aUserData.getLength();
2154 aUserData.realloc(nSize+1);
2155 aUserData[nSize].Name = "master-element";
2156 aUserData[nSize].Value <<= xMasterNode;
2157 rNode.mxNode->setUserData( aUserData );
2159 // insert after effect node into timeline
2160 Reference< XTimeContainer > xContainer( rNode.mxMaster->getParent(), UNO_QUERY_THROW );
2162 if( !rNode.mbOnNextEffect ) // sameClick
2164 // insert the aftereffect after its effect is animated
2165 xContainer->insertAfter( rNode.mxNode, rNode.mxMaster );
2167 else // nextClick
2169 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
2170 // insert the aftereffect in the next group
2172 Reference< XTimeContainer > xClickContainer( xContainer->getParent(), UNO_QUERY_THROW );
2173 Reference< XTimeContainer > xSequenceContainer( xClickContainer->getParent(), UNO_QUERY_THROW );
2175 Reference< XTimeContainer > xNextContainer;
2177 // first try if we have an after effect container
2178 if( !implFindNextContainer( xClickContainer, xContainer, xNextContainer ) )
2180 Reference< XTimeContainer > xNextClickContainer;
2181 // if not, try to find the next click effect container
2182 if( implFindNextContainer( xSequenceContainer, xClickContainer, xNextClickContainer ) )
2184 Reference< XEnumerationAccess > xEnumerationAccess( xNextClickContainer, UNO_QUERY_THROW );
2185 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
2186 if( xEnumeration->hasMoreElements() )
2188 // the next container is the first child container
2189 xEnumeration->nextElement() >>= xNextContainer;
2191 else
2193 // this does not yet have a child container, create one
2194 xNextContainer.set( ParallelTimeContainer::create(xContext), UNO_QUERY_THROW );
2196 Reference< XAnimationNode > xNode( xNextContainer, UNO_QUERY_THROW );
2197 xNode->setBegin( makeAny( (double)0.0 ) );
2198 xNextClickContainer->appendChild( xNode );
2200 DBG_ASSERT( xNextContainer.is(), "ppt::stl_process_after_effect_node_func::operator(), could not find/create container!" );
2204 // if we don't have a next container, we add one to the sequence container
2205 if( !xNextContainer.is() )
2207 Reference< XTimeContainer > xNewClickContainer( ParallelTimeContainer::create( xContext ), UNO_QUERY_THROW );
2209 Reference< XAnimationNode > xNewClickNode( xNewClickContainer, UNO_QUERY_THROW );
2211 Event aEvent;
2212 aEvent.Trigger = EventTrigger::ON_NEXT;
2213 aEvent.Repeat = 0;
2214 xNewClickNode->setBegin( makeAny( aEvent ) );
2216 Reference< XAnimationNode > xRefNode( xClickContainer, UNO_QUERY_THROW );
2217 xSequenceContainer->insertAfter( xNewClickNode, xRefNode );
2219 xNextContainer.set( ParallelTimeContainer::create( xContext ), UNO_QUERY_THROW );
2221 DBG_ASSERT( xNextContainer.is(), "ppt::stl_process_after_effect_node_func::operator(), could not create container!" );
2222 if( xNextContainer.is() )
2224 Reference< XAnimationNode > xNode( xNextContainer, UNO_QUERY_THROW );
2225 xNode->setBegin( makeAny( (double)0.0 ) );
2226 xNewClickContainer->appendChild( xNode );
2230 if( xNextContainer.is() )
2232 // find begin time of first element
2233 Reference< XEnumerationAccess > xEnumerationAccess( xNextContainer, UNO_QUERY_THROW );
2234 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
2235 if( xEnumeration->hasMoreElements() )
2237 Reference< XAnimationNode > xChild;
2238 // the next container is the first child container
2239 xEnumeration->nextElement() >>= xChild;
2240 if( xChild.is() )
2242 Any aBegin( xChild->getBegin() );
2243 double fBegin = 0.0;
2244 if( (aBegin >>= fBegin) && (fBegin >= 0.0))
2245 rNode.mxNode->setBegin( aBegin );
2249 xNextContainer->appendChild( rNode.mxNode );
2254 catch( Exception& )
2256 OSL_FAIL( "ppt::stl_process_after_effect_node_func::operator(), exception caught!" );
2260 // --------------------------------------------------------------------
2262 EffectSequence::iterator EffectSequenceHelper::find( const CustomAnimationEffectPtr& pEffect )
2264 return std::find( maEffects.begin(), maEffects.end(), pEffect );
2267 // --------------------------------------------------------------------
2269 CustomAnimationEffectPtr EffectSequenceHelper::findEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) const
2271 CustomAnimationEffectPtr pEffect;
2273 EffectSequence::const_iterator aIter( maEffects.begin() );
2274 for( ; aIter != maEffects.end(); ++aIter )
2276 if( (*aIter)->getNode() == xNode )
2278 pEffect = (*aIter);
2279 break;
2283 return pEffect;
2286 // --------------------------------------------------------------------
2288 sal_Int32 EffectSequenceHelper::getOffsetFromEffect( const CustomAnimationEffectPtr& xEffect ) const
2290 sal_Int32 nOffset = 0;
2292 EffectSequence::const_iterator aIter( maEffects.begin() );
2293 for( ; aIter != maEffects.end(); ++aIter, nOffset++ )
2295 if( (*aIter) == xEffect )
2296 return nOffset;
2299 return -1;
2302 // --------------------------------------------------------------------
2304 CustomAnimationEffectPtr EffectSequenceHelper::getEffectFromOffset( sal_Int32 nOffset ) const
2306 EffectSequence::const_iterator aIter( maEffects.begin() );
2307 while( nOffset-- && aIter != maEffects.end() )
2308 ++aIter;
2310 CustomAnimationEffectPtr pEffect;
2311 if( aIter != maEffects.end() )
2312 pEffect = (*aIter);
2314 return pEffect;
2317 // --------------------------------------------------------------------
2319 bool EffectSequenceHelper::disposeShape( const Reference< XShape >& xShape )
2321 bool bChanges = false;
2323 EffectSequence::iterator aIter( maEffects.begin() );
2324 while( aIter != maEffects.end() )
2326 if( (*aIter)->getTargetShape() == xShape )
2328 (*aIter)->setEffectSequence( 0 );
2329 bChanges = true;
2330 aIter = maEffects.erase( aIter );
2332 else
2334 ++aIter;
2338 return bChanges;
2341 // --------------------------------------------------------------------
2343 bool EffectSequenceHelper::hasEffect( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape )
2345 EffectSequence::iterator aIter( maEffects.begin() );
2346 while( aIter != maEffects.end() )
2348 if( (*aIter)->getTargetShape() == xShape )
2349 return true;
2350 ++aIter;
2353 return false;
2356 // --------------------------------------------------------------------
2358 void EffectSequenceHelper::insertTextRange( const com::sun::star::uno::Any& aTarget )
2360 bool bChanges = false;
2362 ParagraphTarget aParaTarget;
2363 if( !(aTarget >>= aParaTarget ) )
2364 return;
2366 EffectSequence::iterator aIter( maEffects.begin() );
2367 while( aIter != maEffects.end() )
2369 if( (*aIter)->getTargetShape() == aParaTarget.Shape )
2370 bChanges |= (*aIter)->checkForText();
2371 ++aIter;
2374 if( bChanges )
2375 rebuild();
2378 // --------------------------------------------------------------------
2380 void EffectSequenceHelper::disposeTextRange( const com::sun::star::uno::Any& aTarget )
2382 ParagraphTarget aParaTarget;
2383 if( !(aTarget >>= aParaTarget ) )
2384 return;
2386 bool bChanges = false;
2387 bool bErased = false;
2389 EffectSequence::iterator aIter( maEffects.begin() );
2390 while( aIter != maEffects.end() )
2392 Any aIterTarget( (*aIter)->getTarget() );
2393 if( aIterTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2395 ParagraphTarget aIterParaTarget;
2396 if( (aIterTarget >>= aIterParaTarget) && (aIterParaTarget.Shape == aParaTarget.Shape) )
2398 if( aIterParaTarget.Paragraph == aParaTarget.Paragraph )
2400 // delete this effect if it targets the disposed paragraph directly
2401 (*aIter)->setEffectSequence( 0 );
2402 aIter = maEffects.erase( aIter );
2403 bChanges = true;
2404 bErased = true;
2406 else
2408 if( aIterParaTarget.Paragraph > aParaTarget.Paragraph )
2410 // shift all paragraphs after disposed paragraph
2411 aIterParaTarget.Paragraph--;
2412 (*aIter)->setTarget( makeAny( aIterParaTarget ) );
2417 else if( (*aIter)->getTargetShape() == aParaTarget.Shape )
2419 bChanges |= (*aIter)->checkForText();
2422 if( bErased )
2423 bErased = false;
2424 else
2425 ++aIter;
2428 if( bChanges )
2429 rebuild();
2432 // --------------------------------------------------------------------
2434 CustomAnimationTextGroup::CustomAnimationTextGroup( const Reference< XShape >& rTarget, sal_Int32 nGroupId )
2435 : maTarget( rTarget ),
2436 mnGroupId( nGroupId )
2438 reset();
2441 // --------------------------------------------------------------------
2443 void CustomAnimationTextGroup::reset()
2445 mnTextGrouping = -1;
2446 mbAnimateForm = false;
2447 mbTextReverse = false;
2448 mfGroupingAuto = -1.0;
2449 mnLastPara = -1; // used to check for TextReverse
2451 for (int i = 0; i < PARA_LEVELS; ++i)
2453 mnDepthFlags[i] = 0;
2456 maEffects.clear();
2459 // --------------------------------------------------------------------
2461 void CustomAnimationTextGroup::addEffect( CustomAnimationEffectPtr& pEffect )
2463 maEffects.push_back( pEffect );
2465 Any aTarget( pEffect->getTarget() );
2466 if( aTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2468 // now look at the paragraph
2469 ParagraphTarget aParaTarget;
2470 aTarget >>= aParaTarget;
2472 if( mnLastPara != -1 )
2473 mbTextReverse = mnLastPara > aParaTarget.Paragraph;
2475 mnLastPara = aParaTarget.Paragraph;
2477 const sal_Int32 nParaDepth = pEffect->getParaDepth();
2479 // only look at the first PARA_LEVELS levels
2480 if( nParaDepth < PARA_LEVELS )
2482 // our first paragraph with this level?
2483 if( mnDepthFlags[nParaDepth] == 0 )
2485 // so set it to the first found
2486 mnDepthFlags[nParaDepth] = (sal_Int8)pEffect->getNodeType();
2488 else if( mnDepthFlags[nParaDepth] != pEffect->getNodeType() )
2490 mnDepthFlags[nParaDepth] = -1;
2493 if( pEffect->getNodeType() == EffectNodeType::AFTER_PREVIOUS )
2494 mfGroupingAuto = pEffect->getBegin();
2496 mnTextGrouping = PARA_LEVELS;
2497 while( (mnTextGrouping > 0)
2498 && (mnDepthFlags[mnTextGrouping - 1] <= 0) )
2499 --mnTextGrouping;
2502 else
2504 // if we have an effect with the shape as a target, we animate the background
2505 mbAnimateForm = pEffect->getTargetSubItem() != ShapeAnimationSubType::ONLY_TEXT;
2509 // --------------------------------------------------------------------
2511 class TextGroupMapImpl : public std::map< sal_Int32, CustomAnimationTextGroup* >
2513 public:
2514 CustomAnimationTextGroup* findGroup( sal_Int32 nGroupId );
2517 // --------------------------------------------------------------------
2519 CustomAnimationTextGroupPtr EffectSequenceHelper::findGroup( sal_Int32 nGroupId )
2521 CustomAnimationTextGroupPtr aPtr;
2523 CustomAnimationTextGroupMap::iterator aIter( maGroupMap.find( nGroupId ) );
2524 if( aIter != maGroupMap.end() )
2525 aPtr = (*aIter).second;
2527 return aPtr;
2530 // --------------------------------------------------------------------
2532 void EffectSequenceHelper::updateTextGroups()
2534 maGroupMap.clear();
2536 // first create all the groups
2537 EffectSequence::iterator aIter( maEffects.begin() );
2538 const EffectSequence::iterator aEnd( maEffects.end() );
2539 while( aIter != aEnd )
2541 CustomAnimationEffectPtr pEffect( (*aIter++) );
2543 const sal_Int32 nGroupId = pEffect->getGroupId();
2545 if( nGroupId == -1 )
2546 continue; // trivial case, no group
2548 CustomAnimationTextGroupPtr pGroup = findGroup( nGroupId );
2549 if( !pGroup.get() )
2551 pGroup.reset( new CustomAnimationTextGroup( pEffect->getTargetShape(), nGroupId ) );
2552 maGroupMap[nGroupId] = pGroup;
2555 pGroup->addEffect( pEffect );
2559 // --------------------------------------------------------------------
2561 CustomAnimationTextGroupPtr EffectSequenceHelper::createTextGroup( CustomAnimationEffectPtr pEffect, sal_Int32 nTextGrouping, double fTextGroupingAuto, sal_Bool bAnimateForm, sal_Bool bTextReverse )
2563 // first finde a free group-id
2564 sal_Int32 nGroupId = 0;
2566 CustomAnimationTextGroupMap::iterator aIter( maGroupMap.begin() );
2567 const CustomAnimationTextGroupMap::iterator aEnd( maGroupMap.end() );
2568 while( aIter != aEnd )
2570 if( (*aIter).first == nGroupId )
2572 nGroupId++;
2573 aIter = maGroupMap.begin();
2575 else
2577 ++aIter;
2581 Reference< XShape > xTarget( pEffect->getTargetShape() );
2583 CustomAnimationTextGroupPtr pTextGroup( new CustomAnimationTextGroup( xTarget, nGroupId ) );
2584 maGroupMap[nGroupId] = pTextGroup;
2586 bool bUsed = false;
2588 // do we need to target the shape?
2589 if( (nTextGrouping == 0) || bAnimateForm )
2591 sal_Int16 nSubItem;
2592 if( nTextGrouping == 0)
2593 nSubItem = bAnimateForm ? ShapeAnimationSubType::AS_WHOLE : ShapeAnimationSubType::ONLY_TEXT;
2594 else
2595 nSubItem = ShapeAnimationSubType::ONLY_BACKGROUND;
2597 pEffect->setTarget( makeAny( xTarget ) );
2598 pEffect->setTargetSubItem( nSubItem );
2599 pEffect->setEffectSequence( this );
2600 pEffect->setGroupId( nGroupId );
2602 pTextGroup->addEffect( pEffect );
2603 bUsed = true;
2606 pTextGroup->mnTextGrouping = nTextGrouping;
2607 pTextGroup->mfGroupingAuto = fTextGroupingAuto;
2608 pTextGroup->mbTextReverse = bTextReverse;
2610 // now add an effect for each paragraph
2611 createTextGroupParagraphEffects( pTextGroup, pEffect, bUsed );
2613 notify_listeners();
2615 return pTextGroup;
2618 // --------------------------------------------------------------------
2620 void EffectSequenceHelper::createTextGroupParagraphEffects( CustomAnimationTextGroupPtr pTextGroup, CustomAnimationEffectPtr pEffect, bool bUsed )
2622 Reference< XShape > xTarget( pTextGroup->maTarget );
2624 sal_Int32 nTextGrouping = pTextGroup->mnTextGrouping;
2625 double fTextGroupingAuto = pTextGroup->mfGroupingAuto;
2626 sal_Bool bTextReverse = pTextGroup->mbTextReverse;
2628 // now add an effect for each paragraph
2629 if( nTextGrouping >= 0 ) try
2631 EffectSequence::iterator aInsertIter( find( pEffect ) );
2633 Reference< XEnumerationAccess > xText( xTarget, UNO_QUERY_THROW );
2634 Reference< XEnumeration > xEnumeration( xText->createEnumeration(), UNO_QUERY_THROW );
2636 std::list< sal_Int16 > aParaList;
2637 sal_Int16 nPara;
2639 // fill the list with all valid paragraphs
2640 for( nPara = 0; xEnumeration->hasMoreElements(); nPara++ )
2642 Reference< XTextRange > xRange( xEnumeration->nextElement(), UNO_QUERY );
2643 if( xRange.is() && !xRange->getString().isEmpty() )
2645 if( bTextReverse ) // sort them
2646 aParaList.push_front( nPara );
2647 else
2648 aParaList.push_back( nPara );
2652 ParagraphTarget aTarget;
2653 aTarget.Shape = xTarget;
2655 std::list< sal_Int16 >::iterator aIter( aParaList.begin() );
2656 std::list< sal_Int16 >::iterator aEnd( aParaList.end() );
2657 while( aIter != aEnd )
2659 aTarget.Paragraph = (*aIter++);
2661 CustomAnimationEffectPtr pNewEffect;
2662 if( bUsed )
2664 // clone a new effect from first effect
2665 pNewEffect = pEffect->clone();
2666 ++aInsertIter;
2667 aInsertIter = maEffects.insert( aInsertIter, pNewEffect );
2669 else
2671 // reuse first effect if its not yet used
2672 pNewEffect = pEffect;
2673 bUsed = true;
2674 aInsertIter = find( pNewEffect );
2677 // set target and group-id
2678 pNewEffect->setTarget( makeAny( aTarget ) );
2679 pNewEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT );
2680 pNewEffect->setGroupId( pTextGroup->mnGroupId );
2681 pNewEffect->setEffectSequence( this );
2683 // set correct node type
2684 if( pNewEffect->getParaDepth() < nTextGrouping )
2686 if( fTextGroupingAuto == -1.0 )
2688 pNewEffect->setNodeType( EffectNodeType::ON_CLICK );
2689 pNewEffect->setBegin( 0.0 );
2691 else
2693 pNewEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2694 pNewEffect->setBegin( fTextGroupingAuto );
2697 else
2699 pNewEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2700 pNewEffect->setBegin( 0.0 );
2703 pTextGroup->addEffect( pNewEffect );
2705 notify_listeners();
2707 catch( Exception& )
2709 OSL_FAIL("sd::EffectSequenceHelper::createTextGroup(), exception caught!" );
2713 // --------------------------------------------------------------------
2715 void EffectSequenceHelper::setTextGrouping( CustomAnimationTextGroupPtr pTextGroup, sal_Int32 nTextGrouping )
2717 if( pTextGroup->mnTextGrouping == nTextGrouping )
2719 // first case, trivial case, do nothing
2721 else if( (pTextGroup->mnTextGrouping == -1) && (nTextGrouping >= 0) )
2723 // second case, we need to add new effects for each paragraph
2725 CustomAnimationEffectPtr pEffect( pTextGroup->maEffects.front() );
2727 pTextGroup->mnTextGrouping = nTextGrouping;
2728 createTextGroupParagraphEffects( pTextGroup, pEffect, true );
2729 notify_listeners();
2731 else if( (pTextGroup->mnTextGrouping >= 0) && (nTextGrouping == -1 ) )
2733 // third case, we need to remove effects for each paragraph
2735 EffectSequence aEffects( pTextGroup->maEffects );
2736 pTextGroup->reset();
2738 EffectSequence::iterator aIter( aEffects.begin() );
2739 const EffectSequence::iterator aEnd( aEffects.end() );
2740 while( aIter != aEnd )
2742 CustomAnimationEffectPtr pEffect( (*aIter++) );
2744 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2745 remove( pEffect );
2746 else
2747 pTextGroup->addEffect( pEffect );
2749 notify_listeners();
2751 else
2753 // fourth case, we need to change the node types for the text nodes
2754 double fTextGroupingAuto = pTextGroup->mfGroupingAuto;
2756 EffectSequence aEffects( pTextGroup->maEffects );
2757 pTextGroup->reset();
2759 EffectSequence::iterator aIter( aEffects.begin() );
2760 const EffectSequence::iterator aEnd( aEffects.end() );
2761 while( aIter != aEnd )
2763 CustomAnimationEffectPtr pEffect( (*aIter++) );
2765 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2767 // set correct node type
2768 if( pEffect->getParaDepth() < nTextGrouping )
2770 if( fTextGroupingAuto == -1.0 )
2772 pEffect->setNodeType( EffectNodeType::ON_CLICK );
2773 pEffect->setBegin( 0.0 );
2775 else
2777 pEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2778 pEffect->setBegin( fTextGroupingAuto );
2781 else
2783 pEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2784 pEffect->setBegin( 0.0 );
2788 pTextGroup->addEffect( pEffect );
2791 notify_listeners();
2795 // --------------------------------------------------------------------
2797 void EffectSequenceHelper::setAnimateForm( CustomAnimationTextGroupPtr pTextGroup, sal_Bool bAnimateForm )
2799 if( pTextGroup->mbAnimateForm == bAnimateForm )
2801 // trivial case, do nothing
2803 else
2805 EffectSequence aEffects( pTextGroup->maEffects );
2806 pTextGroup->reset();
2808 SAL_WARN_IF(aEffects.empty(), "sd", "EffectSequenceHelper::setAnimateForm effects empty" );
2810 if (aEffects.empty())
2811 return;
2813 EffectSequence::iterator aIter( aEffects.begin() );
2814 const EffectSequence::iterator aEnd( aEffects.end() );
2816 // first insert if we have to
2817 if( bAnimateForm )
2819 EffectSequence::iterator aInsertIter( find( (*aIter) ) );
2821 CustomAnimationEffectPtr pEffect;
2822 if( (aEffects.size() == 1) && ((*aIter)->getTarget().getValueType() != ::getCppuType((const ParagraphTarget*)0) ) )
2824 // special case, only one effect and that targets whole text,
2825 // convert this to target whole shape
2826 pEffect = (*aIter++);
2827 pEffect->setTargetSubItem( ShapeAnimationSubType::AS_WHOLE );
2829 else
2831 pEffect = (*aIter)->clone();
2832 pEffect->setTarget( makeAny( (*aIter)->getTargetShape() ) );
2833 pEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_BACKGROUND );
2834 maEffects.insert( aInsertIter, pEffect );
2837 pTextGroup->addEffect( pEffect );
2840 if( !bAnimateForm && (aEffects.size() == 1) )
2842 CustomAnimationEffectPtr pEffect( (*aIter) );
2843 pEffect->setTarget( makeAny( (*aIter)->getTargetShape() ) );
2844 pEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT );
2845 pTextGroup->addEffect( pEffect );
2847 else
2849 // readd the rest to the group again
2850 while( aIter != aEnd )
2852 CustomAnimationEffectPtr pEffect( (*aIter++) );
2854 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2856 pTextGroup->addEffect( pEffect );
2858 else
2860 DBG_ASSERT( !bAnimateForm, "sd::EffectSequenceHelper::setAnimateForm(), something is wrong here!" );
2861 remove( pEffect );
2865 notify_listeners();
2869 // --------------------------------------------------------------------
2871 void EffectSequenceHelper::setTextGroupingAuto( CustomAnimationTextGroupPtr pTextGroup, double fTextGroupingAuto )
2873 sal_Int32 nTextGrouping = pTextGroup->mnTextGrouping;
2875 EffectSequence aEffects( pTextGroup->maEffects );
2876 pTextGroup->reset();
2878 EffectSequence::iterator aIter( aEffects.begin() );
2879 const EffectSequence::iterator aEnd( aEffects.end() );
2880 while( aIter != aEnd )
2882 CustomAnimationEffectPtr pEffect( (*aIter++) );
2884 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2886 // set correct node type
2887 if( pEffect->getParaDepth() < nTextGrouping )
2889 if( fTextGroupingAuto == -1.0 )
2891 pEffect->setNodeType( EffectNodeType::ON_CLICK );
2892 pEffect->setBegin( 0.0 );
2894 else
2896 pEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2897 pEffect->setBegin( fTextGroupingAuto );
2900 else
2902 pEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2903 pEffect->setBegin( 0.0 );
2907 pTextGroup->addEffect( pEffect );
2910 notify_listeners();
2913 // --------------------------------------------------------------------
2915 struct ImplStlTextGroupSortHelper
2917 ImplStlTextGroupSortHelper( bool bReverse ) : mbReverse( bReverse ) {};
2918 bool operator()( const CustomAnimationEffectPtr& p1, const CustomAnimationEffectPtr& p2 );
2919 bool mbReverse;
2920 sal_Int32 getTargetParagraph( const CustomAnimationEffectPtr& p1 );
2923 // --------------------------------------------------------------------
2925 sal_Int32 ImplStlTextGroupSortHelper::getTargetParagraph( const CustomAnimationEffectPtr& p1 )
2927 const Any aTarget(p1->getTarget());
2928 if( aTarget.hasValue() && aTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2930 ParagraphTarget aParaTarget;
2931 aTarget >>= aParaTarget;
2932 return aParaTarget.Paragraph;
2934 else
2936 return mbReverse ? 0x7fffffff : -1;
2940 // --------------------------------------------------------------------
2942 bool ImplStlTextGroupSortHelper::operator()( const CustomAnimationEffectPtr& p1, const CustomAnimationEffectPtr& p2 )
2944 if( mbReverse )
2946 return getTargetParagraph( p2 ) < getTargetParagraph( p1 );
2948 else
2950 return getTargetParagraph( p1 ) < getTargetParagraph( p2 );
2954 // --------------------------------------------------------------------
2956 void EffectSequenceHelper::setTextReverse( CustomAnimationTextGroupPtr pTextGroup, sal_Bool bTextReverse )
2958 if( pTextGroup->mbTextReverse == bTextReverse )
2960 // do nothing
2962 else
2964 std::vector< CustomAnimationEffectPtr > aSortedVector(pTextGroup->maEffects.size());
2965 std::copy( pTextGroup->maEffects.begin(), pTextGroup->maEffects.end(), aSortedVector.begin() );
2966 ImplStlTextGroupSortHelper aSortHelper( bTextReverse );
2967 std::sort( aSortedVector.begin(), aSortedVector.end(), aSortHelper );
2969 pTextGroup->reset();
2971 std::vector< CustomAnimationEffectPtr >::iterator aIter( aSortedVector.begin() );
2972 const std::vector< CustomAnimationEffectPtr >::iterator aEnd( aSortedVector.end() );
2974 if( aIter != aEnd )
2976 pTextGroup->addEffect( (*aIter ) );
2977 EffectSequence::iterator aInsertIter( find( (*aIter++) ) );
2978 while( aIter != aEnd )
2980 CustomAnimationEffectPtr pEffect( (*aIter++) );
2981 maEffects.erase( find( pEffect ) );
2982 aInsertIter = maEffects.insert( ++aInsertIter, pEffect );
2983 pTextGroup->addEffect( pEffect );
2986 notify_listeners();
2990 // --------------------------------------------------------------------
2992 void EffectSequenceHelper::addListener( ISequenceListener* pListener )
2994 if( std::find( maListeners.begin(), maListeners.end(), pListener ) == maListeners.end() )
2995 maListeners.push_back( pListener );
2998 // --------------------------------------------------------------------
3000 void EffectSequenceHelper::removeListener( ISequenceListener* pListener )
3002 maListeners.remove( pListener );
3005 // --------------------------------------------------------------------
3007 struct stl_notify_listeners_func : public std::unary_function<ISequenceListener*, void>
3009 stl_notify_listeners_func() {}
3010 void operator()(ISequenceListener* pListener) { pListener->notify_change(); }
3013 // --------------------------------------------------------------------
3015 void EffectSequenceHelper::notify_listeners()
3017 stl_notify_listeners_func aFunc;
3018 std::for_each( maListeners.begin(), maListeners.end(), aFunc );
3021 // --------------------------------------------------------------------
3023 void EffectSequenceHelper::create( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
3025 DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::create(), illegal argument" );
3027 if( xNode.is() ) try
3029 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
3030 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3031 while( xEnumeration->hasMoreElements() )
3033 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3034 createEffectsequence( xChildNode );
3037 catch( Exception& )
3039 OSL_FAIL( "sd::EffectSequenceHelper::create(), exception caught!" );
3043 // --------------------------------------------------------------------
3045 void EffectSequenceHelper::createEffectsequence( const Reference< XAnimationNode >& xNode )
3047 DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::createEffectsequence(), illegal argument" );
3049 if( xNode.is() ) try
3051 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
3052 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3053 while( xEnumeration->hasMoreElements() )
3055 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3057 createEffects( xChildNode );
3060 catch( Exception& )
3062 OSL_FAIL( "sd::EffectSequenceHelper::createEffectsequence(), exception caught!" );
3066 // --------------------------------------------------------------------
3068 void EffectSequenceHelper::createEffects( const Reference< XAnimationNode >& xNode )
3070 DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::createEffects(), illegal argument" );
3072 if( xNode.is() ) try
3074 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
3075 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3076 while( xEnumeration->hasMoreElements() )
3078 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3080 switch( xChildNode->getType() )
3082 // found an effect
3083 case AnimationNodeType::PAR:
3084 case AnimationNodeType::ITERATE:
3086 CustomAnimationEffectPtr pEffect( new CustomAnimationEffect( xChildNode ) );
3088 if( pEffect->mnNodeType != -1 )
3090 pEffect->setEffectSequence( this );
3091 maEffects.push_back(pEffect);
3094 break;
3096 // found an after effect
3097 case AnimationNodeType::SET:
3098 case AnimationNodeType::ANIMATECOLOR:
3100 processAfterEffect( xChildNode );
3102 break;
3106 catch( Exception& )
3108 OSL_FAIL( "sd::EffectSequenceHelper::createEffects(), exception caught!" );
3112 // --------------------------------------------------------------------
3114 void EffectSequenceHelper::processAfterEffect( const Reference< XAnimationNode >& xNode )
3118 Reference< XAnimationNode > xMaster;
3120 Sequence< NamedValue > aUserData( xNode->getUserData() );
3121 sal_Int32 nLength = aUserData.getLength();
3122 const NamedValue* p = aUserData.getConstArray();
3124 while( nLength-- )
3126 if ( p->Name == "master-element" )
3128 p->Value >>= xMaster;
3129 break;
3131 p++;
3134 // only process if this is a valid after effect
3135 if( xMaster.is() )
3137 CustomAnimationEffectPtr pMasterEffect;
3139 // find the master effect
3140 stl_CustomAnimationEffect_search_node_predict aSearchPredict( xMaster );
3141 EffectSequence::iterator aIter( std::find_if( maEffects.begin(), maEffects.end(), aSearchPredict ) );
3142 if( aIter != maEffects.end() )
3143 pMasterEffect = (*aIter );
3145 if( pMasterEffect.get() )
3147 pMasterEffect->setHasAfterEffect( true );
3149 // find out what kind of after effect this is
3150 if( xNode->getType() == AnimationNodeType::ANIMATECOLOR )
3152 // its a dim
3153 Reference< XAnimate > xAnimate( xNode, UNO_QUERY_THROW );
3154 pMasterEffect->setDimColor( xAnimate->getTo() );
3155 pMasterEffect->setAfterEffectOnNext( true );
3157 else
3159 // its a hide
3160 Reference< XChild > xNodeChild( xNode, UNO_QUERY_THROW );
3161 Reference< XChild > xMasterChild( xMaster, UNO_QUERY_THROW );
3162 pMasterEffect->setAfterEffectOnNext( xNodeChild->getParent() != xMasterChild->getParent() );
3167 catch( Exception& )
3169 OSL_FAIL( "sd::EffectSequenceHelper::processAfterEffect(), exception caught!" );
3173 // ====================================================================
3175 class AnimationChangeListener : public cppu::WeakImplHelper1< XChangesListener >
3177 public:
3178 AnimationChangeListener( MainSequence* pMainSequence ) : mpMainSequence( pMainSequence ) {}
3180 virtual void SAL_CALL changesOccurred( const ::com::sun::star::util::ChangesEvent& Event ) throw (RuntimeException);
3181 virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (RuntimeException);
3182 private:
3183 MainSequence* mpMainSequence;
3186 void SAL_CALL AnimationChangeListener::changesOccurred( const ::com::sun::star::util::ChangesEvent& ) throw (RuntimeException)
3188 if( mpMainSequence )
3189 mpMainSequence->startRecreateTimer();
3192 void SAL_CALL AnimationChangeListener::disposing( const ::com::sun::star::lang::EventObject& ) throw (RuntimeException)
3196 // ====================================================================
3198 MainSequence::MainSequence()
3199 : mxTimingRootNode( SequenceTimeContainer::create( ::comphelper::getProcessComponentContext() ) )
3200 , mbRebuilding( false )
3201 , mnRebuildLockGuard( 0 )
3202 , mbPendingRebuildRequest( false )
3204 if( mxTimingRootNode.is() )
3206 Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
3207 aUserData[0].Name = "node-type";
3208 aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::MAIN_SEQUENCE;
3209 mxTimingRootNode->setUserData( aUserData );
3211 init();
3214 // --------------------------------------------------------------------
3216 MainSequence::MainSequence( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
3217 : mxTimingRootNode( xNode, UNO_QUERY )
3218 , mbRebuilding( false )
3219 , mnRebuildLockGuard( 0 )
3220 , mbPendingRebuildRequest( false )
3221 , mbIgnoreChanges( 0 )
3223 init();
3226 // --------------------------------------------------------------------
3228 MainSequence::~MainSequence()
3230 reset();
3233 // --------------------------------------------------------------------
3235 void MainSequence::init()
3237 mnSequenceType = EffectNodeType::MAIN_SEQUENCE;
3239 maTimer.SetTimeoutHdl( LINK(this, MainSequence, onTimerHdl) );
3240 maTimer.SetTimeout(500);
3242 mxChangesListener.set( new AnimationChangeListener( this ) );
3244 createMainSequence();
3247 // --------------------------------------------------------------------
3249 void MainSequence::reset( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xTimingRootNode )
3251 reset();
3253 mxTimingRootNode.set( xTimingRootNode, UNO_QUERY );
3255 createMainSequence();
3258 // --------------------------------------------------------------------
3260 Reference< ::com::sun::star::animations::XAnimationNode > MainSequence::getRootNode()
3262 DBG_ASSERT( mnRebuildLockGuard == 0, "MainSequence::getRootNode(), rebuild is locked, is this really what you want?" );
3264 if( maTimer.IsActive() && mbTimerMode )
3266 // force a rebuild NOW if one is pending
3267 maTimer.Stop();
3268 implRebuild();
3271 return EffectSequenceHelper::getRootNode();
3274 // --------------------------------------------------------------------
3276 void MainSequence::createMainSequence()
3278 if( mxTimingRootNode.is() ) try
3280 Reference< XEnumerationAccess > xEnumerationAccess( mxTimingRootNode, UNO_QUERY_THROW );
3281 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3282 while( xEnumeration->hasMoreElements() )
3284 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3285 sal_Int32 nNodeType = CustomAnimationEffect::get_node_type( xChildNode );
3286 if( nNodeType == EffectNodeType::MAIN_SEQUENCE )
3288 mxSequenceRoot.set( xChildNode, UNO_QUERY );
3289 EffectSequenceHelper::create( xChildNode );
3291 else if( nNodeType == EffectNodeType::INTERACTIVE_SEQUENCE )
3293 Reference< XTimeContainer > xInteractiveRoot( xChildNode, UNO_QUERY_THROW );
3294 InteractiveSequencePtr pIS( new InteractiveSequence( xInteractiveRoot, this ) );
3295 pIS->addListener( this );
3296 maInteractiveSequenceList.push_back( pIS );
3300 // see if we have a mainsequence at all. if not, create one...
3301 if( !mxSequenceRoot.is() )
3303 mxSequenceRoot = SequenceTimeContainer::create( ::comphelper::getProcessComponentContext() );
3305 uno::Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
3306 aUserData[0].Name = "node-type";
3307 aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::MAIN_SEQUENCE;
3308 mxSequenceRoot->setUserData( aUserData );
3310 // empty sequence until now, set duration to 0.0
3311 // explicitly (otherwise, this sequence will never
3312 // end)
3313 mxSequenceRoot->setDuration( makeAny((double)0.0) );
3315 Reference< XAnimationNode > xMainSequenceNode( mxSequenceRoot, UNO_QUERY_THROW );
3316 mxTimingRootNode->appendChild( xMainSequenceNode );
3319 updateTextGroups();
3321 notify_listeners();
3323 Reference< XChangesNotifier > xNotifier( mxTimingRootNode, UNO_QUERY );
3324 if( xNotifier.is() )
3325 xNotifier->addChangesListener( mxChangesListener );
3327 catch( Exception& )
3329 OSL_FAIL( "sd::MainSequence::create(), exception caught!" );
3330 return;
3333 DBG_ASSERT( mxSequenceRoot.is(), "sd::MainSequence::create(), found no main sequence!" );
3336 // --------------------------------------------------------------------
3338 void MainSequence::reset()
3340 EffectSequenceHelper::reset();
3342 InteractiveSequenceList::iterator aIter;
3343 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); ++aIter )
3344 (*aIter)->reset();
3345 maInteractiveSequenceList.clear();
3349 Reference< XChangesNotifier > xNotifier( mxTimingRootNode, UNO_QUERY );
3350 if( xNotifier.is() )
3351 xNotifier->removeChangesListener( mxChangesListener );
3353 catch( Exception& )
3355 // ...
3359 // --------------------------------------------------------------------
3361 InteractiveSequencePtr MainSequence::createInteractiveSequence( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xShape )
3363 InteractiveSequencePtr pIS;
3365 // create a new interactive sequence container
3366 Reference< XTimeContainer > xISRoot = SequenceTimeContainer::create( ::comphelper::getProcessComponentContext() );
3368 uno::Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
3369 aUserData[0].Name = "node-type";
3370 aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::INTERACTIVE_SEQUENCE ;
3371 xISRoot->setUserData( aUserData );
3373 Reference< XChild > xChild( mxSequenceRoot, UNO_QUERY_THROW );
3374 Reference< XAnimationNode > xISNode( xISRoot, UNO_QUERY_THROW );
3375 Reference< XTimeContainer > xParent( xChild->getParent(), UNO_QUERY_THROW );
3376 xParent->appendChild( xISNode );
3378 pIS.reset( new InteractiveSequence( xISRoot, this) );
3379 pIS->setTriggerShape( xShape );
3380 pIS->addListener( this );
3381 maInteractiveSequenceList.push_back( pIS );
3382 return pIS;
3385 // --------------------------------------------------------------------
3387 CustomAnimationEffectPtr MainSequence::findEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) const
3389 CustomAnimationEffectPtr pEffect = EffectSequenceHelper::findEffect( xNode );
3391 if( pEffect.get() == 0 )
3393 InteractiveSequenceList::const_iterator aIter;
3394 for( aIter = maInteractiveSequenceList.begin(); (aIter != maInteractiveSequenceList.end()) && (pEffect.get() == 0); ++aIter )
3396 pEffect = (*aIter)->findEffect( xNode );
3399 return pEffect;
3402 // --------------------------------------------------------------------
3404 sal_Int32 MainSequence::getOffsetFromEffect( const CustomAnimationEffectPtr& pEffect ) const
3406 sal_Int32 nOffset = EffectSequenceHelper::getOffsetFromEffect( pEffect );
3408 if( nOffset != -1 )
3409 return nOffset;
3411 nOffset = EffectSequenceHelper::getCount();
3413 InteractiveSequenceList::const_iterator aIter;
3414 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); ++aIter )
3416 sal_Int32 nTemp = (*aIter)->getOffsetFromEffect( pEffect );
3417 if( nTemp != -1 )
3418 return nOffset + nTemp;
3420 nOffset += (*aIter)->getCount();
3423 return -1;
3426 // --------------------------------------------------------------------
3428 CustomAnimationEffectPtr MainSequence::getEffectFromOffset( sal_Int32 nOffset ) const
3430 if( nOffset >= 0 )
3432 if( nOffset < getCount() )
3433 return EffectSequenceHelper::getEffectFromOffset( nOffset );
3435 nOffset -= getCount();
3437 InteractiveSequenceList::const_iterator aIter( maInteractiveSequenceList.begin() );
3439 while( (aIter != maInteractiveSequenceList.end()) && (nOffset > (*aIter)->getCount()) )
3440 nOffset -= (*aIter++)->getCount();
3442 if( (aIter != maInteractiveSequenceList.end()) && (nOffset >= 0) )
3443 return (*aIter)->getEffectFromOffset( nOffset );
3446 CustomAnimationEffectPtr pEffect;
3447 return pEffect;
3450 // --------------------------------------------------------------------
3452 bool MainSequence::disposeShape( const Reference< XShape >& xShape )
3454 bool bChanges = EffectSequenceHelper::disposeShape( xShape );
3456 InteractiveSequenceList::iterator aIter;
3457 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); )
3459 if( (*aIter)->getTriggerShape() == xShape )
3461 aIter = maInteractiveSequenceList.erase( aIter );
3462 bChanges = true;
3464 else
3466 bChanges |= (*aIter++)->disposeShape( xShape );
3470 if( bChanges )
3471 startRebuildTimer();
3473 return bChanges;
3476 // --------------------------------------------------------------------
3478 bool MainSequence::hasEffect( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape )
3480 if( EffectSequenceHelper::hasEffect( xShape ) )
3481 return true;
3483 InteractiveSequenceList::iterator aIter;
3484 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); )
3486 if( (*aIter)->getTriggerShape() == xShape )
3487 return true;
3489 if( (*aIter++)->hasEffect( xShape ) )
3490 return true;
3493 return false;
3496 // --------------------------------------------------------------------
3498 void MainSequence::insertTextRange( const com::sun::star::uno::Any& aTarget )
3500 EffectSequenceHelper::insertTextRange( aTarget );
3502 InteractiveSequenceList::iterator aIter;
3503 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); ++aIter )
3505 (*aIter)->insertTextRange( aTarget );
3508 // --------------------------------------------------------------------
3510 void MainSequence::disposeTextRange( const com::sun::star::uno::Any& aTarget )
3512 EffectSequenceHelper::disposeTextRange( aTarget );
3514 InteractiveSequenceList::iterator aIter;
3515 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); ++aIter )
3517 (*aIter)->disposeTextRange( aTarget );
3521 // --------------------------------------------------------------------
3523 /** callback from the sd::View when an object just left text edit mode */
3524 void MainSequence::onTextChanged( const Reference< XShape >& xShape )
3526 EffectSequenceHelper::onTextChanged( xShape );
3528 InteractiveSequenceList::iterator aIter;
3529 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); ++aIter )
3531 (*aIter)->onTextChanged( xShape );
3535 // --------------------------------------------------------------------
3537 void EffectSequenceHelper::onTextChanged( const Reference< XShape >& xShape )
3539 bool bChanges = false;
3541 EffectSequence::iterator aIter;
3542 for( aIter = maEffects.begin(); aIter != maEffects.end(); ++aIter )
3544 if( (*aIter)->getTargetShape() == xShape )
3545 bChanges |= (*aIter)->checkForText();
3548 if( bChanges )
3549 EffectSequenceHelper::implRebuild();
3552 // --------------------------------------------------------------------
3554 void MainSequence::rebuild()
3556 startRebuildTimer();
3559 // --------------------------------------------------------------------
3561 void MainSequence::lockRebuilds()
3563 mnRebuildLockGuard++;
3566 // --------------------------------------------------------------------
3568 void MainSequence::unlockRebuilds()
3570 DBG_ASSERT( mnRebuildLockGuard, "sd::MainSequence::unlockRebuilds(), no corresponding lockRebuilds() call!" );
3571 if( mnRebuildLockGuard )
3572 mnRebuildLockGuard--;
3574 if( (mnRebuildLockGuard == 0) && mbPendingRebuildRequest )
3576 mbPendingRebuildRequest = false;
3577 startRebuildTimer();
3581 // --------------------------------------------------------------------
3583 void MainSequence::implRebuild()
3585 if( mnRebuildLockGuard )
3587 mbPendingRebuildRequest = true;
3588 return;
3591 mbRebuilding = true;
3593 EffectSequenceHelper::implRebuild();
3595 InteractiveSequenceList::iterator aIter( maInteractiveSequenceList.begin() );
3596 const InteractiveSequenceList::iterator aEnd( maInteractiveSequenceList.end() );
3597 while( aIter != aEnd )
3599 InteractiveSequencePtr pIS( (*aIter) );
3600 if( pIS->maEffects.empty() )
3602 // remove empty interactive sequences
3603 aIter = maInteractiveSequenceList.erase( aIter );
3605 Reference< XChild > xChild( mxSequenceRoot, UNO_QUERY_THROW );
3606 Reference< XTimeContainer > xParent( xChild->getParent(), UNO_QUERY_THROW );
3607 Reference< XAnimationNode > xISNode( pIS->mxSequenceRoot, UNO_QUERY_THROW );
3608 xParent->removeChild( xISNode );
3610 else
3612 pIS->implRebuild();
3613 ++aIter;
3617 notify_listeners();
3618 mbRebuilding = false;
3621 // --------------------------------------------------------------------
3623 void MainSequence::notify_change()
3625 notify_listeners();
3628 // --------------------------------------------------------------------
3630 bool MainSequence::setTrigger( const CustomAnimationEffectPtr& pEffect, const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xTriggerShape )
3632 EffectSequenceHelper* pOldSequence = pEffect->getEffectSequence();
3634 EffectSequenceHelper* pNewSequence = 0;
3635 if( xTriggerShape.is() )
3637 InteractiveSequenceList::iterator aIter( maInteractiveSequenceList.begin() );
3638 const InteractiveSequenceList::iterator aEnd( maInteractiveSequenceList.end() );
3639 while( aIter != aEnd )
3641 InteractiveSequencePtr pIS( (*aIter++) );
3642 if( pIS->getTriggerShape() == xTriggerShape )
3644 pNewSequence = pIS.get();
3645 break;
3649 if( !pNewSequence )
3650 pNewSequence = createInteractiveSequence( xTriggerShape ).get();
3652 else
3654 pNewSequence = this;
3657 if( pOldSequence != pNewSequence )
3659 if( pOldSequence )
3660 pOldSequence->maEffects.remove( pEffect );
3661 if( pNewSequence )
3662 pNewSequence->maEffects.push_back( pEffect );
3663 pEffect->setEffectSequence( pNewSequence );
3664 return true;
3666 else
3668 return false;
3673 // --------------------------------------------------------------------
3675 IMPL_LINK_NOARG(MainSequence, onTimerHdl)
3677 if( mbTimerMode )
3679 implRebuild();
3681 else
3683 reset();
3684 createMainSequence();
3687 return 0;
3690 // --------------------------------------------------------------------
3692 /** starts a timer that recreates the internal structure from the API core after 1 second */
3693 void MainSequence::startRecreateTimer()
3695 if( !mbRebuilding && (mbIgnoreChanges == 0) )
3697 mbTimerMode = false;
3698 maTimer.Start();
3702 // --------------------------------------------------------------------
3704 /** starts a timer that rebuilds the API core from the internal structure after 1 second */
3705 void MainSequence::startRebuildTimer()
3707 mbTimerMode = true;
3708 maTimer.Start();
3711 // ====================================================================
3713 InteractiveSequence::InteractiveSequence( const Reference< XTimeContainer >& xSequenceRoot, MainSequence* pMainSequence )
3714 : EffectSequenceHelper( xSequenceRoot ), mpMainSequence( pMainSequence )
3716 mnSequenceType = EffectNodeType::INTERACTIVE_SEQUENCE;
3720 if( mxSequenceRoot.is() )
3722 Reference< XEnumerationAccess > xEnumerationAccess( mxSequenceRoot, UNO_QUERY_THROW );
3723 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3724 while( !mxEventSource.is() && xEnumeration->hasMoreElements() )
3726 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3728 Event aEvent;
3729 if( (xChildNode->getBegin() >>= aEvent) && (aEvent.Trigger == EventTrigger::ON_CLICK) )
3730 aEvent.Source >>= mxEventSource;
3734 catch( Exception& )
3736 OSL_FAIL( "sd::InteractiveSequence::InteractiveSequence(), exception caught!" );
3737 return;
3741 // --------------------------------------------------------------------
3743 void InteractiveSequence::rebuild()
3745 mpMainSequence->rebuild();
3748 void InteractiveSequence::implRebuild()
3750 EffectSequenceHelper::implRebuild();
3753 // --------------------------------------------------------------------
3755 MainSequenceRebuildGuard::MainSequenceRebuildGuard( const MainSequencePtr& pMainSequence )
3756 : mpMainSequence( pMainSequence )
3758 if( mpMainSequence.get() )
3759 mpMainSequence->lockRebuilds();
3762 MainSequenceRebuildGuard::~MainSequenceRebuildGuard()
3764 if( mpMainSequence.get() )
3765 mpMainSequence->unlockRebuilds();
3771 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */