1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <tools/debug.hxx>
21 #include <com/sun/star/animations/AnimationNodeType.hpp>
22 #include <com/sun/star/animations/AnimateColor.hpp>
23 #include <com/sun/star/animations/AnimateMotion.hpp>
24 #include <com/sun/star/animations/AnimateSet.hpp>
25 #include <com/sun/star/animations/AnimationFill.hpp>
26 #include <com/sun/star/animations/AnimationTransformType.hpp>
27 #include <com/sun/star/animations/Audio.hpp>
28 #include <com/sun/star/animations/Command.hpp>
29 #include <com/sun/star/animations/Event.hpp>
30 #include <com/sun/star/animations/EventTrigger.hpp>
31 #include <com/sun/star/animations/IterateContainer.hpp>
32 #include <com/sun/star/animations/ParallelTimeContainer.hpp>
33 #include <com/sun/star/animations/SequenceTimeContainer.hpp>
34 #include <com/sun/star/animations/Timing.hpp>
35 #include <com/sun/star/animations/XCommand.hpp>
36 #include <com/sun/star/animations/XIterateContainer.hpp>
37 #include <com/sun/star/animations/XAnimateTransform.hpp>
38 #include <com/sun/star/animations/XAnimateMotion.hpp>
39 #include <com/sun/star/animations/XAnimate.hpp>
40 #include <com/sun/star/beans/NamedValue.hpp>
41 #include <com/sun/star/beans/XPropertySet.hpp>
42 #include <com/sun/star/container/XEnumerationAccess.hpp>
43 #include <com/sun/star/drawing/XDrawPage.hpp>
44 #include <com/sun/star/lang/XInitialization.hpp>
45 #include <com/sun/star/presentation/EffectNodeType.hpp>
46 #include <com/sun/star/presentation/EffectCommands.hpp>
47 #include <com/sun/star/presentation/EffectPresetClass.hpp>
48 #include <com/sun/star/presentation/ParagraphTarget.hpp>
49 #include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
50 #include <com/sun/star/text/XText.hpp>
51 #include <com/sun/star/util/XCloneable.hpp>
52 #include <com/sun/star/util/XChangesNotifier.hpp>
53 #include <comphelper/processfactory.hxx>
54 #include <comphelper/sequence.hxx>
55 #include <com/sun/star/lang/Locale.hpp>
56 #include <com/sun/star/i18n/BreakIterator.hpp>
57 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
58 #include <com/sun/star/i18n/WordType.hpp>
59 #include <com/sun/star/presentation/TextAnimationType.hpp>
61 #include <basegfx/polygon/b2dpolypolygon.hxx>
62 #include <basegfx/polygon/b2dpolypolygontools.hxx>
63 #include <basegfx/matrix/b2dhommatrix.hxx>
64 #include <basegfx/range/b2drange.hxx>
65 #include <basegfx/matrix/b2dhommatrixtools.hxx>
69 #include <cppuhelper/implbase1.hxx>
71 #include <drawinglayer/geometry/viewinformation2d.hxx>
72 #include <svx/sdr/contact/viewcontact.hxx>
73 #include <svx/svdopath.hxx>
74 #include <svx/svdpage.hxx>
75 #include <svx/unoapi.hxx>
76 #include "CustomAnimationEffect.hxx"
77 #include <CustomAnimationPreset.hxx>
78 #include "animations.hxx"
80 using namespace ::com::sun::star
;
81 using namespace ::com::sun::star::uno
;
82 using namespace ::com::sun::star::presentation
;
83 using namespace ::com::sun::star::animations
;
85 using ::com::sun::star::container::XEnumerationAccess
;
86 using ::com::sun::star::container::XEnumeration
;
87 using ::com::sun::star::beans::NamedValue
;
88 using ::com::sun::star::container::XChild
;
89 using ::com::sun::star::container::XElementAccess
;
90 using ::com::sun::star::drawing::XShape
;
91 using ::com::sun::star::lang::XInitialization
;
92 using ::com::sun::star::drawing::XShapes
;
93 using ::com::sun::star::drawing::XDrawPage
;
94 using ::com::sun::star::text::XText
;
95 using ::com::sun::star::text::XTextRange
;
96 using ::com::sun::star::beans::XPropertySet
;
97 using ::com::sun::star::lang::XMultiServiceFactory
;
98 using ::com::sun::star::util::XCloneable
;
99 using ::com::sun::star::lang::Locale
;
100 using ::com::sun::star::util::XChangesNotifier
;
101 using ::com::sun::star::util::XChangesListener
;
105 class MainSequenceChangeGuard
108 MainSequenceChangeGuard( EffectSequenceHelper
* pSequence
)
110 mpMainSequence
= dynamic_cast< MainSequence
* >( pSequence
);
111 if( mpMainSequence
== 0 )
113 InteractiveSequence
* pI
= dynamic_cast< InteractiveSequence
* >( pSequence
);
115 mpMainSequence
= pI
->mpMainSequence
;
117 DBG_ASSERT( mpMainSequence
, "sd::MainSequenceChangeGuard::MainSequenceChangeGuard(), no main sequence to guard!" );
120 mpMainSequence
->mbIgnoreChanges
++;
123 ~MainSequenceChangeGuard()
126 mpMainSequence
->mbIgnoreChanges
++;
130 MainSequence
* mpMainSequence
;
133 CustomAnimationEffect::CustomAnimationEffect( const ::com::sun::star::uno::Reference
< ::com::sun::star::animations::XAnimationNode
>& xNode
)
138 mfAbsoluteDuration(-1.0),
141 mfIterateInterval(0.0),
144 mfAcceleration( 1.0 ),
146 mbAutoReverse(false),
149 mpEffectSequence( 0 ),
150 mbHasAfterEffect(false),
151 mbAfterEffectOnNextEffect(false)
156 void CustomAnimationEffect::setNode( const ::com::sun::star::uno::Reference
< ::com::sun::star::animations::XAnimationNode
>& xNode
)
161 Sequence
< NamedValue
> aUserData( mxNode
->getUserData() );
162 sal_Int32 nLength
= aUserData
.getLength();
163 const NamedValue
* p
= aUserData
.getConstArray();
167 if ( p
->Name
== "node-type" )
169 p
->Value
>>= mnNodeType
;
171 else if ( p
->Name
== "preset-id" )
173 p
->Value
>>= maPresetId
;
175 else if ( p
->Name
== "preset-sub-type" )
177 p
->Value
>>= maPresetSubType
;
179 else if ( p
->Name
== "preset-class" )
181 p
->Value
>>= mnPresetClass
;
183 else if ( p
->Name
== "preset-property" )
185 p
->Value
>>= maProperty
;
187 else if ( p
->Name
== "group-id" )
189 p
->Value
>>= mnGroupId
;
195 // get effect start time
196 mxNode
->getBegin() >>= mfBegin
;
198 mfAcceleration
= mxNode
->getAcceleration();
199 mfDecelerate
= mxNode
->getDecelerate();
200 mbAutoReverse
= mxNode
->getAutoReverse();
202 // get iteration data
203 Reference
< XIterateContainer
> xIter( mxNode
, UNO_QUERY
);
206 mfIterateInterval
= xIter
->getIterateInterval();
207 mnIterateType
= xIter
->getIterateType();
208 maTarget
= xIter
->getTarget();
209 mnTargetSubItem
= xIter
->getSubItem();
213 mfIterateInterval
= 0.0f
;
217 // calculate effect duration and get target shape
218 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
219 if( xEnumerationAccess
.is() )
221 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
222 if( xEnumeration
.is() )
224 while( xEnumeration
->hasMoreElements() )
226 Reference
< XAnimationNode
> xChildNode( xEnumeration
->nextElement(), UNO_QUERY
);
227 if( !xChildNode
.is() )
230 if( xChildNode
->getType() == AnimationNodeType::AUDIO
)
232 mxAudio
.set( xChildNode
, UNO_QUERY
);
234 else if( xChildNode
->getType() == AnimationNodeType::COMMAND
)
236 Reference
< XCommand
> xCommand( xChildNode
, UNO_QUERY
);
239 mnCommand
= xCommand
->getCommand();
240 if( !maTarget
.hasValue() )
241 maTarget
= xCommand
->getTarget();
247 double fDuration
= 0.0;
248 xChildNode
->getBegin() >>= fBegin
;
249 xChildNode
->getDuration() >>= fDuration
;
252 if( fDuration
> mfDuration
)
253 mfDuration
= fDuration
;
255 // no target shape yet?
256 if( !maTarget
.hasValue() )
259 Reference
< XAnimate
> xAnimate( xChildNode
, UNO_QUERY
);
262 maTarget
= xAnimate
->getTarget();
263 mnTargetSubItem
= xAnimate
->getSubItem();
271 mfAbsoluteDuration
= mfDuration
;
272 double fRepeatCount
= 1.0;
273 if( (mxNode
->getRepeatCount()) >>= fRepeatCount
)
274 mfAbsoluteDuration
*= fRepeatCount
;
279 sal_Int32
CustomAnimationEffect::getNumberOfSubitems( const Any
& aTarget
, sal_Int16 nIterateType
)
281 sal_Int32 nSubItems
= 0;
285 // first get target text
286 sal_Int32 nOnlyPara
= -1;
288 Reference
< XText
> xShape
;
292 ParagraphTarget aParaTarget
;
293 if( aTarget
>>= aParaTarget
)
295 xShape
.set( aParaTarget
.Shape
, UNO_QUERY
);
296 nOnlyPara
= aParaTarget
.Paragraph
;
300 // now use the break iterator to iterate over the given text
301 // and count the sub items
305 // TODO/LATER: Optimize this, don't create a break iterator each time
306 Reference
< uno::XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
307 Reference
< i18n::XBreakIterator
> xBI
= i18n::BreakIterator::create(xContext
);
309 Reference
< XEnumerationAccess
> xEA( xShape
, UNO_QUERY_THROW
);
310 Reference
< XEnumeration
> xEnumeration( xEA
->createEnumeration(), UNO_QUERY_THROW
);
312 const OUString
aStrLocaleName( "CharLocale" );
313 Reference
< XTextRange
> xParagraph
;
316 while( xEnumeration
->hasMoreElements() )
318 xEnumeration
->nextElement() >>= xParagraph
;
320 // skip this if its not the only paragraph we want to count
321 if( (nOnlyPara
!= -1) && (nOnlyPara
!= nPara
) )
324 if( nIterateType
== TextAnimationType::BY_PARAGRAPH
)
330 const OUString
aText( xParagraph
->getString() );
331 Reference
< XPropertySet
> xSet( xParagraph
, UNO_QUERY_THROW
);
332 xSet
->getPropertyValue( aStrLocaleName
) >>= aLocale
;
335 const sal_Int32 nEndPos
= aText
.getLength();
337 if( nIterateType
== TextAnimationType::BY_WORD
)
339 for( nPos
= 0; nPos
< nEndPos
; nPos
++ )
341 nPos
= xBI
->getWordBoundary(aText
, nPos
, aLocale
, i18n::WordType::ANY_WORD
, sal_True
).endPos
;
349 for( nPos
= 0; nPos
< nEndPos
; nPos
++ )
351 nPos
= xBI
->nextCharacters(aText
, nPos
, aLocale
, i18n::CharacterIteratorMode::SKIPCELL
, 0, nDone
);
357 if( nPara
== nOnlyPara
)
367 OSL_FAIL( "sd::CustomAnimationEffect::getNumberOfSubitems(), exception caught!" );
373 CustomAnimationEffect::~CustomAnimationEffect()
377 CustomAnimationEffectPtr
CustomAnimationEffect::clone() const
379 Reference
< XCloneable
> xCloneable( mxNode
, UNO_QUERY_THROW
);
380 Reference
< XAnimationNode
> xNode( xCloneable
->createClone(), UNO_QUERY_THROW
);
381 CustomAnimationEffectPtr
pEffect( new CustomAnimationEffect( xNode
) );
382 pEffect
->setEffectSequence( getEffectSequence() );
386 sal_Int32
CustomAnimationEffect::get_node_type( const Reference
< XAnimationNode
>& xNode
)
388 sal_Int16 nNodeType
= -1;
392 Sequence
< NamedValue
> aUserData( xNode
->getUserData() );
393 sal_Int32 nLength
= aUserData
.getLength();
396 const NamedValue
* p
= aUserData
.getConstArray();
399 if ( p
->Name
== "node-type" )
401 p
->Value
>>= nNodeType
;
412 void CustomAnimationEffect::setPresetClass( sal_Int16 nPresetClass
)
414 if( mnPresetClass
!= nPresetClass
)
416 mnPresetClass
= nPresetClass
;
419 // first try to find a "preset-class" entry in the user data
421 Sequence
< NamedValue
> aUserData( mxNode
->getUserData() );
422 sal_Int32 nLength
= aUserData
.getLength();
426 NamedValue
* p
= aUserData
.getArray();
429 if ( p
->Name
== "preset-class" )
431 p
->Value
<<= mnPresetClass
;
439 // no "node-type" entry inside user data, so add it
442 nLength
= aUserData
.getLength();
443 aUserData
.realloc( nLength
+ 1);
444 aUserData
[nLength
].Name
= "preset-class";
445 aUserData
[nLength
].Value
<<= mnPresetClass
;
448 mxNode
->setUserData( aUserData
);
453 void CustomAnimationEffect::setNodeType( sal_Int16 nNodeType
)
455 if( mnNodeType
!= nNodeType
)
457 mnNodeType
= nNodeType
;
460 // first try to find a "node-type" entry in the user data
462 Sequence
< NamedValue
> aUserData( mxNode
->getUserData() );
463 sal_Int32 nLength
= aUserData
.getLength();
467 NamedValue
* p
= aUserData
.getArray();
470 if ( p
->Name
== "node-type" )
472 p
->Value
<<= mnNodeType
;
480 // no "node-type" entry inside user data, so add it
483 nLength
= aUserData
.getLength();
484 aUserData
.realloc( nLength
+ 1);
485 aUserData
[nLength
].Name
= "node-type";
486 aUserData
[nLength
].Value
<<= mnNodeType
;
489 mxNode
->setUserData( aUserData
);
494 void CustomAnimationEffect::setGroupId( sal_Int32 nGroupId
)
496 mnGroupId
= nGroupId
;
499 // first try to find a "group-id" entry in the user data
501 Sequence
< NamedValue
> aUserData( mxNode
->getUserData() );
502 sal_Int32 nLength
= aUserData
.getLength();
506 NamedValue
* p
= aUserData
.getArray();
509 if ( p
->Name
== "group-id" )
511 p
->Value
<<= mnGroupId
;
519 // no "node-type" entry inside user data, so add it
522 nLength
= aUserData
.getLength();
523 aUserData
.realloc( nLength
+ 1);
524 aUserData
[nLength
].Name
= "group-id";
525 aUserData
[nLength
].Value
<<= mnGroupId
;
528 mxNode
->setUserData( aUserData
);
532 /** checks if the text for this effect has changed and updates internal flags.
533 returns true if something changed.
535 bool CustomAnimationEffect::checkForText()
537 bool bChange
= false;
539 Reference
< XText
> xText
;
541 if( maTarget
.getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
544 ParagraphTarget aParaTarget
;
545 maTarget
>>= aParaTarget
;
547 xText
= Reference
< XText
>::query( aParaTarget
.Shape
);
552 Reference
< XEnumerationAccess
> xEA( xText
, UNO_QUERY
);
555 Reference
< XEnumeration
> xEnumeration( xEA
->createEnumeration(), UNO_QUERY
);
556 if( xEnumeration
.is() )
558 bool bHasText
= xEnumeration
->hasMoreElements();
559 bChange
|= bHasText
!= mbHasText
;
560 mbHasText
= bHasText
;
562 sal_Int32 nPara
= aParaTarget
.Paragraph
;
564 while( xEnumeration
->hasMoreElements() && nPara
-- )
565 xEnumeration
->nextElement();
567 if( xEnumeration
->hasMoreElements() )
569 Reference
< XPropertySet
> xParaSet
;
570 xEnumeration
->nextElement() >>= xParaSet
;
573 sal_Int32 nParaDepth
= 0;
574 const OUString
strNumberingLevel( "NumberingLevel" );
575 xParaSet
->getPropertyValue( strNumberingLevel
) >>= nParaDepth
;
576 bChange
|= nParaDepth
!= mnParaDepth
;
577 mnParaDepth
= nParaDepth
;
587 bool bHasText
= xText
.is() && !xText
->getString().isEmpty();
588 bChange
|= bHasText
!= mbHasText
;
589 mbHasText
= bHasText
;
592 bChange
|= calculateIterateDuration();
596 bool CustomAnimationEffect::calculateIterateDuration()
598 bool bChange
= false;
600 // if we have an iteration, we must also calculate the
601 // 'true' container duration, that is
602 // ( ( is form animated ) ? [contained effects duration] : 0 ) +
603 // ( [number of animated children] - 1 ) * [interval-delay] + [contained effects duration]
604 Reference
< XIterateContainer
> xIter( mxNode
, UNO_QUERY
);
607 double fDuration
= mfDuration
;
608 const double fSubEffectDuration
= mfDuration
;
610 if( mnTargetSubItem
!= ShapeAnimationSubType::ONLY_BACKGROUND
) // does not make sense for iterate container but better check
612 const sal_Int32 nSubItems
= getNumberOfSubitems( maTarget
, mnIterateType
);
615 const double f
= (nSubItems
-1) * mfIterateInterval
;
620 // if we also animate the form first, we have to add the
621 // sub effect duration to the whole effect duration
622 if( mnTargetSubItem
== ShapeAnimationSubType::AS_WHOLE
)
623 fDuration
+= fSubEffectDuration
;
625 bChange
|= fDuration
!= mfAbsoluteDuration
;
626 mfAbsoluteDuration
= fDuration
;
632 void CustomAnimationEffect::setTarget( const ::com::sun::star::uno::Any
& rTarget
)
638 // first, check special case for random node
639 Reference
< XInitialization
> xInit( mxNode
, UNO_QUERY
);
642 const Sequence
< Any
> aArgs( &maTarget
, 1 );
643 xInit
->initialize( aArgs
);
647 Reference
< XIterateContainer
> xIter( mxNode
, UNO_QUERY
);
650 xIter
->setTarget(maTarget
);
654 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
655 if( xEnumerationAccess
.is() )
657 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
658 if( xEnumeration
.is() )
660 while( xEnumeration
->hasMoreElements() )
662 const Any
aElem( xEnumeration
->nextElement() );
663 Reference
< XAnimate
> xAnimate( aElem
, UNO_QUERY
);
665 xAnimate
->setTarget( rTarget
);
668 Reference
< XCommand
> xCommand( aElem
, UNO_QUERY
);
670 xCommand
->setTarget( rTarget
);
681 OSL_FAIL( "sd::CustomAnimationEffect::setTarget(), exception caught!" );
685 void CustomAnimationEffect::setTargetSubItem( sal_Int16 nSubItem
)
689 mnTargetSubItem
= nSubItem
;
691 Reference
< XIterateContainer
> xIter( mxNode
, UNO_QUERY
);
694 xIter
->setSubItem(mnTargetSubItem
);
698 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
699 if( xEnumerationAccess
.is() )
701 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
702 if( xEnumeration
.is() )
704 while( xEnumeration
->hasMoreElements() )
706 Reference
< XAnimate
> xAnimate( xEnumeration
->nextElement(), UNO_QUERY
);
708 xAnimate
->setSubItem( mnTargetSubItem
);
716 OSL_FAIL( "sd::CustomAnimationEffect::setTargetSubItem(), exception caught!" );
720 void CustomAnimationEffect::setDuration( double fDuration
)
722 if( (mfDuration
!= -1.0) && (mfDuration
!= fDuration
) ) try
724 double fScale
= fDuration
/ mfDuration
;
725 mfDuration
= fDuration
;
726 double fRepeatCount
= 1.0;
727 getRepeatCount() >>= fRepeatCount
;
728 mfAbsoluteDuration
= mfDuration
* fRepeatCount
;
730 // calculate effect duration and get target shape
731 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
732 if( xEnumerationAccess
.is() )
734 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
735 if( xEnumeration
.is() )
737 while( xEnumeration
->hasMoreElements() )
739 Reference
< XAnimationNode
> xChildNode( xEnumeration
->nextElement(), UNO_QUERY
);
740 if( !xChildNode
.is() )
743 double fChildBegin
= 0.0;
744 xChildNode
->getBegin() >>= fChildBegin
;
745 if( fChildBegin
!= 0.0 )
747 fChildBegin
*= fScale
;
748 xChildNode
->setBegin( makeAny( fChildBegin
) );
751 double fChildDuration
= 0.0;
752 xChildNode
->getDuration() >>= fChildDuration
;
753 if( fChildDuration
!= 0.0 )
755 fChildDuration
*= fScale
;
756 xChildNode
->setDuration( makeAny( fChildDuration
) );
761 calculateIterateDuration();
765 OSL_FAIL( "sd::CustomAnimationEffect::setDuration(), exception caught!" );
769 void CustomAnimationEffect::setBegin( double fBegin
)
771 if( mxNode
.is() ) try
774 mxNode
->setBegin( makeAny( fBegin
) );
778 OSL_FAIL( "sd::CustomAnimationEffect::setBegin(), exception caught!" );
782 void CustomAnimationEffect::setAcceleration( double fAcceleration
)
784 if( mxNode
.is() ) try
786 mfAcceleration
= fAcceleration
;
787 mxNode
->setAcceleration( fAcceleration
);
791 OSL_FAIL( "sd::CustomAnimationEffect::setAcceleration(), exception caught!" );
795 void CustomAnimationEffect::setDecelerate( double fDecelerate
)
797 if( mxNode
.is() ) try
799 mfDecelerate
= fDecelerate
;
800 mxNode
->setDecelerate( fDecelerate
);
804 OSL_FAIL( "sd::CustomAnimationEffect::setDecelerate(), exception caught!" );
808 void CustomAnimationEffect::setAutoReverse( bool bAutoReverse
)
810 if( mxNode
.is() ) try
812 mbAutoReverse
= bAutoReverse
;
813 mxNode
->setAutoReverse( bAutoReverse
);
817 OSL_FAIL( "sd::CustomAnimationEffect::setAutoReverse(), exception caught!" );
821 void CustomAnimationEffect::replaceNode( const ::com::sun::star::uno::Reference
< ::com::sun::star::animations::XAnimationNode
>& xNode
)
823 sal_Int16 nNodeType
= mnNodeType
;
824 Any aTarget
= maTarget
;
826 double fBegin
= mfBegin
;
827 double fDuration
= mfDuration
;
828 double fAcceleration
= mfAcceleration
;
829 double fDecelerate
= mfDecelerate
;
830 bool bAutoReverse
= mbAutoReverse
;
831 Reference
< XAudio
> xAudio( mxAudio
);
832 sal_Int16 nIterateType
= mnIterateType
;
833 double fIterateInterval
= mfIterateInterval
;
834 sal_Int16 nSubItem
= mnTargetSubItem
;
839 setNodeType( nNodeType
);
840 setTarget( aTarget
);
841 setTargetSubItem( nSubItem
);
842 setDuration( fDuration
);
845 setAcceleration( fAcceleration
);
846 setDecelerate( fDecelerate
);
847 setAutoReverse( bAutoReverse
);
849 if( nIterateType
!= mnIterateType
)
850 setIterateType( nIterateType
);
852 if( mnIterateType
&& ( fIterateInterval
!= mfIterateInterval
) )
853 setIterateInterval( fIterateInterval
);
856 Reference
< XShape
> CustomAnimationEffect::getTargetShape() const
858 Reference
< XShape
> xShape
;
862 ParagraphTarget aParaTarget
;
863 if( maTarget
>>= aParaTarget
)
864 xShape
= aParaTarget
.Shape
;
870 Any
CustomAnimationEffect::getRepeatCount() const
874 return mxNode
->getRepeatCount();
883 Any
CustomAnimationEffect::getEnd() const
887 return mxNode
->getEnd();
896 sal_Int16
CustomAnimationEffect::getFill() const
899 return mxNode
->getFill();
904 void CustomAnimationEffect::setRepeatCount( const Any
& rRepeatCount
)
908 mxNode
->setRepeatCount( rRepeatCount
);
909 double fRepeatCount
= 1.0;
910 rRepeatCount
>>= fRepeatCount
;
911 mfAbsoluteDuration
= mfDuration
* fRepeatCount
;
915 void CustomAnimationEffect::setEnd( const Any
& rEnd
)
918 mxNode
->setEnd( rEnd
);
921 void CustomAnimationEffect::setFill( sal_Int16 nFill
)
924 mxNode
->setFill( nFill
);
927 Reference
< XAnimationNode
> CustomAnimationEffect::createAfterEffectNode() const throw (Exception
)
929 DBG_ASSERT( mbHasAfterEffect
, "sd::CustomAnimationEffect::createAfterEffectNode(), this node has no after effect!" );
931 Reference
< XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
933 Reference
< XAnimate
> xAnimate
;
934 if( maDimColor
.hasValue() )
935 xAnimate
= AnimateColor::create( xContext
);
937 xAnimate
= AnimateSet::create( xContext
);
940 OUString aAttributeName
;
942 if( maDimColor
.hasValue() )
945 aAttributeName
= "DimColor";
949 aTo
= makeAny( false );
950 aAttributeName
= "Visibility";
954 if( !mbAfterEffectOnNextEffect
) // sameClick
958 aEvent
.Source
<<= getNode();
959 aEvent
.Trigger
= EventTrigger::END_EVENT
;
966 aBegin
<<= (double)0.0;
969 xAnimate
->setBegin( aBegin
);
970 xAnimate
->setTo( aTo
);
971 xAnimate
->setAttributeName( aAttributeName
);
973 xAnimate
->setDuration( makeAny( (double)0.001 ) );
974 xAnimate
->setFill( AnimationFill::HOLD
);
975 xAnimate
->setTarget( maTarget
);
980 void CustomAnimationEffect::setIterateType( sal_Int16 nIterateType
)
982 if( mnIterateType
!= nIterateType
) try
984 // do we need to exchange the container node?
985 if( (mnIterateType
== 0) || (nIterateType
== 0) )
987 sal_Int16 nTargetSubItem
= mnTargetSubItem
;
989 Reference
< XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
990 Reference
< XTimeContainer
> xNewContainer
;
993 xNewContainer
.set( IterateContainer::create( xContext
) );
996 xNewContainer
.set( ParallelTimeContainer::create( xContext
), UNO_QUERY_THROW
);
998 Reference
< XTimeContainer
> xOldContainer( mxNode
, UNO_QUERY_THROW
);
999 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY_THROW
);
1000 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
1001 while( xEnumeration
->hasMoreElements() )
1003 Reference
< XAnimationNode
> xChildNode( xEnumeration
->nextElement(), UNO_QUERY_THROW
);
1004 xOldContainer
->removeChild( xChildNode
);
1005 xNewContainer
->appendChild( xChildNode
);
1008 xNewContainer
->setBegin( mxNode
->getBegin() );
1009 xNewContainer
->setDuration( mxNode
->getDuration() );
1010 xNewContainer
->setEnd( mxNode
->getEnd() );
1011 xNewContainer
->setEndSync( mxNode
->getEndSync() );
1012 xNewContainer
->setRepeatCount( mxNode
->getRepeatCount() );
1013 xNewContainer
->setFill( mxNode
->getFill() );
1014 xNewContainer
->setFillDefault( mxNode
->getFillDefault() );
1015 xNewContainer
->setRestart( mxNode
->getRestart() );
1016 xNewContainer
->setRestartDefault( mxNode
->getRestartDefault() );
1017 xNewContainer
->setAcceleration( mxNode
->getAcceleration() );
1018 xNewContainer
->setDecelerate( mxNode
->getDecelerate() );
1019 xNewContainer
->setAutoReverse( mxNode
->getAutoReverse() );
1020 xNewContainer
->setRepeatDuration( mxNode
->getRepeatDuration() );
1021 xNewContainer
->setEndSync( mxNode
->getEndSync() );
1022 xNewContainer
->setRepeatCount( mxNode
->getRepeatCount() );
1023 xNewContainer
->setUserData( mxNode
->getUserData() );
1025 mxNode
= xNewContainer
;
1030 Reference
< XIterateContainer
> xIter( mxNode
, UNO_QUERY_THROW
);
1031 xIter
->setTarget(maTarget
);
1032 xIter
->setSubItem( nTargetSubItem
);
1039 Reference
< XEnumerationAccess
> xEA( mxNode
, UNO_QUERY_THROW
);
1040 Reference
< XEnumeration
> xE( xEA
->createEnumeration(), UNO_QUERY_THROW
);
1041 while( xE
->hasMoreElements() )
1043 Reference
< XAnimate
> xAnimate( xE
->nextElement(), UNO_QUERY
);
1046 xAnimate
->setTarget( aTarget
);
1047 xAnimate
->setSubItem( nTargetSubItem
);
1052 mnIterateType
= nIterateType
;
1054 // if we have an iteration container, we must set its type
1057 Reference
< XIterateContainer
> xIter( mxNode
, UNO_QUERY_THROW
);
1058 xIter
->setIterateType( nIterateType
);
1065 OSL_FAIL( "sd::CustomAnimationEffect::setIterateType(), Exception caught!" );
1069 void CustomAnimationEffect::setIterateInterval( double fIterateInterval
)
1071 if( mfIterateInterval
!= fIterateInterval
)
1073 Reference
< XIterateContainer
> xIter( mxNode
, UNO_QUERY
);
1075 DBG_ASSERT( xIter
.is(), "sd::CustomAnimationEffect::setIterateInterval(), not an iteration node" );
1078 mfIterateInterval
= fIterateInterval
;
1079 xIter
->setIterateInterval( fIterateInterval
);
1082 calculateIterateDuration();
1086 OUString
CustomAnimationEffect::getPath() const
1090 if( mxNode
.is() ) try
1092 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY_THROW
);
1093 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
1094 while( xEnumeration
->hasMoreElements() )
1096 Reference
< XAnimateMotion
> xMotion( xEnumeration
->nextElement(), UNO_QUERY
);
1099 xMotion
->getPath() >>= aPath
;
1106 OSL_FAIL("sd::CustomAnimationEffect::getPath(), exception caught!" );
1112 void CustomAnimationEffect::setPath( const OUString
& rPath
)
1114 if( mxNode
.is() ) try
1116 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY_THROW
);
1117 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
1118 while( xEnumeration
->hasMoreElements() )
1120 Reference
< XAnimateMotion
> xMotion( xEnumeration
->nextElement(), UNO_QUERY
);
1124 MainSequenceChangeGuard
aGuard( mpEffectSequence
);
1125 xMotion
->setPath( Any( rPath
) );
1132 OSL_FAIL("sd::CustomAnimationEffect::setPath(), exception caught!" );
1136 Any
CustomAnimationEffect::getProperty( sal_Int32 nNodeType
, const OUString
& rAttributeName
, EValue eValue
)
1139 if( mxNode
.is() ) try
1141 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
1142 if( xEnumerationAccess
.is() )
1144 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
1145 if( xEnumeration
.is() )
1147 while( xEnumeration
->hasMoreElements() && !aProperty
.hasValue() )
1149 Reference
< XAnimate
> xAnimate( xEnumeration
->nextElement(), UNO_QUERY
);
1150 if( !xAnimate
.is() )
1153 if( xAnimate
->getType() == nNodeType
)
1155 if( xAnimate
->getAttributeName() == rAttributeName
)
1159 case VALUE_FROM
: aProperty
= xAnimate
->getFrom(); break;
1160 case VALUE_TO
: aProperty
= xAnimate
->getTo(); break;
1161 case VALUE_BY
: aProperty
= xAnimate
->getBy(); break;
1165 Sequence
<Any
> aValues( xAnimate
->getValues() );
1166 if( aValues
.hasElements() )
1167 aProperty
= aValues
[ eValue
== VALUE_FIRST
? 0 : aValues
.getLength() - 1 ];
1179 OSL_FAIL("sd::CustomAnimationEffect::getProperty(), exception caught!" );
1185 bool CustomAnimationEffect::setProperty( sal_Int32 nNodeType
, const OUString
& rAttributeName
, EValue eValue
, const Any
& rValue
)
1187 bool bChanged
= false;
1188 if( mxNode
.is() ) try
1190 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
1191 if( xEnumerationAccess
.is() )
1193 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
1194 if( xEnumeration
.is() )
1196 while( xEnumeration
->hasMoreElements() )
1198 Reference
< XAnimate
> xAnimate( xEnumeration
->nextElement(), UNO_QUERY
);
1199 if( !xAnimate
.is() )
1202 if( xAnimate
->getType() == nNodeType
)
1204 if( xAnimate
->getAttributeName() == rAttributeName
)
1209 if( xAnimate
->getFrom() != rValue
)
1211 xAnimate
->setFrom( rValue
);
1216 if( xAnimate
->getTo() != rValue
)
1218 xAnimate
->setTo( rValue
);
1223 if( xAnimate
->getTo() != rValue
)
1225 xAnimate
->setBy( rValue
);
1232 Sequence
<Any
> aValues( xAnimate
->getValues() );
1233 if( !aValues
.hasElements() )
1236 sal_Int32 nIndex
= eValue
== VALUE_FIRST
? 0 : aValues
.getLength() - 1;
1238 if( aValues
[ nIndex
] != rValue
)
1240 aValues
[ nIndex
] = rValue
;
1241 xAnimate
->setValues( aValues
);
1254 OSL_FAIL("sd::CustomAnimationEffect::setProperty(), exception caught!" );
1260 static bool implIsColorAttribute( const OUString
& rAttributeName
)
1262 return rAttributeName
== "FillColor" || rAttributeName
== "LineColor" || rAttributeName
== "CharColor";
1265 Any
CustomAnimationEffect::getColor( sal_Int32 nIndex
)
1268 if( mxNode
.is() ) try
1270 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
1271 if( xEnumerationAccess
.is() )
1273 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
1274 if( xEnumeration
.is() )
1276 while( xEnumeration
->hasMoreElements() && !aColor
.hasValue() )
1278 Reference
< XAnimate
> xAnimate( xEnumeration
->nextElement(), UNO_QUERY
);
1279 if( !xAnimate
.is() )
1282 switch( xAnimate
->getType() )
1284 case AnimationNodeType::SET
:
1285 case AnimationNodeType::ANIMATE
:
1286 if( !implIsColorAttribute( xAnimate
->getAttributeName() ) )
1288 case AnimationNodeType::ANIMATECOLOR
:
1289 Sequence
<Any
> aValues( xAnimate
->getValues() );
1290 if( aValues
.hasElements() )
1292 if( aValues
.getLength() > nIndex
)
1293 aColor
= aValues
[nIndex
];
1295 else if( nIndex
== 0 )
1296 aColor
= xAnimate
->getFrom();
1298 aColor
= xAnimate
->getTo();
1306 OSL_FAIL("sd::CustomAnimationEffect::getColor(), exception caught!" );
1312 void CustomAnimationEffect::setColor( sal_Int32 nIndex
, const Any
& rColor
)
1314 if( mxNode
.is() ) try
1316 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
1317 if( xEnumerationAccess
.is() )
1319 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
1320 if( xEnumeration
.is() )
1322 while( xEnumeration
->hasMoreElements() )
1324 Reference
< XAnimate
> xAnimate( xEnumeration
->nextElement(), UNO_QUERY
);
1325 if( !xAnimate
.is() )
1328 switch( xAnimate
->getType() )
1330 case AnimationNodeType::SET
:
1331 case AnimationNodeType::ANIMATE
:
1332 if( !implIsColorAttribute( xAnimate
->getAttributeName() ) )
1334 case AnimationNodeType::ANIMATECOLOR
:
1336 Sequence
<Any
> aValues( xAnimate
->getValues() );
1337 if( aValues
.hasElements() )
1339 if( aValues
.getLength() > nIndex
)
1341 aValues
[nIndex
] = rColor
;
1342 xAnimate
->setValues( aValues
);
1345 else if( (nIndex
== 0) && xAnimate
->getFrom().hasValue() )
1346 xAnimate
->setFrom(rColor
);
1347 else if( (nIndex
== 1) && xAnimate
->getTo().hasValue() )
1348 xAnimate
->setTo(rColor
);
1359 OSL_FAIL("sd::CustomAnimationEffect::setColor(), exception caught!" );
1363 Any
CustomAnimationEffect::getTransformationProperty( sal_Int32 nTransformType
, EValue eValue
)
1366 if( mxNode
.is() ) try
1368 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
1369 if( xEnumerationAccess
.is() )
1371 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
1372 if( xEnumeration
.is() )
1374 while( xEnumeration
->hasMoreElements() && !aProperty
.hasValue() )
1376 Reference
< XAnimateTransform
> xTransform( xEnumeration
->nextElement(), UNO_QUERY
);
1377 if( !xTransform
.is() )
1380 if( xTransform
->getTransformType() == nTransformType
)
1384 case VALUE_FROM
: aProperty
= xTransform
->getFrom(); break;
1385 case VALUE_TO
: aProperty
= xTransform
->getTo(); break;
1386 case VALUE_BY
: aProperty
= xTransform
->getBy(); break;
1390 Sequence
<Any
> aValues( xTransform
->getValues() );
1391 if( aValues
.hasElements() )
1392 aProperty
= aValues
[ eValue
== VALUE_FIRST
? 0 : aValues
.getLength() - 1 ];
1403 OSL_FAIL("sd::CustomAnimationEffect::getTransformationProperty(), exception caught!" );
1409 bool CustomAnimationEffect::setTransformationProperty( sal_Int32 nTransformType
, EValue eValue
, const Any
& rValue
)
1411 bool bChanged
= false;
1412 if( mxNode
.is() ) try
1414 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
1415 if( xEnumerationAccess
.is() )
1417 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
1418 if( xEnumeration
.is() )
1420 while( xEnumeration
->hasMoreElements() )
1422 Reference
< XAnimateTransform
> xTransform( xEnumeration
->nextElement(), UNO_QUERY
);
1423 if( !xTransform
.is() )
1426 if( xTransform
->getTransformType() == nTransformType
)
1431 if( xTransform
->getFrom() != rValue
)
1433 xTransform
->setFrom( rValue
);
1438 if( xTransform
->getTo() != rValue
)
1440 xTransform
->setTo( rValue
);
1445 if( xTransform
->getBy() != rValue
)
1447 xTransform
->setBy( rValue
);
1454 Sequence
<Any
> aValues( xTransform
->getValues() );
1455 if( !aValues
.hasElements() )
1458 sal_Int32 nIndex
= eValue
== VALUE_FIRST
? 0 : aValues
.getLength() - 1;
1459 if( aValues
[nIndex
] != rValue
)
1461 aValues
[nIndex
] = rValue
;
1462 xTransform
->setValues( aValues
);
1474 OSL_FAIL("sd::CustomAnimationEffect::setTransformationProperty(), exception caught!" );
1480 void CustomAnimationEffect::createAudio( const ::com::sun::star::uno::Any
& rSource
, double fVolume
/* = 1.0 */ )
1482 DBG_ASSERT( !mxAudio
.is(), "sd::CustomAnimationEffect::createAudio(), node already has an audio!" );
1484 if( !mxAudio
.is() ) try
1486 Reference
< XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
1487 Reference
< XAudio
> xAudio( Audio::create( xContext
) );
1488 xAudio
->setSource( rSource
);
1489 xAudio
->setVolume( fVolume
);
1494 OSL_FAIL("sd::CustomAnimationEffect::createAudio(), exception caught!" );
1498 static Reference
< XCommand
> findCommandNode( const Reference
< XAnimationNode
>& xRootNode
)
1500 Reference
< XCommand
> xCommand
;
1502 if( xRootNode
.is() ) try
1504 Reference
< XEnumerationAccess
> xEnumerationAccess( xRootNode
, UNO_QUERY_THROW
);
1505 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
1506 while( !xCommand
.is() && xEnumeration
->hasMoreElements() )
1508 Reference
< XAnimationNode
> xNode( xEnumeration
->nextElement(), UNO_QUERY
);
1509 if( xNode
.is() && (xNode
->getType() == AnimationNodeType::COMMAND
) )
1510 xCommand
.set( xNode
, UNO_QUERY_THROW
);
1515 OSL_FAIL("sd::findCommandNode(), exception caught!" );
1521 void CustomAnimationEffect::removeAudio()
1525 Reference
< XAnimationNode
> xChild
;
1529 xChild
.set( mxAudio
, UNO_QUERY
);
1532 else if( mnCommand
== EffectCommands::STOPAUDIO
)
1534 xChild
.set( findCommandNode( mxNode
), UNO_QUERY
);
1540 Reference
< XTimeContainer
> xContainer( mxNode
, UNO_QUERY
);
1541 if( xContainer
.is() )
1542 xContainer
->removeChild( xChild
);
1547 OSL_FAIL("sd::CustomAnimationEffect::removeAudio(), exception caught!" );
1552 void CustomAnimationEffect::setAudio( const Reference
< ::com::sun::star::animations::XAudio
>& xAudio
)
1554 if( mxAudio
!= xAudio
) try
1558 Reference
< XTimeContainer
> xContainer( mxNode
, UNO_QUERY
);
1559 Reference
< XAnimationNode
> xChild( mxAudio
, UNO_QUERY
);
1560 if( xContainer
.is() && xChild
.is() )
1561 xContainer
->appendChild( xChild
);
1565 OSL_FAIL("sd::CustomAnimationEffect::setAudio(), exception caught!" );
1569 void CustomAnimationEffect::setStopAudio()
1571 if( mnCommand
!= EffectCommands::STOPAUDIO
) try
1576 Reference
< XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
1577 Reference
< XCommand
> xCommand( Command::create( xContext
) );
1579 xCommand
->setCommand( EffectCommands::STOPAUDIO
);
1581 Reference
< XTimeContainer
> xContainer( mxNode
, UNO_QUERY_THROW
);
1582 xContainer
->appendChild( xCommand
);
1584 mnCommand
= EffectCommands::STOPAUDIO
;
1588 OSL_FAIL("sd::CustomAnimationEffect::setStopAudio(), exception caught!" );
1592 bool CustomAnimationEffect::getStopAudio() const
1594 return mnCommand
== EffectCommands::STOPAUDIO
;
1597 SdrPathObj
* CustomAnimationEffect::createSdrPathObjFromPath()
1599 SdrPathObj
* pPathObj
= new SdrPathObj( OBJ_PATHLINE
);
1600 updateSdrPathObjFromPath( *pPathObj
);
1604 void CustomAnimationEffect::updateSdrPathObjFromPath( SdrPathObj
& rPathObj
)
1606 ::basegfx::B2DPolyPolygon xPolyPoly
;
1607 if( ::basegfx::tools::importFromSvgD( xPolyPoly
, getPath(), true, 0 ) )
1609 SdrObject
* pObj
= GetSdrObjectFromXShape( getTargetShape() );
1612 SdrPage
* pPage
= pObj
->GetPage();
1615 const Size
aPageSize( pPage
->GetSize() );
1616 xPolyPoly
.transform(basegfx::tools::createScaleB2DHomMatrix((double)aPageSize
.Width(), (double)aPageSize
.Height()));
1619 const Rectangle
aBoundRect( pObj
->GetCurrentBoundRect() );
1620 const Point
aCenter( aBoundRect
.Center() );
1621 xPolyPoly
.transform(basegfx::tools::createTranslateB2DHomMatrix(aCenter
.X(), aCenter
.Y()));
1625 rPathObj
.SetPathPoly( xPolyPoly
);
1628 void CustomAnimationEffect::updatePathFromSdrPathObj( const SdrPathObj
& rPathObj
)
1630 ::basegfx::B2DPolyPolygon
xPolyPoly( rPathObj
.GetPathPoly() );
1632 SdrObject
* pObj
= GetSdrObjectFromXShape( getTargetShape() );
1635 Rectangle
aBoundRect(0,0,0,0);
1637 const drawinglayer::primitive2d::Primitive2DSequence
xPrimitives(pObj
->GetViewContact().getViewIndependentPrimitive2DSequence());
1638 const drawinglayer::geometry::ViewInformation2D aViewInformation2D
;
1639 const basegfx::B2DRange
aRange(drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(xPrimitives
, aViewInformation2D
));
1641 if(!aRange
.isEmpty())
1643 aBoundRect
= Rectangle(
1644 (sal_Int32
)floor(aRange
.getMinX()), (sal_Int32
)floor(aRange
.getMinY()),
1645 (sal_Int32
)ceil(aRange
.getMaxX()), (sal_Int32
)ceil(aRange
.getMaxY()));
1648 const Point
aCenter( aBoundRect
.Center() );
1650 xPolyPoly
.transform(basegfx::tools::createTranslateB2DHomMatrix(-aCenter
.X(), -aCenter
.Y()));
1652 SdrPage
* pPage
= pObj
->GetPage();
1655 const Size
aPageSize( pPage
->GetSize() );
1656 xPolyPoly
.transform(basegfx::tools::createScaleB2DHomMatrix(
1657 1.0 / (double)aPageSize
.Width(), 1.0 / (double)aPageSize
.Height()));
1661 setPath( ::basegfx::tools::exportToSvgD( xPolyPoly
, true, true, true) );
1664 EffectSequenceHelper::EffectSequenceHelper()
1665 : mnSequenceType( EffectNodeType::DEFAULT
)
1669 EffectSequenceHelper::EffectSequenceHelper( const ::com::sun::star::uno::Reference
< ::com::sun::star::animations::XTimeContainer
>& xSequenceRoot
)
1670 : mxSequenceRoot( xSequenceRoot
), mnSequenceType( EffectNodeType::DEFAULT
)
1672 Reference
< XAnimationNode
> xNode( mxSequenceRoot
, UNO_QUERY_THROW
);
1676 EffectSequenceHelper::~EffectSequenceHelper()
1681 void EffectSequenceHelper::reset()
1683 EffectSequence::iterator
aIter( maEffects
.begin() );
1684 EffectSequence::iterator
aEnd( maEffects
.end() );
1687 CustomAnimationEffectPtr pEffect
= (*aIter
++);
1688 pEffect
->setEffectSequence(0);
1693 Reference
< XAnimationNode
> EffectSequenceHelper::getRootNode()
1695 Reference
< XAnimationNode
> xRoot( mxSequenceRoot
, UNO_QUERY
);
1699 void EffectSequenceHelper::append( const CustomAnimationEffectPtr
& pEffect
)
1701 pEffect
->setEffectSequence( this );
1702 maEffects
.push_back(pEffect
);
1706 CustomAnimationEffectPtr
EffectSequenceHelper::append( const CustomAnimationPresetPtr
& pPreset
, const Any
& rTarget
, double fDuration
/* = -1.0 */ )
1708 CustomAnimationEffectPtr pEffect
;
1713 Reference
< XAnimationNode
> xNode( pPreset
->create( strEmpty
) );
1716 // first, filter all only ui relevant user data
1717 std::vector
< NamedValue
> aNewUserData
;
1718 Sequence
< NamedValue
> aUserData( xNode
->getUserData() );
1719 sal_Int32 nLength
= aUserData
.getLength();
1720 const NamedValue
* p
= aUserData
.getConstArray();
1721 bool bFilter
= false;
1725 if( p
->Name
!= "text-only" && p
->Name
!= "preset-property" )
1727 aNewUserData
.push_back( *p
);
1735 aUserData
= ::comphelper::containerToSequence
< NamedValue
, std::vector
< NamedValue
> >( aNewUserData
);
1736 xNode
->setUserData( aUserData
);
1739 // check target, maybe we need to force it to text
1740 Any
aTarget( rTarget
);
1741 sal_Int16 nSubItem
= ShapeAnimationSubType::AS_WHOLE
;
1743 if( aTarget
.getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
1745 nSubItem
= ShapeAnimationSubType::ONLY_TEXT
;
1747 else if( pPreset
->isTextOnly() )
1749 Reference
< XShape
> xShape
;
1753 // thats bad, we target a shape here but the effect is only for text
1754 // so change subitem
1755 nSubItem
= ShapeAnimationSubType::ONLY_TEXT
;
1759 // now create effect from preset
1760 pEffect
.reset( new CustomAnimationEffect( xNode
) );
1761 pEffect
->setEffectSequence( this );
1762 pEffect
->setTarget( aTarget
);
1763 pEffect
->setTargetSubItem( nSubItem
);
1764 if( fDuration
!= -1.0 )
1765 pEffect
->setDuration( fDuration
);
1767 maEffects
.push_back(pEffect
);
1773 DBG_ASSERT( pEffect
.get(), "sd::EffectSequenceHelper::append(), failed!" );
1777 CustomAnimationEffectPtr
EffectSequenceHelper::append( const SdrPathObj
& rPathObj
, const Any
& rTarget
, double fDuration
/* = -1.0 */ )
1779 CustomAnimationEffectPtr pEffect
;
1781 if( fDuration
<= 0.0 )
1786 Reference
< XTimeContainer
> xEffectContainer( ParallelTimeContainer::create( ::comphelper::getProcessComponentContext() ), UNO_QUERY_THROW
);
1787 Reference
< XAnimationNode
> xAnimateMotion( AnimateMotion::create( ::comphelper::getProcessComponentContext() ) );
1789 xAnimateMotion
->setDuration( Any( fDuration
) );
1790 xAnimateMotion
->setFill( AnimationFill::HOLD
);
1791 xEffectContainer
->appendChild( xAnimateMotion
);
1793 sal_Int16 nSubItem
= ShapeAnimationSubType::AS_WHOLE
;
1795 if( rTarget
.getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
1796 nSubItem
= ShapeAnimationSubType::ONLY_TEXT
;
1798 pEffect
.reset( new CustomAnimationEffect( xEffectContainer
) );
1799 pEffect
->setEffectSequence( this );
1800 pEffect
->setTarget( rTarget
);
1801 pEffect
->setTargetSubItem( nSubItem
);
1802 pEffect
->setNodeType( ::com::sun::star::presentation::EffectNodeType::ON_CLICK
);
1803 pEffect
->setPresetClass( ::com::sun::star::presentation::EffectPresetClass::MOTIONPATH
);
1804 pEffect
->setAcceleration( 0.5 );
1805 pEffect
->setDecelerate( 0.5 );
1806 pEffect
->setFill( AnimationFill::HOLD
);
1807 pEffect
->setBegin( 0.0 );
1808 pEffect
->updatePathFromSdrPathObj( rPathObj
);
1809 if( fDuration
!= -1.0 )
1810 pEffect
->setDuration( fDuration
);
1812 maEffects
.push_back(pEffect
);
1818 OSL_FAIL( "sd::EffectSequenceHelper::append(), exception caught!" );
1824 void EffectSequenceHelper::replace( const CustomAnimationEffectPtr
& pEffect
, const CustomAnimationPresetPtr
& pPreset
, const OUString
& rPresetSubType
, double fDuration
/* = -1.0 */ )
1826 if( pEffect
.get() && pPreset
.get() ) try
1828 Reference
< XAnimationNode
> xNewNode( pPreset
->create( rPresetSubType
) );
1831 pEffect
->replaceNode( xNewNode
);
1832 if( fDuration
!= -1.0 )
1833 pEffect
->setDuration( fDuration
);
1840 OSL_FAIL( "sd::EffectSequenceHelper::replace(), exception caught!" );
1844 void EffectSequenceHelper::replace( const CustomAnimationEffectPtr
& pEffect
, const CustomAnimationPresetPtr
& pPreset
, double fDuration
/* = -1.0 */ )
1847 replace( pEffect
, pPreset
, strEmpty
, fDuration
);
1850 void EffectSequenceHelper::remove( const CustomAnimationEffectPtr
& pEffect
)
1854 pEffect
->setEffectSequence( 0 );
1855 maEffects
.remove( pEffect
);
1861 void EffectSequenceHelper::rebuild()
1866 void EffectSequenceHelper::implRebuild()
1870 // first we delete all time containers on the first two levels
1871 Reference
< XEnumerationAccess
> xEnumerationAccess( mxSequenceRoot
, UNO_QUERY_THROW
);
1872 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
1873 while( xEnumeration
->hasMoreElements() )
1875 Reference
< XAnimationNode
> xChildNode( xEnumeration
->nextElement(), UNO_QUERY_THROW
);
1876 Reference
< XTimeContainer
> xChildContainer( xChildNode
, UNO_QUERY_THROW
);
1878 Reference
< XEnumerationAccess
> xChildEnumerationAccess( xChildNode
, UNO_QUERY_THROW
);
1879 Reference
< XEnumeration
> xChildEnumeration( xChildEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
1880 while( xChildEnumeration
->hasMoreElements() )
1882 Reference
< XAnimationNode
> xNode( xChildEnumeration
->nextElement(), UNO_QUERY_THROW
);
1883 xChildContainer
->removeChild( xNode
);
1886 mxSequenceRoot
->removeChild( xChildNode
);
1889 // second, rebuild main sequence
1890 EffectSequence::iterator
aIter( maEffects
.begin() );
1891 EffectSequence::iterator
aEnd( maEffects
.end() );
1894 AfterEffectNodeList aAfterEffects
;
1896 CustomAnimationEffectPtr pEffect
= (*aIter
++);
1901 // create a par container for the next click node and all following with and after effects
1902 Reference
< XTimeContainer
> xOnClickContainer( ParallelTimeContainer::create( ::comphelper::getProcessComponentContext() ), UNO_QUERY_THROW
);
1905 if( mxEventSource
.is() )
1907 aEvent
.Source
<<= mxEventSource
;
1908 aEvent
.Trigger
= EventTrigger::ON_CLICK
;
1912 aEvent
.Trigger
= EventTrigger::ON_NEXT
;
1916 Any
aBegin( makeAny( aEvent
) );
1919 // if the first node is not a click action, this click container
1920 // must not have INDEFINITE begin but start at 0s
1922 if( pEffect
->getNodeType() != EffectNodeType::ON_CLICK
)
1923 aBegin
<<= (double)0.0;
1926 xOnClickContainer
->setBegin( aBegin
);
1928 mxSequenceRoot
->appendChild( xOnClickContainer
);
1930 double fBegin
= 0.0;
1934 // create a par container for the current click or after effect node and all following with effects
1935 Reference
< XTimeContainer
> xWithContainer( ParallelTimeContainer::create( ::comphelper::getProcessComponentContext() ), UNO_QUERY_THROW
);
1936 xWithContainer
->setBegin( makeAny( fBegin
) );
1937 xOnClickContainer
->appendChild( xWithContainer
);
1939 double fDuration
= 0.0;
1942 Reference
< XAnimationNode
> xEffectNode( pEffect
->getNode() );
1943 xWithContainer
->appendChild( xEffectNode
);
1945 if( pEffect
->hasAfterEffect() )
1947 Reference
< XAnimationNode
> xAfterEffect( pEffect
->createAfterEffectNode() );
1948 AfterEffectNode
a( xAfterEffect
, xEffectNode
, pEffect
->IsAfterEffectOnNext() );
1949 aAfterEffects
.push_back( a
);
1952 double fTemp
= pEffect
->getBegin() + pEffect
->getAbsoluteDuration();
1953 if( fTemp
> fDuration
)
1957 pEffect
= (*aIter
++);
1961 while( pEffect
.get() && (pEffect
->getNodeType() == EffectNodeType::WITH_PREVIOUS
) );
1963 fBegin
+= fDuration
;
1965 while( pEffect
.get() && (pEffect
->getNodeType() != EffectNodeType::ON_CLICK
) );
1967 while( pEffect
.get() );
1969 // process after effect nodes
1970 std::for_each( aAfterEffects
.begin(), aAfterEffects
.end(), stl_process_after_effect_node_func
);
1974 // reset duration, might have been altered (see below)
1975 mxSequenceRoot
->setDuration( Any() );
1979 // empty sequence, set duration to 0.0 explicitly
1980 // (otherwise, this sequence will never end)
1981 mxSequenceRoot
->setDuration( makeAny((double)0.0) );
1986 OSL_FAIL( "sd::EffectSequenceHelper::rebuild(), exception caught!" );
1990 stl_CustomAnimationEffect_search_node_predict::stl_CustomAnimationEffect_search_node_predict( const ::com::sun::star::uno::Reference
< ::com::sun::star::animations::XAnimationNode
>& xSearchNode
)
1991 : mxSearchNode( xSearchNode
)
1995 bool stl_CustomAnimationEffect_search_node_predict::operator()( CustomAnimationEffectPtr pEffect
) const
1997 return pEffect
->getNode() == mxSearchNode
;
2000 static bool implFindNextContainer( Reference
< XTimeContainer
>& xParent
, Reference
< XTimeContainer
>& xCurrent
, Reference
< XTimeContainer
>& xNext
)
2003 Reference
< XEnumerationAccess
> xEnumerationAccess( xParent
, UNO_QUERY_THROW
);
2004 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration() );
2005 if( xEnumeration
.is() )
2007 Reference
< XInterface
> x
;
2008 while( xEnumeration
->hasMoreElements() && !xNext
.is() )
2010 if( (xEnumeration
->nextElement() >>= x
) && (x
== xCurrent
) )
2012 if( xEnumeration
->hasMoreElements() )
2013 xEnumeration
->nextElement() >>= xNext
;
2020 void stl_process_after_effect_node_func(AfterEffectNode
& rNode
)
2024 if( rNode
.mxNode
.is() && rNode
.mxMaster
.is() )
2027 Reference
< XAnimationNode
> xMasterNode( rNode
.mxMaster
, UNO_QUERY_THROW
);
2028 Sequence
< NamedValue
> aUserData( rNode
.mxNode
->getUserData() );
2029 sal_Int32 nSize
= aUserData
.getLength();
2030 aUserData
.realloc(nSize
+1);
2031 aUserData
[nSize
].Name
= "master-element";
2032 aUserData
[nSize
].Value
<<= xMasterNode
;
2033 rNode
.mxNode
->setUserData( aUserData
);
2035 // insert after effect node into timeline
2036 Reference
< XTimeContainer
> xContainer( rNode
.mxMaster
->getParent(), UNO_QUERY_THROW
);
2038 if( !rNode
.mbOnNextEffect
) // sameClick
2040 // insert the aftereffect after its effect is animated
2041 xContainer
->insertAfter( rNode
.mxNode
, rNode
.mxMaster
);
2045 Reference
< XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
2046 // insert the aftereffect in the next group
2048 Reference
< XTimeContainer
> xClickContainer( xContainer
->getParent(), UNO_QUERY_THROW
);
2049 Reference
< XTimeContainer
> xSequenceContainer( xClickContainer
->getParent(), UNO_QUERY_THROW
);
2051 Reference
< XTimeContainer
> xNextContainer
;
2053 // first try if we have an after effect container
2054 if( !implFindNextContainer( xClickContainer
, xContainer
, xNextContainer
) )
2056 Reference
< XTimeContainer
> xNextClickContainer
;
2057 // if not, try to find the next click effect container
2058 if( implFindNextContainer( xSequenceContainer
, xClickContainer
, xNextClickContainer
) )
2060 Reference
< XEnumerationAccess
> xEnumerationAccess( xNextClickContainer
, UNO_QUERY_THROW
);
2061 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
2062 if( xEnumeration
->hasMoreElements() )
2064 // the next container is the first child container
2065 xEnumeration
->nextElement() >>= xNextContainer
;
2069 // this does not yet have a child container, create one
2070 xNextContainer
.set( ParallelTimeContainer::create(xContext
), UNO_QUERY_THROW
);
2072 xNextContainer
->setBegin( makeAny( (double)0.0 ) );
2073 xNextClickContainer
->appendChild( xNextContainer
);
2075 DBG_ASSERT( xNextContainer
.is(), "ppt::stl_process_after_effect_node_func::operator(), could not find/create container!" );
2079 // if we don't have a next container, we add one to the sequence container
2080 if( !xNextContainer
.is() )
2082 Reference
< XTimeContainer
> xNewClickContainer( ParallelTimeContainer::create( xContext
), UNO_QUERY_THROW
);
2085 aEvent
.Trigger
= EventTrigger::ON_NEXT
;
2087 xNewClickContainer
->setBegin( makeAny( aEvent
) );
2089 xSequenceContainer
->insertAfter( xNewClickContainer
, xClickContainer
);
2091 xNextContainer
.set( ParallelTimeContainer::create( xContext
), UNO_QUERY_THROW
);
2093 DBG_ASSERT( xNextContainer
.is(), "ppt::stl_process_after_effect_node_func::operator(), could not create container!" );
2094 if( xNextContainer
.is() )
2096 xNextContainer
->setBegin( makeAny( (double)0.0 ) );
2097 xNewClickContainer
->appendChild( xNextContainer
);
2101 if( xNextContainer
.is() )
2103 // find begin time of first element
2104 Reference
< XEnumerationAccess
> xEnumerationAccess( xNextContainer
, UNO_QUERY_THROW
);
2105 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
2106 if( xEnumeration
->hasMoreElements() )
2108 Reference
< XAnimationNode
> xChild
;
2109 // the next container is the first child container
2110 xEnumeration
->nextElement() >>= xChild
;
2113 Any
aBegin( xChild
->getBegin() );
2114 double fBegin
= 0.0;
2115 if( (aBegin
>>= fBegin
) && (fBegin
>= 0.0))
2116 rNode
.mxNode
->setBegin( aBegin
);
2120 xNextContainer
->appendChild( rNode
.mxNode
);
2127 OSL_FAIL( "ppt::stl_process_after_effect_node_func::operator(), exception caught!" );
2131 EffectSequence::iterator
EffectSequenceHelper::find( const CustomAnimationEffectPtr
& pEffect
)
2133 return std::find( maEffects
.begin(), maEffects
.end(), pEffect
);
2136 CustomAnimationEffectPtr
EffectSequenceHelper::findEffect( const ::com::sun::star::uno::Reference
< ::com::sun::star::animations::XAnimationNode
>& xNode
) const
2138 CustomAnimationEffectPtr pEffect
;
2140 EffectSequence::const_iterator
aIter( maEffects
.begin() );
2141 for( ; aIter
!= maEffects
.end(); ++aIter
)
2143 if( (*aIter
)->getNode() == xNode
)
2153 sal_Int32
EffectSequenceHelper::getOffsetFromEffect( const CustomAnimationEffectPtr
& xEffect
) const
2155 sal_Int32 nOffset
= 0;
2157 EffectSequence::const_iterator
aIter( maEffects
.begin() );
2158 for( ; aIter
!= maEffects
.end(); ++aIter
, nOffset
++ )
2160 if( (*aIter
) == xEffect
)
2167 CustomAnimationEffectPtr
EffectSequenceHelper::getEffectFromOffset( sal_Int32 nOffset
) const
2169 EffectSequence::const_iterator
aIter( maEffects
.begin() );
2170 while( nOffset
-- && aIter
!= maEffects
.end() )
2173 CustomAnimationEffectPtr pEffect
;
2174 if( aIter
!= maEffects
.end() )
2180 bool EffectSequenceHelper::disposeShape( const Reference
< XShape
>& xShape
)
2182 bool bChanges
= false;
2184 EffectSequence::iterator
aIter( maEffects
.begin() );
2185 while( aIter
!= maEffects
.end() )
2187 if( (*aIter
)->getTargetShape() == xShape
)
2189 (*aIter
)->setEffectSequence( 0 );
2191 aIter
= maEffects
.erase( aIter
);
2202 bool EffectSequenceHelper::hasEffect( const com::sun::star::uno::Reference
< com::sun::star::drawing::XShape
>& xShape
)
2204 EffectSequence::iterator
aIter( maEffects
.begin() );
2205 while( aIter
!= maEffects
.end() )
2207 if( (*aIter
)->getTargetShape() == xShape
)
2215 void EffectSequenceHelper::insertTextRange( const com::sun::star::uno::Any
& aTarget
)
2217 bool bChanges
= false;
2219 ParagraphTarget aParaTarget
;
2220 if( !(aTarget
>>= aParaTarget
) )
2223 EffectSequence::iterator
aIter( maEffects
.begin() );
2224 while( aIter
!= maEffects
.end() )
2226 if( (*aIter
)->getTargetShape() == aParaTarget
.Shape
)
2227 bChanges
|= (*aIter
)->checkForText();
2235 void EffectSequenceHelper::disposeTextRange( const com::sun::star::uno::Any
& aTarget
)
2237 ParagraphTarget aParaTarget
;
2238 if( !(aTarget
>>= aParaTarget
) )
2241 bool bChanges
= false;
2242 bool bErased
= false;
2244 EffectSequence::iterator
aIter( maEffects
.begin() );
2245 while( aIter
!= maEffects
.end() )
2247 Any
aIterTarget( (*aIter
)->getTarget() );
2248 if( aIterTarget
.getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
2250 ParagraphTarget aIterParaTarget
;
2251 if( (aIterTarget
>>= aIterParaTarget
) && (aIterParaTarget
.Shape
== aParaTarget
.Shape
) )
2253 if( aIterParaTarget
.Paragraph
== aParaTarget
.Paragraph
)
2255 // delete this effect if it targets the disposed paragraph directly
2256 (*aIter
)->setEffectSequence( 0 );
2257 aIter
= maEffects
.erase( aIter
);
2263 if( aIterParaTarget
.Paragraph
> aParaTarget
.Paragraph
)
2265 // shift all paragraphs after disposed paragraph
2266 aIterParaTarget
.Paragraph
--;
2267 (*aIter
)->setTarget( makeAny( aIterParaTarget
) );
2272 else if( (*aIter
)->getTargetShape() == aParaTarget
.Shape
)
2274 bChanges
|= (*aIter
)->checkForText();
2287 CustomAnimationTextGroup::CustomAnimationTextGroup( const Reference
< XShape
>& rTarget
, sal_Int32 nGroupId
)
2288 : maTarget( rTarget
),
2289 mnGroupId( nGroupId
)
2294 void CustomAnimationTextGroup::reset()
2296 mnTextGrouping
= -1;
2297 mbAnimateForm
= false;
2298 mbTextReverse
= false;
2299 mfGroupingAuto
= -1.0;
2300 mnLastPara
= -1; // used to check for TextReverse
2302 for (int i
= 0; i
< PARA_LEVELS
; ++i
)
2304 mnDepthFlags
[i
] = 0;
2310 void CustomAnimationTextGroup::addEffect( CustomAnimationEffectPtr
& pEffect
)
2312 maEffects
.push_back( pEffect
);
2314 Any
aTarget( pEffect
->getTarget() );
2315 if( aTarget
.getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
2317 // now look at the paragraph
2318 ParagraphTarget aParaTarget
;
2319 aTarget
>>= aParaTarget
;
2321 if( mnLastPara
!= -1 )
2322 mbTextReverse
= mnLastPara
> aParaTarget
.Paragraph
;
2324 mnLastPara
= aParaTarget
.Paragraph
;
2326 const sal_Int32 nParaDepth
= pEffect
->getParaDepth();
2328 // only look at the first PARA_LEVELS levels
2329 if( nParaDepth
< PARA_LEVELS
)
2331 // our first paragraph with this level?
2332 if( mnDepthFlags
[nParaDepth
] == 0 )
2334 // so set it to the first found
2335 mnDepthFlags
[nParaDepth
] = (sal_Int8
)pEffect
->getNodeType();
2337 else if( mnDepthFlags
[nParaDepth
] != pEffect
->getNodeType() )
2339 mnDepthFlags
[nParaDepth
] = -1;
2342 if( pEffect
->getNodeType() == EffectNodeType::AFTER_PREVIOUS
)
2343 mfGroupingAuto
= pEffect
->getBegin();
2345 mnTextGrouping
= PARA_LEVELS
;
2346 while( (mnTextGrouping
> 0)
2347 && (mnDepthFlags
[mnTextGrouping
- 1] <= 0) )
2353 // if we have an effect with the shape as a target, we animate the background
2354 mbAnimateForm
= pEffect
->getTargetSubItem() != ShapeAnimationSubType::ONLY_TEXT
;
2358 CustomAnimationTextGroupPtr
EffectSequenceHelper::findGroup( sal_Int32 nGroupId
)
2360 CustomAnimationTextGroupPtr aPtr
;
2362 CustomAnimationTextGroupMap::iterator
aIter( maGroupMap
.find( nGroupId
) );
2363 if( aIter
!= maGroupMap
.end() )
2364 aPtr
= (*aIter
).second
;
2369 void EffectSequenceHelper::updateTextGroups()
2373 // first create all the groups
2374 EffectSequence::iterator
aIter( maEffects
.begin() );
2375 const EffectSequence::iterator
aEnd( maEffects
.end() );
2376 while( aIter
!= aEnd
)
2378 CustomAnimationEffectPtr
pEffect( (*aIter
++) );
2380 const sal_Int32 nGroupId
= pEffect
->getGroupId();
2382 if( nGroupId
== -1 )
2383 continue; // trivial case, no group
2385 CustomAnimationTextGroupPtr pGroup
= findGroup( nGroupId
);
2388 pGroup
.reset( new CustomAnimationTextGroup( pEffect
->getTargetShape(), nGroupId
) );
2389 maGroupMap
[nGroupId
] = pGroup
;
2392 pGroup
->addEffect( pEffect
);
2396 CustomAnimationTextGroupPtr
EffectSequenceHelper::createTextGroup( CustomAnimationEffectPtr pEffect
, sal_Int32 nTextGrouping
, double fTextGroupingAuto
, bool bAnimateForm
, bool bTextReverse
)
2398 // first finde a free group-id
2399 sal_Int32 nGroupId
= 0;
2401 CustomAnimationTextGroupMap::iterator
aIter( maGroupMap
.begin() );
2402 const CustomAnimationTextGroupMap::iterator
aEnd( maGroupMap
.end() );
2403 while( aIter
!= aEnd
)
2405 if( (*aIter
).first
== nGroupId
)
2408 aIter
= maGroupMap
.begin();
2416 Reference
< XShape
> xTarget( pEffect
->getTargetShape() );
2418 CustomAnimationTextGroupPtr
pTextGroup( new CustomAnimationTextGroup( xTarget
, nGroupId
) );
2419 maGroupMap
[nGroupId
] = pTextGroup
;
2423 // do we need to target the shape?
2424 if( (nTextGrouping
== 0) || bAnimateForm
)
2427 if( nTextGrouping
== 0)
2428 nSubItem
= bAnimateForm
? ShapeAnimationSubType::AS_WHOLE
: ShapeAnimationSubType::ONLY_TEXT
;
2430 nSubItem
= ShapeAnimationSubType::ONLY_BACKGROUND
;
2432 pEffect
->setTarget( makeAny( xTarget
) );
2433 pEffect
->setTargetSubItem( nSubItem
);
2434 pEffect
->setEffectSequence( this );
2435 pEffect
->setGroupId( nGroupId
);
2437 pTextGroup
->addEffect( pEffect
);
2441 pTextGroup
->mnTextGrouping
= nTextGrouping
;
2442 pTextGroup
->mfGroupingAuto
= fTextGroupingAuto
;
2443 pTextGroup
->mbTextReverse
= bTextReverse
;
2445 // now add an effect for each paragraph
2446 createTextGroupParagraphEffects( pTextGroup
, pEffect
, bUsed
);
2453 void EffectSequenceHelper::createTextGroupParagraphEffects( CustomAnimationTextGroupPtr pTextGroup
, CustomAnimationEffectPtr pEffect
, bool bUsed
)
2455 Reference
< XShape
> xTarget( pTextGroup
->maTarget
);
2457 sal_Int32 nTextGrouping
= pTextGroup
->mnTextGrouping
;
2458 double fTextGroupingAuto
= pTextGroup
->mfGroupingAuto
;
2459 bool bTextReverse
= pTextGroup
->mbTextReverse
;
2461 // now add an effect for each paragraph
2462 if( nTextGrouping
>= 0 ) try
2464 EffectSequence::iterator
aInsertIter( find( pEffect
) );
2466 Reference
< XEnumerationAccess
> xText( xTarget
, UNO_QUERY_THROW
);
2467 Reference
< XEnumeration
> xEnumeration( xText
->createEnumeration(), UNO_QUERY_THROW
);
2469 std::list
< sal_Int16
> aParaList
;
2472 // fill the list with all valid paragraphs
2473 for( nPara
= 0; xEnumeration
->hasMoreElements(); nPara
++ )
2475 Reference
< XTextRange
> xRange( xEnumeration
->nextElement(), UNO_QUERY
);
2476 if( xRange
.is() && !xRange
->getString().isEmpty() )
2478 if( bTextReverse
) // sort them
2479 aParaList
.push_front( nPara
);
2481 aParaList
.push_back( nPara
);
2485 ParagraphTarget aTarget
;
2486 aTarget
.Shape
= xTarget
;
2488 std::list
< sal_Int16
>::iterator
aIter( aParaList
.begin() );
2489 std::list
< sal_Int16
>::iterator
aEnd( aParaList
.end() );
2490 while( aIter
!= aEnd
)
2492 aTarget
.Paragraph
= (*aIter
++);
2494 CustomAnimationEffectPtr pNewEffect
;
2497 // clone a new effect from first effect
2498 pNewEffect
= pEffect
->clone();
2500 aInsertIter
= maEffects
.insert( aInsertIter
, pNewEffect
);
2504 // reuse first effect if its not yet used
2505 pNewEffect
= pEffect
;
2507 aInsertIter
= find( pNewEffect
);
2510 // set target and group-id
2511 pNewEffect
->setTarget( makeAny( aTarget
) );
2512 pNewEffect
->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT
);
2513 pNewEffect
->setGroupId( pTextGroup
->mnGroupId
);
2514 pNewEffect
->setEffectSequence( this );
2516 // set correct node type
2517 if( pNewEffect
->getParaDepth() < nTextGrouping
)
2519 if( fTextGroupingAuto
== -1.0 )
2521 pNewEffect
->setNodeType( EffectNodeType::ON_CLICK
);
2522 pNewEffect
->setBegin( 0.0 );
2526 pNewEffect
->setNodeType( EffectNodeType::AFTER_PREVIOUS
);
2527 pNewEffect
->setBegin( fTextGroupingAuto
);
2532 pNewEffect
->setNodeType( EffectNodeType::WITH_PREVIOUS
);
2533 pNewEffect
->setBegin( 0.0 );
2536 pTextGroup
->addEffect( pNewEffect
);
2542 OSL_FAIL("sd::EffectSequenceHelper::createTextGroup(), exception caught!" );
2546 void EffectSequenceHelper::setTextGrouping( CustomAnimationTextGroupPtr pTextGroup
, sal_Int32 nTextGrouping
)
2548 if( pTextGroup
->mnTextGrouping
== nTextGrouping
)
2550 // first case, trivial case, do nothing
2552 else if( (pTextGroup
->mnTextGrouping
== -1) && (nTextGrouping
>= 0) )
2554 // second case, we need to add new effects for each paragraph
2556 CustomAnimationEffectPtr
pEffect( pTextGroup
->maEffects
.front() );
2558 pTextGroup
->mnTextGrouping
= nTextGrouping
;
2559 createTextGroupParagraphEffects( pTextGroup
, pEffect
, true );
2562 else if( (pTextGroup
->mnTextGrouping
>= 0) && (nTextGrouping
== -1 ) )
2564 // third case, we need to remove effects for each paragraph
2566 EffectSequence
aEffects( pTextGroup
->maEffects
);
2567 pTextGroup
->reset();
2569 EffectSequence::iterator
aIter( aEffects
.begin() );
2570 const EffectSequence::iterator
aEnd( aEffects
.end() );
2571 while( aIter
!= aEnd
)
2573 CustomAnimationEffectPtr
pEffect( (*aIter
++) );
2575 if( pEffect
->getTarget().getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
2578 pTextGroup
->addEffect( pEffect
);
2584 // fourth case, we need to change the node types for the text nodes
2585 double fTextGroupingAuto
= pTextGroup
->mfGroupingAuto
;
2587 EffectSequence
aEffects( pTextGroup
->maEffects
);
2588 pTextGroup
->reset();
2590 EffectSequence::iterator
aIter( aEffects
.begin() );
2591 const EffectSequence::iterator
aEnd( aEffects
.end() );
2592 while( aIter
!= aEnd
)
2594 CustomAnimationEffectPtr
pEffect( (*aIter
++) );
2596 if( pEffect
->getTarget().getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
2598 // set correct node type
2599 if( pEffect
->getParaDepth() < nTextGrouping
)
2601 if( fTextGroupingAuto
== -1.0 )
2603 pEffect
->setNodeType( EffectNodeType::ON_CLICK
);
2604 pEffect
->setBegin( 0.0 );
2608 pEffect
->setNodeType( EffectNodeType::AFTER_PREVIOUS
);
2609 pEffect
->setBegin( fTextGroupingAuto
);
2614 pEffect
->setNodeType( EffectNodeType::WITH_PREVIOUS
);
2615 pEffect
->setBegin( 0.0 );
2619 pTextGroup
->addEffect( pEffect
);
2626 void EffectSequenceHelper::setAnimateForm( CustomAnimationTextGroupPtr pTextGroup
, bool bAnimateForm
)
2628 if( pTextGroup
->mbAnimateForm
== bAnimateForm
)
2630 // trivial case, do nothing
2634 EffectSequence
aEffects( pTextGroup
->maEffects
);
2635 pTextGroup
->reset();
2637 SAL_WARN_IF(aEffects
.empty(), "sd", "EffectSequenceHelper::setAnimateForm effects empty" );
2639 if (aEffects
.empty())
2642 EffectSequence::iterator
aIter( aEffects
.begin() );
2643 const EffectSequence::iterator
aEnd( aEffects
.end() );
2645 // first insert if we have to
2648 EffectSequence::iterator
aInsertIter( find( (*aIter
) ) );
2650 CustomAnimationEffectPtr pEffect
;
2651 if( (aEffects
.size() == 1) && ((*aIter
)->getTarget().getValueType() != ::cppu::UnoType
<ParagraphTarget
>::get() ) )
2653 // special case, only one effect and that targets whole text,
2654 // convert this to target whole shape
2655 pEffect
= (*aIter
++);
2656 pEffect
->setTargetSubItem( ShapeAnimationSubType::AS_WHOLE
);
2660 pEffect
= (*aIter
)->clone();
2661 pEffect
->setTarget( makeAny( (*aIter
)->getTargetShape() ) );
2662 pEffect
->setTargetSubItem( ShapeAnimationSubType::ONLY_BACKGROUND
);
2663 maEffects
.insert( aInsertIter
, pEffect
);
2666 pTextGroup
->addEffect( pEffect
);
2669 if( !bAnimateForm
&& (aEffects
.size() == 1) )
2671 CustomAnimationEffectPtr
pEffect( (*aIter
) );
2672 pEffect
->setTarget( makeAny( (*aIter
)->getTargetShape() ) );
2673 pEffect
->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT
);
2674 pTextGroup
->addEffect( pEffect
);
2678 // readd the rest to the group again
2679 while( aIter
!= aEnd
)
2681 CustomAnimationEffectPtr
pEffect( (*aIter
++) );
2683 if( pEffect
->getTarget().getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
2685 pTextGroup
->addEffect( pEffect
);
2689 DBG_ASSERT( !bAnimateForm
, "sd::EffectSequenceHelper::setAnimateForm(), something is wrong here!" );
2698 void EffectSequenceHelper::setTextGroupingAuto( CustomAnimationTextGroupPtr pTextGroup
, double fTextGroupingAuto
)
2700 sal_Int32 nTextGrouping
= pTextGroup
->mnTextGrouping
;
2702 EffectSequence
aEffects( pTextGroup
->maEffects
);
2703 pTextGroup
->reset();
2705 EffectSequence::iterator
aIter( aEffects
.begin() );
2706 const EffectSequence::iterator
aEnd( aEffects
.end() );
2707 while( aIter
!= aEnd
)
2709 CustomAnimationEffectPtr
pEffect( (*aIter
++) );
2711 if( pEffect
->getTarget().getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
2713 // set correct node type
2714 if( pEffect
->getParaDepth() < nTextGrouping
)
2716 if( fTextGroupingAuto
== -1.0 )
2718 pEffect
->setNodeType( EffectNodeType::ON_CLICK
);
2719 pEffect
->setBegin( 0.0 );
2723 pEffect
->setNodeType( EffectNodeType::AFTER_PREVIOUS
);
2724 pEffect
->setBegin( fTextGroupingAuto
);
2729 pEffect
->setNodeType( EffectNodeType::WITH_PREVIOUS
);
2730 pEffect
->setBegin( 0.0 );
2734 pTextGroup
->addEffect( pEffect
);
2740 struct ImplStlTextGroupSortHelper
2742 ImplStlTextGroupSortHelper( bool bReverse
) : mbReverse( bReverse
) {};
2743 bool operator()( const CustomAnimationEffectPtr
& p1
, const CustomAnimationEffectPtr
& p2
);
2745 sal_Int32
getTargetParagraph( const CustomAnimationEffectPtr
& p1
);
2748 sal_Int32
ImplStlTextGroupSortHelper::getTargetParagraph( const CustomAnimationEffectPtr
& p1
)
2750 const Any
aTarget(p1
->getTarget());
2751 if( aTarget
.hasValue() && aTarget
.getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
2753 ParagraphTarget aParaTarget
;
2754 aTarget
>>= aParaTarget
;
2755 return aParaTarget
.Paragraph
;
2759 return mbReverse
? 0x7fffffff : -1;
2763 bool ImplStlTextGroupSortHelper::operator()( const CustomAnimationEffectPtr
& p1
, const CustomAnimationEffectPtr
& p2
)
2767 return getTargetParagraph( p2
) < getTargetParagraph( p1
);
2771 return getTargetParagraph( p1
) < getTargetParagraph( p2
);
2775 void EffectSequenceHelper::setTextReverse( CustomAnimationTextGroupPtr pTextGroup
, bool bTextReverse
)
2777 if( pTextGroup
->mbTextReverse
== bTextReverse
)
2783 std::vector
< CustomAnimationEffectPtr
> aSortedVector(pTextGroup
->maEffects
.size());
2784 std::copy( pTextGroup
->maEffects
.begin(), pTextGroup
->maEffects
.end(), aSortedVector
.begin() );
2785 ImplStlTextGroupSortHelper
aSortHelper( bTextReverse
);
2786 std::sort( aSortedVector
.begin(), aSortedVector
.end(), aSortHelper
);
2788 pTextGroup
->reset();
2790 std::vector
< CustomAnimationEffectPtr
>::iterator
aIter( aSortedVector
.begin() );
2791 const std::vector
< CustomAnimationEffectPtr
>::iterator
aEnd( aSortedVector
.end() );
2795 pTextGroup
->addEffect( (*aIter
) );
2796 EffectSequence::iterator
aInsertIter( find( (*aIter
++) ) );
2797 while( aIter
!= aEnd
)
2799 CustomAnimationEffectPtr
pEffect( (*aIter
++) );
2800 maEffects
.erase( find( pEffect
) );
2801 aInsertIter
= maEffects
.insert( ++aInsertIter
, pEffect
);
2802 pTextGroup
->addEffect( pEffect
);
2809 void EffectSequenceHelper::addListener( ISequenceListener
* pListener
)
2811 if( std::find( maListeners
.begin(), maListeners
.end(), pListener
) == maListeners
.end() )
2812 maListeners
.push_back( pListener
);
2815 void EffectSequenceHelper::removeListener( ISequenceListener
* pListener
)
2817 maListeners
.remove( pListener
);
2820 struct stl_notify_listeners_func
: public std::unary_function
<ISequenceListener
*, void>
2822 stl_notify_listeners_func() {}
2823 void operator()(ISequenceListener
* pListener
) { pListener
->notify_change(); }
2826 void EffectSequenceHelper::notify_listeners()
2828 stl_notify_listeners_func aFunc
;
2829 std::for_each( maListeners
.begin(), maListeners
.end(), aFunc
);
2832 void EffectSequenceHelper::create( const ::com::sun::star::uno::Reference
< ::com::sun::star::animations::XAnimationNode
>& xNode
)
2834 DBG_ASSERT( xNode
.is(), "sd::EffectSequenceHelper::create(), illegal argument" );
2836 if( xNode
.is() ) try
2838 Reference
< XEnumerationAccess
> xEnumerationAccess( xNode
, UNO_QUERY_THROW
);
2839 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
2840 while( xEnumeration
->hasMoreElements() )
2842 Reference
< XAnimationNode
> xChildNode( xEnumeration
->nextElement(), UNO_QUERY_THROW
);
2843 createEffectsequence( xChildNode
);
2848 OSL_FAIL( "sd::EffectSequenceHelper::create(), exception caught!" );
2852 void EffectSequenceHelper::createEffectsequence( const Reference
< XAnimationNode
>& xNode
)
2854 DBG_ASSERT( xNode
.is(), "sd::EffectSequenceHelper::createEffectsequence(), illegal argument" );
2856 if( xNode
.is() ) try
2858 Reference
< XEnumerationAccess
> xEnumerationAccess( xNode
, UNO_QUERY_THROW
);
2859 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
2860 while( xEnumeration
->hasMoreElements() )
2862 Reference
< XAnimationNode
> xChildNode( xEnumeration
->nextElement(), UNO_QUERY_THROW
);
2864 createEffects( xChildNode
);
2869 OSL_FAIL( "sd::EffectSequenceHelper::createEffectsequence(), exception caught!" );
2873 void EffectSequenceHelper::createEffects( const Reference
< XAnimationNode
>& xNode
)
2875 DBG_ASSERT( xNode
.is(), "sd::EffectSequenceHelper::createEffects(), illegal argument" );
2877 if( xNode
.is() ) try
2879 Reference
< XEnumerationAccess
> xEnumerationAccess( xNode
, UNO_QUERY_THROW
);
2880 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
2881 while( xEnumeration
->hasMoreElements() )
2883 Reference
< XAnimationNode
> xChildNode( xEnumeration
->nextElement(), UNO_QUERY_THROW
);
2885 switch( xChildNode
->getType() )
2888 case AnimationNodeType::PAR
:
2889 case AnimationNodeType::ITERATE
:
2891 CustomAnimationEffectPtr
pEffect( new CustomAnimationEffect( xChildNode
) );
2893 if( pEffect
->mnNodeType
!= -1 )
2895 pEffect
->setEffectSequence( this );
2896 maEffects
.push_back(pEffect
);
2901 // found an after effect
2902 case AnimationNodeType::SET
:
2903 case AnimationNodeType::ANIMATECOLOR
:
2905 processAfterEffect( xChildNode
);
2913 OSL_FAIL( "sd::EffectSequenceHelper::createEffects(), exception caught!" );
2917 void EffectSequenceHelper::processAfterEffect( const Reference
< XAnimationNode
>& xNode
)
2921 Reference
< XAnimationNode
> xMaster
;
2923 Sequence
< NamedValue
> aUserData( xNode
->getUserData() );
2924 sal_Int32 nLength
= aUserData
.getLength();
2925 const NamedValue
* p
= aUserData
.getConstArray();
2929 if ( p
->Name
== "master-element" )
2931 p
->Value
>>= xMaster
;
2937 // only process if this is a valid after effect
2940 CustomAnimationEffectPtr pMasterEffect
;
2942 // find the master effect
2943 stl_CustomAnimationEffect_search_node_predict
aSearchPredict( xMaster
);
2944 EffectSequence::iterator
aIter( std::find_if( maEffects
.begin(), maEffects
.end(), aSearchPredict
) );
2945 if( aIter
!= maEffects
.end() )
2946 pMasterEffect
= (*aIter
);
2948 if( pMasterEffect
.get() )
2950 pMasterEffect
->setHasAfterEffect( true );
2952 // find out what kind of after effect this is
2953 if( xNode
->getType() == AnimationNodeType::ANIMATECOLOR
)
2956 Reference
< XAnimate
> xAnimate( xNode
, UNO_QUERY_THROW
);
2957 pMasterEffect
->setDimColor( xAnimate
->getTo() );
2958 pMasterEffect
->setAfterEffectOnNext( true );
2963 pMasterEffect
->setAfterEffectOnNext( xNode
->getParent() != xMaster
->getParent() );
2970 OSL_FAIL( "sd::EffectSequenceHelper::processAfterEffect(), exception caught!" );
2974 class AnimationChangeListener
: public cppu::WeakImplHelper1
< XChangesListener
>
2977 AnimationChangeListener( MainSequence
* pMainSequence
) : mpMainSequence( pMainSequence
) {}
2979 virtual void SAL_CALL
changesOccurred( const ::com::sun::star::util::ChangesEvent
& Event
) throw (RuntimeException
, std::exception
) SAL_OVERRIDE
;
2980 virtual void SAL_CALL
disposing( const ::com::sun::star::lang::EventObject
& Source
) throw (RuntimeException
, std::exception
) SAL_OVERRIDE
;
2982 MainSequence
* mpMainSequence
;
2985 void SAL_CALL
AnimationChangeListener::changesOccurred( const ::com::sun::star::util::ChangesEvent
& ) throw (RuntimeException
, std::exception
)
2987 if( mpMainSequence
)
2988 mpMainSequence
->startRecreateTimer();
2991 void SAL_CALL
AnimationChangeListener::disposing( const ::com::sun::star::lang::EventObject
& ) throw (RuntimeException
, std::exception
)
2995 MainSequence::MainSequence()
2996 : mxTimingRootNode(SequenceTimeContainer::create(::comphelper::getProcessComponentContext()))
2997 , mbTimerMode(false)
2998 , mbRebuilding( false )
2999 , mnRebuildLockGuard( 0 )
3000 , mbPendingRebuildRequest( false )
3001 , mbIgnoreChanges( 0 )
3003 if( mxTimingRootNode
.is() )
3005 Sequence
< ::com::sun::star::beans::NamedValue
> aUserData( 1 );
3006 aUserData
[0].Name
= "node-type";
3007 aUserData
[0].Value
<<= ::com::sun::star::presentation::EffectNodeType::MAIN_SEQUENCE
;
3008 mxTimingRootNode
->setUserData( aUserData
);
3013 MainSequence::MainSequence( const ::com::sun::star::uno::Reference
< ::com::sun::star::animations::XAnimationNode
>& xNode
)
3014 : mxTimingRootNode( xNode
, UNO_QUERY
)
3015 , mbTimerMode( false )
3016 , mbRebuilding( false )
3017 , mnRebuildLockGuard( 0 )
3018 , mbPendingRebuildRequest( false )
3019 , mbIgnoreChanges( 0 )
3024 MainSequence::~MainSequence()
3029 void MainSequence::init()
3031 mnSequenceType
= EffectNodeType::MAIN_SEQUENCE
;
3033 maTimer
.SetTimeoutHdl( LINK(this, MainSequence
, onTimerHdl
) );
3034 maTimer
.SetTimeout(500);
3036 mxChangesListener
.set( new AnimationChangeListener( this ) );
3038 createMainSequence();
3041 void MainSequence::reset( const ::com::sun::star::uno::Reference
< ::com::sun::star::animations::XAnimationNode
>& xTimingRootNode
)
3045 mxTimingRootNode
.set( xTimingRootNode
, UNO_QUERY
);
3047 createMainSequence();
3050 Reference
< ::com::sun::star::animations::XAnimationNode
> MainSequence::getRootNode()
3052 DBG_ASSERT( mnRebuildLockGuard
== 0, "MainSequence::getRootNode(), rebuild is locked, is this really what you want?" );
3054 if( maTimer
.IsActive() && mbTimerMode
)
3056 // force a rebuild NOW if one is pending
3061 return EffectSequenceHelper::getRootNode();
3064 void MainSequence::createMainSequence()
3066 if( mxTimingRootNode
.is() ) try
3068 Reference
< XEnumerationAccess
> xEnumerationAccess( mxTimingRootNode
, UNO_QUERY_THROW
);
3069 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
3070 while( xEnumeration
->hasMoreElements() )
3072 Reference
< XAnimationNode
> xChildNode( xEnumeration
->nextElement(), UNO_QUERY_THROW
);
3073 sal_Int32 nNodeType
= CustomAnimationEffect::get_node_type( xChildNode
);
3074 if( nNodeType
== EffectNodeType::MAIN_SEQUENCE
)
3076 mxSequenceRoot
.set( xChildNode
, UNO_QUERY
);
3077 EffectSequenceHelper::create( xChildNode
);
3079 else if( nNodeType
== EffectNodeType::INTERACTIVE_SEQUENCE
)
3081 Reference
< XTimeContainer
> xInteractiveRoot( xChildNode
, UNO_QUERY_THROW
);
3082 InteractiveSequencePtr
pIS( new InteractiveSequence( xInteractiveRoot
, this ) );
3083 pIS
->addListener( this );
3084 maInteractiveSequenceList
.push_back( pIS
);
3088 // see if we have a mainsequence at all. if not, create one...
3089 if( !mxSequenceRoot
.is() )
3091 mxSequenceRoot
= SequenceTimeContainer::create( ::comphelper::getProcessComponentContext() );
3093 uno::Sequence
< ::com::sun::star::beans::NamedValue
> aUserData( 1 );
3094 aUserData
[0].Name
= "node-type";
3095 aUserData
[0].Value
<<= ::com::sun::star::presentation::EffectNodeType::MAIN_SEQUENCE
;
3096 mxSequenceRoot
->setUserData( aUserData
);
3098 // empty sequence until now, set duration to 0.0
3099 // explicitly (otherwise, this sequence will never
3101 mxSequenceRoot
->setDuration( makeAny((double)0.0) );
3103 Reference
< XAnimationNode
> xMainSequenceNode( mxSequenceRoot
, UNO_QUERY_THROW
);
3104 mxTimingRootNode
->appendChild( xMainSequenceNode
);
3111 Reference
< XChangesNotifier
> xNotifier( mxTimingRootNode
, UNO_QUERY
);
3112 if( xNotifier
.is() )
3113 xNotifier
->addChangesListener( mxChangesListener
);
3117 OSL_FAIL( "sd::MainSequence::create(), exception caught!" );
3121 DBG_ASSERT( mxSequenceRoot
.is(), "sd::MainSequence::create(), found no main sequence!" );
3124 void MainSequence::reset()
3126 EffectSequenceHelper::reset();
3128 InteractiveSequenceList::iterator aIter
;
3129 for( aIter
= maInteractiveSequenceList
.begin(); aIter
!= maInteractiveSequenceList
.end(); ++aIter
)
3131 maInteractiveSequenceList
.clear();
3135 Reference
< XChangesNotifier
> xNotifier( mxTimingRootNode
, UNO_QUERY
);
3136 if( xNotifier
.is() )
3137 xNotifier
->removeChangesListener( mxChangesListener
);
3145 InteractiveSequencePtr
MainSequence::createInteractiveSequence( const ::com::sun::star::uno::Reference
< ::com::sun::star::drawing::XShape
>& xShape
)
3147 InteractiveSequencePtr pIS
;
3149 // create a new interactive sequence container
3150 Reference
< XTimeContainer
> xISRoot
= SequenceTimeContainer::create( ::comphelper::getProcessComponentContext() );
3152 uno::Sequence
< ::com::sun::star::beans::NamedValue
> aUserData( 1 );
3153 aUserData
[0].Name
= "node-type";
3154 aUserData
[0].Value
<<= ::com::sun::star::presentation::EffectNodeType::INTERACTIVE_SEQUENCE
;
3155 xISRoot
->setUserData( aUserData
);
3157 Reference
< XChild
> xChild( mxSequenceRoot
, UNO_QUERY_THROW
);
3158 Reference
< XTimeContainer
> xParent( xChild
->getParent(), UNO_QUERY_THROW
);
3159 xParent
->appendChild( xISRoot
);
3161 pIS
.reset( new InteractiveSequence( xISRoot
, this) );
3162 pIS
->setTriggerShape( xShape
);
3163 pIS
->addListener( this );
3164 maInteractiveSequenceList
.push_back( pIS
);
3168 CustomAnimationEffectPtr
MainSequence::findEffect( const ::com::sun::star::uno::Reference
< ::com::sun::star::animations::XAnimationNode
>& xNode
) const
3170 CustomAnimationEffectPtr pEffect
= EffectSequenceHelper::findEffect( xNode
);
3172 if( pEffect
.get() == 0 )
3174 InteractiveSequenceList::const_iterator aIter
;
3175 for( aIter
= maInteractiveSequenceList
.begin(); (aIter
!= maInteractiveSequenceList
.end()) && (pEffect
.get() == 0); ++aIter
)
3177 pEffect
= (*aIter
)->findEffect( xNode
);
3183 sal_Int32
MainSequence::getOffsetFromEffect( const CustomAnimationEffectPtr
& pEffect
) const
3185 sal_Int32 nOffset
= EffectSequenceHelper::getOffsetFromEffect( pEffect
);
3190 nOffset
= EffectSequenceHelper::getCount();
3192 InteractiveSequenceList::const_iterator aIter
;
3193 for( aIter
= maInteractiveSequenceList
.begin(); aIter
!= maInteractiveSequenceList
.end(); ++aIter
)
3195 sal_Int32 nTemp
= (*aIter
)->getOffsetFromEffect( pEffect
);
3197 return nOffset
+ nTemp
;
3199 nOffset
+= (*aIter
)->getCount();
3205 CustomAnimationEffectPtr
MainSequence::getEffectFromOffset( sal_Int32 nOffset
) const
3209 if( nOffset
< getCount() )
3210 return EffectSequenceHelper::getEffectFromOffset( nOffset
);
3212 nOffset
-= getCount();
3214 InteractiveSequenceList::const_iterator
aIter( maInteractiveSequenceList
.begin() );
3216 while( (aIter
!= maInteractiveSequenceList
.end()) && (nOffset
> (*aIter
)->getCount()) )
3217 nOffset
-= (*aIter
++)->getCount();
3219 if( (aIter
!= maInteractiveSequenceList
.end()) && (nOffset
>= 0) )
3220 return (*aIter
)->getEffectFromOffset( nOffset
);
3223 CustomAnimationEffectPtr pEffect
;
3227 bool MainSequence::disposeShape( const Reference
< XShape
>& xShape
)
3229 bool bChanges
= EffectSequenceHelper::disposeShape( xShape
);
3231 InteractiveSequenceList::iterator aIter
;
3232 for( aIter
= maInteractiveSequenceList
.begin(); aIter
!= maInteractiveSequenceList
.end(); )
3234 bChanges
|= (*aIter
++)->disposeShape( xShape
);
3238 startRebuildTimer();
3243 bool MainSequence::hasEffect( const com::sun::star::uno::Reference
< com::sun::star::drawing::XShape
>& xShape
)
3245 if( EffectSequenceHelper::hasEffect( xShape
) )
3248 InteractiveSequenceList::iterator aIter
;
3249 for( aIter
= maInteractiveSequenceList
.begin(); aIter
!= maInteractiveSequenceList
.end(); )
3251 if( (*aIter
)->getTriggerShape() == xShape
)
3254 if( (*aIter
++)->hasEffect( xShape
) )
3261 void MainSequence::insertTextRange( const com::sun::star::uno::Any
& aTarget
)
3263 EffectSequenceHelper::insertTextRange( aTarget
);
3265 InteractiveSequenceList::iterator aIter
;
3266 for( aIter
= maInteractiveSequenceList
.begin(); aIter
!= maInteractiveSequenceList
.end(); ++aIter
)
3268 (*aIter
)->insertTextRange( aTarget
);
3272 void MainSequence::disposeTextRange( const com::sun::star::uno::Any
& aTarget
)
3274 EffectSequenceHelper::disposeTextRange( aTarget
);
3276 InteractiveSequenceList::iterator aIter
;
3277 for( aIter
= maInteractiveSequenceList
.begin(); aIter
!= maInteractiveSequenceList
.end(); ++aIter
)
3279 (*aIter
)->disposeTextRange( aTarget
);
3283 /** callback from the sd::View when an object just left text edit mode */
3284 void MainSequence::onTextChanged( const Reference
< XShape
>& xShape
)
3286 EffectSequenceHelper::onTextChanged( xShape
);
3288 InteractiveSequenceList::iterator aIter
;
3289 for( aIter
= maInteractiveSequenceList
.begin(); aIter
!= maInteractiveSequenceList
.end(); ++aIter
)
3291 (*aIter
)->onTextChanged( xShape
);
3295 void EffectSequenceHelper::onTextChanged( const Reference
< XShape
>& xShape
)
3297 bool bChanges
= false;
3299 EffectSequence::iterator aIter
;
3300 for( aIter
= maEffects
.begin(); aIter
!= maEffects
.end(); ++aIter
)
3302 if( (*aIter
)->getTargetShape() == xShape
)
3303 bChanges
|= (*aIter
)->checkForText();
3307 EffectSequenceHelper::implRebuild();
3310 void MainSequence::rebuild()
3312 startRebuildTimer();
3315 void MainSequence::lockRebuilds()
3317 mnRebuildLockGuard
++;
3320 void MainSequence::unlockRebuilds()
3322 DBG_ASSERT( mnRebuildLockGuard
, "sd::MainSequence::unlockRebuilds(), no corresponding lockRebuilds() call!" );
3323 if( mnRebuildLockGuard
)
3324 mnRebuildLockGuard
--;
3326 if( (mnRebuildLockGuard
== 0) && mbPendingRebuildRequest
)
3328 mbPendingRebuildRequest
= false;
3329 startRebuildTimer();
3333 void MainSequence::implRebuild()
3335 if( mnRebuildLockGuard
)
3337 mbPendingRebuildRequest
= true;
3341 mbRebuilding
= true;
3343 EffectSequenceHelper::implRebuild();
3345 InteractiveSequenceList::iterator
aIter( maInteractiveSequenceList
.begin() );
3346 const InteractiveSequenceList::iterator
aEnd( maInteractiveSequenceList
.end() );
3347 while( aIter
!= aEnd
)
3349 InteractiveSequencePtr
pIS( (*aIter
) );
3350 if( pIS
->maEffects
.empty() )
3352 // remove empty interactive sequences
3353 aIter
= maInteractiveSequenceList
.erase( aIter
);
3355 Reference
< XChild
> xChild( mxSequenceRoot
, UNO_QUERY_THROW
);
3356 Reference
< XTimeContainer
> xParent( xChild
->getParent(), UNO_QUERY_THROW
);
3357 Reference
< XAnimationNode
> xISNode( pIS
->mxSequenceRoot
, UNO_QUERY_THROW
);
3358 xParent
->removeChild( xISNode
);
3368 mbRebuilding
= false;
3371 void MainSequence::notify_change()
3376 bool MainSequence::setTrigger( const CustomAnimationEffectPtr
& pEffect
, const ::com::sun::star::uno::Reference
< ::com::sun::star::drawing::XShape
>& xTriggerShape
)
3378 EffectSequenceHelper
* pOldSequence
= pEffect
->getEffectSequence();
3380 EffectSequenceHelper
* pNewSequence
= 0;
3381 if( xTriggerShape
.is() )
3383 InteractiveSequenceList::iterator
aIter( maInteractiveSequenceList
.begin() );
3384 const InteractiveSequenceList::iterator
aEnd( maInteractiveSequenceList
.end() );
3385 while( aIter
!= aEnd
)
3387 InteractiveSequencePtr
pIS( (*aIter
++) );
3388 if( pIS
->getTriggerShape() == xTriggerShape
)
3390 pNewSequence
= pIS
.get();
3396 pNewSequence
= createInteractiveSequence( xTriggerShape
).get();
3400 pNewSequence
= this;
3403 if( pOldSequence
!= pNewSequence
)
3406 pOldSequence
->maEffects
.remove( pEffect
);
3408 pNewSequence
->maEffects
.push_back( pEffect
);
3409 pEffect
->setEffectSequence( pNewSequence
);
3419 IMPL_LINK_NOARG_TYPED(MainSequence
, onTimerHdl
, Timer
*, void)
3428 createMainSequence();
3432 /** starts a timer that recreates the internal structure from the API core after 1 second */
3433 void MainSequence::startRecreateTimer()
3435 if( !mbRebuilding
&& (mbIgnoreChanges
== 0) )
3437 mbTimerMode
= false;
3442 /** starts a timer that rebuilds the API core from the internal structure after 1 second */
3443 void MainSequence::startRebuildTimer()
3449 InteractiveSequence::InteractiveSequence( const Reference
< XTimeContainer
>& xSequenceRoot
, MainSequence
* pMainSequence
)
3450 : EffectSequenceHelper( xSequenceRoot
), mpMainSequence( pMainSequence
)
3452 mnSequenceType
= EffectNodeType::INTERACTIVE_SEQUENCE
;
3456 if( mxSequenceRoot
.is() )
3458 Reference
< XEnumerationAccess
> xEnumerationAccess( mxSequenceRoot
, UNO_QUERY_THROW
);
3459 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
3460 while( !mxEventSource
.is() && xEnumeration
->hasMoreElements() )
3462 Reference
< XAnimationNode
> xChildNode( xEnumeration
->nextElement(), UNO_QUERY_THROW
);
3465 if( (xChildNode
->getBegin() >>= aEvent
) && (aEvent
.Trigger
== EventTrigger::ON_CLICK
) )
3466 aEvent
.Source
>>= mxEventSource
;
3472 OSL_FAIL( "sd::InteractiveSequence::InteractiveSequence(), exception caught!" );
3477 void InteractiveSequence::rebuild()
3479 mpMainSequence
->rebuild();
3482 void InteractiveSequence::implRebuild()
3484 EffectSequenceHelper::implRebuild();
3487 MainSequenceRebuildGuard::MainSequenceRebuildGuard( const MainSequencePtr
& pMainSequence
)
3488 : mpMainSequence( pMainSequence
)
3490 if( mpMainSequence
.get() )
3491 mpMainSequence
->lockRebuilds();
3494 MainSequenceRebuildGuard::~MainSequenceRebuildGuard()
3496 if( mpMainSequence
.get() )
3497 mpMainSequence
->unlockRebuilds();
3502 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */