update emoji autocorrect entries from po-files
[LibreOffice.git] / sd / source / core / CustomAnimationEffect.cxx
blob4cc6db56287182929871fddb564d11bb4bfeb312
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <tools/debug.hxx>
21 #include <com/sun/star/animations/AnimationNodeType.hpp>
22 #include <com/sun/star/animations/AnimateColor.hpp>
23 #include <com/sun/star/animations/AnimateMotion.hpp>
24 #include <com/sun/star/animations/AnimateSet.hpp>
25 #include <com/sun/star/animations/AnimationFill.hpp>
26 #include <com/sun/star/animations/AnimationTransformType.hpp>
27 #include <com/sun/star/animations/Audio.hpp>
28 #include <com/sun/star/animations/Command.hpp>
29 #include <com/sun/star/animations/Event.hpp>
30 #include <com/sun/star/animations/EventTrigger.hpp>
31 #include <com/sun/star/animations/IterateContainer.hpp>
32 #include <com/sun/star/animations/ParallelTimeContainer.hpp>
33 #include <com/sun/star/animations/SequenceTimeContainer.hpp>
34 #include <com/sun/star/animations/Timing.hpp>
35 #include <com/sun/star/animations/XCommand.hpp>
36 #include <com/sun/star/animations/XIterateContainer.hpp>
37 #include <com/sun/star/animations/XAnimateTransform.hpp>
38 #include <com/sun/star/animations/XAnimateMotion.hpp>
39 #include <com/sun/star/animations/XAnimate.hpp>
40 #include <com/sun/star/beans/NamedValue.hpp>
41 #include <com/sun/star/beans/XPropertySet.hpp>
42 #include <com/sun/star/container/XEnumerationAccess.hpp>
43 #include <com/sun/star/drawing/XDrawPage.hpp>
44 #include <com/sun/star/lang/XInitialization.hpp>
45 #include <com/sun/star/presentation/EffectNodeType.hpp>
46 #include <com/sun/star/presentation/EffectCommands.hpp>
47 #include <com/sun/star/presentation/EffectPresetClass.hpp>
48 #include <com/sun/star/presentation/ParagraphTarget.hpp>
49 #include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
50 #include <com/sun/star/text/XText.hpp>
51 #include <com/sun/star/util/XCloneable.hpp>
52 #include <com/sun/star/util/XChangesNotifier.hpp>
53 #include <comphelper/processfactory.hxx>
54 #include <comphelper/sequence.hxx>
55 #include <com/sun/star/lang/Locale.hpp>
56 #include <com/sun/star/i18n/BreakIterator.hpp>
57 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
58 #include <com/sun/star/i18n/WordType.hpp>
59 #include <com/sun/star/presentation/TextAnimationType.hpp>
61 #include <basegfx/polygon/b2dpolypolygon.hxx>
62 #include <basegfx/polygon/b2dpolypolygontools.hxx>
63 #include <basegfx/matrix/b2dhommatrix.hxx>
64 #include <basegfx/range/b2drange.hxx>
65 #include <basegfx/matrix/b2dhommatrixtools.hxx>
67 #include <algorithm>
69 #include <cppuhelper/implbase1.hxx>
71 #include <drawinglayer/geometry/viewinformation2d.hxx>
72 #include <svx/sdr/contact/viewcontact.hxx>
73 #include <svx/svdopath.hxx>
74 #include <svx/svdpage.hxx>
75 #include <svx/unoapi.hxx>
76 #include "CustomAnimationEffect.hxx"
77 #include <CustomAnimationPreset.hxx>
78 #include "animations.hxx"
80 using namespace ::com::sun::star;
81 using namespace ::com::sun::star::uno;
82 using namespace ::com::sun::star::presentation;
83 using namespace ::com::sun::star::animations;
85 using ::com::sun::star::container::XEnumerationAccess;
86 using ::com::sun::star::container::XEnumeration;
87 using ::com::sun::star::beans::NamedValue;
88 using ::com::sun::star::container::XChild;
89 using ::com::sun::star::container::XElementAccess;
90 using ::com::sun::star::drawing::XShape;
91 using ::com::sun::star::lang::XInitialization;
92 using ::com::sun::star::drawing::XShapes;
93 using ::com::sun::star::drawing::XDrawPage;
94 using ::com::sun::star::text::XText;
95 using ::com::sun::star::text::XTextRange;
96 using ::com::sun::star::beans::XPropertySet;
97 using ::com::sun::star::lang::XMultiServiceFactory;
98 using ::com::sun::star::util::XCloneable;
99 using ::com::sun::star::lang::Locale;
100 using ::com::sun::star::util::XChangesNotifier;
101 using ::com::sun::star::util::XChangesListener;
103 namespace sd
105 class MainSequenceChangeGuard
107 public:
108 MainSequenceChangeGuard( EffectSequenceHelper* pSequence )
110 mpMainSequence = dynamic_cast< MainSequence* >( pSequence );
111 if( mpMainSequence == 0 )
113 InteractiveSequence* pI = dynamic_cast< InteractiveSequence* >( pSequence );
114 if( pI )
115 mpMainSequence = pI->mpMainSequence;
117 DBG_ASSERT( mpMainSequence, "sd::MainSequenceChangeGuard::MainSequenceChangeGuard(), no main sequence to guard!" );
119 if( mpMainSequence )
120 mpMainSequence->mbIgnoreChanges++;
123 ~MainSequenceChangeGuard()
125 if( mpMainSequence )
126 mpMainSequence->mbIgnoreChanges++;
129 private:
130 MainSequence* mpMainSequence;
133 CustomAnimationEffect::CustomAnimationEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
134 : mnNodeType(-1),
135 mnPresetClass(-1),
136 mfBegin(-1.0),
137 mfDuration(-1.0),
138 mfAbsoluteDuration(-1.0),
139 mnGroupId(-1),
140 mnIterateType(0),
141 mfIterateInterval(0.0),
142 mnParaDepth( -1 ),
143 mbHasText(false),
144 mfAcceleration( 1.0 ),
145 mfDecelerate( 1.0 ),
146 mbAutoReverse(false),
147 mnTargetSubItem(0),
148 mnCommand(0),
149 mpEffectSequence( 0 ),
150 mbHasAfterEffect(false),
151 mbAfterEffectOnNextEffect(false)
153 setNode( xNode );
156 void CustomAnimationEffect::setNode( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
158 mxNode = xNode;
159 mxAudio.clear();
161 Sequence< NamedValue > aUserData( mxNode->getUserData() );
162 sal_Int32 nLength = aUserData.getLength();
163 const NamedValue* p = aUserData.getConstArray();
165 while( nLength-- )
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;
192 p++;
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 );
204 if( xIter.is() )
206 mfIterateInterval = xIter->getIterateInterval();
207 mnIterateType = xIter->getIterateType();
208 maTarget = xIter->getTarget();
209 mnTargetSubItem = xIter->getSubItem();
211 else
213 mfIterateInterval = 0.0f;
214 mnIterateType = 0;
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() )
228 continue;
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 );
237 if( xCommand.is() )
239 mnCommand = xCommand->getCommand();
240 if( !maTarget.hasValue() )
241 maTarget = xCommand->getTarget();
244 else
246 double fBegin = 0.0;
247 double fDuration = 0.0;
248 xChildNode->getBegin() >>= fBegin;
249 xChildNode->getDuration() >>= fDuration;
251 fDuration += fBegin;
252 if( fDuration > mfDuration )
253 mfDuration = fDuration;
255 // no target shape yet?
256 if( !maTarget.hasValue() )
258 // go get it boys!
259 Reference< XAnimate > xAnimate( xChildNode, UNO_QUERY );
260 if( xAnimate.is() )
262 maTarget = xAnimate->getTarget();
263 mnTargetSubItem = xAnimate->getSubItem();
271 mfAbsoluteDuration = mfDuration;
272 double fRepeatCount = 1.0;
273 if( (mxNode->getRepeatCount()) >>= fRepeatCount )
274 mfAbsoluteDuration *= fRepeatCount;
276 checkForText();
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;
289 aTarget >>= xShape;
290 if( !xShape.is() )
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
303 if( xShape.is() )
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 );
311 Locale aLocale;
312 const OUString aStrLocaleName( "CharLocale" );
313 Reference< XTextRange > xParagraph;
315 sal_Int32 nPara = 0;
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 ) )
322 continue;
324 if( nIterateType == TextAnimationType::BY_PARAGRAPH )
326 nSubItems++;
328 else
330 const OUString aText( xParagraph->getString() );
331 Reference< XPropertySet > xSet( xParagraph, UNO_QUERY_THROW );
332 xSet->getPropertyValue( aStrLocaleName ) >>= aLocale;
334 sal_Int32 nPos;
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;
342 nSubItems++;
344 break;
346 else
348 sal_Int32 nDone;
349 for( nPos = 0; nPos < nEndPos; nPos++ )
351 nPos = xBI->nextCharacters(aText, nPos, aLocale, i18n::CharacterIteratorMode::SKIPCELL, 0, nDone);
352 nSubItems++;
357 if( nPara == nOnlyPara )
358 break;
360 nPara++;
364 catch( Exception& )
366 nSubItems = 0;
367 OSL_FAIL( "sd::CustomAnimationEffect::getNumberOfSubitems(), exception caught!" );
370 return nSubItems;
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() );
383 return pEffect;
386 sal_Int32 CustomAnimationEffect::get_node_type( const Reference< XAnimationNode >& xNode )
388 sal_Int16 nNodeType = -1;
390 if( xNode.is() )
392 Sequence< NamedValue > aUserData( xNode->getUserData() );
393 sal_Int32 nLength = aUserData.getLength();
394 if( nLength )
396 const NamedValue* p = aUserData.getConstArray();
397 while( nLength-- )
399 if ( p->Name == "node-type" )
401 p->Value >>= nNodeType;
402 break;
404 p++;
409 return nNodeType;
412 void CustomAnimationEffect::setPresetClass( sal_Int16 nPresetClass )
414 if( mnPresetClass != nPresetClass )
416 mnPresetClass = nPresetClass;
417 if( mxNode.is() )
419 // first try to find a "preset-class" entry in the user data
420 // and change it
421 Sequence< NamedValue > aUserData( mxNode->getUserData() );
422 sal_Int32 nLength = aUserData.getLength();
423 bool bFound = false;
424 if( nLength )
426 NamedValue* p = aUserData.getArray();
427 while( nLength-- )
429 if ( p->Name == "preset-class" )
431 p->Value <<= mnPresetClass;
432 bFound = true;
433 break;
435 p++;
439 // no "node-type" entry inside user data, so add it
440 if( !bFound )
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;
458 if( mxNode.is() )
460 // first try to find a "node-type" entry in the user data
461 // and change it
462 Sequence< NamedValue > aUserData( mxNode->getUserData() );
463 sal_Int32 nLength = aUserData.getLength();
464 bool bFound = false;
465 if( nLength )
467 NamedValue* p = aUserData.getArray();
468 while( nLength-- )
470 if ( p->Name == "node-type" )
472 p->Value <<= mnNodeType;
473 bFound = true;
474 break;
476 p++;
480 // no "node-type" entry inside user data, so add it
481 if( !bFound )
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;
497 if( mxNode.is() )
499 // first try to find a "group-id" entry in the user data
500 // and change it
501 Sequence< NamedValue > aUserData( mxNode->getUserData() );
502 sal_Int32 nLength = aUserData.getLength();
503 bool bFound = false;
504 if( nLength )
506 NamedValue* p = aUserData.getArray();
507 while( nLength-- )
509 if ( p->Name == "group-id" )
511 p->Value <<= mnGroupId;
512 bFound = true;
513 break;
515 p++;
519 // no "node-type" entry inside user data, so add it
520 if( !bFound )
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() )
543 // calc para depth
544 ParagraphTarget aParaTarget;
545 maTarget >>= aParaTarget;
547 xText = Reference< XText >::query( aParaTarget.Shape );
549 // get paragraph
550 if( xText.is() )
552 Reference< XEnumerationAccess > xEA( xText, UNO_QUERY );
553 if( xEA.is() )
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;
571 if( xParaSet.is() )
573 sal_Int32 nParaDepth = 0;
574 const OUString strNumberingLevel( "NumberingLevel" );
575 xParaSet->getPropertyValue( strNumberingLevel ) >>= nParaDepth;
576 bChange |= nParaDepth != mnParaDepth;
577 mnParaDepth = nParaDepth;
584 else
586 maTarget >>= xText;
587 bool bHasText = xText.is() && !xText->getString().isEmpty();
588 bChange |= bHasText != mbHasText;
589 mbHasText = bHasText;
592 bChange |= calculateIterateDuration();
593 return bChange;
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 );
605 if( xIter.is() )
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 );
613 if( nSubItems )
615 const double f = (nSubItems-1) * mfIterateInterval;
616 fDuration += f;
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;
629 return bChange;
632 void CustomAnimationEffect::setTarget( const ::com::sun::star::uno::Any& rTarget )
636 maTarget = rTarget;
638 // first, check special case for random node
639 Reference< XInitialization > xInit( mxNode, UNO_QUERY );
640 if( xInit.is() )
642 const Sequence< Any > aArgs( &maTarget, 1 );
643 xInit->initialize( aArgs );
645 else
647 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
648 if( xIter.is() )
650 xIter->setTarget(maTarget);
652 else
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 );
664 if( xAnimate.is() )
665 xAnimate->setTarget( rTarget );
666 else
668 Reference< XCommand > xCommand( aElem, UNO_QUERY );
669 if( xCommand.is() )
670 xCommand->setTarget( rTarget );
677 checkForText();
679 catch( Exception& )
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 );
692 if( xIter.is() )
694 xIter->setSubItem(mnTargetSubItem);
696 else
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 );
707 if( xAnimate.is() )
708 xAnimate->setSubItem( mnTargetSubItem );
714 catch( Exception& )
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() )
741 continue;
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();
763 catch( Exception& )
765 OSL_FAIL( "sd::CustomAnimationEffect::setDuration(), exception caught!" );
769 void CustomAnimationEffect::setBegin( double fBegin )
771 if( mxNode.is() ) try
773 mfBegin = fBegin;
774 mxNode->setBegin( makeAny( fBegin ) );
776 catch( Exception& )
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 );
789 catch( Exception& )
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 );
802 catch( Exception& )
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 );
815 catch( Exception& )
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;
836 setNode( xNode );
838 setAudio( xAudio );
839 setNodeType( nNodeType );
840 setTarget( aTarget );
841 setTargetSubItem( nSubItem );
842 setDuration( fDuration );
843 setBegin( fBegin );
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;
859 maTarget >>= xShape;
860 if( !xShape.is() )
862 ParagraphTarget aParaTarget;
863 if( maTarget >>= aParaTarget )
864 xShape = aParaTarget.Shape;
867 return xShape;
870 Any CustomAnimationEffect::getRepeatCount() const
872 if( mxNode.is() )
874 return mxNode->getRepeatCount();
876 else
878 Any aAny;
879 return aAny;
883 Any CustomAnimationEffect::getEnd() const
885 if( mxNode.is() )
887 return mxNode->getEnd();
889 else
891 Any aAny;
892 return aAny;
896 sal_Int16 CustomAnimationEffect::getFill() const
898 if( mxNode.is() )
899 return mxNode->getFill();
900 else
901 return 0;
904 void CustomAnimationEffect::setRepeatCount( const Any& rRepeatCount )
906 if( mxNode.is() )
908 mxNode->setRepeatCount( rRepeatCount );
909 double fRepeatCount = 1.0;
910 rRepeatCount >>= fRepeatCount;
911 mfAbsoluteDuration = mfDuration * fRepeatCount;
915 void CustomAnimationEffect::setEnd( const Any& rEnd )
917 if( mxNode.is() )
918 mxNode->setEnd( rEnd );
921 void CustomAnimationEffect::setFill( sal_Int16 nFill )
923 if( mxNode.is() )
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 );
936 else
937 xAnimate = AnimateSet::create( xContext );
939 Any aTo;
940 OUString aAttributeName;
942 if( maDimColor.hasValue() )
944 aTo = maDimColor;
945 aAttributeName = "DimColor";
947 else
949 aTo = makeAny( false );
950 aAttributeName = "Visibility";
953 Any aBegin;
954 if( !mbAfterEffectOnNextEffect ) // sameClick
956 Event aEvent;
958 aEvent.Source <<= getNode();
959 aEvent.Trigger = EventTrigger::END_EVENT;
960 aEvent.Repeat = 0;
962 aBegin <<= aEvent;
964 else
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 );
977 return xAnimate;
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;
991 if(nIterateType)
993 xNewContainer.set( IterateContainer::create( xContext ) );
995 else
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;
1027 Any aTarget;
1028 if( nIterateType )
1030 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY_THROW );
1031 xIter->setTarget(maTarget);
1032 xIter->setSubItem( nTargetSubItem );
1034 else
1036 aTarget = maTarget;
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 );
1044 if( xAnimate.is() )
1046 xAnimate->setTarget( aTarget );
1047 xAnimate->setSubItem( nTargetSubItem );
1052 mnIterateType = nIterateType;
1054 // if we have an iteration container, we must set its type
1055 if( mnIterateType )
1057 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY_THROW );
1058 xIter->setIterateType( nIterateType );
1061 checkForText();
1063 catch( Exception& )
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" );
1076 if( xIter.is() )
1078 mfIterateInterval = fIterateInterval;
1079 xIter->setIterateInterval( fIterateInterval );
1082 calculateIterateDuration();
1086 OUString CustomAnimationEffect::getPath() const
1088 OUString aPath;
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 );
1097 if( xMotion.is() )
1099 xMotion->getPath() >>= aPath;
1100 break;
1104 catch( Exception& )
1106 OSL_FAIL("sd::CustomAnimationEffect::getPath(), exception caught!" );
1109 return aPath;
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 );
1121 if( xMotion.is() )
1124 MainSequenceChangeGuard aGuard( mpEffectSequence );
1125 xMotion->setPath( Any( rPath ) );
1126 break;
1130 catch( Exception& )
1132 OSL_FAIL("sd::CustomAnimationEffect::setPath(), exception caught!" );
1136 Any CustomAnimationEffect::getProperty( sal_Int32 nNodeType, const OUString& rAttributeName, EValue eValue )
1138 Any aProperty;
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() )
1151 continue;
1153 if( xAnimate->getType() == nNodeType )
1155 if( xAnimate->getAttributeName() == rAttributeName )
1157 switch( eValue )
1159 case VALUE_FROM: aProperty = xAnimate->getFrom(); break;
1160 case VALUE_TO: aProperty = xAnimate->getTo(); break;
1161 case VALUE_BY: aProperty = xAnimate->getBy(); break;
1162 case VALUE_FIRST:
1163 case VALUE_LAST:
1165 Sequence<Any> aValues( xAnimate->getValues() );
1166 if( aValues.hasElements() )
1167 aProperty = aValues[ eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1 ];
1169 break;
1177 catch( Exception& )
1179 OSL_FAIL("sd::CustomAnimationEffect::getProperty(), exception caught!" );
1182 return aProperty;
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() )
1200 continue;
1202 if( xAnimate->getType() == nNodeType )
1204 if( xAnimate->getAttributeName() == rAttributeName )
1206 switch( eValue )
1208 case VALUE_FROM:
1209 if( xAnimate->getFrom() != rValue )
1211 xAnimate->setFrom( rValue );
1212 bChanged = true;
1214 break;
1215 case VALUE_TO:
1216 if( xAnimate->getTo() != rValue )
1218 xAnimate->setTo( rValue );
1219 bChanged = true;
1221 break;
1222 case VALUE_BY:
1223 if( xAnimate->getTo() != rValue )
1225 xAnimate->setBy( rValue );
1226 bChanged = true;
1228 break;
1229 case VALUE_FIRST:
1230 case VALUE_LAST:
1232 Sequence<Any> aValues( xAnimate->getValues() );
1233 if( !aValues.hasElements() )
1234 aValues.realloc(1);
1236 sal_Int32 nIndex = eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1;
1238 if( aValues[ nIndex ] != rValue )
1240 aValues[ nIndex ] = rValue;
1241 xAnimate->setValues( aValues );
1242 bChanged = true;
1252 catch( Exception& )
1254 OSL_FAIL("sd::CustomAnimationEffect::setProperty(), exception caught!" );
1257 return bChanged;
1260 static bool implIsColorAttribute( const OUString& rAttributeName )
1262 return rAttributeName == "FillColor" || rAttributeName == "LineColor" || rAttributeName == "CharColor";
1265 Any CustomAnimationEffect::getColor( sal_Int32 nIndex )
1267 Any aColor;
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() )
1280 continue;
1282 switch( xAnimate->getType() )
1284 case AnimationNodeType::SET:
1285 case AnimationNodeType::ANIMATE:
1286 if( !implIsColorAttribute( xAnimate->getAttributeName() ) )
1287 break;
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();
1297 else
1298 aColor = xAnimate->getTo();
1304 catch( Exception& )
1306 OSL_FAIL("sd::CustomAnimationEffect::getColor(), exception caught!" );
1309 return aColor;
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() )
1326 continue;
1328 switch( xAnimate->getType() )
1330 case AnimationNodeType::SET:
1331 case AnimationNodeType::ANIMATE:
1332 if( !implIsColorAttribute( xAnimate->getAttributeName() ) )
1333 break;
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);
1350 break;
1357 catch( Exception& )
1359 OSL_FAIL("sd::CustomAnimationEffect::setColor(), exception caught!" );
1363 Any CustomAnimationEffect::getTransformationProperty( sal_Int32 nTransformType, EValue eValue )
1365 Any aProperty;
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() )
1378 continue;
1380 if( xTransform->getTransformType() == nTransformType )
1382 switch( eValue )
1384 case VALUE_FROM: aProperty = xTransform->getFrom(); break;
1385 case VALUE_TO: aProperty = xTransform->getTo(); break;
1386 case VALUE_BY: aProperty = xTransform->getBy(); break;
1387 case VALUE_FIRST:
1388 case VALUE_LAST:
1390 Sequence<Any> aValues( xTransform->getValues() );
1391 if( aValues.hasElements() )
1392 aProperty = aValues[ eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1 ];
1394 break;
1401 catch( Exception& )
1403 OSL_FAIL("sd::CustomAnimationEffect::getTransformationProperty(), exception caught!" );
1406 return aProperty;
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() )
1424 continue;
1426 if( xTransform->getTransformType() == nTransformType )
1428 switch( eValue )
1430 case VALUE_FROM:
1431 if( xTransform->getFrom() != rValue )
1433 xTransform->setFrom( rValue );
1434 bChanged = true;
1436 break;
1437 case VALUE_TO:
1438 if( xTransform->getTo() != rValue )
1440 xTransform->setTo( rValue );
1441 bChanged = true;
1443 break;
1444 case VALUE_BY:
1445 if( xTransform->getBy() != rValue )
1447 xTransform->setBy( rValue );
1448 bChanged = true;
1450 break;
1451 case VALUE_FIRST:
1452 case VALUE_LAST:
1454 Sequence<Any> aValues( xTransform->getValues() );
1455 if( !aValues.hasElements() )
1456 aValues.realloc(1);
1458 sal_Int32 nIndex = eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1;
1459 if( aValues[nIndex] != rValue )
1461 aValues[nIndex] = rValue;
1462 xTransform->setValues( aValues );
1463 bChanged = true;
1472 catch( Exception& )
1474 OSL_FAIL("sd::CustomAnimationEffect::setTransformationProperty(), exception caught!" );
1477 return bChanged;
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 );
1490 setAudio( xAudio );
1492 catch( Exception& )
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 );
1513 catch( Exception& )
1515 OSL_FAIL("sd::findCommandNode(), exception caught!" );
1518 return xCommand;
1521 void CustomAnimationEffect::removeAudio()
1525 Reference< XAnimationNode > xChild;
1527 if( mxAudio.is() )
1529 xChild.set( mxAudio, UNO_QUERY );
1530 mxAudio.clear();
1532 else if( mnCommand == EffectCommands::STOPAUDIO )
1534 xChild.set( findCommandNode( mxNode ), UNO_QUERY );
1535 mnCommand = 0;
1538 if( xChild.is() )
1540 Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY );
1541 if( xContainer.is() )
1542 xContainer->removeChild( xChild );
1545 catch( Exception& )
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
1556 removeAudio();
1557 mxAudio = xAudio;
1558 Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY );
1559 Reference< XAnimationNode > xChild( mxAudio, UNO_QUERY );
1560 if( xContainer.is() && xChild.is() )
1561 xContainer->appendChild( xChild );
1563 catch( Exception& )
1565 OSL_FAIL("sd::CustomAnimationEffect::setAudio(), exception caught!" );
1569 void CustomAnimationEffect::setStopAudio()
1571 if( mnCommand != EffectCommands::STOPAUDIO ) try
1573 if( mxAudio.is() )
1574 removeAudio();
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;
1586 catch( Exception& )
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 );
1601 return 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() );
1610 if( pObj )
1612 SdrPage* pPage = pObj->GetPage();
1613 if( pPage )
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() );
1633 if( pObj )
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();
1653 if( pPage )
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 );
1673 create( xNode );
1676 EffectSequenceHelper::~EffectSequenceHelper()
1678 reset();
1681 void EffectSequenceHelper::reset()
1683 EffectSequence::iterator aIter( maEffects.begin() );
1684 EffectSequence::iterator aEnd( maEffects.end() );
1685 if( aIter != aEnd )
1687 CustomAnimationEffectPtr pEffect = (*aIter++);
1688 pEffect->setEffectSequence(0);
1690 maEffects.clear();
1693 Reference< XAnimationNode > EffectSequenceHelper::getRootNode()
1695 Reference< XAnimationNode > xRoot( mxSequenceRoot, UNO_QUERY );
1696 return xRoot;
1699 void EffectSequenceHelper::append( const CustomAnimationEffectPtr& pEffect )
1701 pEffect->setEffectSequence( this );
1702 maEffects.push_back(pEffect);
1703 rebuild();
1706 CustomAnimationEffectPtr EffectSequenceHelper::append( const CustomAnimationPresetPtr& pPreset, const Any& rTarget, double fDuration /* = -1.0 */ )
1708 CustomAnimationEffectPtr pEffect;
1710 if( pPreset.get() )
1712 OUString strEmpty;
1713 Reference< XAnimationNode > xNode( pPreset->create( strEmpty ) );
1714 if( xNode.is() )
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;
1723 while( nLength-- )
1725 if( p->Name != "text-only" && p->Name != "preset-property" )
1727 aNewUserData.push_back( *p );
1728 bFilter = true;
1730 p++;
1733 if( bFilter )
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;
1750 aTarget >>= xShape;
1751 if( xShape.is() )
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);
1769 rebuild();
1773 DBG_ASSERT( pEffect.get(), "sd::EffectSequenceHelper::append(), failed!" );
1774 return pEffect;
1777 CustomAnimationEffectPtr EffectSequenceHelper::append( const SdrPathObj& rPathObj, const Any& rTarget, double fDuration /* = -1.0 */ )
1779 CustomAnimationEffectPtr pEffect;
1781 if( fDuration <= 0.0 )
1782 fDuration = 2.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);
1814 rebuild();
1816 catch( Exception& )
1818 OSL_FAIL( "sd::EffectSequenceHelper::append(), exception caught!" );
1821 return pEffect;
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 ) );
1829 if( xNewNode.is() )
1831 pEffect->replaceNode( xNewNode );
1832 if( fDuration != -1.0 )
1833 pEffect->setDuration( fDuration );
1836 rebuild();
1838 catch( Exception& )
1840 OSL_FAIL( "sd::EffectSequenceHelper::replace(), exception caught!" );
1844 void EffectSequenceHelper::replace( const CustomAnimationEffectPtr& pEffect, const CustomAnimationPresetPtr& pPreset, double fDuration /* = -1.0 */ )
1846 OUString strEmpty;
1847 replace( pEffect, pPreset, strEmpty, fDuration );
1850 void EffectSequenceHelper::remove( const CustomAnimationEffectPtr& pEffect )
1852 if( pEffect.get() )
1854 pEffect->setEffectSequence( 0 );
1855 maEffects.remove( pEffect );
1858 rebuild();
1861 void EffectSequenceHelper::rebuild()
1863 implRebuild();
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() );
1892 if( aIter != aEnd )
1894 AfterEffectNodeList aAfterEffects;
1896 CustomAnimationEffectPtr pEffect = (*aIter++);
1898 bool bFirst = true;
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 );
1904 Event aEvent;
1905 if( mxEventSource.is() )
1907 aEvent.Source <<= mxEventSource;
1908 aEvent.Trigger = EventTrigger::ON_CLICK;
1910 else
1912 aEvent.Trigger = EventTrigger::ON_NEXT;
1914 aEvent.Repeat = 0;
1916 Any aBegin( makeAny( aEvent ) );
1917 if( bFirst )
1919 // if the first node is not a click action, this click container
1920 // must not have INDEFINITE begin but start at 0s
1921 bFirst = false;
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 )
1954 fDuration = fTemp;
1956 if( aIter != aEnd )
1957 pEffect = (*aIter++);
1958 else
1959 pEffect.reset();
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 );
1972 updateTextGroups();
1974 // reset duration, might have been altered (see below)
1975 mxSequenceRoot->setDuration( Any() );
1977 else
1979 // empty sequence, set duration to 0.0 explicitly
1980 // (otherwise, this sequence will never end)
1981 mxSequenceRoot->setDuration( makeAny((double)0.0) );
1984 catch( Exception& )
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 )
2001 throw(Exception)
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;
2017 return xNext.is();
2020 void stl_process_after_effect_node_func(AfterEffectNode& rNode)
2024 if( rNode.mxNode.is() && rNode.mxMaster.is() )
2026 // set master node
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 );
2043 else // nextClick
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;
2067 else
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 );
2084 Event aEvent;
2085 aEvent.Trigger = EventTrigger::ON_NEXT;
2086 aEvent.Repeat = 0;
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;
2111 if( xChild.is() )
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 );
2125 catch( Exception& )
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 )
2145 pEffect = (*aIter);
2146 break;
2150 return pEffect;
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 )
2161 return nOffset;
2164 return -1;
2167 CustomAnimationEffectPtr EffectSequenceHelper::getEffectFromOffset( sal_Int32 nOffset ) const
2169 EffectSequence::const_iterator aIter( maEffects.begin() );
2170 while( nOffset-- && aIter != maEffects.end() )
2171 ++aIter;
2173 CustomAnimationEffectPtr pEffect;
2174 if( aIter != maEffects.end() )
2175 pEffect = (*aIter);
2177 return pEffect;
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 );
2190 bChanges = true;
2191 aIter = maEffects.erase( aIter );
2193 else
2195 ++aIter;
2199 return bChanges;
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 )
2208 return true;
2209 ++aIter;
2212 return false;
2215 void EffectSequenceHelper::insertTextRange( const com::sun::star::uno::Any& aTarget )
2217 bool bChanges = false;
2219 ParagraphTarget aParaTarget;
2220 if( !(aTarget >>= aParaTarget ) )
2221 return;
2223 EffectSequence::iterator aIter( maEffects.begin() );
2224 while( aIter != maEffects.end() )
2226 if( (*aIter)->getTargetShape() == aParaTarget.Shape )
2227 bChanges |= (*aIter)->checkForText();
2228 ++aIter;
2231 if( bChanges )
2232 rebuild();
2235 void EffectSequenceHelper::disposeTextRange( const com::sun::star::uno::Any& aTarget )
2237 ParagraphTarget aParaTarget;
2238 if( !(aTarget >>= aParaTarget ) )
2239 return;
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 );
2258 bChanges = true;
2259 bErased = true;
2261 else
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();
2277 if( bErased )
2278 bErased = false;
2279 else
2280 ++aIter;
2283 if( bChanges )
2284 rebuild();
2287 CustomAnimationTextGroup::CustomAnimationTextGroup( const Reference< XShape >& rTarget, sal_Int32 nGroupId )
2288 : maTarget( rTarget ),
2289 mnGroupId( nGroupId )
2291 reset();
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;
2307 maEffects.clear();
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) )
2348 --mnTextGrouping;
2351 else
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;
2366 return aPtr;
2369 void EffectSequenceHelper::updateTextGroups()
2371 maGroupMap.clear();
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 );
2386 if( !pGroup.get() )
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 )
2407 nGroupId++;
2408 aIter = maGroupMap.begin();
2410 else
2412 ++aIter;
2416 Reference< XShape > xTarget( pEffect->getTargetShape() );
2418 CustomAnimationTextGroupPtr pTextGroup( new CustomAnimationTextGroup( xTarget, nGroupId ) );
2419 maGroupMap[nGroupId] = pTextGroup;
2421 bool bUsed = false;
2423 // do we need to target the shape?
2424 if( (nTextGrouping == 0) || bAnimateForm )
2426 sal_Int16 nSubItem;
2427 if( nTextGrouping == 0)
2428 nSubItem = bAnimateForm ? ShapeAnimationSubType::AS_WHOLE : ShapeAnimationSubType::ONLY_TEXT;
2429 else
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 );
2438 bUsed = true;
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 );
2448 notify_listeners();
2450 return pTextGroup;
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;
2470 sal_Int16 nPara;
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 );
2480 else
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;
2495 if( bUsed )
2497 // clone a new effect from first effect
2498 pNewEffect = pEffect->clone();
2499 ++aInsertIter;
2500 aInsertIter = maEffects.insert( aInsertIter, pNewEffect );
2502 else
2504 // reuse first effect if its not yet used
2505 pNewEffect = pEffect;
2506 bUsed = true;
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 );
2524 else
2526 pNewEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2527 pNewEffect->setBegin( fTextGroupingAuto );
2530 else
2532 pNewEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2533 pNewEffect->setBegin( 0.0 );
2536 pTextGroup->addEffect( pNewEffect );
2538 notify_listeners();
2540 catch( Exception& )
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 );
2560 notify_listeners();
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() )
2576 remove( pEffect );
2577 else
2578 pTextGroup->addEffect( pEffect );
2580 notify_listeners();
2582 else
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 );
2606 else
2608 pEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2609 pEffect->setBegin( fTextGroupingAuto );
2612 else
2614 pEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2615 pEffect->setBegin( 0.0 );
2619 pTextGroup->addEffect( pEffect );
2622 notify_listeners();
2626 void EffectSequenceHelper::setAnimateForm( CustomAnimationTextGroupPtr pTextGroup, bool bAnimateForm )
2628 if( pTextGroup->mbAnimateForm == bAnimateForm )
2630 // trivial case, do nothing
2632 else
2634 EffectSequence aEffects( pTextGroup->maEffects );
2635 pTextGroup->reset();
2637 SAL_WARN_IF(aEffects.empty(), "sd", "EffectSequenceHelper::setAnimateForm effects empty" );
2639 if (aEffects.empty())
2640 return;
2642 EffectSequence::iterator aIter( aEffects.begin() );
2643 const EffectSequence::iterator aEnd( aEffects.end() );
2645 // first insert if we have to
2646 if( bAnimateForm )
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 );
2658 else
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 );
2676 else
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 );
2687 else
2689 DBG_ASSERT( !bAnimateForm, "sd::EffectSequenceHelper::setAnimateForm(), something is wrong here!" );
2690 remove( pEffect );
2694 notify_listeners();
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 );
2721 else
2723 pEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2724 pEffect->setBegin( fTextGroupingAuto );
2727 else
2729 pEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2730 pEffect->setBegin( 0.0 );
2734 pTextGroup->addEffect( pEffect );
2737 notify_listeners();
2740 struct ImplStlTextGroupSortHelper
2742 ImplStlTextGroupSortHelper( bool bReverse ) : mbReverse( bReverse ) {};
2743 bool operator()( const CustomAnimationEffectPtr& p1, const CustomAnimationEffectPtr& p2 );
2744 bool mbReverse;
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;
2757 else
2759 return mbReverse ? 0x7fffffff : -1;
2763 bool ImplStlTextGroupSortHelper::operator()( const CustomAnimationEffectPtr& p1, const CustomAnimationEffectPtr& p2 )
2765 if( mbReverse )
2767 return getTargetParagraph( p2 ) < getTargetParagraph( p1 );
2769 else
2771 return getTargetParagraph( p1 ) < getTargetParagraph( p2 );
2775 void EffectSequenceHelper::setTextReverse( CustomAnimationTextGroupPtr pTextGroup, bool bTextReverse )
2777 if( pTextGroup->mbTextReverse == bTextReverse )
2779 // do nothing
2781 else
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() );
2793 if( aIter != aEnd )
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 );
2805 notify_listeners();
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 );
2846 catch( Exception& )
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 );
2867 catch( Exception& )
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() )
2887 // found an effect
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);
2899 break;
2901 // found an after effect
2902 case AnimationNodeType::SET:
2903 case AnimationNodeType::ANIMATECOLOR:
2905 processAfterEffect( xChildNode );
2907 break;
2911 catch( Exception& )
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();
2927 while( nLength-- )
2929 if ( p->Name == "master-element" )
2931 p->Value >>= xMaster;
2932 break;
2934 p++;
2937 // only process if this is a valid after effect
2938 if( xMaster.is() )
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 )
2955 // it's a dim
2956 Reference< XAnimate > xAnimate( xNode, UNO_QUERY_THROW );
2957 pMasterEffect->setDimColor( xAnimate->getTo() );
2958 pMasterEffect->setAfterEffectOnNext( true );
2960 else
2962 // it's a hide
2963 pMasterEffect->setAfterEffectOnNext( xNode->getParent() != xMaster->getParent() );
2968 catch( Exception& )
2970 OSL_FAIL( "sd::EffectSequenceHelper::processAfterEffect(), exception caught!" );
2974 class AnimationChangeListener : public cppu::WeakImplHelper1< XChangesListener >
2976 public:
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;
2981 private:
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 );
3010 init();
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 )
3021 init();
3024 MainSequence::~MainSequence()
3026 reset();
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 )
3043 reset();
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
3057 maTimer.Stop();
3058 implRebuild();
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
3100 // end)
3101 mxSequenceRoot->setDuration( makeAny((double)0.0) );
3103 Reference< XAnimationNode > xMainSequenceNode( mxSequenceRoot, UNO_QUERY_THROW );
3104 mxTimingRootNode->appendChild( xMainSequenceNode );
3107 updateTextGroups();
3109 notify_listeners();
3111 Reference< XChangesNotifier > xNotifier( mxTimingRootNode, UNO_QUERY );
3112 if( xNotifier.is() )
3113 xNotifier->addChangesListener( mxChangesListener );
3115 catch( Exception& )
3117 OSL_FAIL( "sd::MainSequence::create(), exception caught!" );
3118 return;
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 )
3130 (*aIter)->reset();
3131 maInteractiveSequenceList.clear();
3135 Reference< XChangesNotifier > xNotifier( mxTimingRootNode, UNO_QUERY );
3136 if( xNotifier.is() )
3137 xNotifier->removeChangesListener( mxChangesListener );
3139 catch( Exception& )
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 );
3165 return 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 );
3180 return pEffect;
3183 sal_Int32 MainSequence::getOffsetFromEffect( const CustomAnimationEffectPtr& pEffect ) const
3185 sal_Int32 nOffset = EffectSequenceHelper::getOffsetFromEffect( pEffect );
3187 if( nOffset != -1 )
3188 return nOffset;
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 );
3196 if( nTemp != -1 )
3197 return nOffset + nTemp;
3199 nOffset += (*aIter)->getCount();
3202 return -1;
3205 CustomAnimationEffectPtr MainSequence::getEffectFromOffset( sal_Int32 nOffset ) const
3207 if( nOffset >= 0 )
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;
3224 return 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 );
3237 if( bChanges )
3238 startRebuildTimer();
3240 return bChanges;
3243 bool MainSequence::hasEffect( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape )
3245 if( EffectSequenceHelper::hasEffect( xShape ) )
3246 return true;
3248 InteractiveSequenceList::iterator aIter;
3249 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); )
3251 if( (*aIter)->getTriggerShape() == xShape )
3252 return true;
3254 if( (*aIter++)->hasEffect( xShape ) )
3255 return true;
3258 return false;
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();
3306 if( bChanges )
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;
3338 return;
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 );
3360 else
3362 pIS->implRebuild();
3363 ++aIter;
3367 notify_listeners();
3368 mbRebuilding = false;
3371 void MainSequence::notify_change()
3373 notify_listeners();
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();
3391 break;
3395 if( !pNewSequence )
3396 pNewSequence = createInteractiveSequence( xTriggerShape ).get();
3398 else
3400 pNewSequence = this;
3403 if( pOldSequence != pNewSequence )
3405 if( pOldSequence )
3406 pOldSequence->maEffects.remove( pEffect );
3407 if( pNewSequence )
3408 pNewSequence->maEffects.push_back( pEffect );
3409 pEffect->setEffectSequence( pNewSequence );
3410 return true;
3412 else
3414 return false;
3419 IMPL_LINK_NOARG_TYPED(MainSequence, onTimerHdl, Timer *, void)
3421 if( mbTimerMode )
3423 implRebuild();
3425 else
3427 reset();
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;
3438 maTimer.Start();
3442 /** starts a timer that rebuilds the API core from the internal structure after 1 second */
3443 void MainSequence::startRebuildTimer()
3445 mbTimerMode = true;
3446 maTimer.Start();
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 );
3464 Event aEvent;
3465 if( (xChildNode->getBegin() >>= aEvent) && (aEvent.Trigger == EventTrigger::ON_CLICK) )
3466 aEvent.Source >>= mxEventSource;
3470 catch( Exception& )
3472 OSL_FAIL( "sd::InteractiveSequence::InteractiveSequence(), exception caught!" );
3473 return;
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: */