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/Audio.hpp>
27 #include <com/sun/star/animations/Command.hpp>
28 #include <com/sun/star/animations/Event.hpp>
29 #include <com/sun/star/animations/EventTrigger.hpp>
30 #include <com/sun/star/animations/IterateContainer.hpp>
31 #include <com/sun/star/animations/ParallelTimeContainer.hpp>
32 #include <com/sun/star/animations/SequenceTimeContainer.hpp>
33 #include <com/sun/star/animations/Timing.hpp>
34 #include <com/sun/star/animations/XCommand.hpp>
35 #include <com/sun/star/animations/XIterateContainer.hpp>
36 #include <com/sun/star/animations/XAnimateTransform.hpp>
37 #include <com/sun/star/animations/XAnimateMotion.hpp>
38 #include <com/sun/star/animations/XAnimate.hpp>
39 #include <com/sun/star/beans/NamedValue.hpp>
40 #include <com/sun/star/beans/XPropertySet.hpp>
41 #include <com/sun/star/container/XEnumerationAccess.hpp>
42 #include <com/sun/star/lang/XInitialization.hpp>
43 #include <com/sun/star/presentation/EffectNodeType.hpp>
44 #include <com/sun/star/presentation/EffectCommands.hpp>
45 #include <com/sun/star/presentation/EffectPresetClass.hpp>
46 #include <com/sun/star/presentation/ParagraphTarget.hpp>
47 #include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
48 #include <com/sun/star/text/XText.hpp>
49 #include <com/sun/star/util/XCloneable.hpp>
50 #include <com/sun/star/util/XChangesNotifier.hpp>
51 #include <comphelper/processfactory.hxx>
52 #include <comphelper/sequence.hxx>
53 #include <com/sun/star/lang/Locale.hpp>
54 #include <com/sun/star/i18n/BreakIterator.hpp>
55 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
56 #include <com/sun/star/i18n/WordType.hpp>
57 #include <com/sun/star/presentation/TextAnimationType.hpp>
59 #include <basegfx/polygon/b2dpolypolygon.hxx>
60 #include <basegfx/polygon/b2dpolypolygontools.hxx>
61 #include <basegfx/matrix/b2dhommatrix.hxx>
62 #include <basegfx/range/b2drange.hxx>
63 #include <basegfx/matrix/b2dhommatrixtools.hxx>
68 #include <cppuhelper/implbase.hxx>
70 #include <drawinglayer/geometry/viewinformation2d.hxx>
71 #include <svx/sdr/contact/viewcontact.hxx>
72 #include <svx/svdopath.hxx>
73 #include <svx/svdpage.hxx>
74 #include <svx/unoapi.hxx>
75 #include <CustomAnimationEffect.hxx>
76 #include <CustomAnimationPreset.hxx>
77 #include <animations.hxx>
79 using namespace ::com::sun::star
;
80 using namespace ::com::sun::star::uno
;
81 using namespace ::com::sun::star::presentation
;
82 using namespace ::com::sun::star::animations
;
84 using ::com::sun::star::container::XEnumerationAccess
;
85 using ::com::sun::star::container::XEnumeration
;
86 using ::com::sun::star::beans::NamedValue
;
87 using ::com::sun::star::container::XChild
;
88 using ::com::sun::star::drawing::XShape
;
89 using ::com::sun::star::lang::XInitialization
;
90 using ::com::sun::star::text::XText
;
91 using ::com::sun::star::text::XTextRange
;
92 using ::com::sun::star::beans::XPropertySet
;
93 using ::com::sun::star::util::XCloneable
;
94 using ::com::sun::star::lang::Locale
;
95 using ::com::sun::star::util::XChangesNotifier
;
96 using ::com::sun::star::util::XChangesListener
;
100 class MainSequenceChangeGuard
103 explicit MainSequenceChangeGuard( EffectSequenceHelper
* pSequence
)
105 mpMainSequence
= dynamic_cast< MainSequence
* >( pSequence
);
106 if( mpMainSequence
== nullptr )
108 InteractiveSequence
* pI
= dynamic_cast< InteractiveSequence
* >( pSequence
);
110 mpMainSequence
= pI
->mpMainSequence
;
112 DBG_ASSERT( mpMainSequence
, "sd::MainSequenceChangeGuard::MainSequenceChangeGuard(), no main sequence to guard!" );
115 mpMainSequence
->mbIgnoreChanges
++;
118 ~MainSequenceChangeGuard()
121 mpMainSequence
->mbIgnoreChanges
++;
125 MainSequence
* mpMainSequence
;
128 CustomAnimationEffect::CustomAnimationEffect( const css::uno::Reference
< css::animations::XAnimationNode
>& xNode
)
133 mfAbsoluteDuration(-1.0),
136 mfIterateInterval(0.0),
139 mfAcceleration( 1.0 ),
141 mbAutoReverse(false),
144 mpEffectSequence( nullptr ),
145 mbHasAfterEffect(false),
146 mbAfterEffectOnNextEffect(false)
151 void CustomAnimationEffect::setNode( const css::uno::Reference
< css::animations::XAnimationNode
>& xNode
)
156 Sequence
< NamedValue
> aUserData( mxNode
->getUserData() );
157 sal_Int32 nLength
= aUserData
.getLength();
158 const NamedValue
* p
= aUserData
.getConstArray();
162 if ( p
->Name
== "node-type" )
164 p
->Value
>>= mnNodeType
;
166 else if ( p
->Name
== "preset-id" )
168 p
->Value
>>= maPresetId
;
170 else if ( p
->Name
== "preset-sub-type" )
172 p
->Value
>>= maPresetSubType
;
174 else if ( p
->Name
== "preset-class" )
176 p
->Value
>>= mnPresetClass
;
178 else if ( p
->Name
== "preset-property" )
180 p
->Value
>>= maProperty
;
182 else if ( p
->Name
== "group-id" )
184 p
->Value
>>= mnGroupId
;
190 // get effect start time
191 mxNode
->getBegin() >>= mfBegin
;
193 mfAcceleration
= mxNode
->getAcceleration();
194 mfDecelerate
= mxNode
->getDecelerate();
195 mbAutoReverse
= mxNode
->getAutoReverse();
197 // get iteration data
198 Reference
< XIterateContainer
> xIter( mxNode
, UNO_QUERY
);
201 mfIterateInterval
= xIter
->getIterateInterval();
202 mnIterateType
= xIter
->getIterateType();
203 maTarget
= xIter
->getTarget();
204 mnTargetSubItem
= xIter
->getSubItem();
208 mfIterateInterval
= 0.0f
;
212 // calculate effect duration and get target shape
213 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
214 if( xEnumerationAccess
.is() )
216 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
217 if( xEnumeration
.is() )
219 while( xEnumeration
->hasMoreElements() )
221 Reference
< XAnimationNode
> xChildNode( xEnumeration
->nextElement(), UNO_QUERY
);
222 if( !xChildNode
.is() )
225 if( xChildNode
->getType() == AnimationNodeType::AUDIO
)
227 mxAudio
.set( xChildNode
, UNO_QUERY
);
229 else if( xChildNode
->getType() == AnimationNodeType::COMMAND
)
231 Reference
< XCommand
> xCommand( xChildNode
, UNO_QUERY
);
234 mnCommand
= xCommand
->getCommand();
235 if( !maTarget
.hasValue() )
236 maTarget
= xCommand
->getTarget();
242 double fDuration
= 0.0;
243 xChildNode
->getBegin() >>= fBegin
;
244 xChildNode
->getDuration() >>= fDuration
;
247 if( fDuration
> mfDuration
)
248 mfDuration
= fDuration
;
250 // no target shape yet?
251 if( !maTarget
.hasValue() )
254 Reference
< XAnimate
> xAnimate( xChildNode
, UNO_QUERY
);
257 maTarget
= xAnimate
->getTarget();
258 mnTargetSubItem
= xAnimate
->getSubItem();
266 mfAbsoluteDuration
= mfDuration
;
267 double fRepeatCount
= 1.0;
268 if( (mxNode
->getRepeatCount()) >>= fRepeatCount
)
269 mfAbsoluteDuration
*= fRepeatCount
;
274 sal_Int32
CustomAnimationEffect::getNumberOfSubitems( const Any
& aTarget
, sal_Int16 nIterateType
)
276 sal_Int32 nSubItems
= 0;
280 // first get target text
281 sal_Int32 nOnlyPara
= -1;
283 Reference
< XText
> xShape
;
287 ParagraphTarget aParaTarget
;
288 if( aTarget
>>= aParaTarget
)
290 xShape
.set( aParaTarget
.Shape
, UNO_QUERY
);
291 nOnlyPara
= aParaTarget
.Paragraph
;
295 // now use the break iterator to iterate over the given text
296 // and count the sub items
300 // TODO/LATER: Optimize this, don't create a break iterator each time
301 Reference
< uno::XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
302 Reference
< i18n::XBreakIterator
> xBI
= i18n::BreakIterator::create(xContext
);
304 Reference
< XEnumerationAccess
> xEA( xShape
, UNO_QUERY_THROW
);
305 Reference
< XEnumeration
> xEnumeration( xEA
->createEnumeration(), UNO_QUERY_THROW
);
306 css::lang::Locale aLocale
;
307 const OUString
aStrLocaleName( "CharLocale" );
308 Reference
< XTextRange
> xParagraph
;
311 while( xEnumeration
->hasMoreElements() )
313 xEnumeration
->nextElement() >>= xParagraph
;
315 // skip this if it's not the only paragraph we want to count
316 if( (nOnlyPara
!= -1) && (nOnlyPara
!= nPara
) )
319 if( nIterateType
== TextAnimationType::BY_PARAGRAPH
)
325 const OUString
aText( xParagraph
->getString() );
326 Reference
< XPropertySet
> xSet( xParagraph
, UNO_QUERY_THROW
);
327 xSet
->getPropertyValue( aStrLocaleName
) >>= aLocale
;
330 const sal_Int32 nEndPos
= aText
.getLength();
332 if( nIterateType
== TextAnimationType::BY_WORD
)
334 for( nPos
= 0; nPos
< nEndPos
; nPos
++ )
336 nPos
= xBI
->getWordBoundary(aText
, nPos
, aLocale
, i18n::WordType::ANY_WORD
, true).endPos
;
344 for( nPos
= 0; nPos
< nEndPos
; nPos
++ )
346 nPos
= xBI
->nextCharacters(aText
, nPos
, aLocale
, i18n::CharacterIteratorMode::SKIPCELL
, 0, nDone
);
352 if( nPara
== nOnlyPara
)
362 OSL_FAIL( "sd::CustomAnimationEffect::getNumberOfSubitems(), exception caught!" );
368 CustomAnimationEffect::~CustomAnimationEffect()
372 CustomAnimationEffectPtr
CustomAnimationEffect::clone() const
374 Reference
< XCloneable
> xCloneable( mxNode
, UNO_QUERY_THROW
);
375 Reference
< XAnimationNode
> xNode( xCloneable
->createClone(), UNO_QUERY_THROW
);
376 CustomAnimationEffectPtr
pEffect( new CustomAnimationEffect( xNode
) );
377 pEffect
->setEffectSequence( getEffectSequence() );
381 sal_Int32
CustomAnimationEffect::get_node_type( const Reference
< XAnimationNode
>& xNode
)
383 sal_Int16 nNodeType
= -1;
387 Sequence
< NamedValue
> aUserData( xNode
->getUserData() );
388 sal_Int32 nLength
= aUserData
.getLength();
391 const NamedValue
* p
= aUserData
.getConstArray();
394 if ( p
->Name
== "node-type" )
396 p
->Value
>>= nNodeType
;
407 void CustomAnimationEffect::setPresetClass( sal_Int16 nPresetClass
)
409 if( mnPresetClass
!= nPresetClass
)
411 mnPresetClass
= nPresetClass
;
414 // first try to find a "preset-class" entry in the user data
416 Sequence
< NamedValue
> aUserData( mxNode
->getUserData() );
417 sal_Int32 nLength
= aUserData
.getLength();
421 NamedValue
* p
= aUserData
.getArray();
424 if ( p
->Name
== "preset-class" )
426 p
->Value
<<= mnPresetClass
;
434 // no "node-type" entry inside user data, so add it
437 nLength
= aUserData
.getLength();
438 aUserData
.realloc( nLength
+ 1);
439 aUserData
[nLength
].Name
= "preset-class";
440 aUserData
[nLength
].Value
<<= mnPresetClass
;
443 mxNode
->setUserData( aUserData
);
448 void CustomAnimationEffect::setNodeType( sal_Int16 nNodeType
)
450 if( mnNodeType
!= nNodeType
)
452 mnNodeType
= nNodeType
;
455 // first try to find a "node-type" entry in the user data
457 Sequence
< NamedValue
> aUserData( mxNode
->getUserData() );
458 sal_Int32 nLength
= aUserData
.getLength();
462 NamedValue
* p
= aUserData
.getArray();
465 if ( p
->Name
== "node-type" )
467 p
->Value
<<= mnNodeType
;
475 // no "node-type" entry inside user data, so add it
478 nLength
= aUserData
.getLength();
479 aUserData
.realloc( nLength
+ 1);
480 aUserData
[nLength
].Name
= "node-type";
481 aUserData
[nLength
].Value
<<= mnNodeType
;
484 mxNode
->setUserData( aUserData
);
489 void CustomAnimationEffect::setGroupId( sal_Int32 nGroupId
)
491 mnGroupId
= nGroupId
;
494 // first try to find a "group-id" entry in the user data
496 Sequence
< NamedValue
> aUserData( mxNode
->getUserData() );
497 sal_Int32 nLength
= aUserData
.getLength();
501 NamedValue
* p
= aUserData
.getArray();
504 if ( p
->Name
== "group-id" )
506 p
->Value
<<= mnGroupId
;
514 // no "node-type" entry inside user data, so add it
517 nLength
= aUserData
.getLength();
518 aUserData
.realloc( nLength
+ 1);
519 aUserData
[nLength
].Name
= "group-id";
520 aUserData
[nLength
].Value
<<= mnGroupId
;
523 mxNode
->setUserData( aUserData
);
527 /** checks if the text for this effect has changed and updates internal flags.
528 returns true if something changed.
530 bool CustomAnimationEffect::checkForText()
532 bool bChange
= false;
534 Reference
< XText
> xText
;
536 if( maTarget
.getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
539 ParagraphTarget aParaTarget
;
540 maTarget
>>= aParaTarget
;
542 xText
.set( aParaTarget
.Shape
, UNO_QUERY
);
547 Reference
< XEnumerationAccess
> xEA( xText
, UNO_QUERY
);
550 Reference
< XEnumeration
> xEnumeration( xEA
->createEnumeration(), UNO_QUERY
);
551 if( xEnumeration
.is() )
553 bool bHasText
= xEnumeration
->hasMoreElements();
554 bChange
|= bHasText
!= mbHasText
;
555 mbHasText
= bHasText
;
557 sal_Int32 nPara
= aParaTarget
.Paragraph
;
559 while( xEnumeration
->hasMoreElements() && nPara
-- )
560 xEnumeration
->nextElement();
562 if( xEnumeration
->hasMoreElements() )
564 Reference
< XPropertySet
> xParaSet
;
565 xEnumeration
->nextElement() >>= xParaSet
;
568 sal_Int32 nParaDepth
= 0;
569 const OUString
strNumberingLevel( "NumberingLevel" );
570 xParaSet
->getPropertyValue( strNumberingLevel
) >>= nParaDepth
;
571 bChange
|= nParaDepth
!= mnParaDepth
;
572 mnParaDepth
= nParaDepth
;
582 bool bHasText
= xText
.is() && !xText
->getString().isEmpty();
583 bChange
|= bHasText
!= mbHasText
;
584 mbHasText
= bHasText
;
587 bChange
|= calculateIterateDuration();
591 bool CustomAnimationEffect::calculateIterateDuration()
593 bool bChange
= false;
595 // if we have an iteration, we must also calculate the
596 // 'true' container duration, that is
597 // ( ( is form animated ) ? [contained effects duration] : 0 ) +
598 // ( [number of animated children] - 1 ) * [interval-delay] + [contained effects duration]
599 Reference
< XIterateContainer
> xIter( mxNode
, UNO_QUERY
);
602 double fDuration
= mfDuration
;
603 const double fSubEffectDuration
= mfDuration
;
605 if( mnTargetSubItem
!= ShapeAnimationSubType::ONLY_BACKGROUND
) // does not make sense for iterate container but better check
607 const sal_Int32 nSubItems
= getNumberOfSubitems( maTarget
, mnIterateType
);
610 const double f
= (nSubItems
-1) * mfIterateInterval
;
615 // if we also animate the form first, we have to add the
616 // sub effect duration to the whole effect duration
617 if( mnTargetSubItem
== ShapeAnimationSubType::AS_WHOLE
)
618 fDuration
+= fSubEffectDuration
;
620 bChange
|= fDuration
!= mfAbsoluteDuration
;
621 mfAbsoluteDuration
= fDuration
;
627 void CustomAnimationEffect::setTarget( const css::uno::Any
& rTarget
)
633 // first, check special case for random node
634 Reference
< XInitialization
> xInit( mxNode
, UNO_QUERY
);
637 const Sequence
< Any
> aArgs( &maTarget
, 1 );
638 xInit
->initialize( aArgs
);
642 Reference
< XIterateContainer
> xIter( mxNode
, UNO_QUERY
);
645 xIter
->setTarget(maTarget
);
649 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
650 if( xEnumerationAccess
.is() )
652 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
653 if( xEnumeration
.is() )
655 while( xEnumeration
->hasMoreElements() )
657 const Any
aElem( xEnumeration
->nextElement() );
658 Reference
< XAnimate
> xAnimate( aElem
, UNO_QUERY
);
660 xAnimate
->setTarget( rTarget
);
663 Reference
< XCommand
> xCommand( aElem
, UNO_QUERY
);
665 xCommand
->setTarget( rTarget
);
676 OSL_FAIL( "sd::CustomAnimationEffect::setTarget(), exception caught!" );
680 void CustomAnimationEffect::setTargetSubItem( sal_Int16 nSubItem
)
684 mnTargetSubItem
= nSubItem
;
686 Reference
< XIterateContainer
> xIter( mxNode
, UNO_QUERY
);
689 xIter
->setSubItem(mnTargetSubItem
);
693 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
694 if( xEnumerationAccess
.is() )
696 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
697 if( xEnumeration
.is() )
699 while( xEnumeration
->hasMoreElements() )
701 Reference
< XAnimate
> xAnimate( xEnumeration
->nextElement(), UNO_QUERY
);
703 xAnimate
->setSubItem( mnTargetSubItem
);
711 OSL_FAIL( "sd::CustomAnimationEffect::setTargetSubItem(), exception caught!" );
715 void CustomAnimationEffect::setDuration( double fDuration
)
717 if( (mfDuration
!= -1.0) && (mfDuration
!= fDuration
) ) try
719 double fScale
= fDuration
/ mfDuration
;
720 mfDuration
= fDuration
;
721 double fRepeatCount
= 1.0;
722 getRepeatCount() >>= fRepeatCount
;
723 mfAbsoluteDuration
= mfDuration
* fRepeatCount
;
725 // calculate effect duration and get target shape
726 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
727 if( xEnumerationAccess
.is() )
729 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
730 if( xEnumeration
.is() )
732 while( xEnumeration
->hasMoreElements() )
734 Reference
< XAnimationNode
> xChildNode( xEnumeration
->nextElement(), UNO_QUERY
);
735 if( !xChildNode
.is() )
738 double fChildBegin
= 0.0;
739 xChildNode
->getBegin() >>= fChildBegin
;
740 if( fChildBegin
!= 0.0 )
742 fChildBegin
*= fScale
;
743 xChildNode
->setBegin( makeAny( fChildBegin
) );
746 double fChildDuration
= 0.0;
747 xChildNode
->getDuration() >>= fChildDuration
;
748 if( fChildDuration
!= 0.0 )
750 fChildDuration
*= fScale
;
751 xChildNode
->setDuration( makeAny( fChildDuration
) );
756 calculateIterateDuration();
760 OSL_FAIL( "sd::CustomAnimationEffect::setDuration(), exception caught!" );
764 void CustomAnimationEffect::setBegin( double fBegin
)
766 if( mxNode
.is() ) try
769 mxNode
->setBegin( makeAny( fBegin
) );
773 OSL_FAIL( "sd::CustomAnimationEffect::setBegin(), exception caught!" );
777 void CustomAnimationEffect::setAcceleration( double fAcceleration
)
779 if( mxNode
.is() ) try
781 mfAcceleration
= fAcceleration
;
782 mxNode
->setAcceleration( fAcceleration
);
786 OSL_FAIL( "sd::CustomAnimationEffect::setAcceleration(), exception caught!" );
790 void CustomAnimationEffect::setDecelerate( double fDecelerate
)
792 if( mxNode
.is() ) try
794 mfDecelerate
= fDecelerate
;
795 mxNode
->setDecelerate( fDecelerate
);
799 OSL_FAIL( "sd::CustomAnimationEffect::setDecelerate(), exception caught!" );
803 void CustomAnimationEffect::setAutoReverse( bool bAutoReverse
)
805 if( mxNode
.is() ) try
807 mbAutoReverse
= bAutoReverse
;
808 mxNode
->setAutoReverse( bAutoReverse
);
812 OSL_FAIL( "sd::CustomAnimationEffect::setAutoReverse(), exception caught!" );
816 void CustomAnimationEffect::replaceNode( const css::uno::Reference
< css::animations::XAnimationNode
>& xNode
)
818 sal_Int16 nNodeType
= mnNodeType
;
819 Any aTarget
= maTarget
;
821 double fBegin
= mfBegin
;
822 double fDuration
= mfDuration
;
823 double fAcceleration
= mfAcceleration
;
824 double fDecelerate
= mfDecelerate
;
825 bool bAutoReverse
= mbAutoReverse
;
826 Reference
< XAudio
> xAudio( mxAudio
);
827 sal_Int16 nIterateType
= mnIterateType
;
828 double fIterateInterval
= mfIterateInterval
;
829 sal_Int16 nSubItem
= mnTargetSubItem
;
834 setNodeType( nNodeType
);
835 setTarget( aTarget
);
836 setTargetSubItem( nSubItem
);
837 setDuration( fDuration
);
840 setAcceleration( fAcceleration
);
841 setDecelerate( fDecelerate
);
842 setAutoReverse( bAutoReverse
);
844 if( nIterateType
!= mnIterateType
)
845 setIterateType( nIterateType
);
847 if( mnIterateType
&& ( fIterateInterval
!= mfIterateInterval
) )
848 setIterateInterval( fIterateInterval
);
851 Reference
< XShape
> CustomAnimationEffect::getTargetShape() const
853 Reference
< XShape
> xShape
;
857 ParagraphTarget aParaTarget
;
858 if( maTarget
>>= aParaTarget
)
859 xShape
= aParaTarget
.Shape
;
865 Any
CustomAnimationEffect::getRepeatCount() const
869 return mxNode
->getRepeatCount();
878 Any
CustomAnimationEffect::getEnd() const
882 return mxNode
->getEnd();
891 sal_Int16
CustomAnimationEffect::getFill() const
894 return mxNode
->getFill();
899 void CustomAnimationEffect::setRepeatCount( const Any
& rRepeatCount
)
903 mxNode
->setRepeatCount( rRepeatCount
);
904 double fRepeatCount
= 1.0;
905 rRepeatCount
>>= fRepeatCount
;
906 mfAbsoluteDuration
= mfDuration
* fRepeatCount
;
910 void CustomAnimationEffect::setEnd( const Any
& rEnd
)
913 mxNode
->setEnd( rEnd
);
916 void CustomAnimationEffect::setFill( sal_Int16 nFill
)
919 mxNode
->setFill( nFill
);
922 Reference
< XAnimationNode
> CustomAnimationEffect::createAfterEffectNode() const
924 DBG_ASSERT( mbHasAfterEffect
, "sd::CustomAnimationEffect::createAfterEffectNode(), this node has no after effect!" );
926 Reference
< XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
928 Reference
< XAnimate
> xAnimate
;
929 if( maDimColor
.hasValue() )
930 xAnimate
= AnimateColor::create( xContext
);
932 xAnimate
= AnimateSet::create( xContext
);
935 OUString aAttributeName
;
937 if( maDimColor
.hasValue() )
940 aAttributeName
= "DimColor";
945 aAttributeName
= "Visibility";
949 if( !mbAfterEffectOnNextEffect
) // sameClick
953 aEvent
.Source
<<= getNode();
954 aEvent
.Trigger
= EventTrigger::END_EVENT
;
964 xAnimate
->setBegin( aBegin
);
965 xAnimate
->setTo( aTo
);
966 xAnimate
->setAttributeName( aAttributeName
);
968 xAnimate
->setDuration( makeAny( 0.001 ) );
969 xAnimate
->setFill( AnimationFill::HOLD
);
970 xAnimate
->setTarget( maTarget
);
975 void CustomAnimationEffect::setIterateType( sal_Int16 nIterateType
)
977 if( mnIterateType
!= nIterateType
) try
979 // do we need to exchange the container node?
980 if( (mnIterateType
== 0) || (nIterateType
== 0) )
982 sal_Int16 nTargetSubItem
= mnTargetSubItem
;
984 Reference
< XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
985 Reference
< XTimeContainer
> xNewContainer
;
988 xNewContainer
.set( IterateContainer::create( xContext
) );
991 xNewContainer
.set( ParallelTimeContainer::create( xContext
), UNO_QUERY_THROW
);
993 Reference
< XTimeContainer
> xOldContainer( mxNode
, UNO_QUERY_THROW
);
994 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY_THROW
);
995 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
996 while( xEnumeration
->hasMoreElements() )
998 Reference
< XAnimationNode
> xChildNode( xEnumeration
->nextElement(), UNO_QUERY_THROW
);
999 xOldContainer
->removeChild( xChildNode
);
1000 xNewContainer
->appendChild( xChildNode
);
1003 xNewContainer
->setBegin( mxNode
->getBegin() );
1004 xNewContainer
->setDuration( mxNode
->getDuration() );
1005 xNewContainer
->setEnd( mxNode
->getEnd() );
1006 xNewContainer
->setEndSync( mxNode
->getEndSync() );
1007 xNewContainer
->setRepeatCount( mxNode
->getRepeatCount() );
1008 xNewContainer
->setFill( mxNode
->getFill() );
1009 xNewContainer
->setFillDefault( mxNode
->getFillDefault() );
1010 xNewContainer
->setRestart( mxNode
->getRestart() );
1011 xNewContainer
->setRestartDefault( mxNode
->getRestartDefault() );
1012 xNewContainer
->setAcceleration( mxNode
->getAcceleration() );
1013 xNewContainer
->setDecelerate( mxNode
->getDecelerate() );
1014 xNewContainer
->setAutoReverse( mxNode
->getAutoReverse() );
1015 xNewContainer
->setRepeatDuration( mxNode
->getRepeatDuration() );
1016 xNewContainer
->setEndSync( mxNode
->getEndSync() );
1017 xNewContainer
->setRepeatCount( mxNode
->getRepeatCount() );
1018 xNewContainer
->setUserData( mxNode
->getUserData() );
1020 mxNode
= xNewContainer
;
1025 Reference
< XIterateContainer
> xIter( mxNode
, UNO_QUERY_THROW
);
1026 xIter
->setTarget(maTarget
);
1027 xIter
->setSubItem( nTargetSubItem
);
1034 Reference
< XEnumerationAccess
> xEA( mxNode
, UNO_QUERY_THROW
);
1035 Reference
< XEnumeration
> xE( xEA
->createEnumeration(), UNO_QUERY_THROW
);
1036 while( xE
->hasMoreElements() )
1038 Reference
< XAnimate
> xAnimate( xE
->nextElement(), UNO_QUERY
);
1041 xAnimate
->setTarget( aTarget
);
1042 xAnimate
->setSubItem( nTargetSubItem
);
1047 mnIterateType
= nIterateType
;
1049 // if we have an iteration container, we must set its type
1052 Reference
< XIterateContainer
> xIter( mxNode
, UNO_QUERY_THROW
);
1053 xIter
->setIterateType( nIterateType
);
1060 OSL_FAIL( "sd::CustomAnimationEffect::setIterateType(), Exception caught!" );
1064 void CustomAnimationEffect::setIterateInterval( double fIterateInterval
)
1066 if( mfIterateInterval
!= fIterateInterval
)
1068 Reference
< XIterateContainer
> xIter( mxNode
, UNO_QUERY
);
1070 DBG_ASSERT( xIter
.is(), "sd::CustomAnimationEffect::setIterateInterval(), not an iteration node" );
1073 mfIterateInterval
= fIterateInterval
;
1074 xIter
->setIterateInterval( fIterateInterval
);
1077 calculateIterateDuration();
1081 OUString
CustomAnimationEffect::getPath() const
1085 if( mxNode
.is() ) try
1087 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY_THROW
);
1088 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
1089 while( xEnumeration
->hasMoreElements() )
1091 Reference
< XAnimateMotion
> xMotion( xEnumeration
->nextElement(), UNO_QUERY
);
1094 xMotion
->getPath() >>= aPath
;
1101 OSL_FAIL("sd::CustomAnimationEffect::getPath(), exception caught!" );
1107 void CustomAnimationEffect::setPath( const OUString
& rPath
)
1109 if( mxNode
.is() ) try
1111 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY_THROW
);
1112 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
1113 while( xEnumeration
->hasMoreElements() )
1115 Reference
< XAnimateMotion
> xMotion( xEnumeration
->nextElement(), UNO_QUERY
);
1119 MainSequenceChangeGuard
aGuard( mpEffectSequence
);
1120 xMotion
->setPath( Any( rPath
) );
1127 OSL_FAIL("sd::CustomAnimationEffect::setPath(), exception caught!" );
1131 Any
CustomAnimationEffect::getProperty( sal_Int32 nNodeType
, const OUString
& rAttributeName
, EValue eValue
)
1134 if( mxNode
.is() ) try
1136 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
1137 if( xEnumerationAccess
.is() )
1139 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
1140 if( xEnumeration
.is() )
1142 while( xEnumeration
->hasMoreElements() && !aProperty
.hasValue() )
1144 Reference
< XAnimate
> xAnimate( xEnumeration
->nextElement(), UNO_QUERY
);
1145 if( !xAnimate
.is() )
1148 if( xAnimate
->getType() == nNodeType
)
1150 if( xAnimate
->getAttributeName() == rAttributeName
)
1154 case EValue::To
: aProperty
= xAnimate
->getTo(); break;
1155 case EValue::By
: aProperty
= xAnimate
->getBy(); break;
1165 OSL_FAIL("sd::CustomAnimationEffect::getProperty(), exception caught!" );
1171 bool CustomAnimationEffect::setProperty( sal_Int32 nNodeType
, const OUString
& rAttributeName
, EValue eValue
, const Any
& rValue
)
1173 bool bChanged
= false;
1174 if( mxNode
.is() ) try
1176 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
1177 if( xEnumerationAccess
.is() )
1179 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
1180 if( xEnumeration
.is() )
1182 while( xEnumeration
->hasMoreElements() )
1184 Reference
< XAnimate
> xAnimate( xEnumeration
->nextElement(), UNO_QUERY
);
1185 if( !xAnimate
.is() )
1188 if( xAnimate
->getType() == nNodeType
)
1190 if( xAnimate
->getAttributeName() == rAttributeName
)
1195 if( xAnimate
->getTo() != rValue
)
1197 xAnimate
->setTo( rValue
);
1202 if( xAnimate
->getTo() != rValue
)
1204 xAnimate
->setBy( rValue
);
1217 OSL_FAIL("sd::CustomAnimationEffect::setProperty(), exception caught!" );
1223 static bool implIsColorAttribute( const OUString
& rAttributeName
)
1225 return rAttributeName
== "FillColor" || rAttributeName
== "LineColor" || rAttributeName
== "CharColor";
1228 Any
CustomAnimationEffect::getColor( sal_Int32 nIndex
)
1231 if( mxNode
.is() ) try
1233 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
1234 if( xEnumerationAccess
.is() )
1236 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
1237 if( xEnumeration
.is() )
1239 while( xEnumeration
->hasMoreElements() && !aColor
.hasValue() )
1241 Reference
< XAnimate
> xAnimate( xEnumeration
->nextElement(), UNO_QUERY
);
1242 if( !xAnimate
.is() )
1245 switch( xAnimate
->getType() )
1247 case AnimationNodeType::SET
:
1248 case AnimationNodeType::ANIMATE
:
1249 if( !implIsColorAttribute( xAnimate
->getAttributeName() ) )
1252 case AnimationNodeType::ANIMATECOLOR
:
1253 Sequence
<Any
> aValues( xAnimate
->getValues() );
1254 if( aValues
.hasElements() )
1256 if( aValues
.getLength() > nIndex
)
1257 aColor
= aValues
[nIndex
];
1259 else if( nIndex
== 0 )
1260 aColor
= xAnimate
->getFrom();
1262 aColor
= xAnimate
->getTo();
1270 OSL_FAIL("sd::CustomAnimationEffect::getColor(), exception caught!" );
1276 void CustomAnimationEffect::setColor( sal_Int32 nIndex
, const Any
& rColor
)
1278 if( mxNode
.is() ) try
1280 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
1281 if( xEnumerationAccess
.is() )
1283 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
1284 if( xEnumeration
.is() )
1286 while( xEnumeration
->hasMoreElements() )
1288 Reference
< XAnimate
> xAnimate( xEnumeration
->nextElement(), UNO_QUERY
);
1289 if( !xAnimate
.is() )
1292 switch( xAnimate
->getType() )
1294 case AnimationNodeType::SET
:
1295 case AnimationNodeType::ANIMATE
:
1296 if( !implIsColorAttribute( xAnimate
->getAttributeName() ) )
1299 case AnimationNodeType::ANIMATECOLOR
:
1301 Sequence
<Any
> aValues( xAnimate
->getValues() );
1302 if( aValues
.hasElements() )
1304 if( aValues
.getLength() > nIndex
)
1306 aValues
[nIndex
] = rColor
;
1307 xAnimate
->setValues( aValues
);
1310 else if( (nIndex
== 0) && xAnimate
->getFrom().hasValue() )
1311 xAnimate
->setFrom(rColor
);
1312 else if( (nIndex
== 1) && xAnimate
->getTo().hasValue() )
1313 xAnimate
->setTo(rColor
);
1324 OSL_FAIL("sd::CustomAnimationEffect::setColor(), exception caught!" );
1328 Any
CustomAnimationEffect::getTransformationProperty( sal_Int32 nTransformType
, EValue eValue
)
1331 if( mxNode
.is() ) try
1333 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
1334 if( xEnumerationAccess
.is() )
1336 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
1337 if( xEnumeration
.is() )
1339 while( xEnumeration
->hasMoreElements() && !aProperty
.hasValue() )
1341 Reference
< XAnimateTransform
> xTransform( xEnumeration
->nextElement(), UNO_QUERY
);
1342 if( !xTransform
.is() )
1345 if( xTransform
->getTransformType() == nTransformType
)
1349 case EValue::To
: aProperty
= xTransform
->getTo(); break;
1350 case EValue::By
: aProperty
= xTransform
->getBy(); break;
1359 OSL_FAIL("sd::CustomAnimationEffect::getTransformationProperty(), exception caught!" );
1365 bool CustomAnimationEffect::setTransformationProperty( sal_Int32 nTransformType
, EValue eValue
, const Any
& rValue
)
1367 bool bChanged
= false;
1368 if( mxNode
.is() ) try
1370 Reference
< XEnumerationAccess
> xEnumerationAccess( mxNode
, UNO_QUERY
);
1371 if( xEnumerationAccess
.is() )
1373 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY
);
1374 if( xEnumeration
.is() )
1376 while( xEnumeration
->hasMoreElements() )
1378 Reference
< XAnimateTransform
> xTransform( xEnumeration
->nextElement(), UNO_QUERY
);
1379 if( !xTransform
.is() )
1382 if( xTransform
->getTransformType() == nTransformType
)
1387 if( xTransform
->getTo() != rValue
)
1389 xTransform
->setTo( rValue
);
1394 if( xTransform
->getBy() != rValue
)
1396 xTransform
->setBy( rValue
);
1408 OSL_FAIL("sd::CustomAnimationEffect::setTransformationProperty(), exception caught!" );
1414 void CustomAnimationEffect::createAudio( const css::uno::Any
& rSource
)
1416 DBG_ASSERT( !mxAudio
.is(), "sd::CustomAnimationEffect::createAudio(), node already has an audio!" );
1418 if( !mxAudio
.is() ) try
1420 Reference
< XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
1421 Reference
< XAudio
> xAudio( Audio::create( xContext
) );
1422 xAudio
->setSource( rSource
);
1423 xAudio
->setVolume( 1.0 );
1428 OSL_FAIL("sd::CustomAnimationEffect::createAudio(), exception caught!" );
1432 static Reference
< XCommand
> findCommandNode( const Reference
< XAnimationNode
>& xRootNode
)
1434 Reference
< XCommand
> xCommand
;
1436 if( xRootNode
.is() ) try
1438 Reference
< XEnumerationAccess
> xEnumerationAccess( xRootNode
, UNO_QUERY_THROW
);
1439 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
1440 while( !xCommand
.is() && xEnumeration
->hasMoreElements() )
1442 Reference
< XAnimationNode
> xNode( xEnumeration
->nextElement(), UNO_QUERY
);
1443 if( xNode
.is() && (xNode
->getType() == AnimationNodeType::COMMAND
) )
1444 xCommand
.set( xNode
, UNO_QUERY_THROW
);
1449 OSL_FAIL("sd::findCommandNode(), exception caught!" );
1455 void CustomAnimationEffect::removeAudio()
1459 Reference
< XAnimationNode
> xChild
;
1463 xChild
.set( mxAudio
, UNO_QUERY
);
1466 else if( mnCommand
== EffectCommands::STOPAUDIO
)
1468 xChild
.set( findCommandNode( mxNode
), UNO_QUERY
);
1474 Reference
< XTimeContainer
> xContainer( mxNode
, UNO_QUERY
);
1475 if( xContainer
.is() )
1476 xContainer
->removeChild( xChild
);
1481 OSL_FAIL("sd::CustomAnimationEffect::removeAudio(), exception caught!" );
1486 void CustomAnimationEffect::setAudio( const Reference
< css::animations::XAudio
>& xAudio
)
1488 if( mxAudio
!= xAudio
) try
1492 Reference
< XTimeContainer
> xContainer( mxNode
, UNO_QUERY
);
1493 Reference
< XAnimationNode
> xChild( mxAudio
, UNO_QUERY
);
1494 if( xContainer
.is() && xChild
.is() )
1495 xContainer
->appendChild( xChild
);
1499 OSL_FAIL("sd::CustomAnimationEffect::setAudio(), exception caught!" );
1503 void CustomAnimationEffect::setStopAudio()
1505 if( mnCommand
!= EffectCommands::STOPAUDIO
) try
1510 Reference
< XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
1511 Reference
< XCommand
> xCommand( Command::create( xContext
) );
1513 xCommand
->setCommand( EffectCommands::STOPAUDIO
);
1515 Reference
< XTimeContainer
> xContainer( mxNode
, UNO_QUERY_THROW
);
1516 xContainer
->appendChild( xCommand
);
1518 mnCommand
= EffectCommands::STOPAUDIO
;
1522 OSL_FAIL("sd::CustomAnimationEffect::setStopAudio(), exception caught!" );
1526 bool CustomAnimationEffect::getStopAudio() const
1528 return mnCommand
== EffectCommands::STOPAUDIO
;
1531 SdrPathObj
* CustomAnimationEffect::createSdrPathObjFromPath(SdrModel
& rTargetModel
)
1533 SdrPathObj
* pPathObj
= new SdrPathObj(rTargetModel
, OBJ_PATHLINE
);
1534 updateSdrPathObjFromPath( *pPathObj
);
1538 void CustomAnimationEffect::updateSdrPathObjFromPath( SdrPathObj
& rPathObj
)
1540 ::basegfx::B2DPolyPolygon aPolyPoly
;
1541 if( ::basegfx::utils::importFromSvgD( aPolyPoly
, getPath(), true, nullptr ) )
1543 SdrObject
* pObj
= GetSdrObjectFromXShape( getTargetShape() );
1546 SdrPage
* pPage
= pObj
->GetPage();
1549 const Size
aPageSize( pPage
->GetSize() );
1550 aPolyPoly
.transform(basegfx::utils::createScaleB2DHomMatrix(static_cast<double>(aPageSize
.Width()), static_cast<double>(aPageSize
.Height())));
1553 const ::tools::Rectangle
aBoundRect( pObj
->GetCurrentBoundRect() );
1554 const Point
aCenter( aBoundRect
.Center() );
1555 aPolyPoly
.transform(basegfx::utils::createTranslateB2DHomMatrix(aCenter
.X(), aCenter
.Y()));
1559 rPathObj
.SetPathPoly( aPolyPoly
);
1562 void CustomAnimationEffect::updatePathFromSdrPathObj( const SdrPathObj
& rPathObj
)
1564 ::basegfx::B2DPolyPolygon
aPolyPoly( rPathObj
.GetPathPoly() );
1566 SdrObject
* pObj
= GetSdrObjectFromXShape( getTargetShape() );
1569 ::tools::Rectangle
aBoundRect(0,0,0,0);
1571 const drawinglayer::primitive2d::Primitive2DContainer
xPrimitives(pObj
->GetViewContact().getViewIndependentPrimitive2DContainer());
1572 const drawinglayer::geometry::ViewInformation2D aViewInformation2D
;
1573 const basegfx::B2DRange
aRange(xPrimitives
.getB2DRange(aViewInformation2D
));
1575 if(!aRange
.isEmpty())
1577 aBoundRect
= ::tools::Rectangle(
1578 static_cast<sal_Int32
>(floor(aRange
.getMinX())), static_cast<sal_Int32
>(floor(aRange
.getMinY())),
1579 static_cast<sal_Int32
>(ceil(aRange
.getMaxX())), static_cast<sal_Int32
>(ceil(aRange
.getMaxY())));
1582 const Point
aCenter( aBoundRect
.Center() );
1584 aPolyPoly
.transform(basegfx::utils::createTranslateB2DHomMatrix(-aCenter
.X(), -aCenter
.Y()));
1586 SdrPage
* pPage
= pObj
->GetPage();
1589 const Size
aPageSize( pPage
->GetSize() );
1590 aPolyPoly
.transform(basegfx::utils::createScaleB2DHomMatrix(
1591 1.0 / static_cast<double>(aPageSize
.Width()), 1.0 / static_cast<double>(aPageSize
.Height())));
1595 setPath( ::basegfx::utils::exportToSvgD( aPolyPoly
, true, true, true) );
1598 EffectSequenceHelper::EffectSequenceHelper()
1599 : mnSequenceType( EffectNodeType::DEFAULT
)
1603 EffectSequenceHelper::EffectSequenceHelper( const css::uno::Reference
< css::animations::XTimeContainer
>& xSequenceRoot
)
1604 : mxSequenceRoot( xSequenceRoot
), mnSequenceType( EffectNodeType::DEFAULT
)
1606 Reference
< XAnimationNode
> xNode( mxSequenceRoot
, UNO_QUERY_THROW
);
1610 EffectSequenceHelper::~EffectSequenceHelper()
1615 void EffectSequenceHelper::reset()
1617 EffectSequence::iterator
aIter( maEffects
.begin() );
1618 EffectSequence::iterator
aEnd( maEffects
.end() );
1621 CustomAnimationEffectPtr pEffect
= (*aIter
++);
1622 pEffect
->setEffectSequence(nullptr);
1627 Reference
< XAnimationNode
> EffectSequenceHelper::getRootNode()
1629 Reference
< XAnimationNode
> xRoot( mxSequenceRoot
, UNO_QUERY
);
1633 void EffectSequenceHelper::append( const CustomAnimationEffectPtr
& pEffect
)
1635 pEffect
->setEffectSequence( this );
1636 maEffects
.push_back(pEffect
);
1640 CustomAnimationEffectPtr
EffectSequenceHelper::append( const CustomAnimationPresetPtr
& pPreset
, const Any
& rTarget
, double fDuration
/* = -1.0 */ )
1642 CustomAnimationEffectPtr pEffect
;
1646 Reference
< XAnimationNode
> xNode( pPreset
->create( "" ) );
1649 // first, filter all only ui relevant user data
1650 std::vector
< NamedValue
> aNewUserData
;
1651 Sequence
< NamedValue
> aUserData( xNode
->getUserData() );
1652 sal_Int32 nLength
= aUserData
.getLength();
1653 const NamedValue
* p
= aUserData
.getConstArray();
1654 bool bFilter
= false;
1658 if( p
->Name
!= "text-only" && p
->Name
!= "preset-property" )
1660 aNewUserData
.push_back( *p
);
1668 aUserData
= ::comphelper::containerToSequence( aNewUserData
);
1669 xNode
->setUserData( aUserData
);
1672 // check target, maybe we need to force it to text
1673 sal_Int16 nSubItem
= ShapeAnimationSubType::AS_WHOLE
;
1675 if( rTarget
.getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
1677 nSubItem
= ShapeAnimationSubType::ONLY_TEXT
;
1679 else if( pPreset
->isTextOnly() )
1681 Reference
< XShape
> xShape
;
1685 // that's bad, we target a shape here but the effect is only for text
1686 // so change subitem
1687 nSubItem
= ShapeAnimationSubType::ONLY_TEXT
;
1691 // now create effect from preset
1692 pEffect
.reset( new CustomAnimationEffect( xNode
) );
1693 pEffect
->setEffectSequence( this );
1694 pEffect
->setTarget( rTarget
);
1695 pEffect
->setTargetSubItem( nSubItem
);
1696 if( fDuration
!= -1.0 )
1697 pEffect
->setDuration( fDuration
);
1699 maEffects
.push_back(pEffect
);
1705 DBG_ASSERT( pEffect
.get(), "sd::EffectSequenceHelper::append(), failed!" );
1709 CustomAnimationEffectPtr
EffectSequenceHelper::append( const SdrPathObj
& rPathObj
, const Any
& rTarget
, double fDuration
/* = -1.0 */ )
1711 CustomAnimationEffectPtr pEffect
;
1713 if( fDuration
<= 0.0 )
1718 Reference
< XTimeContainer
> xEffectContainer( ParallelTimeContainer::create( ::comphelper::getProcessComponentContext() ), UNO_QUERY_THROW
);
1719 Reference
< XAnimationNode
> xAnimateMotion( AnimateMotion::create( ::comphelper::getProcessComponentContext() ) );
1721 xAnimateMotion
->setDuration( Any( fDuration
) );
1722 xAnimateMotion
->setFill( AnimationFill::HOLD
);
1723 xEffectContainer
->appendChild( xAnimateMotion
);
1725 sal_Int16 nSubItem
= ShapeAnimationSubType::AS_WHOLE
;
1727 if( rTarget
.getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
1728 nSubItem
= ShapeAnimationSubType::ONLY_TEXT
;
1730 pEffect
.reset( new CustomAnimationEffect( xEffectContainer
) );
1731 pEffect
->setEffectSequence( this );
1732 pEffect
->setTarget( rTarget
);
1733 pEffect
->setTargetSubItem( nSubItem
);
1734 pEffect
->setNodeType( css::presentation::EffectNodeType::ON_CLICK
);
1735 pEffect
->setPresetClass( css::presentation::EffectPresetClass::MOTIONPATH
);
1736 pEffect
->setAcceleration( 0.5 );
1737 pEffect
->setDecelerate( 0.5 );
1738 pEffect
->setFill( AnimationFill::HOLD
);
1739 pEffect
->setBegin( 0.0 );
1740 pEffect
->updatePathFromSdrPathObj( rPathObj
);
1741 if( fDuration
!= -1.0 )
1742 pEffect
->setDuration( fDuration
);
1744 maEffects
.push_back(pEffect
);
1750 OSL_FAIL( "sd::EffectSequenceHelper::append(), exception caught!" );
1756 void EffectSequenceHelper::replace( const CustomAnimationEffectPtr
& pEffect
, const CustomAnimationPresetPtr
& pPreset
, const OUString
& rPresetSubType
, double fDuration
/* = -1.0 */ )
1758 if( pEffect
.get() && pPreset
.get() ) try
1760 Reference
< XAnimationNode
> xNewNode( pPreset
->create( rPresetSubType
) );
1763 pEffect
->replaceNode( xNewNode
);
1764 if( fDuration
!= -1.0 )
1765 pEffect
->setDuration( fDuration
);
1772 OSL_FAIL( "sd::EffectSequenceHelper::replace(), exception caught!" );
1776 void EffectSequenceHelper::replace( const CustomAnimationEffectPtr
& pEffect
, const CustomAnimationPresetPtr
& pPreset
, double fDuration
/* = -1.0 */ )
1778 replace( pEffect
, pPreset
, "", fDuration
);
1781 void EffectSequenceHelper::remove( const CustomAnimationEffectPtr
& pEffect
)
1785 pEffect
->setEffectSequence( nullptr );
1786 maEffects
.remove( pEffect
);
1792 void EffectSequenceHelper::rebuild()
1797 void EffectSequenceHelper::implRebuild()
1801 // first we delete all time containers on the first two levels
1802 Reference
< XEnumerationAccess
> xEnumerationAccess( mxSequenceRoot
, UNO_QUERY_THROW
);
1803 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
1804 while( xEnumeration
->hasMoreElements() )
1806 Reference
< XAnimationNode
> xChildNode( xEnumeration
->nextElement(), UNO_QUERY_THROW
);
1807 Reference
< XTimeContainer
> xChildContainer( xChildNode
, UNO_QUERY_THROW
);
1809 Reference
< XEnumerationAccess
> xChildEnumerationAccess( xChildNode
, UNO_QUERY_THROW
);
1810 Reference
< XEnumeration
> xChildEnumeration( xChildEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
1811 while( xChildEnumeration
->hasMoreElements() )
1813 Reference
< XAnimationNode
> xNode( xChildEnumeration
->nextElement(), UNO_QUERY_THROW
);
1814 xChildContainer
->removeChild( xNode
);
1817 mxSequenceRoot
->removeChild( xChildNode
);
1820 // second, rebuild main sequence
1821 EffectSequence::iterator
aIter( maEffects
.begin() );
1822 EffectSequence::iterator
aEnd( maEffects
.end() );
1825 std::vector
< sd::AfterEffectNode
> aAfterEffects
;
1827 CustomAnimationEffectPtr pEffect
= (*aIter
++);
1832 // create a par container for the next click node and all following with and after effects
1833 Reference
< XTimeContainer
> xOnClickContainer( ParallelTimeContainer::create( ::comphelper::getProcessComponentContext() ), UNO_QUERY_THROW
);
1836 if( mxEventSource
.is() )
1838 aEvent
.Source
<<= mxEventSource
;
1839 aEvent
.Trigger
= EventTrigger::ON_CLICK
;
1843 aEvent
.Trigger
= EventTrigger::ON_NEXT
;
1847 Any
aBegin( makeAny( aEvent
) );
1850 // if the first node is not a click action, this click container
1851 // must not have INDEFINITE begin but start at 0s
1853 if( pEffect
->getNodeType() != EffectNodeType::ON_CLICK
)
1857 xOnClickContainer
->setBegin( aBegin
);
1859 mxSequenceRoot
->appendChild( xOnClickContainer
);
1861 double fBegin
= 0.0;
1865 // create a par container for the current click or after effect node and all following with effects
1866 Reference
< XTimeContainer
> xWithContainer( ParallelTimeContainer::create( ::comphelper::getProcessComponentContext() ), UNO_QUERY_THROW
);
1867 xWithContainer
->setBegin( makeAny( fBegin
) );
1868 xOnClickContainer
->appendChild( xWithContainer
);
1870 double fDuration
= 0.0;
1873 Reference
< XAnimationNode
> xEffectNode( pEffect
->getNode() );
1874 xWithContainer
->appendChild( xEffectNode
);
1876 if( pEffect
->hasAfterEffect() )
1878 Reference
< XAnimationNode
> xAfterEffect( pEffect
->createAfterEffectNode() );
1879 AfterEffectNode
a( xAfterEffect
, xEffectNode
, pEffect
->IsAfterEffectOnNext() );
1880 aAfterEffects
.push_back( a
);
1883 double fTemp
= pEffect
->getBegin() + pEffect
->getAbsoluteDuration();
1884 if( fTemp
> fDuration
)
1888 pEffect
= (*aIter
++);
1892 while( pEffect
.get() && (pEffect
->getNodeType() == EffectNodeType::WITH_PREVIOUS
) );
1894 fBegin
+= fDuration
;
1896 while( pEffect
.get() && (pEffect
->getNodeType() != EffectNodeType::ON_CLICK
) );
1898 while( pEffect
.get() );
1900 // process after effect nodes
1901 std::for_each( aAfterEffects
.begin(), aAfterEffects
.end(), stl_process_after_effect_node_func
);
1905 // reset duration, might have been altered (see below)
1906 mxSequenceRoot
->setDuration( Any() );
1910 // empty sequence, set duration to 0.0 explicitly
1911 // (otherwise, this sequence will never end)
1912 mxSequenceRoot
->setDuration( makeAny(0.0) );
1917 OSL_FAIL( "sd::EffectSequenceHelper::rebuild(), exception caught!" );
1921 stl_CustomAnimationEffect_search_node_predict::stl_CustomAnimationEffect_search_node_predict( const css::uno::Reference
< css::animations::XAnimationNode
>& xSearchNode
)
1922 : mxSearchNode( xSearchNode
)
1926 bool stl_CustomAnimationEffect_search_node_predict::operator()( const CustomAnimationEffectPtr
& pEffect
) const
1928 return pEffect
->getNode() == mxSearchNode
;
1931 /// @throws Exception
1932 static bool implFindNextContainer( Reference
< XTimeContainer
> const & xParent
, Reference
< XTimeContainer
> const & xCurrent
, Reference
< XTimeContainer
>& xNext
)
1934 Reference
< XEnumerationAccess
> xEnumerationAccess( xParent
, UNO_QUERY_THROW
);
1935 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration() );
1936 if( xEnumeration
.is() )
1938 Reference
< XInterface
> x
;
1939 while( xEnumeration
->hasMoreElements() && !xNext
.is() )
1941 if( (xEnumeration
->nextElement() >>= x
) && (x
== xCurrent
) )
1943 if( xEnumeration
->hasMoreElements() )
1944 xEnumeration
->nextElement() >>= xNext
;
1951 void stl_process_after_effect_node_func(AfterEffectNode
const & rNode
)
1955 if( rNode
.mxNode
.is() && rNode
.mxMaster
.is() )
1958 Reference
< XAnimationNode
> xMasterNode( rNode
.mxMaster
, UNO_QUERY_THROW
);
1959 Sequence
< NamedValue
> aUserData( rNode
.mxNode
->getUserData() );
1960 sal_Int32 nSize
= aUserData
.getLength();
1961 aUserData
.realloc(nSize
+1);
1962 aUserData
[nSize
].Name
= "master-element";
1963 aUserData
[nSize
].Value
<<= xMasterNode
;
1964 rNode
.mxNode
->setUserData( aUserData
);
1966 // insert after effect node into timeline
1967 Reference
< XTimeContainer
> xContainer( rNode
.mxMaster
->getParent(), UNO_QUERY_THROW
);
1969 if( !rNode
.mbOnNextEffect
) // sameClick
1971 // insert the aftereffect after its effect is animated
1972 xContainer
->insertAfter( rNode
.mxNode
, rNode
.mxMaster
);
1976 Reference
< XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
1977 // insert the aftereffect in the next group
1979 Reference
< XTimeContainer
> xClickContainer( xContainer
->getParent(), UNO_QUERY_THROW
);
1980 Reference
< XTimeContainer
> xSequenceContainer( xClickContainer
->getParent(), UNO_QUERY_THROW
);
1982 Reference
< XTimeContainer
> xNextContainer
;
1984 // first try if we have an after effect container
1985 if( !implFindNextContainer( xClickContainer
, xContainer
, xNextContainer
) )
1987 Reference
< XTimeContainer
> xNextClickContainer
;
1988 // if not, try to find the next click effect container
1989 if( implFindNextContainer( xSequenceContainer
, xClickContainer
, xNextClickContainer
) )
1991 Reference
< XEnumerationAccess
> xEnumerationAccess( xNextClickContainer
, UNO_QUERY_THROW
);
1992 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
1993 if( xEnumeration
->hasMoreElements() )
1995 // the next container is the first child container
1996 xEnumeration
->nextElement() >>= xNextContainer
;
2000 // this does not yet have a child container, create one
2001 xNextContainer
.set( ParallelTimeContainer::create(xContext
), UNO_QUERY_THROW
);
2003 xNextContainer
->setBegin( makeAny( 0.0 ) );
2004 xNextClickContainer
->appendChild( xNextContainer
);
2006 DBG_ASSERT( xNextContainer
.is(), "ppt::stl_process_after_effect_node_func::operator(), could not find/create container!" );
2010 // if we don't have a next container, we add one to the sequence container
2011 if( !xNextContainer
.is() )
2013 Reference
< XTimeContainer
> xNewClickContainer( ParallelTimeContainer::create( xContext
), UNO_QUERY_THROW
);
2016 aEvent
.Trigger
= EventTrigger::ON_NEXT
;
2018 xNewClickContainer
->setBegin( makeAny( aEvent
) );
2020 xSequenceContainer
->insertAfter( xNewClickContainer
, xClickContainer
);
2022 xNextContainer
.set( ParallelTimeContainer::create( xContext
), UNO_QUERY_THROW
);
2024 DBG_ASSERT( xNextContainer
.is(), "ppt::stl_process_after_effect_node_func::operator(), could not create container!" );
2025 if( xNextContainer
.is() )
2027 xNextContainer
->setBegin( makeAny( 0.0 ) );
2028 xNewClickContainer
->appendChild( xNextContainer
);
2032 if( xNextContainer
.is() )
2034 // find begin time of first element
2035 Reference
< XEnumerationAccess
> xEnumerationAccess( xNextContainer
, UNO_QUERY_THROW
);
2036 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
2037 if( xEnumeration
->hasMoreElements() )
2039 Reference
< XAnimationNode
> xChild
;
2040 // the next container is the first child container
2041 xEnumeration
->nextElement() >>= xChild
;
2044 Any
aBegin( xChild
->getBegin() );
2045 double fBegin
= 0.0;
2046 if( (aBegin
>>= fBegin
) && (fBegin
>= 0.0))
2047 rNode
.mxNode
->setBegin( aBegin
);
2051 xNextContainer
->appendChild( rNode
.mxNode
);
2058 OSL_FAIL( "ppt::stl_process_after_effect_node_func::operator(), exception caught!" );
2062 EffectSequence::iterator
EffectSequenceHelper::find( const CustomAnimationEffectPtr
& pEffect
)
2064 return std::find( maEffects
.begin(), maEffects
.end(), pEffect
);
2067 CustomAnimationEffectPtr
EffectSequenceHelper::findEffect( const css::uno::Reference
< css::animations::XAnimationNode
>& xNode
) const
2069 CustomAnimationEffectPtr pEffect
;
2071 EffectSequence::const_iterator
aIter( maEffects
.begin() );
2072 for( ; aIter
!= maEffects
.end(); ++aIter
)
2074 if( (*aIter
)->getNode() == xNode
)
2084 sal_Int32
EffectSequenceHelper::getOffsetFromEffect( const CustomAnimationEffectPtr
& xEffect
) const
2086 sal_Int32 nOffset
= 0;
2088 EffectSequence::const_iterator
aIter( maEffects
.begin() );
2089 for( ; aIter
!= maEffects
.end(); ++aIter
, nOffset
++ )
2091 if( (*aIter
) == xEffect
)
2098 CustomAnimationEffectPtr
EffectSequenceHelper::getEffectFromOffset( sal_Int32 nOffset
) const
2100 EffectSequence::const_iterator
aIter( maEffects
.begin() );
2101 while( nOffset
-- && aIter
!= maEffects
.end() )
2104 CustomAnimationEffectPtr pEffect
;
2105 if( aIter
!= maEffects
.end() )
2111 bool EffectSequenceHelper::disposeShape( const Reference
< XShape
>& xShape
)
2113 bool bChanges
= false;
2115 EffectSequence::iterator
aIter( maEffects
.begin() );
2116 while( aIter
!= maEffects
.end() )
2118 if( (*aIter
)->getTargetShape() == xShape
)
2120 (*aIter
)->setEffectSequence( nullptr );
2122 aIter
= maEffects
.erase( aIter
);
2133 bool EffectSequenceHelper::hasEffect( const css::uno::Reference
< css::drawing::XShape
>& xShape
)
2135 EffectSequence::iterator
aIter( maEffects
.begin() );
2136 while( aIter
!= maEffects
.end() )
2138 if( (*aIter
)->getTargetShape() == xShape
)
2146 void EffectSequenceHelper::insertTextRange( const css::uno::Any
& aTarget
)
2148 bool bChanges
= false;
2150 ParagraphTarget aParaTarget
;
2151 if( !(aTarget
>>= aParaTarget
) )
2154 EffectSequence::iterator
aIter( maEffects
.begin() );
2155 while( aIter
!= maEffects
.end() )
2157 if( (*aIter
)->getTargetShape() == aParaTarget
.Shape
)
2158 bChanges
|= (*aIter
)->checkForText();
2166 void EffectSequenceHelper::disposeTextRange( const css::uno::Any
& aTarget
)
2168 ParagraphTarget aParaTarget
;
2169 if( !(aTarget
>>= aParaTarget
) )
2172 bool bChanges
= false;
2173 bool bErased
= false;
2175 EffectSequence::iterator
aIter( maEffects
.begin() );
2176 while( aIter
!= maEffects
.end() )
2178 Any
aIterTarget( (*aIter
)->getTarget() );
2179 if( aIterTarget
.getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
2181 ParagraphTarget aIterParaTarget
;
2182 if( (aIterTarget
>>= aIterParaTarget
) && (aIterParaTarget
.Shape
== aParaTarget
.Shape
) )
2184 if( aIterParaTarget
.Paragraph
== aParaTarget
.Paragraph
)
2186 // delete this effect if it targets the disposed paragraph directly
2187 (*aIter
)->setEffectSequence( nullptr );
2188 aIter
= maEffects
.erase( aIter
);
2194 if( aIterParaTarget
.Paragraph
> aParaTarget
.Paragraph
)
2196 // shift all paragraphs after disposed paragraph
2197 aIterParaTarget
.Paragraph
--;
2198 (*aIter
)->setTarget( makeAny( aIterParaTarget
) );
2203 else if( (*aIter
)->getTargetShape() == aParaTarget
.Shape
)
2205 bChanges
|= (*aIter
)->checkForText();
2218 CustomAnimationTextGroup::CustomAnimationTextGroup( const Reference
< XShape
>& rTarget
, sal_Int32 nGroupId
)
2219 : maTarget( rTarget
),
2220 mnGroupId( nGroupId
)
2225 void CustomAnimationTextGroup::reset()
2227 mnTextGrouping
= -1;
2228 mbAnimateForm
= false;
2229 mbTextReverse
= false;
2230 mfGroupingAuto
= -1.0;
2231 mnLastPara
= -1; // used to check for TextReverse
2233 for (sal_Int8
& rn
: mnDepthFlags
)
2241 void CustomAnimationTextGroup::addEffect( CustomAnimationEffectPtr
const & pEffect
)
2243 maEffects
.push_back( pEffect
);
2245 Any
aTarget( pEffect
->getTarget() );
2246 if( aTarget
.getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
2248 // now look at the paragraph
2249 ParagraphTarget aParaTarget
;
2250 aTarget
>>= aParaTarget
;
2252 if( mnLastPara
!= -1 )
2253 mbTextReverse
= mnLastPara
> aParaTarget
.Paragraph
;
2255 mnLastPara
= aParaTarget
.Paragraph
;
2257 const sal_Int32 nParaDepth
= pEffect
->getParaDepth();
2259 // only look at the first PARA_LEVELS levels
2260 if( nParaDepth
< PARA_LEVELS
)
2262 // our first paragraph with this level?
2263 if( mnDepthFlags
[nParaDepth
] == 0 )
2265 // so set it to the first found
2266 mnDepthFlags
[nParaDepth
] = static_cast<sal_Int8
>(pEffect
->getNodeType());
2268 else if( mnDepthFlags
[nParaDepth
] != pEffect
->getNodeType() )
2270 mnDepthFlags
[nParaDepth
] = -1;
2273 if( pEffect
->getNodeType() == EffectNodeType::AFTER_PREVIOUS
)
2274 mfGroupingAuto
= pEffect
->getBegin();
2276 mnTextGrouping
= PARA_LEVELS
;
2277 while( (mnTextGrouping
> 0)
2278 && (mnDepthFlags
[mnTextGrouping
- 1] <= 0) )
2284 // if we have an effect with the shape as a target, we animate the background
2285 mbAnimateForm
= pEffect
->getTargetSubItem() != ShapeAnimationSubType::ONLY_TEXT
;
2289 CustomAnimationTextGroupPtr
EffectSequenceHelper::findGroup( sal_Int32 nGroupId
)
2291 CustomAnimationTextGroupPtr aPtr
;
2293 CustomAnimationTextGroupMap::iterator
aIter( maGroupMap
.find( nGroupId
) );
2294 if( aIter
!= maGroupMap
.end() )
2295 aPtr
= (*aIter
).second
;
2300 void EffectSequenceHelper::updateTextGroups()
2304 // first create all the groups
2305 EffectSequence::iterator
aIter( maEffects
.begin() );
2306 const EffectSequence::iterator
aEnd( maEffects
.end() );
2307 while( aIter
!= aEnd
)
2309 CustomAnimationEffectPtr
pEffect( (*aIter
++) );
2311 const sal_Int32 nGroupId
= pEffect
->getGroupId();
2313 if( nGroupId
== -1 )
2314 continue; // trivial case, no group
2316 CustomAnimationTextGroupPtr pGroup
= findGroup( nGroupId
);
2319 pGroup
.reset( new CustomAnimationTextGroup( pEffect
->getTargetShape(), nGroupId
) );
2320 maGroupMap
[nGroupId
] = pGroup
;
2323 pGroup
->addEffect( pEffect
);
2327 CustomAnimationTextGroupPtr
EffectSequenceHelper::createTextGroup( CustomAnimationEffectPtr pEffect
, sal_Int32 nTextGrouping
, double fTextGroupingAuto
, bool bAnimateForm
, bool bTextReverse
)
2329 // first finde a free group-id
2330 sal_Int32 nGroupId
= 0;
2332 CustomAnimationTextGroupMap::iterator
aIter( maGroupMap
.begin() );
2333 const CustomAnimationTextGroupMap::iterator
aEnd( maGroupMap
.end() );
2334 while( aIter
!= aEnd
)
2336 if( (*aIter
).first
== nGroupId
)
2339 aIter
= maGroupMap
.begin();
2347 Reference
< XShape
> xTarget( pEffect
->getTargetShape() );
2349 CustomAnimationTextGroupPtr
pTextGroup( new CustomAnimationTextGroup( xTarget
, nGroupId
) );
2350 maGroupMap
[nGroupId
] = pTextGroup
;
2354 // do we need to target the shape?
2355 if( (nTextGrouping
== 0) || bAnimateForm
)
2358 if( nTextGrouping
== 0)
2359 nSubItem
= bAnimateForm
? ShapeAnimationSubType::AS_WHOLE
: ShapeAnimationSubType::ONLY_TEXT
;
2361 nSubItem
= ShapeAnimationSubType::ONLY_BACKGROUND
;
2363 pEffect
->setTarget( makeAny( xTarget
) );
2364 pEffect
->setTargetSubItem( nSubItem
);
2365 pEffect
->setEffectSequence( this );
2366 pEffect
->setGroupId( nGroupId
);
2368 pTextGroup
->addEffect( pEffect
);
2372 pTextGroup
->mnTextGrouping
= nTextGrouping
;
2373 pTextGroup
->mfGroupingAuto
= fTextGroupingAuto
;
2374 pTextGroup
->mbTextReverse
= bTextReverse
;
2376 // now add an effect for each paragraph
2377 createTextGroupParagraphEffects( pTextGroup
, pEffect
, bUsed
);
2384 void EffectSequenceHelper::createTextGroupParagraphEffects( const CustomAnimationTextGroupPtr
& pTextGroup
, const CustomAnimationEffectPtr
& pEffect
, bool bUsed
)
2386 Reference
< XShape
> xTarget( pTextGroup
->maTarget
);
2388 sal_Int32 nTextGrouping
= pTextGroup
->mnTextGrouping
;
2389 double fTextGroupingAuto
= pTextGroup
->mfGroupingAuto
;
2390 bool bTextReverse
= pTextGroup
->mbTextReverse
;
2392 // now add an effect for each paragraph
2393 if( nTextGrouping
>= 0 ) try
2395 EffectSequence::iterator
aInsertIter( find( pEffect
) );
2397 Reference
< XEnumerationAccess
> xText( xTarget
, UNO_QUERY_THROW
);
2398 Reference
< XEnumeration
> xEnumeration( xText
->createEnumeration(), UNO_QUERY_THROW
);
2400 std::deque
< sal_Int16
> aParaList
;
2403 // fill the list with all valid paragraphs
2404 for( nPara
= 0; xEnumeration
->hasMoreElements(); nPara
++ )
2406 Reference
< XTextRange
> xRange( xEnumeration
->nextElement(), UNO_QUERY
);
2407 if( xRange
.is() && !xRange
->getString().isEmpty() )
2409 if( bTextReverse
) // sort them
2410 aParaList
.push_front( nPara
);
2412 aParaList
.push_back( nPara
);
2416 ParagraphTarget aTarget
;
2417 aTarget
.Shape
= xTarget
;
2419 for( const auto i
: aParaList
)
2421 aTarget
.Paragraph
= i
;
2423 CustomAnimationEffectPtr pNewEffect
;
2426 // clone a new effect from first effect
2427 pNewEffect
= pEffect
->clone();
2429 aInsertIter
= maEffects
.insert( aInsertIter
, pNewEffect
);
2433 // reuse first effect if it's not yet used
2434 pNewEffect
= pEffect
;
2436 aInsertIter
= find( pNewEffect
);
2439 // set target and group-id
2440 pNewEffect
->setTarget( makeAny( aTarget
) );
2441 pNewEffect
->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT
);
2442 pNewEffect
->setGroupId( pTextGroup
->mnGroupId
);
2443 pNewEffect
->setEffectSequence( this );
2445 // set correct node type
2446 if( pNewEffect
->getParaDepth() < nTextGrouping
)
2448 if( fTextGroupingAuto
== -1.0 )
2450 pNewEffect
->setNodeType( EffectNodeType::ON_CLICK
);
2451 pNewEffect
->setBegin( 0.0 );
2455 pNewEffect
->setNodeType( EffectNodeType::AFTER_PREVIOUS
);
2456 pNewEffect
->setBegin( fTextGroupingAuto
);
2461 pNewEffect
->setNodeType( EffectNodeType::WITH_PREVIOUS
);
2462 pNewEffect
->setBegin( 0.0 );
2465 pTextGroup
->addEffect( pNewEffect
);
2471 OSL_FAIL("sd::EffectSequenceHelper::createTextGroup(), exception caught!" );
2475 void EffectSequenceHelper::setTextGrouping( const CustomAnimationTextGroupPtr
& pTextGroup
, sal_Int32 nTextGrouping
)
2477 if( pTextGroup
->mnTextGrouping
== nTextGrouping
)
2479 // first case, trivial case, do nothing
2481 else if( (pTextGroup
->mnTextGrouping
== -1) && (nTextGrouping
>= 0) )
2483 // second case, we need to add new effects for each paragraph
2485 CustomAnimationEffectPtr
pEffect( pTextGroup
->maEffects
.front() );
2487 pTextGroup
->mnTextGrouping
= nTextGrouping
;
2488 createTextGroupParagraphEffects( pTextGroup
, pEffect
, true );
2491 else if( (pTextGroup
->mnTextGrouping
>= 0) && (nTextGrouping
== -1 ) )
2493 // third case, we need to remove effects for each paragraph
2495 EffectSequence
aEffects( pTextGroup
->maEffects
);
2496 pTextGroup
->reset();
2498 EffectSequence::iterator
aIter( aEffects
.begin() );
2499 const EffectSequence::iterator
aEnd( aEffects
.end() );
2500 while( aIter
!= aEnd
)
2502 CustomAnimationEffectPtr
pEffect( (*aIter
++) );
2504 if( pEffect
->getTarget().getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
2507 pTextGroup
->addEffect( pEffect
);
2513 // fourth case, we need to change the node types for the text nodes
2514 double fTextGroupingAuto
= pTextGroup
->mfGroupingAuto
;
2516 EffectSequence
aEffects( pTextGroup
->maEffects
);
2517 pTextGroup
->reset();
2519 EffectSequence::iterator
aIter( aEffects
.begin() );
2520 const EffectSequence::iterator
aEnd( aEffects
.end() );
2521 while( aIter
!= aEnd
)
2523 CustomAnimationEffectPtr
pEffect( (*aIter
++) );
2525 if( pEffect
->getTarget().getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
2527 // set correct node type
2528 if( pEffect
->getParaDepth() < nTextGrouping
)
2530 if( fTextGroupingAuto
== -1.0 )
2532 pEffect
->setNodeType( EffectNodeType::ON_CLICK
);
2533 pEffect
->setBegin( 0.0 );
2537 pEffect
->setNodeType( EffectNodeType::AFTER_PREVIOUS
);
2538 pEffect
->setBegin( fTextGroupingAuto
);
2543 pEffect
->setNodeType( EffectNodeType::WITH_PREVIOUS
);
2544 pEffect
->setBegin( 0.0 );
2548 pTextGroup
->addEffect( pEffect
);
2555 void EffectSequenceHelper::setAnimateForm( const CustomAnimationTextGroupPtr
& pTextGroup
, bool bAnimateForm
)
2557 if( pTextGroup
->mbAnimateForm
== bAnimateForm
)
2559 // trivial case, do nothing
2563 EffectSequence
aEffects( pTextGroup
->maEffects
);
2564 pTextGroup
->reset();
2566 SAL_WARN_IF(aEffects
.empty(), "sd", "EffectSequenceHelper::setAnimateForm effects empty" );
2568 if (aEffects
.empty())
2571 EffectSequence::iterator
aIter( aEffects
.begin() );
2572 const EffectSequence::iterator
aEnd( aEffects
.end() );
2574 // first insert if we have to
2577 EffectSequence::iterator
aInsertIter( find( *aIter
) );
2579 CustomAnimationEffectPtr pEffect
;
2580 if( (aEffects
.size() == 1) && ((*aIter
)->getTarget().getValueType() != ::cppu::UnoType
<ParagraphTarget
>::get() ) )
2582 // special case, only one effect and that targets whole text,
2583 // convert this to target whole shape
2584 pEffect
= (*aIter
++);
2585 pEffect
->setTargetSubItem( ShapeAnimationSubType::AS_WHOLE
);
2589 pEffect
= (*aIter
)->clone();
2590 pEffect
->setTarget( makeAny( (*aIter
)->getTargetShape() ) );
2591 pEffect
->setTargetSubItem( ShapeAnimationSubType::ONLY_BACKGROUND
);
2592 maEffects
.insert( aInsertIter
, pEffect
);
2595 pTextGroup
->addEffect( pEffect
);
2598 if( !bAnimateForm
&& (aEffects
.size() == 1) )
2600 CustomAnimationEffectPtr
pEffect( (*aIter
) );
2601 pEffect
->setTarget( makeAny( (*aIter
)->getTargetShape() ) );
2602 pEffect
->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT
);
2603 pTextGroup
->addEffect( pEffect
);
2607 // read the rest to the group again
2608 while( aIter
!= aEnd
)
2610 CustomAnimationEffectPtr
pEffect( (*aIter
++) );
2612 if( pEffect
->getTarget().getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
2614 pTextGroup
->addEffect( pEffect
);
2618 DBG_ASSERT( !bAnimateForm
, "sd::EffectSequenceHelper::setAnimateForm(), something is wrong here!" );
2627 void EffectSequenceHelper::setTextGroupingAuto( const CustomAnimationTextGroupPtr
& pTextGroup
, double fTextGroupingAuto
)
2629 sal_Int32 nTextGrouping
= pTextGroup
->mnTextGrouping
;
2631 EffectSequence
aEffects( pTextGroup
->maEffects
);
2632 pTextGroup
->reset();
2634 EffectSequence::iterator
aIter( aEffects
.begin() );
2635 const EffectSequence::iterator
aEnd( aEffects
.end() );
2636 while( aIter
!= aEnd
)
2638 CustomAnimationEffectPtr
pEffect( (*aIter
++) );
2640 if( pEffect
->getTarget().getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
2642 // set correct node type
2643 if( pEffect
->getParaDepth() < nTextGrouping
)
2645 if( fTextGroupingAuto
== -1.0 )
2647 pEffect
->setNodeType( EffectNodeType::ON_CLICK
);
2648 pEffect
->setBegin( 0.0 );
2652 pEffect
->setNodeType( EffectNodeType::AFTER_PREVIOUS
);
2653 pEffect
->setBegin( fTextGroupingAuto
);
2658 pEffect
->setNodeType( EffectNodeType::WITH_PREVIOUS
);
2659 pEffect
->setBegin( 0.0 );
2663 pTextGroup
->addEffect( pEffect
);
2669 struct ImplStlTextGroupSortHelper
2671 explicit ImplStlTextGroupSortHelper( bool bReverse
) : mbReverse( bReverse
) {};
2672 bool operator()( const CustomAnimationEffectPtr
& p1
, const CustomAnimationEffectPtr
& p2
);
2674 sal_Int32
getTargetParagraph( const CustomAnimationEffectPtr
& p1
);
2677 sal_Int32
ImplStlTextGroupSortHelper::getTargetParagraph( const CustomAnimationEffectPtr
& p1
)
2679 const Any
aTarget(p1
->getTarget());
2680 if( aTarget
.hasValue() && aTarget
.getValueType() == ::cppu::UnoType
<ParagraphTarget
>::get() )
2682 ParagraphTarget aParaTarget
;
2683 aTarget
>>= aParaTarget
;
2684 return aParaTarget
.Paragraph
;
2688 return mbReverse
? 0x7fffffff : -1;
2692 bool ImplStlTextGroupSortHelper::operator()( const CustomAnimationEffectPtr
& p1
, const CustomAnimationEffectPtr
& p2
)
2696 return getTargetParagraph( p2
) < getTargetParagraph( p1
);
2700 return getTargetParagraph( p1
) < getTargetParagraph( p2
);
2704 void EffectSequenceHelper::setTextReverse( const CustomAnimationTextGroupPtr
& pTextGroup
, bool bTextReverse
)
2706 if( pTextGroup
->mbTextReverse
== bTextReverse
)
2712 std::vector
< CustomAnimationEffectPtr
> aSortedVector(pTextGroup
->maEffects
.size());
2713 std::copy( pTextGroup
->maEffects
.begin(), pTextGroup
->maEffects
.end(), aSortedVector
.begin() );
2714 ImplStlTextGroupSortHelper
aSortHelper( bTextReverse
);
2715 std::sort( aSortedVector
.begin(), aSortedVector
.end(), aSortHelper
);
2717 pTextGroup
->reset();
2719 std::vector
< CustomAnimationEffectPtr
>::iterator
aIter( aSortedVector
.begin() );
2720 const std::vector
< CustomAnimationEffectPtr
>::iterator
aEnd( aSortedVector
.end() );
2724 pTextGroup
->addEffect( *aIter
);
2725 EffectSequence::iterator
aInsertIter( find( *aIter
++ ) );
2726 while( aIter
!= aEnd
)
2728 CustomAnimationEffectPtr
pEffect( (*aIter
++) );
2729 maEffects
.erase( find( pEffect
) );
2730 aInsertIter
= maEffects
.insert( ++aInsertIter
, pEffect
);
2731 pTextGroup
->addEffect( pEffect
);
2738 void EffectSequenceHelper::addListener( ISequenceListener
* pListener
)
2740 if( std::find( maListeners
.begin(), maListeners
.end(), pListener
) == maListeners
.end() )
2741 maListeners
.push_back( pListener
);
2744 void EffectSequenceHelper::removeListener( ISequenceListener
* pListener
)
2746 maListeners
.remove( pListener
);
2749 struct stl_notify_listeners_func
2751 stl_notify_listeners_func() {}
2752 void operator()(ISequenceListener
* pListener
) { pListener
->notify_change(); }
2755 void EffectSequenceHelper::notify_listeners()
2757 stl_notify_listeners_func aFunc
;
2758 std::for_each( maListeners
.begin(), maListeners
.end(), aFunc
);
2761 void EffectSequenceHelper::create( const css::uno::Reference
< css::animations::XAnimationNode
>& xNode
)
2763 DBG_ASSERT( xNode
.is(), "sd::EffectSequenceHelper::create(), illegal argument" );
2765 if( xNode
.is() ) try
2767 Reference
< XEnumerationAccess
> xEnumerationAccess( xNode
, UNO_QUERY_THROW
);
2768 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
2769 while( xEnumeration
->hasMoreElements() )
2771 Reference
< XAnimationNode
> xChildNode( xEnumeration
->nextElement(), UNO_QUERY_THROW
);
2772 createEffectsequence( xChildNode
);
2777 OSL_FAIL( "sd::EffectSequenceHelper::create(), exception caught!" );
2781 void EffectSequenceHelper::createEffectsequence( const Reference
< XAnimationNode
>& xNode
)
2783 DBG_ASSERT( xNode
.is(), "sd::EffectSequenceHelper::createEffectsequence(), illegal argument" );
2785 if( xNode
.is() ) try
2787 Reference
< XEnumerationAccess
> xEnumerationAccess( xNode
, UNO_QUERY_THROW
);
2788 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
2789 while( xEnumeration
->hasMoreElements() )
2791 Reference
< XAnimationNode
> xChildNode( xEnumeration
->nextElement(), UNO_QUERY_THROW
);
2793 createEffects( xChildNode
);
2798 OSL_FAIL( "sd::EffectSequenceHelper::createEffectsequence(), exception caught!" );
2802 void EffectSequenceHelper::createEffects( const Reference
< XAnimationNode
>& xNode
)
2804 DBG_ASSERT( xNode
.is(), "sd::EffectSequenceHelper::createEffects(), illegal argument" );
2806 if( xNode
.is() ) try
2808 Reference
< XEnumerationAccess
> xEnumerationAccess( xNode
, UNO_QUERY_THROW
);
2809 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
2810 while( xEnumeration
->hasMoreElements() )
2812 Reference
< XAnimationNode
> xChildNode( xEnumeration
->nextElement(), UNO_QUERY_THROW
);
2814 switch( xChildNode
->getType() )
2817 case AnimationNodeType::PAR
:
2818 case AnimationNodeType::ITERATE
:
2820 CustomAnimationEffectPtr
pEffect( new CustomAnimationEffect( xChildNode
) );
2822 if( pEffect
->mnNodeType
!= -1 )
2824 pEffect
->setEffectSequence( this );
2825 maEffects
.push_back(pEffect
);
2830 // found an after effect
2831 case AnimationNodeType::SET
:
2832 case AnimationNodeType::ANIMATECOLOR
:
2834 processAfterEffect( xChildNode
);
2842 OSL_FAIL( "sd::EffectSequenceHelper::createEffects(), exception caught!" );
2846 void EffectSequenceHelper::processAfterEffect( const Reference
< XAnimationNode
>& xNode
)
2850 Reference
< XAnimationNode
> xMaster
;
2852 Sequence
< NamedValue
> aUserData( xNode
->getUserData() );
2853 sal_Int32 nLength
= aUserData
.getLength();
2854 const NamedValue
* p
= aUserData
.getConstArray();
2858 if ( p
->Name
== "master-element" )
2860 p
->Value
>>= xMaster
;
2866 // only process if this is a valid after effect
2869 CustomAnimationEffectPtr pMasterEffect
;
2871 // find the master effect
2872 stl_CustomAnimationEffect_search_node_predict
aSearchPredict( xMaster
);
2873 EffectSequence::iterator
aIter( std::find_if( maEffects
.begin(), maEffects
.end(), aSearchPredict
) );
2874 if( aIter
!= maEffects
.end() )
2875 pMasterEffect
= (*aIter
);
2877 if( pMasterEffect
.get() )
2879 pMasterEffect
->setHasAfterEffect( true );
2881 // find out what kind of after effect this is
2882 if( xNode
->getType() == AnimationNodeType::ANIMATECOLOR
)
2885 Reference
< XAnimate
> xAnimate( xNode
, UNO_QUERY_THROW
);
2886 pMasterEffect
->setDimColor( xAnimate
->getTo() );
2887 pMasterEffect
->setAfterEffectOnNext( true );
2892 pMasterEffect
->setAfterEffectOnNext( xNode
->getParent() != xMaster
->getParent() );
2899 OSL_FAIL( "sd::EffectSequenceHelper::processAfterEffect(), exception caught!" );
2903 class AnimationChangeListener
: public cppu::WeakImplHelper
< XChangesListener
>
2906 explicit AnimationChangeListener( MainSequence
* pMainSequence
) : mpMainSequence( pMainSequence
) {}
2908 virtual void SAL_CALL
changesOccurred( const css::util::ChangesEvent
& Event
) override
;
2909 virtual void SAL_CALL
disposing( const css::lang::EventObject
& Source
) override
;
2911 MainSequence
* mpMainSequence
;
2914 void SAL_CALL
AnimationChangeListener::changesOccurred( const css::util::ChangesEvent
& )
2916 if( mpMainSequence
)
2917 mpMainSequence
->startRecreateTimer();
2920 void SAL_CALL
AnimationChangeListener::disposing( const css::lang::EventObject
& )
2924 MainSequence::MainSequence()
2925 : mxTimingRootNode(SequenceTimeContainer::create(::comphelper::getProcessComponentContext()))
2926 , mbTimerMode(false)
2927 , mbRebuilding( false )
2928 , mnRebuildLockGuard( 0 )
2929 , mbPendingRebuildRequest( false )
2930 , mbIgnoreChanges( 0 )
2932 if( mxTimingRootNode
.is() )
2934 Sequence
< css::beans::NamedValue
> aUserData
2935 { { "node-type", css::uno::makeAny(css::presentation::EffectNodeType::MAIN_SEQUENCE
) } };
2936 mxTimingRootNode
->setUserData( aUserData
);
2941 MainSequence::MainSequence( const css::uno::Reference
< css::animations::XAnimationNode
>& xNode
)
2942 : mxTimingRootNode( xNode
, UNO_QUERY
)
2943 , mbTimerMode( false )
2944 , mbRebuilding( false )
2945 , mnRebuildLockGuard( 0 )
2946 , mbPendingRebuildRequest( false )
2947 , mbIgnoreChanges( 0 )
2952 MainSequence::~MainSequence()
2957 void MainSequence::init()
2959 mnSequenceType
= EffectNodeType::MAIN_SEQUENCE
;
2961 maTimer
.SetInvokeHandler( LINK(this, MainSequence
, onTimerHdl
) );
2962 maTimer
.SetTimeout(500);
2964 mxChangesListener
.set( new AnimationChangeListener( this ) );
2966 createMainSequence();
2969 void MainSequence::reset( const css::uno::Reference
< css::animations::XAnimationNode
>& xTimingRootNode
)
2973 mxTimingRootNode
.set( xTimingRootNode
, UNO_QUERY
);
2975 createMainSequence();
2978 Reference
< css::animations::XAnimationNode
> MainSequence::getRootNode()
2980 DBG_ASSERT( mnRebuildLockGuard
== 0, "MainSequence::getRootNode(), rebuild is locked, is this really what you want?" );
2982 if( maTimer
.IsActive() && mbTimerMode
)
2984 // force a rebuild NOW if one is pending
2989 return EffectSequenceHelper::getRootNode();
2992 void MainSequence::createMainSequence()
2994 if( mxTimingRootNode
.is() ) try
2996 Reference
< XEnumerationAccess
> xEnumerationAccess( mxTimingRootNode
, UNO_QUERY_THROW
);
2997 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
2998 while( xEnumeration
->hasMoreElements() )
3000 Reference
< XAnimationNode
> xChildNode( xEnumeration
->nextElement(), UNO_QUERY_THROW
);
3001 sal_Int32 nNodeType
= CustomAnimationEffect::get_node_type( xChildNode
);
3002 if( nNodeType
== EffectNodeType::MAIN_SEQUENCE
)
3004 mxSequenceRoot
.set( xChildNode
, UNO_QUERY
);
3005 EffectSequenceHelper::create( xChildNode
);
3007 else if( nNodeType
== EffectNodeType::INTERACTIVE_SEQUENCE
)
3009 Reference
< XTimeContainer
> xInteractiveRoot( xChildNode
, UNO_QUERY_THROW
);
3010 InteractiveSequencePtr
pIS( new InteractiveSequence( xInteractiveRoot
, this ) );
3011 pIS
->addListener( this );
3012 maInteractiveSequenceVector
.push_back( pIS
);
3016 // see if we have a mainsequence at all. if not, create one...
3017 if( !mxSequenceRoot
.is() )
3019 mxSequenceRoot
= SequenceTimeContainer::create( ::comphelper::getProcessComponentContext() );
3021 uno::Sequence
< css::beans::NamedValue
> aUserData
3022 { { "node-type", css::uno::makeAny(css::presentation::EffectNodeType::MAIN_SEQUENCE
) } };
3023 mxSequenceRoot
->setUserData( aUserData
);
3025 // empty sequence until now, set duration to 0.0
3026 // explicitly (otherwise, this sequence will never
3028 mxSequenceRoot
->setDuration( makeAny(0.0) );
3030 Reference
< XAnimationNode
> xMainSequenceNode( mxSequenceRoot
, UNO_QUERY_THROW
);
3031 mxTimingRootNode
->appendChild( xMainSequenceNode
);
3038 Reference
< XChangesNotifier
> xNotifier( mxTimingRootNode
, UNO_QUERY
);
3039 if( xNotifier
.is() )
3040 xNotifier
->addChangesListener( mxChangesListener
);
3044 OSL_FAIL( "sd::MainSequence::create(), exception caught!" );
3048 DBG_ASSERT( mxSequenceRoot
.is(), "sd::MainSequence::create(), found no main sequence!" );
3051 void MainSequence::reset()
3053 EffectSequenceHelper::reset();
3055 for (auto const& interactiveSequence
: maInteractiveSequenceVector
)
3056 interactiveSequence
->reset();
3057 maInteractiveSequenceVector
.clear();
3061 Reference
< XChangesNotifier
> xNotifier( mxTimingRootNode
, UNO_QUERY
);
3062 if( xNotifier
.is() )
3063 xNotifier
->removeChangesListener( mxChangesListener
);
3071 InteractiveSequencePtr
MainSequence::createInteractiveSequence( const css::uno::Reference
< css::drawing::XShape
>& xShape
)
3073 InteractiveSequencePtr pIS
;
3075 // create a new interactive sequence container
3076 Reference
< XTimeContainer
> xISRoot
= SequenceTimeContainer::create( ::comphelper::getProcessComponentContext() );
3078 uno::Sequence
< css::beans::NamedValue
> aUserData
3079 { { "node-type", css::uno::makeAny(css::presentation::EffectNodeType::INTERACTIVE_SEQUENCE
) } };
3080 xISRoot
->setUserData( aUserData
);
3082 Reference
< XChild
> xChild( mxSequenceRoot
, UNO_QUERY_THROW
);
3083 Reference
< XTimeContainer
> xParent( xChild
->getParent(), UNO_QUERY_THROW
);
3084 xParent
->appendChild( xISRoot
);
3086 pIS
.reset( new InteractiveSequence( xISRoot
, this) );
3087 pIS
->setTriggerShape( xShape
);
3088 pIS
->addListener( this );
3089 maInteractiveSequenceVector
.push_back( pIS
);
3093 CustomAnimationEffectPtr
MainSequence::findEffect( const css::uno::Reference
< css::animations::XAnimationNode
>& xNode
) const
3095 CustomAnimationEffectPtr pEffect
= EffectSequenceHelper::findEffect( xNode
);
3097 if( pEffect
.get() == nullptr )
3099 for (auto const& interactiveSequence
: maInteractiveSequenceVector
)
3101 pEffect
= interactiveSequence
->findEffect( xNode
);
3109 sal_Int32
MainSequence::getOffsetFromEffect( const CustomAnimationEffectPtr
& pEffect
) const
3111 sal_Int32 nOffset
= EffectSequenceHelper::getOffsetFromEffect( pEffect
);
3116 nOffset
= EffectSequenceHelper::getCount();
3118 for (auto const& interactiveSequence
: maInteractiveSequenceVector
)
3120 sal_Int32 nTemp
= interactiveSequence
->getOffsetFromEffect( pEffect
);
3122 return nOffset
+ nTemp
;
3124 nOffset
+= interactiveSequence
->getCount();
3130 CustomAnimationEffectPtr
MainSequence::getEffectFromOffset( sal_Int32 nOffset
) const
3134 if( nOffset
< getCount() )
3135 return EffectSequenceHelper::getEffectFromOffset( nOffset
);
3137 nOffset
-= getCount();
3139 auto aIter( maInteractiveSequenceVector
.begin() );
3141 while( (aIter
!= maInteractiveSequenceVector
.end()) && (nOffset
> (*aIter
)->getCount()) )
3142 nOffset
-= (*aIter
++)->getCount();
3144 if( (aIter
!= maInteractiveSequenceVector
.end()) && (nOffset
>= 0) )
3145 return (*aIter
)->getEffectFromOffset( nOffset
);
3148 CustomAnimationEffectPtr pEffect
;
3152 bool MainSequence::disposeShape( const Reference
< XShape
>& xShape
)
3154 bool bChanges
= EffectSequenceHelper::disposeShape( xShape
);
3156 for (auto const& iterativeSequence
: maInteractiveSequenceVector
)
3158 bChanges
|= iterativeSequence
->disposeShape( xShape
);
3162 startRebuildTimer();
3167 bool MainSequence::hasEffect( const css::uno::Reference
< css::drawing::XShape
>& xShape
)
3169 if( EffectSequenceHelper::hasEffect( xShape
) )
3172 for (auto const& iterativeSequence
: maInteractiveSequenceVector
)
3174 if( iterativeSequence
->getTriggerShape() == xShape
)
3177 if( iterativeSequence
->hasEffect( xShape
) )
3184 void MainSequence::insertTextRange( const css::uno::Any
& aTarget
)
3186 EffectSequenceHelper::insertTextRange( aTarget
);
3188 for (auto const& iterativeSequence
: maInteractiveSequenceVector
)
3190 iterativeSequence
->insertTextRange( aTarget
);
3194 void MainSequence::disposeTextRange( const css::uno::Any
& aTarget
)
3196 EffectSequenceHelper::disposeTextRange( aTarget
);
3198 for (auto const& iterativeSequence
: maInteractiveSequenceVector
)
3200 iterativeSequence
->disposeTextRange( aTarget
);
3204 /** callback from the sd::View when an object just left text edit mode */
3205 void MainSequence::onTextChanged( const Reference
< XShape
>& xShape
)
3207 EffectSequenceHelper::onTextChanged( xShape
);
3209 for (auto const& iterativeSequence
: maInteractiveSequenceVector
)
3211 iterativeSequence
->onTextChanged( xShape
);
3215 void EffectSequenceHelper::onTextChanged( const Reference
< XShape
>& xShape
)
3217 bool bChanges
= false;
3219 EffectSequence::iterator aIter
;
3220 for( aIter
= maEffects
.begin(); aIter
!= maEffects
.end(); ++aIter
)
3222 if( (*aIter
)->getTargetShape() == xShape
)
3223 bChanges
|= (*aIter
)->checkForText();
3227 EffectSequenceHelper::implRebuild();
3230 void MainSequence::rebuild()
3232 startRebuildTimer();
3235 void MainSequence::lockRebuilds()
3237 mnRebuildLockGuard
++;
3240 void MainSequence::unlockRebuilds()
3242 DBG_ASSERT( mnRebuildLockGuard
, "sd::MainSequence::unlockRebuilds(), no corresponding lockRebuilds() call!" );
3243 if( mnRebuildLockGuard
)
3244 mnRebuildLockGuard
--;
3246 if( (mnRebuildLockGuard
== 0) && mbPendingRebuildRequest
)
3248 mbPendingRebuildRequest
= false;
3249 startRebuildTimer();
3253 void MainSequence::implRebuild()
3255 if( mnRebuildLockGuard
)
3257 mbPendingRebuildRequest
= true;
3261 mbRebuilding
= true;
3263 EffectSequenceHelper::implRebuild();
3265 auto aIter( maInteractiveSequenceVector
.begin() );
3266 while( aIter
!= maInteractiveSequenceVector
.end() )
3268 InteractiveSequencePtr
pIS( (*aIter
) );
3269 if( pIS
->maEffects
.empty() )
3271 // remove empty interactive sequences
3272 aIter
= maInteractiveSequenceVector
.erase( aIter
);
3274 Reference
< XChild
> xChild( mxSequenceRoot
, UNO_QUERY_THROW
);
3275 Reference
< XTimeContainer
> xParent( xChild
->getParent(), UNO_QUERY_THROW
);
3276 Reference
< XAnimationNode
> xISNode( pIS
->mxSequenceRoot
, UNO_QUERY_THROW
);
3277 xParent
->removeChild( xISNode
);
3287 mbRebuilding
= false;
3290 void MainSequence::notify_change()
3295 bool MainSequence::setTrigger( const CustomAnimationEffectPtr
& pEffect
, const css::uno::Reference
< css::drawing::XShape
>& xTriggerShape
)
3297 EffectSequenceHelper
* pOldSequence
= pEffect
->getEffectSequence();
3299 EffectSequenceHelper
* pNewSequence
= nullptr;
3300 if( xTriggerShape
.is() )
3302 for (auto const& iteractiveSequence
: maInteractiveSequenceVector
)
3304 InteractiveSequencePtr
pIS(iteractiveSequence
);
3305 if( pIS
->getTriggerShape() == xTriggerShape
)
3307 pNewSequence
= pIS
.get();
3313 pNewSequence
= createInteractiveSequence( xTriggerShape
).get();
3317 pNewSequence
= this;
3320 if( pOldSequence
!= pNewSequence
)
3323 pOldSequence
->maEffects
.remove( pEffect
);
3325 pNewSequence
->maEffects
.push_back( pEffect
);
3326 pEffect
->setEffectSequence( pNewSequence
);
3336 IMPL_LINK_NOARG(MainSequence
, onTimerHdl
, Timer
*, void)
3345 createMainSequence();
3349 /** starts a timer that recreates the internal structure from the API core after 1 second */
3350 void MainSequence::startRecreateTimer()
3352 if( !mbRebuilding
&& (mbIgnoreChanges
== 0) )
3354 mbTimerMode
= false;
3359 /** starts a timer that rebuilds the API core from the internal structure after 1 second */
3360 void MainSequence::startRebuildTimer()
3366 InteractiveSequence::InteractiveSequence( const Reference
< XTimeContainer
>& xSequenceRoot
, MainSequence
* pMainSequence
)
3367 : EffectSequenceHelper( xSequenceRoot
), mpMainSequence( pMainSequence
)
3369 mnSequenceType
= EffectNodeType::INTERACTIVE_SEQUENCE
;
3373 if( mxSequenceRoot
.is() )
3375 Reference
< XEnumerationAccess
> xEnumerationAccess( mxSequenceRoot
, UNO_QUERY_THROW
);
3376 Reference
< XEnumeration
> xEnumeration( xEnumerationAccess
->createEnumeration(), UNO_QUERY_THROW
);
3377 while( !mxEventSource
.is() && xEnumeration
->hasMoreElements() )
3379 Reference
< XAnimationNode
> xChildNode( xEnumeration
->nextElement(), UNO_QUERY_THROW
);
3382 if( (xChildNode
->getBegin() >>= aEvent
) && (aEvent
.Trigger
== EventTrigger::ON_CLICK
) )
3383 aEvent
.Source
>>= mxEventSource
;
3389 OSL_FAIL( "sd::InteractiveSequence::InteractiveSequence(), exception caught!" );
3394 void InteractiveSequence::rebuild()
3396 mpMainSequence
->rebuild();
3399 void InteractiveSequence::implRebuild()
3401 EffectSequenceHelper::implRebuild();
3404 MainSequenceRebuildGuard::MainSequenceRebuildGuard( const MainSequencePtr
& pMainSequence
)
3405 : mpMainSequence( pMainSequence
)
3407 if( mpMainSequence
.get() )
3408 mpMainSequence
->lockRebuilds();
3411 MainSequenceRebuildGuard::~MainSequenceRebuildGuard()
3413 if( mpMainSequence
.get() )
3414 mpMainSequence
->unlockRebuilds();
3419 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */