Update ooo320-m1
[ooovba.git] / sd / source / core / CustomAnimationEffect.cxx
blobffa1778011bf4b4ea3136114f44f2431e9a05f4b
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: CustomAnimationEffect.cxx,v $
10 * $Revision: 1.17.74.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sd.hxx"
33 #include <tools/debug.hxx>
34 #include <com/sun/star/util/XCloneable.hpp>
35 #include <com/sun/star/animations/AnimationFill.hpp>
36 #include <com/sun/star/container/XEnumerationAccess.hpp>
37 #include <com/sun/star/presentation/EffectNodeType.hpp>
38 #include <com/sun/star/presentation/EffectCommands.hpp>
39 #include <com/sun/star/presentation/EffectPresetClass.hpp>
40 #include <com/sun/star/presentation/ParagraphTarget.hpp>
41 #include <com/sun/star/lang/XInitialization.hpp>
42 #include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
43 #include <com/sun/star/animations/AnimationNodeType.hpp>
44 #include <com/sun/star/animations/XCommand.hpp>
45 #include <com/sun/star/animations/AnimationTransformType.hpp>
46 #include <com/sun/star/animations/XIterateContainer.hpp>
47 #include <com/sun/star/animations/XAnimateTransform.hpp>
48 #include <com/sun/star/animations/Event.hpp>
49 #include <com/sun/star/animations/EventTrigger.hpp>
50 #include <com/sun/star/animations/Timing.hpp>
51 #include <com/sun/star/drawing/XDrawPage.hpp>
52 #include <com/sun/star/text/XText.hpp>
53 #include <com/sun/star/animations/XAnimate.hpp>
54 #include <com/sun/star/beans/NamedValue.hpp>
55 #include <com/sun/star/beans/XPropertySet.hpp>
56 #include <com/sun/star/util/XChangesNotifier.hpp>
57 #include <com/sun/star/animations/XAnimateMotion.hpp>
58 #include <comphelper/processfactory.hxx>
59 #include <comphelper/sequence.hxx>
60 #include <com/sun/star/lang/Locale.hpp>
61 #include <com/sun/star/i18n/XBreakIterator.hpp>
62 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
63 #ifndef _COM_SUN_STAR_TEXT_WORDTYPE_HPP_
64 #include <com/sun/star/i18n/WordType.hpp>
65 #endif
66 #include <com/sun/star/presentation/TextAnimationType.hpp>
68 #include <basegfx/polygon/b2dpolypolygon.hxx>
69 #include <basegfx/polygon/b2dpolypolygontools.hxx>
70 #include <basegfx/matrix/b2dhommatrix.hxx>
71 #include <basegfx/range/b2drange.hxx>
73 #include <algorithm>
75 #include <cppuhelper/implbase1.hxx>
77 #include <svx/svdopath.hxx>
78 #include <svx/svdpage.hxx>
79 #include <svx/unoapi.hxx>
80 #include "CustomAnimationEffect.hxx"
81 #include <CustomAnimationPreset.hxx>
82 #include "animations.hxx"
84 using namespace ::com::sun::star;
85 using namespace ::com::sun::star::presentation;
86 using namespace ::com::sun::star::animations;
88 using ::rtl::OUString;
89 using ::com::sun::star::uno::Reference;
90 using ::com::sun::star::uno::Sequence;
91 using ::com::sun::star::uno::XInterface;
92 using ::com::sun::star::uno::UNO_QUERY;
93 using ::com::sun::star::uno::UNO_QUERY_THROW;
94 using ::com::sun::star::uno::Any;
95 using ::com::sun::star::uno::makeAny;
96 using ::com::sun::star::uno::Exception;
97 using ::com::sun::star::uno::RuntimeException;
98 using ::com::sun::star::container::XEnumerationAccess;
99 using ::com::sun::star::container::XEnumeration;
100 using ::com::sun::star::beans::NamedValue;
101 using ::com::sun::star::container::XChild;
102 using ::com::sun::star::container::XElementAccess;
103 using ::com::sun::star::drawing::XShape;
104 using ::com::sun::star::lang::XInitialization;
105 using ::com::sun::star::drawing::XShapes;
106 using ::com::sun::star::drawing::XDrawPage;
107 using ::com::sun::star::text::XText;
108 using ::com::sun::star::text::XTextRange;
109 using ::com::sun::star::beans::XPropertySet;
110 using ::com::sun::star::lang::XMultiServiceFactory;
111 using ::com::sun::star::util::XCloneable;
112 using ::com::sun::star::lang::Locale;
113 using ::com::sun::star::util::XChangesNotifier;
114 using ::com::sun::star::util::XChangesListener;
116 namespace sd
118 class MainSequenceChangeGuard
120 public:
121 MainSequenceChangeGuard( EffectSequenceHelper* pSequence )
123 mpMainSequence = dynamic_cast< MainSequence* >( pSequence );
124 if( mpMainSequence == 0 )
126 InteractiveSequence* pI = dynamic_cast< InteractiveSequence* >( pSequence );
127 if( pI )
128 mpMainSequence = pI->mpMainSequence;
130 DBG_ASSERT( mpMainSequence, "sd::MainSequenceChangeGuard::MainSequenceChangeGuard(), no main sequence to guard!" );
132 if( mpMainSequence )
133 mpMainSequence->mbIgnoreChanges++;
136 ~MainSequenceChangeGuard()
138 if( mpMainSequence )
139 mpMainSequence->mbIgnoreChanges++;
142 private:
143 MainSequence* mpMainSequence;
146 CustomAnimationEffect::CustomAnimationEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
147 : mnNodeType(-1),
148 mnPresetClass(-1),
149 mfBegin(-1.0),
150 mfDuration(-1.0),
151 mfAbsoluteDuration(-1.0),
152 mnGroupId(-1),
153 mnIterateType(0),
154 mfIterateInterval(0.0),
155 mnParaDepth( -1 ),
156 mbHasText(sal_False),
157 mfAcceleration( 1.0 ),
158 mfDecelerate( 1.0 ),
159 mbAutoReverse(false),
160 mnTargetSubItem(0),
161 mnCommand(0),
162 mpEffectSequence( 0 ),
163 mbHasAfterEffect(false),
164 mbAfterEffectOnNextEffect(false)
166 setNode( xNode );
169 // --------------------------------------------------------------------
171 void CustomAnimationEffect::setNode( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
173 mxNode = xNode;
174 mxAudio.clear();
176 Sequence< NamedValue > aUserData( mxNode->getUserData() );
177 sal_Int32 nLength = aUserData.getLength();
178 const NamedValue* p = aUserData.getConstArray();
180 while( nLength-- )
182 if( p->Name.equalsAscii( "node-type" ) )
184 p->Value >>= mnNodeType;
186 else if( p->Name.equalsAscii( "preset-id" ) )
188 p->Value >>= maPresetId;
190 else if( p->Name.equalsAscii( "preset-sub-type" ) )
192 p->Value >>= maPresetSubType;
194 else if( p->Name.equalsAscii( "preset-class" ) )
196 p->Value >>= mnPresetClass;
198 else if( p->Name.equalsAscii( "preset-property" ) )
200 p->Value >>= maProperty;
202 else if( p->Name.equalsAscii( "group-id" ) )
204 p->Value >>= mnGroupId;
207 p++;
210 // get effect start time
211 mxNode->getBegin() >>= mfBegin;
213 mfAcceleration = mxNode->getAcceleration();
214 mfDecelerate = mxNode->getDecelerate();
215 mbAutoReverse = mxNode->getAutoReverse();
217 // get iteration data
218 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
219 if( xIter.is() )
221 mfIterateInterval = xIter->getIterateInterval();
222 mnIterateType = xIter->getIterateType();
223 maTarget = xIter->getTarget();
224 mnTargetSubItem = xIter->getSubItem();
226 else
228 mfIterateInterval = 0.0f;
229 mnIterateType = 0;
232 // calculate effect duration and get target shape
233 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
234 if( xEnumerationAccess.is() )
236 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
237 if( xEnumeration.is() )
239 while( xEnumeration->hasMoreElements() )
241 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
242 if( !xChildNode.is() )
243 continue;
245 if( xChildNode->getType() == AnimationNodeType::AUDIO )
247 mxAudio.set( xChildNode, UNO_QUERY );
249 else if( xChildNode->getType() == AnimationNodeType::COMMAND )
251 Reference< XCommand > xCommand( xChildNode, UNO_QUERY );
252 if( xCommand.is() )
254 mnCommand = xCommand->getCommand();
255 if( !maTarget.hasValue() )
256 maTarget = xCommand->getTarget();
259 else
261 double fBegin = 0.0;
262 double fDuration = 0.0;
263 xChildNode->getBegin() >>= fBegin;
264 xChildNode->getDuration() >>= fDuration;
266 fDuration += fBegin;
267 if( fDuration > mfDuration )
268 mfDuration = fDuration;
270 // no target shape yet?
271 if( !maTarget.hasValue() )
273 // go get it boys!
274 Reference< XAnimate > xAnimate( xChildNode, UNO_QUERY );
275 if( xAnimate.is() )
277 maTarget = xAnimate->getTarget();
278 mnTargetSubItem = xAnimate->getSubItem();
286 mfAbsoluteDuration = mfDuration;
287 checkForText();
290 // --------------------------------------------------------------------
292 sal_Int32 CustomAnimationEffect::getNumberOfSubitems( const Any& aTarget, sal_Int16 nIterateType )
294 sal_Int32 nSubItems = 0;
298 // first get target text
299 sal_Int32 nOnlyPara = -1;
301 Reference< XText > xShape;
302 aTarget >>= xShape;
303 if( !xShape.is() )
305 ParagraphTarget aParaTarget;
306 if( aTarget >>= aParaTarget )
308 xShape.set( aParaTarget.Shape, UNO_QUERY );
309 nOnlyPara = aParaTarget.Paragraph;
313 // now use the break iterator to iterate over the given text
314 // and count the sub items
316 if( xShape.is() )
318 // TODO/LATER: Optimize this, don't create a break iterator each time
319 Reference< lang::XMultiServiceFactory > xMSF( ::comphelper::getProcessServiceFactory() );
320 Reference < i18n::XBreakIterator > xBI( xMSF->createInstance( OUString::createFromAscii( "com.sun.star.i18n.BreakIterator" ) ), UNO_QUERY );
321 DBG_ASSERT( xBI.is(), "sd::CustomAnimationEffect::getNumberOfSubitems(), could not create a 'com.sun.star.i18n.BreakIterator'!" );
323 if( xBI.is() )
325 Reference< XEnumerationAccess > xEA( xShape, UNO_QUERY_THROW );
326 Reference< XEnumeration > xEnumeration( xEA->createEnumeration(), UNO_QUERY_THROW );
327 Locale aLocale;
328 const OUString aStrLocaleName( RTL_CONSTASCII_USTRINGPARAM("CharLocale") );
329 Reference< XTextRange > xParagraph;
331 sal_Int32 nPara = 0;
332 while( xEnumeration->hasMoreElements() )
334 xEnumeration->nextElement() >>= xParagraph;
336 // skip this if its not the only paragraph we want to count
337 if( (nOnlyPara != -1) && (nOnlyPara != nPara ) )
338 continue;
340 if( nIterateType == TextAnimationType::BY_PARAGRAPH )
342 nSubItems++;
344 else
346 const OUString aText( xParagraph->getString() );
347 Reference< XPropertySet > xSet( xParagraph, UNO_QUERY_THROW );
348 xSet->getPropertyValue( aStrLocaleName ) >>= aLocale;
350 sal_Int32 nPos;
351 const sal_Int32 nEndPos = aText.getLength();
353 if( nIterateType == TextAnimationType::BY_WORD )
355 for( nPos = 0; nPos < nEndPos; nPos++ )
357 nPos = xBI->getWordBoundary(aText, nPos, aLocale, i18n::WordType::ANY_WORD, sal_True).endPos;
358 nSubItems++;
360 break;
362 else
364 sal_Int32 nDone;
365 for( nPos = 0; nPos < nEndPos; nPos++ )
367 nPos = xBI->nextCharacters(aText, nPos, aLocale, i18n::CharacterIteratorMode::SKIPCELL, 0, nDone);
368 nSubItems++;
373 if( nPara == nOnlyPara )
374 break;
376 nPara++;
381 catch( Exception& e )
383 (void)e;
384 nSubItems = 0;
385 DBG_ERROR( "sd::CustomAnimationEffect::getNumberOfSubitems(), exception cought!" );
388 return nSubItems;
391 // --------------------------------------------------------------------
393 CustomAnimationEffect::~CustomAnimationEffect()
397 // --------------------------------------------------------------------
399 CustomAnimationEffectPtr CustomAnimationEffect::clone() const
401 Reference< XCloneable > xCloneable( mxNode, UNO_QUERY_THROW );
402 Reference< XAnimationNode > xNode( xCloneable->createClone(), UNO_QUERY_THROW );
403 CustomAnimationEffectPtr pEffect( new CustomAnimationEffect( xNode ) );
404 pEffect->setEffectSequence( getEffectSequence() );
405 return pEffect;
408 // --------------------------------------------------------------------
410 sal_Int32 CustomAnimationEffect::get_node_type( const Reference< XAnimationNode >& xNode )
412 sal_Int16 nNodeType = -1;
414 if( xNode.is() )
416 Sequence< NamedValue > aUserData( xNode->getUserData() );
417 sal_Int32 nLength = aUserData.getLength();
418 if( nLength )
420 const NamedValue* p = aUserData.getConstArray();
421 while( nLength-- )
423 if( p->Name.equalsAscii( "node-type" ) )
425 p->Value >>= nNodeType;
426 break;
428 p++;
433 return nNodeType;
436 // --------------------------------------------------------------------
438 void CustomAnimationEffect::setPresetClass( sal_Int16 nPresetClass )
440 if( mnPresetClass != nPresetClass )
442 mnPresetClass = nPresetClass;
443 if( mxNode.is() )
445 // first try to find a "preset-class" entry in the user data
446 // and change it
447 Sequence< NamedValue > aUserData( mxNode->getUserData() );
448 sal_Int32 nLength = aUserData.getLength();
449 bool bFound = false;
450 if( nLength )
452 NamedValue* p = aUserData.getArray();
453 while( nLength-- )
455 if( p->Name.equalsAscii( "preset-class" ) )
457 p->Value <<= mnPresetClass;
458 bFound = true;
459 break;
461 p++;
465 // no "node-type" entry inside user data, so add it
466 if( !bFound )
468 nLength = aUserData.getLength();
469 aUserData.realloc( nLength + 1);
470 aUserData[nLength].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "preset-class" ) );
471 aUserData[nLength].Value <<= mnPresetClass;
474 mxNode->setUserData( aUserData );
479 void CustomAnimationEffect::setNodeType( sal_Int16 nNodeType )
481 if( mnNodeType != nNodeType )
483 mnNodeType = nNodeType;
484 if( mxNode.is() )
486 // first try to find a "node-type" entry in the user data
487 // and change it
488 Sequence< NamedValue > aUserData( mxNode->getUserData() );
489 sal_Int32 nLength = aUserData.getLength();
490 bool bFound = false;
491 if( nLength )
493 NamedValue* p = aUserData.getArray();
494 while( nLength-- )
496 if( p->Name.equalsAscii( "node-type" ) )
498 p->Value <<= mnNodeType;
499 bFound = true;
500 break;
502 p++;
506 // no "node-type" entry inside user data, so add it
507 if( !bFound )
509 nLength = aUserData.getLength();
510 aUserData.realloc( nLength + 1);
511 aUserData[nLength].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
512 aUserData[nLength].Value <<= mnNodeType;
515 mxNode->setUserData( aUserData );
520 // --------------------------------------------------------------------
522 void CustomAnimationEffect::setGroupId( sal_Int32 nGroupId )
524 mnGroupId = nGroupId;
525 if( mxNode.is() )
527 // first try to find a "group-id" entry in the user data
528 // and change it
529 Sequence< NamedValue > aUserData( mxNode->getUserData() );
530 sal_Int32 nLength = aUserData.getLength();
531 bool bFound = false;
532 if( nLength )
534 NamedValue* p = aUserData.getArray();
535 while( nLength-- )
537 if( p->Name.equalsAscii( "group-id" ) )
539 p->Value <<= mnGroupId;
540 bFound = true;
541 break;
543 p++;
547 // no "node-type" entry inside user data, so add it
548 if( !bFound )
550 nLength = aUserData.getLength();
551 aUserData.realloc( nLength + 1);
552 aUserData[nLength].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "group-id" ) );
553 aUserData[nLength].Value <<= mnGroupId;
556 mxNode->setUserData( aUserData );
560 // --------------------------------------------------------------------
562 /** checks if the text for this effect has changed and updates internal flags.
563 returns true if something changed.
565 bool CustomAnimationEffect::checkForText()
567 bool bChange = false;
569 Reference< XText > xText;
571 if( maTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
573 // calc para depth
574 ParagraphTarget aParaTarget;
575 maTarget >>= aParaTarget;
577 xText = Reference< XText >::query( aParaTarget.Shape );
579 // get paragraph
580 if( xText.is() )
582 Reference< XEnumerationAccess > xEA( xText, UNO_QUERY );
583 if( xEA.is() )
585 Reference< XEnumeration > xEnumeration( xEA->createEnumeration(), UNO_QUERY );
586 if( xEnumeration.is() )
588 sal_Bool bHasText = xEnumeration->hasMoreElements();
589 bChange |= bHasText != mbHasText;
590 mbHasText = bHasText;
592 sal_Int32 nPara = aParaTarget.Paragraph;
594 while( xEnumeration->hasMoreElements() && nPara-- )
595 xEnumeration->nextElement();
597 if( xEnumeration->hasMoreElements() )
599 Reference< XPropertySet > xParaSet;
600 xEnumeration->nextElement() >>= xParaSet;
601 if( xParaSet.is() )
603 sal_Int32 nParaDepth = 0;
604 const OUString strNumberingLevel( RTL_CONSTASCII_USTRINGPARAM("NumberingLevel") );
605 xParaSet->getPropertyValue( strNumberingLevel ) >>= nParaDepth;
606 bChange |= nParaDepth != mnParaDepth;
607 mnParaDepth = nParaDepth;
614 else
616 maTarget >>= xText;
617 sal_Bool bHasText = xText.is() && xText->getString().getLength();
618 bChange |= bHasText != mbHasText;
619 mbHasText = bHasText;
622 bChange |= calculateIterateDuration();
623 return bChange;
626 bool CustomAnimationEffect::calculateIterateDuration()
628 bool bChange = false;
630 // if we have an iteration, we must also calculate the
631 // 'true' container duration, that is
632 // ( ( is form animated ) ? [contained effects duration] : 0 ) +
633 // ( [number of animated children] - 1 ) * [interval-delay] + [contained effects duration]
634 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
635 if( xIter.is() )
637 double fDuration = mfDuration;
638 const double fSubEffectDuration = mfDuration;
640 if( mnTargetSubItem != ShapeAnimationSubType::ONLY_BACKGROUND ) // does not make sense for iterate container but better check
642 const sal_Int32 nSubItems = getNumberOfSubitems( maTarget, mnIterateType );
643 if( nSubItems )
645 const double f = (nSubItems-1) * mfIterateInterval;
646 fDuration += f;
650 // if we also animate the form first, we have to add the
651 // sub effect duration to the whole effect duration
652 if( mnTargetSubItem == ShapeAnimationSubType::AS_WHOLE )
653 fDuration += fSubEffectDuration;
655 bChange |= fDuration != mfAbsoluteDuration;
656 mfAbsoluteDuration = fDuration;
659 return bChange;
662 // --------------------------------------------------------------------
664 void CustomAnimationEffect::setTarget( const ::com::sun::star::uno::Any& rTarget )
668 maTarget = rTarget;
670 // first, check special case for random node
671 Reference< XInitialization > xInit( mxNode, UNO_QUERY );
672 if( xInit.is() )
674 const Sequence< Any > aArgs( &maTarget, 1 );
675 xInit->initialize( aArgs );
677 else
679 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
680 if( xIter.is() )
682 xIter->setTarget(maTarget);
684 else
686 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
687 if( xEnumerationAccess.is() )
689 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
690 if( xEnumeration.is() )
692 while( xEnumeration->hasMoreElements() )
694 const Any aElem( xEnumeration->nextElement() );
695 Reference< XAnimate > xAnimate( aElem, UNO_QUERY );
696 if( xAnimate.is() )
697 xAnimate->setTarget( rTarget );
698 else
700 Reference< XCommand > xCommand( aElem, UNO_QUERY );
701 if( xCommand.is() )
702 xCommand->setTarget( rTarget );
709 checkForText();
711 catch( Exception& )
713 DBG_ERROR( "sd::CustomAnimationEffect::setTarget(), exception cought!" );
717 // --------------------------------------------------------------------
719 void CustomAnimationEffect::setTargetSubItem( sal_Int16 nSubItem )
723 mnTargetSubItem = nSubItem;
725 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
726 if( xIter.is() )
728 xIter->setSubItem(mnTargetSubItem);
730 else
732 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
733 if( xEnumerationAccess.is() )
735 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
736 if( xEnumeration.is() )
738 while( xEnumeration->hasMoreElements() )
740 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
741 if( xAnimate.is() )
742 xAnimate->setSubItem( mnTargetSubItem );
748 catch( Exception& )
750 DBG_ERROR( "sd::CustomAnimationEffect::setTargetSubItem(), exception cought!" );
754 // --------------------------------------------------------------------
756 void CustomAnimationEffect::setDuration( double fDuration )
758 if( (mfDuration != -1.0) && (mfDuration != fDuration) ) try
760 double fScale = fDuration / mfDuration;
761 mfDuration = fDuration;
762 mfAbsoluteDuration = mfDuration;
764 // calculate effect duration and get target shape
765 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
766 if( xEnumerationAccess.is() )
768 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
769 if( xEnumeration.is() )
771 while( xEnumeration->hasMoreElements() )
773 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
774 if( !xChildNode.is() )
775 continue;
778 double fChildBegin = 0.0;
779 xChildNode->getBegin() >>= fChildBegin;
780 if( fChildBegin != 0.0 )
782 fChildBegin *= fScale;
783 xChildNode->setBegin( makeAny( fChildBegin ) );
786 double fChildDuration = 0.0;
787 xChildNode->getDuration() >>= fChildDuration;
788 if( fChildDuration != 0.0 )
790 fChildDuration *= fScale;
791 xChildNode->setDuration( makeAny( fChildDuration ) );
796 calculateIterateDuration();
798 catch( Exception& )
800 DBG_ERROR( "sd::CustomAnimationEffect::setDuration(), exception cought!" );
804 // --------------------------------------------------------------------
806 void CustomAnimationEffect::setBegin( double fBegin )
808 if( mxNode.is() ) try
810 mfBegin = fBegin;
811 mxNode->setBegin( makeAny( fBegin ) );
813 catch( Exception& )
815 DBG_ERROR( "sd::CustomAnimationEffect::setBegin(), exception cought!" );
819 // --------------------------------------------------------------------
821 void CustomAnimationEffect::setAcceleration( double fAcceleration )
823 if( mxNode.is() ) try
825 mfAcceleration = fAcceleration;
826 mxNode->setAcceleration( fAcceleration );
828 catch( Exception& )
830 DBG_ERROR( "sd::CustomAnimationEffect::setAcceleration(), exception cought!" );
833 // --------------------------------------------------------------------
835 void CustomAnimationEffect::setDecelerate( double fDecelerate )
837 if( mxNode.is() ) try
839 mfDecelerate = fDecelerate;
840 mxNode->setDecelerate( fDecelerate );
842 catch( Exception& )
844 DBG_ERROR( "sd::CustomAnimationEffect::setDecelerate(), exception cought!" );
848 // --------------------------------------------------------------------
850 void CustomAnimationEffect::setAutoReverse( sal_Bool bAutoReverse )
852 if( mxNode.is() ) try
854 mbAutoReverse = bAutoReverse;
855 mxNode->setAutoReverse( bAutoReverse );
857 catch( Exception& )
859 DBG_ERROR( "sd::CustomAnimationEffect::setAutoReverse(), exception cought!" );
863 // --------------------------------------------------------------------
865 void CustomAnimationEffect::replaceNode( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
867 sal_Int16 nNodeType = mnNodeType;
868 Any aTarget = maTarget;
870 double fBegin = mfBegin;
871 double fDuration = mfDuration;
872 double fAcceleration = mfAcceleration;
873 double fDecelerate = mfDecelerate ;
874 sal_Bool bAutoReverse = mbAutoReverse;
875 Reference< XAudio > xAudio( mxAudio );
876 sal_Int16 nIterateType = mnIterateType;
877 double fIterateInterval = mfIterateInterval;
878 sal_Int16 nSubItem = mnTargetSubItem;
880 setNode( xNode );
882 setAudio( xAudio );
883 setNodeType( nNodeType );
884 setTarget( aTarget );
885 setTargetSubItem( nSubItem );
886 setDuration( fDuration );
887 setBegin( fBegin );
889 setAcceleration( fAcceleration );
890 setDecelerate( fDecelerate );
891 setAutoReverse( bAutoReverse );
893 if( nIterateType != mnIterateType )
894 setIterateType( nIterateType );
896 if( mnIterateType && ( fIterateInterval != mfIterateInterval ) )
897 setIterateInterval( fIterateInterval );
900 // --------------------------------------------------------------------
902 Reference< XShape > CustomAnimationEffect::getTargetShape() const
904 Reference< XShape > xShape;
905 maTarget >>= xShape;
906 if( !xShape.is() )
908 ParagraphTarget aParaTarget;
909 if( maTarget >>= aParaTarget )
910 xShape = aParaTarget.Shape;
913 return xShape;
916 // --------------------------------------------------------------------
918 Any CustomAnimationEffect::getRepeatCount() const
920 if( mxNode.is() )
922 return mxNode->getRepeatCount();
924 else
926 Any aAny;
927 return aAny;
931 // --------------------------------------------------------------------
933 Any CustomAnimationEffect::getEnd() const
935 if( mxNode.is() )
937 return mxNode->getEnd();
939 else
941 Any aAny;
942 return aAny;
946 // --------------------------------------------------------------------
948 sal_Int16 CustomAnimationEffect::getFill() const
950 if( mxNode.is() )
951 return mxNode->getFill();
952 else
953 return 0;
956 // --------------------------------------------------------------------
958 void CustomAnimationEffect::setRepeatCount( const Any& rRepeatCount )
960 if( mxNode.is() )
961 mxNode->setRepeatCount( rRepeatCount );
964 // --------------------------------------------------------------------
966 void CustomAnimationEffect::setEnd( const Any& rEnd )
968 if( mxNode.is() )
969 mxNode->setEnd( rEnd );
972 // --------------------------------------------------------------------
974 void CustomAnimationEffect::setFill( sal_Int16 nFill )
976 if( mxNode.is() )
977 mxNode->setFill( nFill );
980 // --------------------------------------------------------------------
982 Reference< XAnimationNode > CustomAnimationEffect::createAfterEffectNode() const throw (Exception)
984 DBG_ASSERT( mbHasAfterEffect, "sd::CustomAnimationEffect::createAfterEffectNode(), this node has no after effect!" );
986 Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() );
988 const char* pServiceName = maDimColor.hasValue() ?
989 "com.sun.star.animations.AnimateColor" : "com.sun.star.animations.AnimateSet";
991 Reference< XAnimate > xAnimate( xMsf->createInstance(OUString::createFromAscii(pServiceName) ), UNO_QUERY_THROW );
993 Any aTo;
994 OUString aAttributeName;
996 if( maDimColor.hasValue() )
998 aTo = maDimColor;
999 aAttributeName = OUString( RTL_CONSTASCII_USTRINGPARAM( "DimColor" ) );
1001 else
1003 aTo = makeAny( (sal_Bool)sal_False );
1004 aAttributeName = OUString( RTL_CONSTASCII_USTRINGPARAM( "Visibility" ) );
1007 Any aBegin;
1008 if( !mbAfterEffectOnNextEffect ) // sameClick
1010 Event aEvent;
1012 aEvent.Source <<= getNode();
1013 aEvent.Trigger = EventTrigger::END_EVENT;
1014 aEvent.Repeat = 0;
1016 aBegin <<= aEvent;
1018 else
1020 aBegin <<= (double)0.0;
1023 xAnimate->setBegin( aBegin );
1024 xAnimate->setTo( aTo );
1025 xAnimate->setAttributeName( aAttributeName );
1027 xAnimate->setDuration( makeAny( (double)0.001 ) );
1028 xAnimate->setFill( AnimationFill::HOLD );
1029 xAnimate->setTarget( maTarget );
1031 return Reference< XAnimationNode >( xAnimate, UNO_QUERY_THROW );
1034 // --------------------------------------------------------------------
1036 void CustomAnimationEffect::setIterateType( sal_Int16 nIterateType )
1038 if( mnIterateType != nIterateType ) try
1040 // do we need to exchange the container node?
1041 if( (mnIterateType == 0) || (nIterateType == 0) )
1043 sal_Int16 nTargetSubItem = mnTargetSubItem;
1045 Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() );
1046 const char * pServiceName =
1047 nIterateType ? "com.sun.star.animations.IterateContainer" : "com.sun.star.animations.ParallelTimeContainer";
1048 Reference< XTimeContainer > xNewContainer(
1049 xMsf->createInstance( OUString::createFromAscii(pServiceName) ), UNO_QUERY_THROW );
1051 Reference< XTimeContainer > xOldContainer( mxNode, UNO_QUERY_THROW );
1052 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW );
1053 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1054 while( xEnumeration->hasMoreElements() )
1056 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
1057 xOldContainer->removeChild( xChildNode );
1058 xNewContainer->appendChild( xChildNode );
1061 Reference< XAnimationNode > xNewNode( xNewContainer, UNO_QUERY_THROW );
1063 xNewNode->setBegin( mxNode->getBegin() );
1064 xNewNode->setDuration( mxNode->getDuration() );
1065 xNewNode->setEnd( mxNode->getEnd() );
1066 xNewNode->setEndSync( mxNode->getEndSync() );
1067 xNewNode->setRepeatCount( mxNode->getRepeatCount() );
1068 xNewNode->setFill( mxNode->getFill() );
1069 xNewNode->setFillDefault( mxNode->getFillDefault() );
1070 xNewNode->setRestart( mxNode->getRestart() );
1071 xNewNode->setRestartDefault( mxNode->getRestartDefault() );
1072 xNewNode->setAcceleration( mxNode->getAcceleration() );
1073 xNewNode->setDecelerate( mxNode->getDecelerate() );
1074 xNewNode->setAutoReverse( mxNode->getAutoReverse() );
1075 xNewNode->setRepeatDuration( mxNode->getRepeatDuration() );
1076 xNewNode->setEndSync( mxNode->getEndSync() );
1077 xNewNode->setRepeatCount( mxNode->getRepeatCount() );
1078 xNewNode->setUserData( mxNode->getUserData() );
1080 mxNode = xNewNode;
1082 Any aTarget;
1083 if( nIterateType )
1085 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY_THROW );
1086 xIter->setTarget(maTarget);
1087 xIter->setSubItem( nTargetSubItem );
1089 else
1091 aTarget = maTarget;
1094 Reference< XEnumerationAccess > xEA( mxNode, UNO_QUERY_THROW );
1095 Reference< XEnumeration > xE( xEA->createEnumeration(), UNO_QUERY_THROW );
1096 while( xE->hasMoreElements() )
1098 Reference< XAnimate > xAnimate( xE->nextElement(), UNO_QUERY );
1099 if( xAnimate.is() )
1101 xAnimate->setTarget( aTarget );
1102 xAnimate->setSubItem( nTargetSubItem );
1107 mnIterateType = nIterateType;
1109 // if we have an iteration container, we must set its type
1110 if( mnIterateType )
1112 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY_THROW );
1113 xIter->setIterateType( nIterateType );
1116 checkForText();
1118 catch( Exception& e )
1120 (void)e;
1121 DBG_ERROR( "sd::CustomAnimationEffect::setIterateType(), Exception cought!" );
1125 // --------------------------------------------------------------------
1127 void CustomAnimationEffect::setIterateInterval( double fIterateInterval )
1129 if( mfIterateInterval != fIterateInterval )
1131 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
1133 DBG_ASSERT( xIter.is(), "sd::CustomAnimationEffect::setIterateInterval(), not an iteration node" );
1134 if( xIter.is() )
1136 mfIterateInterval = fIterateInterval;
1137 xIter->setIterateInterval( fIterateInterval );
1140 calculateIterateDuration();
1144 // --------------------------------------------------------------------
1146 ::rtl::OUString CustomAnimationEffect::getPath() const
1148 ::rtl::OUString aPath;
1150 if( mxNode.is() ) try
1152 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW );
1153 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1154 while( xEnumeration->hasMoreElements() )
1156 Reference< XAnimateMotion > xMotion( xEnumeration->nextElement(), UNO_QUERY );
1157 if( xMotion.is() )
1159 xMotion->getPath() >>= aPath;
1160 break;
1164 catch( Exception& e )
1166 (void)e;
1167 DBG_ERROR("sd::CustomAnimationEffect::getPath(), exception cought!" );
1170 return aPath;
1173 // --------------------------------------------------------------------
1175 void CustomAnimationEffect::setPath( const ::rtl::OUString& rPath )
1177 if( mxNode.is() ) try
1179 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW );
1180 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1181 while( xEnumeration->hasMoreElements() )
1183 Reference< XAnimateMotion > xMotion( xEnumeration->nextElement(), UNO_QUERY );
1184 if( xMotion.is() )
1187 MainSequenceChangeGuard aGuard( mpEffectSequence );
1188 xMotion->setPath( Any( rPath ) );
1189 break;
1193 catch( Exception& e )
1195 (void)e;
1196 DBG_ERROR("sd::CustomAnimationEffect::setPath(), exception cought!" );
1200 // --------------------------------------------------------------------
1202 Any CustomAnimationEffect::getProperty( sal_Int32 nNodeType, const OUString& rAttributeName, EValue eValue )
1204 Any aProperty;
1205 if( mxNode.is() ) try
1207 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1208 if( xEnumerationAccess.is() )
1210 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1211 if( xEnumeration.is() )
1213 while( xEnumeration->hasMoreElements() && !aProperty.hasValue() )
1215 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1216 if( !xAnimate.is() )
1217 continue;
1219 if( xAnimate->getType() == nNodeType )
1221 if( xAnimate->getAttributeName() == rAttributeName )
1223 switch( eValue )
1225 case VALUE_FROM: aProperty = xAnimate->getFrom(); break;
1226 case VALUE_TO: aProperty = xAnimate->getTo(); break;
1227 case VALUE_BY: aProperty = xAnimate->getBy(); break;
1228 case VALUE_FIRST:
1229 case VALUE_LAST:
1231 Sequence<Any> aValues( xAnimate->getValues() );
1232 if( aValues.hasElements() )
1233 aProperty = aValues[ eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1 ];
1235 break;
1243 catch( Exception& e )
1245 (void)e;
1246 DBG_ERROR("sd::CustomAnimationEffect::getProperty(), exception cought!" );
1249 return aProperty;
1252 // --------------------------------------------------------------------
1254 bool CustomAnimationEffect::setProperty( sal_Int32 nNodeType, const OUString& rAttributeName, EValue eValue, const Any& rValue )
1256 bool bChanged = false;
1257 if( mxNode.is() ) try
1259 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1260 if( xEnumerationAccess.is() )
1262 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1263 if( xEnumeration.is() )
1265 while( xEnumeration->hasMoreElements() )
1267 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1268 if( !xAnimate.is() )
1269 continue;
1271 if( xAnimate->getType() == nNodeType )
1273 if( xAnimate->getAttributeName() == rAttributeName )
1275 switch( eValue )
1277 case VALUE_FROM:
1278 if( xAnimate->getFrom() != rValue )
1280 xAnimate->setFrom( rValue );
1281 bChanged = true;
1283 break;
1284 case VALUE_TO:
1285 if( xAnimate->getTo() != rValue )
1287 xAnimate->setTo( rValue );
1288 bChanged = true;
1290 break;
1291 case VALUE_BY:
1292 if( xAnimate->getTo() != rValue )
1294 xAnimate->setBy( rValue );
1295 bChanged = true;
1297 break;
1298 case VALUE_FIRST:
1299 case VALUE_LAST:
1301 Sequence<Any> aValues( xAnimate->getValues() );
1302 if( !aValues.hasElements() )
1303 aValues.realloc(1);
1305 sal_Int32 nIndex = eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1;
1307 if( aValues[ nIndex ] != rValue )
1309 aValues[ nIndex ] = rValue;
1310 xAnimate->setValues( aValues );
1311 bChanged = true;
1321 catch( Exception& e )
1323 (void)e;
1324 DBG_ERROR("sd::CustomAnimationEffect::setProperty(), exception cought!" );
1327 return bChanged;
1330 // --------------------------------------------------------------------
1332 static bool implIsColorAttribute( const OUString& rAttributeName )
1334 return rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("FillColor") ) ||
1335 rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("LineColor") ) ||
1336 rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("CharColor") );
1339 // --------------------------------------------------------------------
1341 Any CustomAnimationEffect::getColor( sal_Int32 nIndex )
1343 Any aColor;
1344 if( mxNode.is() ) try
1346 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1347 if( xEnumerationAccess.is() )
1349 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1350 if( xEnumeration.is() )
1352 while( xEnumeration->hasMoreElements() && !aColor.hasValue() )
1354 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1355 if( !xAnimate.is() )
1356 continue;
1358 switch( xAnimate->getType() )
1360 case AnimationNodeType::SET:
1361 case AnimationNodeType::ANIMATE:
1362 if( !implIsColorAttribute( xAnimate->getAttributeName() ) )
1363 break;
1364 case AnimationNodeType::ANIMATECOLOR:
1365 Sequence<Any> aValues( xAnimate->getValues() );
1366 if( aValues.hasElements() )
1368 if( aValues.getLength() > nIndex )
1369 aColor = aValues[nIndex];
1371 else if( nIndex == 0 )
1372 aColor = xAnimate->getFrom();
1373 else
1374 aColor = xAnimate->getTo();
1380 catch( Exception& e )
1382 (void)e;
1383 DBG_ERROR("sd::CustomAnimationEffect::getColor(), exception cought!" );
1386 return aColor;
1389 // --------------------------------------------------------------------
1391 void CustomAnimationEffect::setColor( sal_Int32 nIndex, const Any& rColor )
1393 if( mxNode.is() ) try
1395 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1396 if( xEnumerationAccess.is() )
1398 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1399 if( xEnumeration.is() )
1401 while( xEnumeration->hasMoreElements() )
1403 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1404 if( !xAnimate.is() )
1405 continue;
1407 switch( xAnimate->getType() )
1409 case AnimationNodeType::SET:
1410 case AnimationNodeType::ANIMATE:
1411 if( !implIsColorAttribute( xAnimate->getAttributeName() ) )
1412 break;
1413 case AnimationNodeType::ANIMATECOLOR:
1415 Sequence<Any> aValues( xAnimate->getValues() );
1416 if( aValues.hasElements() )
1418 if( aValues.getLength() > nIndex )
1420 aValues[nIndex] = rColor;
1421 xAnimate->setValues( aValues );
1424 else if( (nIndex == 0) && xAnimate->getFrom().hasValue() )
1425 xAnimate->setFrom(rColor);
1426 else if( (nIndex == 1) && xAnimate->getTo().hasValue() )
1427 xAnimate->setTo(rColor);
1429 break;
1436 catch( Exception& e )
1438 (void)e;
1439 DBG_ERROR("sd::CustomAnimationEffect::setColor(), exception cought!" );
1443 // --------------------------------------------------------------------
1445 Any CustomAnimationEffect::getTransformationProperty( sal_Int32 nTransformType, EValue eValue )
1447 Any aProperty;
1448 if( mxNode.is() ) try
1450 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1451 if( xEnumerationAccess.is() )
1453 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1454 if( xEnumeration.is() )
1456 while( xEnumeration->hasMoreElements() && !aProperty.hasValue() )
1458 Reference< XAnimateTransform > xTransform( xEnumeration->nextElement(), UNO_QUERY );
1459 if( !xTransform.is() )
1460 continue;
1462 if( xTransform->getTransformType() == nTransformType )
1464 switch( eValue )
1466 case VALUE_FROM: aProperty = xTransform->getFrom(); break;
1467 case VALUE_TO: aProperty = xTransform->getTo(); break;
1468 case VALUE_BY: aProperty = xTransform->getBy(); break;
1469 case VALUE_FIRST:
1470 case VALUE_LAST:
1472 Sequence<Any> aValues( xTransform->getValues() );
1473 if( aValues.hasElements() )
1474 aProperty = aValues[ eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1 ];
1476 break;
1483 catch( Exception& e )
1485 (void)e;
1486 DBG_ERROR("sd::CustomAnimationEffect::getTransformationProperty(), exception cought!" );
1489 return aProperty;
1492 // --------------------------------------------------------------------
1494 bool CustomAnimationEffect::setTransformationProperty( sal_Int32 nTransformType, EValue eValue, const Any& rValue )
1496 bool bChanged = false;
1497 if( mxNode.is() ) try
1499 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1500 if( xEnumerationAccess.is() )
1502 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1503 if( xEnumeration.is() )
1505 while( xEnumeration->hasMoreElements() )
1507 Reference< XAnimateTransform > xTransform( xEnumeration->nextElement(), UNO_QUERY );
1508 if( !xTransform.is() )
1509 continue;
1511 if( xTransform->getTransformType() == nTransformType )
1513 switch( eValue )
1515 case VALUE_FROM:
1516 if( xTransform->getFrom() != rValue )
1518 xTransform->setFrom( rValue );
1519 bChanged = true;
1521 break;
1522 case VALUE_TO:
1523 if( xTransform->getTo() != rValue )
1525 xTransform->setTo( rValue );
1526 bChanged = true;
1528 break;
1529 case VALUE_BY:
1530 if( xTransform->getBy() != rValue )
1532 xTransform->setBy( rValue );
1533 bChanged = true;
1535 break;
1536 case VALUE_FIRST:
1537 case VALUE_LAST:
1539 Sequence<Any> aValues( xTransform->getValues() );
1540 if( !aValues.hasElements() )
1541 aValues.realloc(1);
1543 sal_Int32 nIndex = eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1;
1544 if( aValues[nIndex] != rValue )
1546 aValues[nIndex] = rValue;
1547 xTransform->setValues( aValues );
1548 bChanged = true;
1557 catch( Exception& e )
1559 (void)e;
1560 DBG_ERROR("sd::CustomAnimationEffect::setTransformationProperty(), exception cought!" );
1563 return bChanged;
1566 // --------------------------------------------------------------------
1568 void CustomAnimationEffect::createAudio( const ::com::sun::star::uno::Any& rSource, double fVolume /* = 1.0 */ )
1570 DBG_ASSERT( !mxAudio.is(), "sd::CustomAnimationEffect::createAudio(), node already has an audio!" );
1572 if( !mxAudio.is() ) try
1574 Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() );
1575 Reference< XAudio > xAudio( xMsf->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.Audio") ) ), UNO_QUERY_THROW );
1576 xAudio->setSource( rSource );
1577 xAudio->setVolume( fVolume );
1578 setAudio( xAudio );
1580 catch( Exception& e )
1582 (void)e;
1583 DBG_ERROR("sd::CustomAnimationEffect::createAudio(), exception cought!" );
1587 // --------------------------------------------------------------------
1589 static Reference< XCommand > findCommandNode( const Reference< XAnimationNode >& xRootNode )
1591 Reference< XCommand > xCommand;
1593 if( xRootNode.is() ) try
1595 Reference< XEnumerationAccess > xEnumerationAccess( xRootNode, UNO_QUERY_THROW );
1596 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1597 while( !xCommand.is() && xEnumeration->hasMoreElements() )
1599 Reference< XAnimationNode > xNode( xEnumeration->nextElement(), UNO_QUERY );
1600 if( xNode.is() && (xNode->getType() == AnimationNodeType::COMMAND) )
1601 xCommand.set( xNode, UNO_QUERY_THROW );
1604 catch( Exception& e )
1606 (void)e;
1607 DBG_ERROR("sd::findCommandNode(), exception caught!" );
1610 return xCommand;
1613 void CustomAnimationEffect::removeAudio()
1617 Reference< XAnimationNode > xChild;
1619 if( mxAudio.is() )
1621 xChild.set( mxAudio, UNO_QUERY );
1622 mxAudio.clear();
1624 else if( mnCommand == EffectCommands::STOPAUDIO )
1626 xChild.set( findCommandNode( mxNode ), UNO_QUERY );
1627 mnCommand = 0;
1630 if( xChild.is() )
1632 Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY );
1633 if( xContainer.is() )
1634 xContainer->removeChild( xChild );
1637 catch( Exception& e )
1639 (void)e;
1640 DBG_ERROR("sd::CustomAnimationEffect::removeAudio(), exception caught!" );
1645 // --------------------------------------------------------------------
1647 void CustomAnimationEffect::setAudio( const Reference< ::com::sun::star::animations::XAudio >& xAudio )
1649 if( mxAudio != xAudio ) try
1651 removeAudio();
1652 mxAudio = xAudio;
1653 Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY );
1654 Reference< XAnimationNode > xChild( mxAudio, UNO_QUERY );
1655 if( xContainer.is() && xChild.is() )
1656 xContainer->appendChild( xChild );
1658 catch( Exception& e )
1660 (void)e;
1661 DBG_ERROR("sd::CustomAnimationEffect::setAudio(), exception caught!" );
1665 // --------------------------------------------------------------------
1667 void CustomAnimationEffect::setStopAudio()
1669 if( mnCommand != EffectCommands::STOPAUDIO ) try
1671 if( mxAudio.is() )
1672 removeAudio();
1674 Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() );
1675 Reference< XCommand > xCommand( xMsf->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.Command") ) ), UNO_QUERY_THROW );
1677 xCommand->setCommand( EffectCommands::STOPAUDIO );
1679 Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY_THROW );
1680 Reference< XAnimationNode > xChild( xCommand, UNO_QUERY_THROW );
1681 xContainer->appendChild( xChild );
1683 mnCommand = EffectCommands::STOPAUDIO;
1685 catch( Exception& e )
1687 (void)e;
1688 DBG_ERROR("sd::CustomAnimationEffect::setStopAudio(), exception caught!" );
1692 // --------------------------------------------------------------------
1694 bool CustomAnimationEffect::getStopAudio() const
1696 return mnCommand == EffectCommands::STOPAUDIO;
1699 // --------------------------------------------------------------------
1701 SdrPathObj* CustomAnimationEffect::createSdrPathObjFromPath()
1703 SdrPathObj * pPathObj = new SdrPathObj( OBJ_PATHLINE );
1704 updateSdrPathObjFromPath( *pPathObj );
1705 return pPathObj;
1708 // --------------------------------------------------------------------
1710 void CustomAnimationEffect::updateSdrPathObjFromPath( SdrPathObj& rPathObj )
1712 ::basegfx::B2DPolyPolygon xPolyPoly;
1713 if( ::basegfx::tools::importFromSvgD( xPolyPoly, getPath() ) )
1715 SdrObject* pObj = GetSdrObjectFromXShape( getTargetShape() );
1716 if( pObj )
1718 ::basegfx::B2DHomMatrix aTransform;
1720 SdrPage* pPage = pObj->GetPage();
1721 if( pPage )
1723 const Size aPageSize( pPage->GetSize() );
1724 aTransform.scale( (double)aPageSize.Width(), (double)aPageSize.Height() );
1725 xPolyPoly.transform( aTransform );
1726 aTransform.identity();
1729 const Rectangle aBoundRect( pObj->GetCurrentBoundRect() );
1730 const Point aCenter( aBoundRect.Center() );
1731 aTransform.translate( aCenter.X(), aCenter.Y() );
1732 xPolyPoly.transform( aTransform );
1736 rPathObj.SetPathPoly( xPolyPoly );
1739 // --------------------------------------------------------------------
1741 void CustomAnimationEffect::updatePathFromSdrPathObj( const SdrPathObj& rPathObj )
1743 ::basegfx::B2DPolyPolygon xPolyPoly( rPathObj.GetPathPoly() );
1745 SdrObject* pObj = GetSdrObjectFromXShape( getTargetShape() );
1746 if( pObj )
1748 const Rectangle aBoundRect( pObj->GetCurrentBoundRect() );
1749 const Point aCenter( aBoundRect.Center() );
1751 ::basegfx::B2DHomMatrix aTransform;
1752 aTransform.translate( -aCenter.X(), -aCenter.Y() );
1753 xPolyPoly.transform( aTransform );
1755 SdrPage* pPage = pObj->GetPage();
1756 if( pPage )
1758 aTransform.identity();
1759 const Size aPageSize( pPage->GetSize() );
1760 aTransform.scale( 1.0 / (double)aPageSize.Width(), 1.0 / (double)aPageSize.Height() );
1761 xPolyPoly.transform( aTransform );
1765 setPath( ::basegfx::tools::exportToSvgD( xPolyPoly ) );
1768 // ====================================================================
1770 EffectSequenceHelper::EffectSequenceHelper()
1771 : mnSequenceType( EffectNodeType::DEFAULT )
1775 // --------------------------------------------------------------------
1777 EffectSequenceHelper::EffectSequenceHelper( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XTimeContainer >& xSequenceRoot )
1778 : mxSequenceRoot( xSequenceRoot ), mnSequenceType( EffectNodeType::DEFAULT )
1780 Reference< XAnimationNode > xNode( mxSequenceRoot, UNO_QUERY_THROW );
1781 create( xNode );
1784 // --------------------------------------------------------------------
1786 EffectSequenceHelper::~EffectSequenceHelper()
1788 reset();
1791 // --------------------------------------------------------------------
1793 void EffectSequenceHelper::reset()
1795 EffectSequence::iterator aIter( maEffects.begin() );
1796 EffectSequence::iterator aEnd( maEffects.end() );
1797 if( aIter != aEnd )
1799 CustomAnimationEffectPtr pEffect = (*aIter++);
1800 pEffect->setEffectSequence(0);
1802 maEffects.clear();
1805 Reference< XAnimationNode > EffectSequenceHelper::getRootNode()
1807 Reference< XAnimationNode > xRoot( mxSequenceRoot, UNO_QUERY );
1808 return xRoot;
1811 // --------------------------------------------------------------------
1813 void EffectSequenceHelper::append( const CustomAnimationEffectPtr& pEffect )
1815 pEffect->setEffectSequence( this );
1816 maEffects.push_back(pEffect);
1817 rebuild();
1820 // --------------------------------------------------------------------
1822 void EffectSequenceHelper::insert( EffectSequence::iterator& rPos, const CustomAnimationEffectPtr& pEffect )
1824 pEffect->setEffectSequence( this );
1825 maEffects.insert( rPos, pEffect );
1826 rebuild();
1829 // --------------------------------------------------------------------
1831 CustomAnimationEffectPtr EffectSequenceHelper::append( const CustomAnimationPresetPtr& pPreset, const Any& rTarget, double fDuration /* = -1.0 */ )
1833 CustomAnimationEffectPtr pEffect;
1835 if( pPreset.get() )
1837 OUString strEmpty;
1838 Reference< XAnimationNode > xNode( pPreset->create( strEmpty ) );
1839 if( xNode.is() )
1841 // first, filter all only ui relevant user data
1842 std::vector< NamedValue > aNewUserData;
1843 Sequence< NamedValue > aUserData( xNode->getUserData() );
1844 sal_Int32 nLength = aUserData.getLength();
1845 const NamedValue* p = aUserData.getConstArray();
1846 bool bFilter = false;
1848 while( nLength-- )
1850 if( !p->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "text-only" ) ) &&
1851 !p->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "preset-property" ) ) )
1853 aNewUserData.push_back( *p );
1854 bFilter = true;
1856 p++;
1859 if( bFilter )
1861 aUserData = ::comphelper::containerToSequence< NamedValue, std::vector< NamedValue > >( aNewUserData );
1862 xNode->setUserData( aUserData );
1865 // check target, maybe we need to force it to text
1866 Any aTarget( rTarget );
1867 sal_Int16 nSubItem = ShapeAnimationSubType::AS_WHOLE;
1869 if( aTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
1871 nSubItem = ShapeAnimationSubType::ONLY_TEXT;
1873 else if( pPreset->isTextOnly() )
1875 Reference< XShape > xShape;
1876 aTarget >>= xShape;
1877 if( xShape.is() )
1879 // thats bad, we target a shape here but the effect is only for text
1880 // so change subitem
1881 nSubItem = ShapeAnimationSubType::ONLY_TEXT;
1885 // now create effect from preset
1886 pEffect.reset( new CustomAnimationEffect( xNode ) );
1887 pEffect->setEffectSequence( this );
1888 pEffect->setTarget( aTarget );
1889 pEffect->setTargetSubItem( nSubItem );
1890 if( fDuration != -1.0 )
1891 pEffect->setDuration( fDuration );
1893 maEffects.push_back(pEffect);
1895 rebuild();
1899 DBG_ASSERT( pEffect.get(), "sd::EffectSequenceHelper::append(), failed!" );
1900 return pEffect;
1903 // --------------------------------------------------------------------
1905 CustomAnimationEffectPtr EffectSequenceHelper::append( const SdrPathObj& rPathObj, const Any& rTarget, double fDuration /* = -1.0 */ )
1907 CustomAnimationEffectPtr pEffect;
1909 if( fDuration <= 0.0 )
1910 fDuration = 2.0;
1914 Reference< XTimeContainer > xEffectContainer( createParallelTimeContainer() );
1915 const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.animations.AnimateMotion" ) );
1916 Reference< XAnimationNode > xAnimateMotion( ::comphelper::getProcessServiceFactory()->createInstance(aServiceName), UNO_QUERY_THROW );
1918 xAnimateMotion->setDuration( Any( fDuration ) );
1919 xAnimateMotion->setFill( AnimationFill::HOLD );
1920 xEffectContainer->appendChild( xAnimateMotion );
1922 sal_Int16 nSubItem = ShapeAnimationSubType::AS_WHOLE;
1924 if( rTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
1925 nSubItem = ShapeAnimationSubType::ONLY_TEXT;
1927 Reference< XAnimationNode > xEffectNode( xEffectContainer, UNO_QUERY_THROW );
1928 pEffect.reset( new CustomAnimationEffect( xEffectNode ) );
1929 pEffect->setEffectSequence( this );
1930 pEffect->setTarget( rTarget );
1931 pEffect->setTargetSubItem( nSubItem );
1932 pEffect->setNodeType( ::com::sun::star::presentation::EffectNodeType::ON_CLICK );
1933 pEffect->setPresetClass( ::com::sun::star::presentation::EffectPresetClass::MOTIONPATH );
1934 pEffect->setAcceleration( 0.5 );
1935 pEffect->setDecelerate( 0.5 );
1936 pEffect->setFill( AnimationFill::HOLD );
1937 pEffect->setBegin( 0.0 );
1938 pEffect->updatePathFromSdrPathObj( rPathObj );
1939 if( fDuration != -1.0 )
1940 pEffect->setDuration( fDuration );
1942 maEffects.push_back(pEffect);
1944 rebuild();
1946 catch( Exception& )
1948 DBG_ERROR( "sd::EffectSequenceHelper::append(), exception cought!" );
1951 return pEffect;
1954 // --------------------------------------------------------------------
1956 void EffectSequenceHelper::replace( const CustomAnimationEffectPtr& pEffect, const CustomAnimationPresetPtr& pPreset, const OUString& rPresetSubType, double fDuration /* = -1.0 */ )
1958 if( pEffect.get() && pPreset.get() ) try
1960 Reference< XAnimationNode > xNewNode( pPreset->create( rPresetSubType ) );
1961 if( xNewNode.is() )
1963 pEffect->replaceNode( xNewNode );
1964 if( fDuration != -1.0 )
1965 pEffect->setDuration( fDuration );
1968 rebuild();
1970 catch( Exception& e )
1972 (void)e;
1973 DBG_ERROR( "sd::EffectSequenceHelper::replace(), exception cought!" );
1977 // --------------------------------------------------------------------
1979 void EffectSequenceHelper::replace( const CustomAnimationEffectPtr& pEffect, const CustomAnimationPresetPtr& pPreset, double fDuration /* = -1.0 */ )
1981 OUString strEmpty;
1982 replace( pEffect, pPreset, strEmpty, fDuration );
1985 // --------------------------------------------------------------------
1987 void EffectSequenceHelper::remove( const CustomAnimationEffectPtr& pEffect )
1989 if( pEffect.get() )
1991 pEffect->setEffectSequence( 0 );
1992 maEffects.remove( pEffect );
1995 rebuild();
1998 // --------------------------------------------------------------------
2000 void EffectSequenceHelper::rebuild()
2002 implRebuild();
2005 // --------------------------------------------------------------------
2007 void EffectSequenceHelper::implRebuild()
2011 // first we delete all time containers on the first two levels
2012 Reference< XEnumerationAccess > xEnumerationAccess( mxSequenceRoot, UNO_QUERY_THROW );
2013 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
2014 while( xEnumeration->hasMoreElements() )
2016 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
2017 Reference< XTimeContainer > xChildContainer( xChildNode, UNO_QUERY_THROW );
2019 Reference< XEnumerationAccess > xChildEnumerationAccess( xChildNode, UNO_QUERY_THROW );
2020 Reference< XEnumeration > xChildEnumeration( xChildEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
2021 while( xChildEnumeration->hasMoreElements() )
2023 Reference< XAnimationNode > xNode( xChildEnumeration->nextElement(), UNO_QUERY_THROW );
2024 xChildContainer->removeChild( xNode );
2027 mxSequenceRoot->removeChild( xChildNode );
2030 // second, rebuild main sequence
2031 EffectSequence::iterator aIter( maEffects.begin() );
2032 EffectSequence::iterator aEnd( maEffects.end() );
2033 if( aIter != aEnd )
2035 AfterEffectNodeList aAfterEffects;
2037 CustomAnimationEffectPtr pEffect = (*aIter++);
2039 bool bFirst = true;
2042 // create a par container for the next click node and all following with and after effects
2043 Reference< XTimeContainer > xOnClickContainer( createParallelTimeContainer() );
2045 Event aEvent;
2046 if( mxEventSource.is() )
2048 aEvent.Source <<= mxEventSource;
2049 aEvent.Trigger = EventTrigger::ON_CLICK;
2051 else
2053 aEvent.Trigger = EventTrigger::ON_NEXT;
2055 aEvent.Repeat = 0;
2057 Any aBegin( makeAny( aEvent ) );
2058 if( bFirst )
2060 // if the first node is not a click action, this click container
2061 // must not have INDEFINITE begin but start at 0s
2062 bFirst = false;
2063 if( pEffect->getNodeType() != EffectNodeType::ON_CLICK )
2064 aBegin <<= (double)0.0;
2067 xOnClickContainer->setBegin( aBegin );
2069 Reference< XAnimationNode > xOnClickContainerNode( xOnClickContainer, UNO_QUERY_THROW );
2070 mxSequenceRoot->appendChild( xOnClickContainerNode );
2072 double fBegin = 0.0;
2076 // create a par container for the current click or after effect node and all following with effects
2077 Reference< XTimeContainer > xWithContainer( createParallelTimeContainer() );
2078 Reference< XAnimationNode > xWithContainerNode( xWithContainer, UNO_QUERY_THROW );
2079 xWithContainer->setBegin( makeAny( fBegin ) );
2080 xOnClickContainer->appendChild( xWithContainerNode );
2082 double fDuration = 0.0;
2085 Reference< XAnimationNode > xEffectNode( pEffect->getNode() );
2086 xWithContainer->appendChild( xEffectNode );
2088 if( pEffect->hasAfterEffect() )
2090 Reference< XAnimationNode > xAfterEffect( pEffect->createAfterEffectNode() );
2091 AfterEffectNode a( xAfterEffect, xEffectNode, pEffect->IsAfterEffectOnNext() );
2092 aAfterEffects.push_back( a );
2095 double fTemp = pEffect->getBegin() + pEffect->getAbsoluteDuration();
2096 if( fTemp > fDuration )
2097 fDuration = fTemp;
2099 if( aIter != aEnd )
2100 pEffect = (*aIter++);
2101 else
2102 pEffect.reset();
2104 while( pEffect.get() && (pEffect->getNodeType() == EffectNodeType::WITH_PREVIOUS) );
2106 fBegin += fDuration;
2108 while( pEffect.get() && (pEffect->getNodeType() != EffectNodeType::ON_CLICK) );
2110 while( pEffect.get() );
2112 // process after effect nodes
2113 std::for_each( aAfterEffects.begin(), aAfterEffects.end(), stl_process_after_effect_node_func );
2115 updateTextGroups();
2117 // reset duration, might have been altered (see below)
2118 mxSequenceRoot->setDuration( Any() );
2120 else
2122 // empty sequence, set duration to 0.0 explicitely
2123 // (otherwise, this sequence will never end)
2124 mxSequenceRoot->setDuration( makeAny((double)0.0) );
2127 catch( Exception& e )
2129 (void)e;
2130 DBG_ERROR( "sd::EffectSequenceHelper::rebuild(), exception cought!" );
2134 // --------------------------------------------------------------------
2136 Reference< XTimeContainer > EffectSequenceHelper::createParallelTimeContainer() const
2138 const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.animations.ParallelTimeContainer" ) );
2139 return Reference< XTimeContainer >( ::comphelper::getProcessServiceFactory()->createInstance(aServiceName), UNO_QUERY );
2142 // --------------------------------------------------------------------
2144 stl_CustomAnimationEffect_search_node_predict::stl_CustomAnimationEffect_search_node_predict( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xSearchNode )
2145 : mxSearchNode( xSearchNode )
2149 // --------------------------------------------------------------------
2151 bool stl_CustomAnimationEffect_search_node_predict::operator()( CustomAnimationEffectPtr pEffect ) const
2153 return pEffect->getNode() == mxSearchNode;
2156 // --------------------------------------------------------------------
2158 static bool implFindNextContainer( Reference< XTimeContainer >& xParent, Reference< XTimeContainer >& xCurrent, Reference< XTimeContainer >& xNext )
2159 throw(Exception)
2161 Reference< XEnumerationAccess > xEnumerationAccess( xParent, UNO_QUERY_THROW );
2162 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration() );
2163 if( xEnumeration.is() )
2165 Reference< XInterface > x;
2166 while( xEnumeration->hasMoreElements() && !xNext.is() )
2168 if( (xEnumeration->nextElement() >>= x) && (x == xCurrent) )
2170 if( xEnumeration->hasMoreElements() )
2171 xEnumeration->nextElement() >>= xNext;
2175 return xNext.is();
2178 // --------------------------------------------------------------------
2180 void stl_process_after_effect_node_func(AfterEffectNode& rNode)
2184 if( rNode.mxNode.is() && rNode.mxMaster.is() )
2186 // set master node
2187 Reference< XAnimationNode > xMasterNode( rNode.mxMaster, UNO_QUERY_THROW );
2188 Sequence< NamedValue > aUserData( rNode.mxNode->getUserData() );
2189 sal_Int32 nSize = aUserData.getLength();
2190 aUserData.realloc(nSize+1);
2191 aUserData[nSize].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "master-element" ) );
2192 aUserData[nSize].Value <<= xMasterNode;
2193 rNode.mxNode->setUserData( aUserData );
2195 // insert after effect node into timeline
2196 Reference< XTimeContainer > xContainer( rNode.mxMaster->getParent(), UNO_QUERY_THROW );
2198 if( !rNode.mbOnNextEffect ) // sameClick
2200 // insert the aftereffect after its effect is animated
2201 xContainer->insertAfter( rNode.mxNode, rNode.mxMaster );
2203 else // nextClick
2205 Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() );
2206 // insert the aftereffect in the next group
2208 Reference< XTimeContainer > xClickContainer( xContainer->getParent(), UNO_QUERY_THROW );
2209 Reference< XTimeContainer > xSequenceContainer( xClickContainer->getParent(), UNO_QUERY_THROW );
2211 Reference< XTimeContainer > xNextContainer;
2213 // first try if we have an after effect container
2214 if( !implFindNextContainer( xClickContainer, xContainer, xNextContainer ) )
2216 Reference< XTimeContainer > xNextClickContainer;
2217 // if not, try to find the next click effect container
2218 if( implFindNextContainer( xSequenceContainer, xClickContainer, xNextClickContainer ) )
2220 Reference< XEnumerationAccess > xEnumerationAccess( xNextClickContainer, UNO_QUERY_THROW );
2221 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
2222 if( xEnumeration->hasMoreElements() )
2224 // the next container is the first child container
2225 xEnumeration->nextElement() >>= xNextContainer;
2227 else
2229 // this does not yet have a child container, create one
2230 const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.ParallelTimeContainer") );
2231 xNextContainer = Reference< XTimeContainer >::query( xMsf->createInstance(aServiceName) );
2233 if( xNextContainer.is() )
2235 Reference< XAnimationNode > xNode( xNextContainer, UNO_QUERY_THROW );
2236 xNode->setBegin( makeAny( (double)0.0 ) );
2237 // xNode->setFill( AnimationFill::HOLD );
2238 xNextClickContainer->appendChild( xNode );
2241 DBG_ASSERT( xNextContainer.is(), "ppt::stl_process_after_effect_node_func::operator(), could not find/create container!" );
2245 // if we don't have a next container, we add one to the sequence container
2246 if( !xNextContainer.is() )
2248 const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.ParallelTimeContainer") );
2249 Reference< XTimeContainer > xNewClickContainer( xMsf->createInstance(aServiceName), UNO_QUERY_THROW );
2251 Reference< XAnimationNode > xNewClickNode( xNewClickContainer, UNO_QUERY_THROW );
2253 Event aEvent;
2254 aEvent.Trigger = EventTrigger::ON_NEXT;
2255 aEvent.Repeat = 0;
2256 xNewClickNode->setBegin( makeAny( aEvent ) );
2258 Reference< XAnimationNode > xRefNode( xClickContainer, UNO_QUERY_THROW );
2259 xSequenceContainer->insertAfter( xNewClickNode, xRefNode );
2261 xNextContainer = Reference< XTimeContainer >::query( xMsf->createInstance(aServiceName) );
2263 DBG_ASSERT( xNextContainer.is(), "ppt::stl_process_after_effect_node_func::operator(), could not create container!" );
2264 if( xNextContainer.is() )
2266 Reference< XAnimationNode > xNode( xNextContainer, UNO_QUERY_THROW );
2267 xNode->setBegin( makeAny( (double)0.0 ) );
2268 // xNode->setFill( AnimationFill::HOLD );
2269 xNewClickContainer->appendChild( xNode );
2273 if( xNextContainer.is() )
2275 // find begin time of first element
2276 Reference< XEnumerationAccess > xEnumerationAccess( xNextContainer, UNO_QUERY_THROW );
2277 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
2278 if( xEnumeration->hasMoreElements() )
2280 Reference< XAnimationNode > xChild;
2281 // the next container is the first child container
2282 xEnumeration->nextElement() >>= xChild;
2283 if( xChild.is() )
2285 Any aBegin( xChild->getBegin() );
2286 double fBegin = 0.0;
2287 if( (aBegin >>= fBegin) && (fBegin >= 0.0))
2288 rNode.mxNode->setBegin( aBegin );
2292 xNextContainer->appendChild( rNode.mxNode );
2297 catch( Exception& e )
2299 (void)e;
2300 DBG_ERROR( "ppt::stl_process_after_effect_node_func::operator(), exception cought!" );
2304 // --------------------------------------------------------------------
2306 EffectSequence::iterator EffectSequenceHelper::find( const CustomAnimationEffectPtr& pEffect )
2308 return std::find( maEffects.begin(), maEffects.end(), pEffect );
2311 // --------------------------------------------------------------------
2313 CustomAnimationEffectPtr EffectSequenceHelper::findEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) const
2315 CustomAnimationEffectPtr pEffect;
2317 EffectSequence::const_iterator aIter( maEffects.begin() );
2318 for( ; aIter != maEffects.end(); aIter++ )
2320 if( (*aIter)->getNode() == xNode )
2322 pEffect = (*aIter);
2323 break;
2327 return pEffect;
2330 // --------------------------------------------------------------------
2332 sal_Int32 EffectSequenceHelper::getOffsetFromEffect( const CustomAnimationEffectPtr& xEffect ) const
2334 sal_Int32 nOffset = 0;
2336 EffectSequence::const_iterator aIter( maEffects.begin() );
2337 for( ; aIter != maEffects.end(); aIter++, nOffset++ )
2339 if( (*aIter) == xEffect )
2340 return nOffset;
2343 return -1;
2346 // --------------------------------------------------------------------
2348 CustomAnimationEffectPtr EffectSequenceHelper::getEffectFromOffset( sal_Int32 nOffset ) const
2350 EffectSequence::const_iterator aIter( maEffects.begin() );
2351 while( nOffset-- && aIter != maEffects.end() )
2352 aIter++;
2354 CustomAnimationEffectPtr pEffect;
2355 if( aIter != maEffects.end() )
2356 pEffect = (*aIter);
2358 return pEffect;
2361 // --------------------------------------------------------------------
2363 bool EffectSequenceHelper::disposeShape( const Reference< XShape >& xShape )
2365 bool bChanges = false;
2367 EffectSequence::iterator aIter( maEffects.begin() );
2368 while( aIter != maEffects.end() )
2370 if( (*aIter)->getTargetShape() == xShape )
2372 (*aIter)->setEffectSequence( 0 );
2373 bChanges = true;
2374 aIter = maEffects.erase( aIter );
2376 else
2378 aIter++;
2382 return bChanges;
2385 // --------------------------------------------------------------------
2387 bool EffectSequenceHelper::hasEffect( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape )
2389 EffectSequence::iterator aIter( maEffects.begin() );
2390 while( aIter != maEffects.end() )
2392 if( (*aIter)->getTargetShape() == xShape )
2393 return true;
2394 aIter++;
2397 return false;
2400 // --------------------------------------------------------------------
2402 void EffectSequenceHelper::insertTextRange( const com::sun::star::uno::Any& aTarget )
2404 bool bChanges = false;
2406 ParagraphTarget aParaTarget;
2407 if( !(aTarget >>= aParaTarget ) )
2408 return;
2410 EffectSequence::iterator aIter( maEffects.begin() );
2411 while( aIter != maEffects.end() )
2413 if( (*aIter)->getTargetShape() == aParaTarget.Shape )
2414 bChanges |= (*aIter)->checkForText();
2415 aIter++;
2418 if( bChanges )
2419 rebuild();
2422 // --------------------------------------------------------------------
2424 void EffectSequenceHelper::disposeTextRange( const com::sun::star::uno::Any& aTarget )
2426 ParagraphTarget aParaTarget;
2427 if( !(aTarget >>= aParaTarget ) )
2428 return;
2430 bool bChanges = false;
2431 bool bErased = false;
2433 EffectSequence::iterator aIter( maEffects.begin() );
2434 while( aIter != maEffects.end() )
2436 Any aIterTarget( (*aIter)->getTarget() );
2437 if( aIterTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2439 ParagraphTarget aIterParaTarget;
2440 if( (aIterTarget >>= aIterParaTarget) && (aIterParaTarget.Shape == aParaTarget.Shape) )
2442 if( aIterParaTarget.Paragraph == aParaTarget.Paragraph )
2444 // delete this effect if it targets the disposed paragraph directly
2445 (*aIter)->setEffectSequence( 0 );
2446 aIter = maEffects.erase( aIter );
2447 bChanges = true;
2448 bErased = true;
2450 else
2452 if( aIterParaTarget.Paragraph > aParaTarget.Paragraph )
2454 // shift all paragraphs after disposed paragraph
2455 aIterParaTarget.Paragraph--;
2456 (*aIter)->setTarget( makeAny( aIterParaTarget ) );
2461 else if( (*aIter)->getTargetShape() == aParaTarget.Shape )
2463 bChanges |= (*aIter)->checkForText();
2466 if( bErased )
2467 bErased = false;
2468 else
2469 aIter++;
2472 if( bChanges )
2473 rebuild();
2476 // --------------------------------------------------------------------
2478 CustomAnimationTextGroup::CustomAnimationTextGroup( const Reference< XShape >& rTarget, sal_Int32 nGroupId )
2479 : maTarget( rTarget ),
2480 mnGroupId( nGroupId )
2482 reset();
2485 // --------------------------------------------------------------------
2487 void CustomAnimationTextGroup::reset()
2489 mnTextGrouping = -1;
2490 mbAnimateForm = false;
2491 mbTextReverse = false;
2492 mfGroupingAuto = -1.0;
2493 mnLastPara = -1; // used to check for TextReverse
2495 int i = 5;
2496 while( i-- ) mnDepthFlags[i] = 0;
2498 maEffects.clear();
2501 // --------------------------------------------------------------------
2503 void CustomAnimationTextGroup::addEffect( CustomAnimationEffectPtr& pEffect )
2505 maEffects.push_back( pEffect );
2507 Any aTarget( pEffect->getTarget() );
2508 if( aTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2510 // now look at the paragraph
2511 ParagraphTarget aParaTarget;
2512 aTarget >>= aParaTarget;
2514 if( mnLastPara != -1 )
2515 mbTextReverse = mnLastPara > aParaTarget.Paragraph;
2517 mnLastPara = aParaTarget.Paragraph;
2519 const sal_Int32 nParaDepth = pEffect->getParaDepth();
2521 // only look at the first 5 levels
2522 if( nParaDepth < 5 )
2524 // our first paragraph with this level?
2525 if( mnDepthFlags[nParaDepth] == 0 )
2527 // so set it to the first found
2528 mnDepthFlags[nParaDepth] = (sal_Int8)pEffect->getNodeType();
2530 else if( mnDepthFlags[nParaDepth] != pEffect->getNodeType() )
2532 mnDepthFlags[nParaDepth] = -1;
2535 if( pEffect->getNodeType() == EffectNodeType::AFTER_PREVIOUS )
2536 mfGroupingAuto = pEffect->getBegin();
2538 mnTextGrouping = 0;
2539 while( (mnTextGrouping < 5) && (mnDepthFlags[mnTextGrouping] > 0) )
2540 mnTextGrouping++;
2543 else
2545 // if we have an effect with the shape as a target, we animate the background
2546 mbAnimateForm = pEffect->getTargetSubItem() != ShapeAnimationSubType::ONLY_TEXT;
2550 // --------------------------------------------------------------------
2552 class TextGroupMapImpl : public std::map< sal_Int32, CustomAnimationTextGroup* >
2554 public:
2555 CustomAnimationTextGroup* findGroup( sal_Int32 nGroupId );
2558 // --------------------------------------------------------------------
2560 CustomAnimationTextGroupPtr EffectSequenceHelper::findGroup( sal_Int32 nGroupId )
2562 CustomAnimationTextGroupPtr aPtr;
2564 CustomAnimationTextGroupMap::iterator aIter( maGroupMap.find( nGroupId ) );
2565 if( aIter != maGroupMap.end() )
2566 aPtr = (*aIter).second;
2568 return aPtr;
2571 // --------------------------------------------------------------------
2573 void EffectSequenceHelper::updateTextGroups()
2575 maGroupMap.clear();
2577 // first create all the groups
2578 EffectSequence::iterator aIter( maEffects.begin() );
2579 const EffectSequence::iterator aEnd( maEffects.end() );
2580 while( aIter != aEnd )
2582 CustomAnimationEffectPtr pEffect( (*aIter++) );
2584 const sal_Int32 nGroupId = pEffect->getGroupId();
2586 if( nGroupId == -1 )
2587 continue; // trivial case, no group
2589 CustomAnimationTextGroupPtr pGroup = findGroup( nGroupId );
2590 if( !pGroup.get() )
2592 pGroup.reset( new CustomAnimationTextGroup( pEffect->getTargetShape(), nGroupId ) );
2593 maGroupMap[nGroupId] = pGroup;
2596 pGroup->addEffect( pEffect );
2600 // --------------------------------------------------------------------
2602 CustomAnimationTextGroupPtr EffectSequenceHelper::createTextGroup( CustomAnimationEffectPtr pEffect, sal_Int32 nTextGrouping, double fTextGroupingAuto, sal_Bool bAnimateForm, sal_Bool bTextReverse )
2604 // first finde a free group-id
2605 sal_Int32 nGroupId = 0;
2607 CustomAnimationTextGroupMap::iterator aIter( maGroupMap.begin() );
2608 const CustomAnimationTextGroupMap::iterator aEnd( maGroupMap.end() );
2609 while( aIter != aEnd )
2611 if( (*aIter).first == nGroupId )
2613 nGroupId++;
2614 aIter = maGroupMap.begin();
2616 else
2618 aIter++;
2622 Reference< XShape > xTarget( pEffect->getTargetShape() );
2624 CustomAnimationTextGroupPtr pTextGroup( new CustomAnimationTextGroup( xTarget, nGroupId ) );
2625 maGroupMap[nGroupId] = pTextGroup;
2627 bool bUsed = false;
2629 // do we need to target the shape?
2630 if( (nTextGrouping == 0) || bAnimateForm )
2632 sal_Int16 nSubItem;
2633 if( nTextGrouping == 0)
2634 nSubItem = bAnimateForm ? ShapeAnimationSubType::AS_WHOLE : ShapeAnimationSubType::ONLY_TEXT;
2635 else
2636 nSubItem = ShapeAnimationSubType::ONLY_BACKGROUND;
2638 pEffect->setTarget( makeAny( xTarget ) );
2639 pEffect->setTargetSubItem( nSubItem );
2640 pEffect->setEffectSequence( this );
2641 pEffect->setGroupId( nGroupId );
2643 pTextGroup->addEffect( pEffect );
2644 bUsed = true;
2647 pTextGroup->mnTextGrouping = nTextGrouping;
2648 pTextGroup->mfGroupingAuto = fTextGroupingAuto;
2649 pTextGroup->mbTextReverse = bTextReverse;
2651 // now add an effect for each paragraph
2652 createTextGroupParagraphEffects( pTextGroup, pEffect, bUsed );
2654 notify_listeners();
2656 return pTextGroup;
2659 // --------------------------------------------------------------------
2661 void EffectSequenceHelper::createTextGroupParagraphEffects( CustomAnimationTextGroupPtr pTextGroup, CustomAnimationEffectPtr pEffect, bool bUsed )
2663 Reference< XShape > xTarget( pTextGroup->maTarget );
2665 sal_Int32 nTextGrouping = pTextGroup->mnTextGrouping;
2666 double fTextGroupingAuto = pTextGroup->mfGroupingAuto;
2667 sal_Bool bTextReverse = pTextGroup->mbTextReverse;
2669 // now add an effect for each paragraph
2670 if( nTextGrouping >= 0 ) try
2672 EffectSequence::iterator aInsertIter( find( pEffect ) );
2674 const OUString strNumberingLevel( RTL_CONSTASCII_USTRINGPARAM("NumberingLevel") );
2675 Reference< XEnumerationAccess > xText( xTarget, UNO_QUERY_THROW );
2676 Reference< XEnumeration > xEnumeration( xText->createEnumeration(), UNO_QUERY_THROW );
2678 std::list< sal_Int16 > aParaList;
2679 sal_Int16 nPara;
2681 // fill the list with all valid paragraphs
2682 for( nPara = 0; xEnumeration->hasMoreElements(); nPara++ )
2684 Reference< XTextRange > xRange( xEnumeration->nextElement(), UNO_QUERY );
2685 if( xRange.is() && xRange->getString().getLength() )
2687 if( bTextReverse ) // sort them
2688 aParaList.push_front( nPara );
2689 else
2690 aParaList.push_back( nPara );
2694 ParagraphTarget aTarget;
2695 aTarget.Shape = xTarget;
2697 std::list< sal_Int16 >::iterator aIter( aParaList.begin() );
2698 std::list< sal_Int16 >::iterator aEnd( aParaList.end() );
2699 while( aIter != aEnd )
2701 aTarget.Paragraph = (*aIter++);
2703 CustomAnimationEffectPtr pNewEffect;
2704 if( bUsed )
2706 // clone a new effect from first effect
2707 pNewEffect = pEffect->clone();
2708 ++aInsertIter;
2709 aInsertIter = maEffects.insert( aInsertIter, pNewEffect );
2711 else
2713 // reuse first effect if its not yet used
2714 pNewEffect = pEffect;
2715 bUsed = true;
2716 aInsertIter = find( pNewEffect );
2719 // set target and group-id
2720 pNewEffect->setTarget( makeAny( aTarget ) );
2721 pNewEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT );
2722 pNewEffect->setGroupId( pTextGroup->mnGroupId );
2723 pNewEffect->setEffectSequence( this );
2725 // set correct node type
2726 if( pNewEffect->getParaDepth() < nTextGrouping )
2728 if( fTextGroupingAuto == -1.0 )
2730 pNewEffect->setNodeType( EffectNodeType::ON_CLICK );
2731 pNewEffect->setBegin( 0.0 );
2733 else
2735 pNewEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2736 pNewEffect->setBegin( fTextGroupingAuto );
2739 else
2741 pNewEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2742 pNewEffect->setBegin( 0.0 );
2745 pTextGroup->addEffect( pNewEffect );
2747 notify_listeners();
2749 catch( Exception& e )
2751 (void)e;
2752 DBG_ERROR("sd::EffectSequenceHelper::createTextGroup(), exception cought!" );
2756 // --------------------------------------------------------------------
2758 void EffectSequenceHelper::setTextGrouping( CustomAnimationTextGroupPtr pTextGroup, sal_Int32 nTextGrouping )
2760 if( pTextGroup->mnTextGrouping == nTextGrouping )
2762 // first case, trivial case, do nothing
2764 else if( (pTextGroup->mnTextGrouping == -1) && (nTextGrouping >= 0) )
2766 // second case, we need to add new effects for each paragraph
2768 CustomAnimationEffectPtr pEffect( pTextGroup->maEffects.front() );
2770 pTextGroup->mnTextGrouping = nTextGrouping;
2771 createTextGroupParagraphEffects( pTextGroup, pEffect, true );
2772 notify_listeners();
2774 else if( (pTextGroup->mnTextGrouping >= 0) && (nTextGrouping == -1 ) )
2776 // third case, we need to remove effects for each paragraph
2778 EffectSequence aEffects( pTextGroup->maEffects );
2779 pTextGroup->reset();
2781 EffectSequence::iterator aIter( aEffects.begin() );
2782 const EffectSequence::iterator aEnd( aEffects.end() );
2783 while( aIter != aEnd )
2785 CustomAnimationEffectPtr pEffect( (*aIter++) );
2787 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2788 remove( pEffect );
2789 else
2790 pTextGroup->addEffect( pEffect );
2792 notify_listeners();
2794 else
2796 // fourth case, we need to change the node types for the text nodes
2797 double fTextGroupingAuto = pTextGroup->mfGroupingAuto;
2799 EffectSequence aEffects( pTextGroup->maEffects );
2800 pTextGroup->reset();
2802 EffectSequence::iterator aIter( aEffects.begin() );
2803 const EffectSequence::iterator aEnd( aEffects.end() );
2804 while( aIter != aEnd )
2806 CustomAnimationEffectPtr pEffect( (*aIter++) );
2808 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2810 // set correct node type
2811 if( pEffect->getParaDepth() < nTextGrouping )
2813 if( fTextGroupingAuto == -1.0 )
2815 pEffect->setNodeType( EffectNodeType::ON_CLICK );
2816 pEffect->setBegin( 0.0 );
2818 else
2820 pEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2821 pEffect->setBegin( fTextGroupingAuto );
2824 else
2826 pEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2827 pEffect->setBegin( 0.0 );
2831 pTextGroup->addEffect( pEffect );
2834 notify_listeners();
2838 // --------------------------------------------------------------------
2840 void EffectSequenceHelper::setAnimateForm( CustomAnimationTextGroupPtr pTextGroup, sal_Bool bAnimateForm )
2842 if( pTextGroup->mbAnimateForm == bAnimateForm )
2844 // trivial case, do nothing
2846 else
2848 EffectSequence aEffects( pTextGroup->maEffects );
2849 pTextGroup->reset();
2851 EffectSequence::iterator aIter( aEffects.begin() );
2852 const EffectSequence::iterator aEnd( aEffects.end() );
2854 // first insert if we have to
2855 if( bAnimateForm )
2857 EffectSequence::iterator aInsertIter( find( (*aIter) ) );
2859 CustomAnimationEffectPtr pEffect;
2860 if( (aEffects.size() == 1) && ((*aIter)->getTarget().getValueType() != ::getCppuType((const ParagraphTarget*)0) ) )
2862 // special case, only one effect and that targets whole text,
2863 // convert this to target whole shape
2864 pEffect = (*aIter++);
2865 pEffect->setTargetSubItem( ShapeAnimationSubType::AS_WHOLE );
2867 else
2869 pEffect = (*aIter)->clone();
2870 pEffect->setTarget( makeAny( (*aIter)->getTargetShape() ) );
2871 pEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_BACKGROUND );
2872 maEffects.insert( aInsertIter, pEffect );
2875 pTextGroup->addEffect( pEffect );
2878 if( !bAnimateForm && (aEffects.size() == 1) )
2880 CustomAnimationEffectPtr pEffect( (*aIter) );
2881 pEffect->setTarget( makeAny( (*aIter)->getTargetShape() ) );
2882 pEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT );
2883 pTextGroup->addEffect( pEffect );
2885 else
2887 // readd the rest to the group again
2888 while( aIter != aEnd )
2890 CustomAnimationEffectPtr pEffect( (*aIter++) );
2892 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2894 pTextGroup->addEffect( pEffect );
2896 else
2898 DBG_ASSERT( !bAnimateForm, "sd::EffectSequenceHelper::setAnimateForm(), something is wrong here!" );
2899 remove( pEffect );
2903 notify_listeners();
2907 // --------------------------------------------------------------------
2909 void EffectSequenceHelper::setTextGroupingAuto( CustomAnimationTextGroupPtr pTextGroup, double fTextGroupingAuto )
2911 sal_Int32 nTextGrouping = pTextGroup->mnTextGrouping;
2913 EffectSequence aEffects( pTextGroup->maEffects );
2914 pTextGroup->reset();
2916 EffectSequence::iterator aIter( aEffects.begin() );
2917 const EffectSequence::iterator aEnd( aEffects.end() );
2918 while( aIter != aEnd )
2920 CustomAnimationEffectPtr pEffect( (*aIter++) );
2922 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2924 // set correct node type
2925 if( pEffect->getParaDepth() < nTextGrouping )
2927 if( fTextGroupingAuto == -1.0 )
2929 pEffect->setNodeType( EffectNodeType::ON_CLICK );
2930 pEffect->setBegin( 0.0 );
2932 else
2934 pEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2935 pEffect->setBegin( fTextGroupingAuto );
2938 else
2940 pEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2941 pEffect->setBegin( 0.0 );
2945 pTextGroup->addEffect( pEffect );
2948 notify_listeners();
2951 // --------------------------------------------------------------------
2953 struct ImplStlTextGroupSortHelper
2955 ImplStlTextGroupSortHelper( bool bReverse ) : mbReverse( bReverse ) {};
2956 bool operator()( const CustomAnimationEffectPtr& p1, const CustomAnimationEffectPtr& p2 );
2957 bool mbReverse;
2958 sal_Int32 getTargetParagraph( const CustomAnimationEffectPtr& p1 );
2961 // --------------------------------------------------------------------
2963 sal_Int32 ImplStlTextGroupSortHelper::getTargetParagraph( const CustomAnimationEffectPtr& p1 )
2965 const Any aTarget(p1->getTarget());
2966 if( aTarget.hasValue() && aTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2968 ParagraphTarget aParaTarget;
2969 aTarget >>= aParaTarget;
2970 return aParaTarget.Paragraph;
2972 else
2974 return mbReverse ? 0x7fffffff : -1;
2978 // --------------------------------------------------------------------
2980 bool ImplStlTextGroupSortHelper::operator()( const CustomAnimationEffectPtr& p1, const CustomAnimationEffectPtr& p2 )
2982 if( mbReverse )
2984 return getTargetParagraph( p2 ) < getTargetParagraph( p1 );
2986 else
2988 return getTargetParagraph( p1 ) < getTargetParagraph( p2 );
2992 // --------------------------------------------------------------------
2994 void EffectSequenceHelper::setTextReverse( CustomAnimationTextGroupPtr pTextGroup, sal_Bool bTextReverse )
2996 if( pTextGroup->mbTextReverse == bTextReverse )
2998 // do nothing
3000 else
3002 std::vector< CustomAnimationEffectPtr > aSortedVector(pTextGroup->maEffects.size());
3003 std::copy( pTextGroup->maEffects.begin(), pTextGroup->maEffects.end(), aSortedVector.begin() );
3004 ImplStlTextGroupSortHelper aSortHelper( bTextReverse );
3005 std::sort( aSortedVector.begin(), aSortedVector.end(), aSortHelper );
3007 pTextGroup->reset();
3009 std::vector< CustomAnimationEffectPtr >::iterator aIter( aSortedVector.begin() );
3010 const std::vector< CustomAnimationEffectPtr >::iterator aEnd( aSortedVector.end() );
3012 if( aIter != aEnd )
3014 pTextGroup->addEffect( (*aIter ) );
3015 EffectSequence::iterator aInsertIter( find( (*aIter++) ) );
3016 while( aIter != aEnd )
3018 CustomAnimationEffectPtr pEffect( (*aIter++) );
3019 maEffects.erase( find( pEffect ) );
3020 aInsertIter = maEffects.insert( ++aInsertIter, pEffect );
3021 pTextGroup->addEffect( pEffect );
3024 notify_listeners();
3028 // --------------------------------------------------------------------
3030 void EffectSequenceHelper::addListener( ISequenceListener* pListener )
3032 if( std::find( maListeners.begin(), maListeners.end(), pListener ) == maListeners.end() )
3033 maListeners.push_back( pListener );
3036 // --------------------------------------------------------------------
3038 void EffectSequenceHelper::removeListener( ISequenceListener* pListener )
3040 maListeners.remove( pListener );
3043 // --------------------------------------------------------------------
3045 struct stl_notify_listeners_func : public std::unary_function<ISequenceListener*, void>
3047 stl_notify_listeners_func() {}
3048 void operator()(ISequenceListener* pListener) { pListener->notify_change(); }
3051 // --------------------------------------------------------------------
3053 void EffectSequenceHelper::notify_listeners()
3055 stl_notify_listeners_func aFunc;
3056 std::for_each( maListeners.begin(), maListeners.end(), aFunc );
3059 // --------------------------------------------------------------------
3061 void EffectSequenceHelper::create( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
3063 DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::create(), illegal argument" );
3065 if( xNode.is() ) try
3067 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
3068 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3069 while( xEnumeration->hasMoreElements() )
3071 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3072 createEffectsequence( xChildNode );
3075 catch( Exception& )
3077 DBG_ERROR( "sd::EffectSequenceHelper::create(), exception cought!" );
3081 // --------------------------------------------------------------------
3083 void EffectSequenceHelper::createEffectsequence( const Reference< XAnimationNode >& xNode )
3085 DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::createEffectsequence(), illegal argument" );
3087 if( xNode.is() ) try
3089 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
3090 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3091 while( xEnumeration->hasMoreElements() )
3093 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3095 createEffects( xChildNode );
3098 catch( Exception& )
3100 DBG_ERROR( "sd::EffectSequenceHelper::createEffectsequence(), exception cought!" );
3104 // --------------------------------------------------------------------
3106 void EffectSequenceHelper::createEffects( const Reference< XAnimationNode >& xNode )
3108 DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::createEffects(), illegal argument" );
3110 if( xNode.is() ) try
3112 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
3113 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3114 while( xEnumeration->hasMoreElements() )
3116 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3118 switch( xChildNode->getType() )
3120 // found an effect
3121 case AnimationNodeType::PAR:
3122 case AnimationNodeType::ITERATE:
3124 CustomAnimationEffectPtr pEffect( new CustomAnimationEffect( xChildNode ) );
3126 if( pEffect->mnNodeType != -1 )
3128 pEffect->setEffectSequence( this );
3129 maEffects.push_back(pEffect);
3132 break;
3134 // found an after effect
3135 case AnimationNodeType::SET:
3136 case AnimationNodeType::ANIMATECOLOR:
3138 processAfterEffect( xChildNode );
3140 break;
3144 catch( Exception& e )
3146 (void)e;
3147 DBG_ERROR( "sd::EffectSequenceHelper::createEffects(), exception cought!" );
3151 // --------------------------------------------------------------------
3153 void EffectSequenceHelper::processAfterEffect( const Reference< XAnimationNode >& xNode )
3157 Reference< XAnimationNode > xMaster;
3159 Sequence< NamedValue > aUserData( xNode->getUserData() );
3160 sal_Int32 nLength = aUserData.getLength();
3161 const NamedValue* p = aUserData.getConstArray();
3163 while( nLength-- )
3165 if( p->Name.equalsAscii( "master-element" ) )
3167 p->Value >>= xMaster;
3168 break;
3170 p++;
3173 // only process if this is a valid after effect
3174 if( xMaster.is() )
3176 CustomAnimationEffectPtr pMasterEffect;
3178 // find the master effect
3179 stl_CustomAnimationEffect_search_node_predict aSearchPredict( xMaster );
3180 EffectSequence::iterator aIter( std::find_if( maEffects.begin(), maEffects.end(), aSearchPredict ) );
3181 if( aIter != maEffects.end() )
3182 pMasterEffect = (*aIter );
3184 if( pMasterEffect.get() )
3186 pMasterEffect->setHasAfterEffect( true );
3188 // find out what kind of after effect this is
3189 if( xNode->getType() == AnimationNodeType::ANIMATECOLOR )
3191 // its a dim
3192 Reference< XAnimate > xAnimate( xNode, UNO_QUERY_THROW );
3193 pMasterEffect->setDimColor( xAnimate->getTo() );
3194 pMasterEffect->setAfterEffectOnNext( true );
3196 else
3198 // its a hide
3199 Reference< XChild > xNodeChild( xNode, UNO_QUERY_THROW );
3200 Reference< XChild > xMasterChild( xMaster, UNO_QUERY_THROW );
3201 pMasterEffect->setAfterEffectOnNext( xNodeChild->getParent() != xMasterChild->getParent() );
3206 catch( Exception& e )
3208 (void)e;
3209 DBG_ERROR( "sd::EffectSequenceHelper::processAfterEffect(), exception cought!" );
3214 double EffectSequenceHelper::calculateIterateNodeDuration(
3216 Reference< i18n::XBreakIterator > xBI( ImplGetBreakIterator() );
3218 sal_Int32 nDone;
3219 sal_Int32 nNextCellBreak( xBI->nextCharacters(rTxt, nIdx, rLocale, i18n::CharacterIteratorMode::SKIPCELL, 0, nDone) );
3220 i18n::Boundary nNextWordBoundary( xBI->getWordBoundary(rTxt, nIdx, rLocale, i18n::WordType::ANY_WORD, sal_True) );
3221 sal_Int32 nNextSentenceBreak( xBI->endOfSentence(rTxt, nIdx, rLocale) );
3223 const sal_Int32 nEndPos( nIdx + nLen );
3224 sal_Int32 i, currOffset(0);
3225 for( i=nIdx; i<nEndPos; ++i )
3227 // TODO: Check whether position update is valid for CTL/BiDi
3228 rOutDev.DrawText( rPos + Point(currOffset,0), rTxt, i, 1 );
3229 currOffset = *pDXArray++;
3231 // issue the comments at the respective break positions
3232 if( i == nNextCellBreak )
3234 rMtf.AddAction( new MetaCommentAction( "XTEXT_EOC" ) );
3235 nNextCellBreak = xBI->nextCharacters(rTxt, i, rLocale, i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
3237 if( i == nNextWordBoundary.endPos )
3239 rMtf.AddAction( new MetaCommentAction( "XTEXT_EOW" ) );
3240 nNextWordBoundary = xBI->getWordBoundary(rTxt, i+1, rLocale, i18n::WordType::ANY_WORD, sal_True);
3242 if( i == nNextSentenceBreak )
3244 rMtf.AddAction( new MetaCommentAction( "XTEXT_EOS" ) );
3245 nNextSentenceBreak = xBI->endOfSentence(rTxt, i+1, rLocale);
3251 // ====================================================================
3253 class AnimationChangeListener : public cppu::WeakImplHelper1< XChangesListener >
3255 public:
3256 AnimationChangeListener( MainSequence* pMainSequence ) : mpMainSequence( pMainSequence ) {}
3258 virtual void SAL_CALL changesOccurred( const ::com::sun::star::util::ChangesEvent& Event ) throw (RuntimeException);
3259 virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (RuntimeException);
3260 private:
3261 MainSequence* mpMainSequence;
3264 void SAL_CALL AnimationChangeListener::changesOccurred( const ::com::sun::star::util::ChangesEvent& ) throw (RuntimeException)
3266 if( mpMainSequence )
3267 mpMainSequence->startRecreateTimer();
3270 void SAL_CALL AnimationChangeListener::disposing( const ::com::sun::star::lang::EventObject& ) throw (RuntimeException)
3274 // ====================================================================
3276 MainSequence::MainSequence()
3277 : mxTimingRootNode( ::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.SequenceTimeContainer"))), UNO_QUERY )
3278 , mbRebuilding( false )
3279 , mnRebuildLockGuard( 0 )
3280 , mbPendingRebuildRequest( false )
3282 if( mxTimingRootNode.is() )
3284 Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
3285 aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
3286 aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::MAIN_SEQUENCE;
3287 mxTimingRootNode->setUserData( aUserData );
3289 init();
3292 // --------------------------------------------------------------------
3294 MainSequence::MainSequence( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
3295 : mxTimingRootNode( xNode, UNO_QUERY )
3296 , mbRebuilding( false )
3297 , mnRebuildLockGuard( 0 )
3298 , mbPendingRebuildRequest( false )
3299 , mbIgnoreChanges( 0 )
3301 init();
3304 // --------------------------------------------------------------------
3306 MainSequence::~MainSequence()
3308 reset();
3311 // --------------------------------------------------------------------
3313 void MainSequence::init()
3315 mnSequenceType = EffectNodeType::MAIN_SEQUENCE;
3317 maTimer.SetTimeoutHdl( LINK(this, MainSequence, onTimerHdl) );
3318 maTimer.SetTimeout(500);
3320 mxChangesListener.set( new AnimationChangeListener( this ) );
3322 createMainSequence();
3325 // --------------------------------------------------------------------
3327 void MainSequence::reset( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xTimingRootNode )
3329 reset();
3331 mxTimingRootNode.set( xTimingRootNode, UNO_QUERY );
3333 createMainSequence();
3336 // --------------------------------------------------------------------
3338 Reference< ::com::sun::star::animations::XAnimationNode > MainSequence::getRootNode()
3340 DBG_ASSERT( mnRebuildLockGuard == 0, "MainSequence::getRootNode(), rebuild is locked, ist this really what you want?" );
3342 if( maTimer.IsActive() && mbTimerMode )
3344 // force a rebuild NOW if one is pending
3345 maTimer.Stop();
3346 implRebuild();
3349 return EffectSequenceHelper::getRootNode();
3352 // --------------------------------------------------------------------
3354 void MainSequence::createMainSequence()
3356 if( mxTimingRootNode.is() ) try
3358 Reference< XEnumerationAccess > xEnumerationAccess( mxTimingRootNode, UNO_QUERY_THROW );
3359 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3360 while( xEnumeration->hasMoreElements() )
3362 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3363 sal_Int32 nNodeType = CustomAnimationEffect::get_node_type( xChildNode );
3364 if( nNodeType == EffectNodeType::MAIN_SEQUENCE )
3366 mxSequenceRoot.set( xChildNode, UNO_QUERY );
3367 EffectSequenceHelper::create( xChildNode );
3369 else if( nNodeType == EffectNodeType::INTERACTIVE_SEQUENCE )
3371 Reference< XTimeContainer > xInteractiveRoot( xChildNode, UNO_QUERY_THROW );
3372 InteractiveSequencePtr pIS( new InteractiveSequence( xInteractiveRoot, this ) );
3373 pIS->addListener( this );
3374 maInteractiveSequenceList.push_back( pIS );
3378 // see if we have a mainsequence at all. if not, create one...
3379 if( !mxSequenceRoot.is() )
3381 mxSequenceRoot = Reference< XTimeContainer >::query(::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.SequenceTimeContainer"))));
3382 if( mxSequenceRoot.is() )
3384 uno::Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
3385 aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
3386 aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::MAIN_SEQUENCE;
3387 mxSequenceRoot->setUserData( aUserData );
3389 // empty sequence until now, set duration to 0.0
3390 // explicitely (otherwise, this sequence will never
3391 // end)
3392 mxSequenceRoot->setDuration( makeAny((double)0.0) );
3394 Reference< XAnimationNode > xMainSequenceNode( mxSequenceRoot, UNO_QUERY_THROW );
3395 mxTimingRootNode->appendChild( xMainSequenceNode );
3399 updateTextGroups();
3401 notify_listeners();
3403 Reference< XChangesNotifier > xNotifier( mxTimingRootNode, UNO_QUERY );
3404 if( xNotifier.is() )
3405 xNotifier->addChangesListener( mxChangesListener );
3407 catch( Exception& e )
3409 (void)e;
3410 DBG_ERROR( "sd::MainSequence::create(), exception cought!" );
3411 return;
3414 DBG_ASSERT( mxSequenceRoot.is(), "sd::MainSequence::create(), found no main sequence!" );
3417 // --------------------------------------------------------------------
3419 void MainSequence::reset()
3421 EffectSequenceHelper::reset();
3423 InteractiveSequenceList::iterator aIter;
3424 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3425 (*aIter)->reset();
3426 maInteractiveSequenceList.clear();
3430 Reference< XChangesNotifier > xNotifier( mxTimingRootNode, UNO_QUERY );
3431 if( xNotifier.is() )
3432 xNotifier->removeChangesListener( mxChangesListener );
3434 catch( Exception& )
3436 // ...
3440 // --------------------------------------------------------------------
3442 InteractiveSequencePtr MainSequence::createInteractiveSequence( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xShape )
3444 InteractiveSequencePtr pIS;
3446 // create a new interactive sequence container
3447 Reference< XTimeContainer > xISRoot( ::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.SequenceTimeContainer"))), UNO_QUERY );
3448 DBG_ASSERT( xISRoot.is(), "sd::MainSequence::createInteractiveSequence(), could not create \"com.sun.star.animations.SequenceTimeContainer\"!");
3449 if( xISRoot.is() )
3451 uno::Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
3452 aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
3453 aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::INTERACTIVE_SEQUENCE ;
3454 xISRoot->setUserData( aUserData );
3456 Reference< XChild > xChild( mxSequenceRoot, UNO_QUERY_THROW );
3457 Reference< XAnimationNode > xISNode( xISRoot, UNO_QUERY_THROW );
3458 Reference< XTimeContainer > xParent( xChild->getParent(), UNO_QUERY_THROW );
3459 xParent->appendChild( xISNode );
3461 pIS.reset( new InteractiveSequence( xISRoot, this) );
3462 pIS->setTriggerShape( xShape );
3463 pIS->addListener( this );
3464 maInteractiveSequenceList.push_back( pIS );
3465 return pIS;
3468 // --------------------------------------------------------------------
3470 CustomAnimationEffectPtr MainSequence::findEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) const
3472 CustomAnimationEffectPtr pEffect = EffectSequenceHelper::findEffect( xNode );
3474 if( pEffect.get() == 0 )
3476 InteractiveSequenceList::const_iterator aIter;
3477 for( aIter = maInteractiveSequenceList.begin(); (aIter != maInteractiveSequenceList.end()) && (pEffect.get() == 0); aIter++ )
3479 pEffect = (*aIter)->findEffect( xNode );
3482 return pEffect;
3485 // --------------------------------------------------------------------
3487 sal_Int32 MainSequence::getOffsetFromEffect( const CustomAnimationEffectPtr& pEffect ) const
3489 sal_Int32 nOffset = EffectSequenceHelper::getOffsetFromEffect( pEffect );
3491 if( nOffset != -1 )
3492 return nOffset;
3494 nOffset = EffectSequenceHelper::getCount();
3496 InteractiveSequenceList::const_iterator aIter;
3497 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3499 sal_Int32 nTemp = (*aIter)->getOffsetFromEffect( pEffect );
3500 if( nTemp != -1 )
3501 return nOffset + nTemp;
3503 nOffset += (*aIter)->getCount();
3506 return -1;
3509 // --------------------------------------------------------------------
3511 CustomAnimationEffectPtr MainSequence::getEffectFromOffset( sal_Int32 nOffset ) const
3513 if( nOffset >= 0 )
3515 if( nOffset < getCount() )
3516 return EffectSequenceHelper::getEffectFromOffset( nOffset );
3518 nOffset -= getCount();
3520 InteractiveSequenceList::const_iterator aIter( maInteractiveSequenceList.begin() );
3522 while( (aIter != maInteractiveSequenceList.end()) && (nOffset > (*aIter)->getCount()) )
3523 nOffset -= (*aIter++)->getCount();
3525 if( (aIter != maInteractiveSequenceList.end()) && (nOffset >= 0) )
3526 return (*aIter)->getEffectFromOffset( nOffset );
3529 CustomAnimationEffectPtr pEffect;
3530 return pEffect;
3533 // --------------------------------------------------------------------
3535 bool MainSequence::disposeShape( const Reference< XShape >& xShape )
3537 bool bChanges = EffectSequenceHelper::disposeShape( xShape );
3539 InteractiveSequenceList::iterator aIter;
3540 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); )
3542 if( (*aIter)->getTriggerShape() == xShape )
3544 aIter = maInteractiveSequenceList.erase( aIter );
3545 bChanges = true;
3547 else
3549 bChanges |= (*aIter++)->disposeShape( xShape );
3553 if( bChanges )
3554 startRebuildTimer();
3556 return bChanges;
3559 // --------------------------------------------------------------------
3561 bool MainSequence::hasEffect( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape )
3563 if( EffectSequenceHelper::hasEffect( xShape ) )
3564 return true;
3566 InteractiveSequenceList::iterator aIter;
3567 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); )
3569 if( (*aIter)->getTriggerShape() == xShape )
3570 return true;
3572 if( (*aIter++)->hasEffect( xShape ) )
3573 return true;
3576 return false;
3579 // --------------------------------------------------------------------
3581 void MainSequence::insertTextRange( const com::sun::star::uno::Any& aTarget )
3583 EffectSequenceHelper::insertTextRange( aTarget );
3585 InteractiveSequenceList::iterator aIter;
3586 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3588 (*aIter)->insertTextRange( aTarget );
3591 // --------------------------------------------------------------------
3593 void MainSequence::disposeTextRange( const com::sun::star::uno::Any& aTarget )
3595 EffectSequenceHelper::disposeTextRange( aTarget );
3597 InteractiveSequenceList::iterator aIter;
3598 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3600 (*aIter)->disposeTextRange( aTarget );
3604 // --------------------------------------------------------------------
3606 /** callback from the sd::View when an object just left text edit mode */
3607 void MainSequence::onTextChanged( const Reference< XShape >& xShape )
3609 EffectSequenceHelper::onTextChanged( xShape );
3611 InteractiveSequenceList::iterator aIter;
3612 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3614 (*aIter)->onTextChanged( xShape );
3618 // --------------------------------------------------------------------
3620 void EffectSequenceHelper::onTextChanged( const Reference< XShape >& xShape )
3622 bool bChanges = false;
3624 EffectSequence::iterator aIter;
3625 for( aIter = maEffects.begin(); aIter != maEffects.end(); aIter++ )
3627 if( (*aIter)->getTargetShape() == xShape )
3628 bChanges |= (*aIter)->checkForText();
3631 if( bChanges )
3632 EffectSequenceHelper::implRebuild();
3635 // --------------------------------------------------------------------
3637 void MainSequence::rebuild()
3639 startRebuildTimer();
3642 // --------------------------------------------------------------------
3644 void MainSequence::lockRebuilds()
3646 mnRebuildLockGuard++;
3649 // --------------------------------------------------------------------
3651 void MainSequence::unlockRebuilds()
3653 DBG_ASSERT( mnRebuildLockGuard, "sd::MainSequence::unlockRebuilds(), no corresponding lockRebuilds() call!" );
3654 if( mnRebuildLockGuard )
3655 mnRebuildLockGuard--;
3657 if( (mnRebuildLockGuard == 0) && mbPendingRebuildRequest )
3659 mbPendingRebuildRequest = false;
3660 startRebuildTimer();
3664 // --------------------------------------------------------------------
3666 void MainSequence::implRebuild()
3668 if( mnRebuildLockGuard )
3670 mbPendingRebuildRequest = true;
3671 return;
3674 mbRebuilding = true;
3676 EffectSequenceHelper::implRebuild();
3678 InteractiveSequenceList::iterator aIter( maInteractiveSequenceList.begin() );
3679 const InteractiveSequenceList::iterator aEnd( maInteractiveSequenceList.end() );
3680 while( aIter != aEnd )
3682 InteractiveSequencePtr pIS( (*aIter) );
3683 if( pIS->maEffects.empty() )
3685 // remove empty interactive sequences
3686 aIter = maInteractiveSequenceList.erase( aIter );
3688 Reference< XChild > xChild( mxSequenceRoot, UNO_QUERY_THROW );
3689 Reference< XTimeContainer > xParent( xChild->getParent(), UNO_QUERY_THROW );
3690 Reference< XAnimationNode > xISNode( pIS->mxSequenceRoot, UNO_QUERY_THROW );
3691 xParent->removeChild( xISNode );
3693 else
3695 pIS->implRebuild();
3696 aIter++;
3700 notify_listeners();
3701 mbRebuilding = false;
3704 // --------------------------------------------------------------------
3706 void MainSequence::notify_change()
3708 notify_listeners();
3711 // --------------------------------------------------------------------
3713 bool MainSequence::setTrigger( const CustomAnimationEffectPtr& pEffect, const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xTriggerShape )
3715 EffectSequenceHelper* pOldSequence = pEffect->getEffectSequence();
3717 EffectSequenceHelper* pNewSequence = 0;
3718 if( xTriggerShape.is() )
3720 InteractiveSequenceList::iterator aIter( maInteractiveSequenceList.begin() );
3721 const InteractiveSequenceList::iterator aEnd( maInteractiveSequenceList.end() );
3722 while( aIter != aEnd )
3724 InteractiveSequencePtr pIS( (*aIter++) );
3725 if( pIS->getTriggerShape() == xTriggerShape )
3727 pNewSequence = pIS.get();
3728 break;
3732 if( !pNewSequence )
3733 pNewSequence = createInteractiveSequence( xTriggerShape ).get();
3735 else
3737 pNewSequence = this;
3740 if( pOldSequence != pNewSequence )
3742 if( pOldSequence )
3743 pOldSequence->maEffects.remove( pEffect );
3744 if( pNewSequence )
3745 pNewSequence->maEffects.push_back( pEffect );
3746 pEffect->setEffectSequence( pNewSequence );
3747 return true;
3749 else
3751 return false;
3756 // --------------------------------------------------------------------
3758 IMPL_LINK( MainSequence, onTimerHdl, Timer *, EMPTYARG )
3760 if( mbTimerMode )
3762 implRebuild();
3764 else
3766 reset();
3767 createMainSequence();
3770 return 0;
3773 // --------------------------------------------------------------------
3775 /** starts a timer that recreates the internal structure from the API core after 1 second */
3776 void MainSequence::startRecreateTimer()
3778 if( !mbRebuilding && (mbIgnoreChanges == 0) )
3780 mbTimerMode = false;
3781 maTimer.Start();
3785 // --------------------------------------------------------------------
3787 /** starts a timer that rebuilds the API core from the internal structure after 1 second */
3788 void MainSequence::startRebuildTimer()
3790 mbTimerMode = true;
3791 maTimer.Start();
3794 // ====================================================================
3796 InteractiveSequence::InteractiveSequence( const Reference< XTimeContainer >& xSequenceRoot, MainSequence* pMainSequence )
3797 : EffectSequenceHelper( xSequenceRoot ), mpMainSequence( pMainSequence )
3799 mnSequenceType = EffectNodeType::INTERACTIVE_SEQUENCE;
3803 if( mxSequenceRoot.is() )
3805 Reference< XEnumerationAccess > xEnumerationAccess( mxSequenceRoot, UNO_QUERY_THROW );
3806 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3807 while( !mxEventSource.is() && xEnumeration->hasMoreElements() )
3809 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3811 Event aEvent;
3812 if( (xChildNode->getBegin() >>= aEvent) && (aEvent.Trigger == EventTrigger::ON_CLICK) )
3813 aEvent.Source >>= mxEventSource;
3817 catch( Exception& e )
3819 (void)e;
3820 DBG_ERROR( "sd::InteractiveSequence::InteractiveSequence(), exception cought!" );
3821 return;
3825 // --------------------------------------------------------------------
3827 void InteractiveSequence::rebuild()
3829 mpMainSequence->rebuild();
3832 void InteractiveSequence::implRebuild()
3834 EffectSequenceHelper::implRebuild();
3837 // --------------------------------------------------------------------
3839 MainSequenceRebuildGuard::MainSequenceRebuildGuard( const MainSequencePtr& pMainSequence )
3840 : mpMainSequence( pMainSequence )
3842 if( mpMainSequence.get() )
3843 mpMainSequence->lockRebuilds();
3846 MainSequenceRebuildGuard::~MainSequenceRebuildGuard()
3848 if( mpMainSequence.get() )
3849 mpMainSequence->unlockRebuilds();