xref: /trunk/main/sd/source/core/CustomAnimationEffect.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956) !
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sd.hxx"
26 #include <tools/debug.hxx>
27 #include <com/sun/star/util/XCloneable.hpp>
28 #include <com/sun/star/animations/AnimationFill.hpp>
29 #include <com/sun/star/container/XEnumerationAccess.hpp>
30 #include <com/sun/star/presentation/EffectNodeType.hpp>
31 #include <com/sun/star/presentation/EffectCommands.hpp>
32 #include <com/sun/star/presentation/EffectPresetClass.hpp>
33 #include <com/sun/star/presentation/ParagraphTarget.hpp>
34 #include <com/sun/star/lang/XInitialization.hpp>
35 #include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
36 #include <com/sun/star/animations/AnimationNodeType.hpp>
37 #include <com/sun/star/animations/XCommand.hpp>
38 #include <com/sun/star/animations/AnimationTransformType.hpp>
39 #include <com/sun/star/animations/XIterateContainer.hpp>
40 #include <com/sun/star/animations/XAnimateTransform.hpp>
41 #include <com/sun/star/animations/Event.hpp>
42 #include <com/sun/star/animations/EventTrigger.hpp>
43 #include <com/sun/star/animations/Timing.hpp>
44 #include <com/sun/star/drawing/XDrawPage.hpp>
45 #include <com/sun/star/text/XText.hpp>
46 #include <com/sun/star/animations/XAnimate.hpp>
47 #include <com/sun/star/beans/NamedValue.hpp>
48 #include <com/sun/star/beans/XPropertySet.hpp>
49 #include <com/sun/star/util/XChangesNotifier.hpp>
50 #include <com/sun/star/animations/XAnimateMotion.hpp>
51 #include <comphelper/processfactory.hxx>
52 #include <comphelper/sequence.hxx>
53 #include <com/sun/star/lang/Locale.hpp>
54 #include <com/sun/star/i18n/XBreakIterator.hpp>
55 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
56 #ifndef _COM_SUN_STAR_TEXT_WORDTYPE_HPP_
57 #include <com/sun/star/i18n/WordType.hpp>
58 #endif
59 #include <com/sun/star/presentation/TextAnimationType.hpp>
60 
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>
66 
67 #include <algorithm>
68 
69 #include <cppuhelper/implbase1.hxx>
70 
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"
79 
80 using namespace ::com::sun::star;
81 using namespace ::com::sun::star::presentation;
82 using namespace ::com::sun::star::animations;
83 
84 using ::rtl::OUString;
85 using ::com::sun::star::uno::Reference;
86 using ::com::sun::star::uno::Sequence;
87 using ::com::sun::star::uno::XInterface;
88 using ::com::sun::star::uno::UNO_QUERY;
89 using ::com::sun::star::uno::UNO_QUERY_THROW;
90 using ::com::sun::star::uno::Any;
91 using ::com::sun::star::uno::makeAny;
92 using ::com::sun::star::uno::Exception;
93 using ::com::sun::star::uno::RuntimeException;
94 using ::com::sun::star::container::XEnumerationAccess;
95 using ::com::sun::star::container::XEnumeration;
96 using ::com::sun::star::beans::NamedValue;
97 using ::com::sun::star::container::XChild;
98 using ::com::sun::star::container::XElementAccess;
99 using ::com::sun::star::drawing::XShape;
100 using ::com::sun::star::lang::XInitialization;
101 using ::com::sun::star::drawing::XShapes;
102 using ::com::sun::star::drawing::XDrawPage;
103 using ::com::sun::star::text::XText;
104 using ::com::sun::star::text::XTextRange;
105 using ::com::sun::star::beans::XPropertySet;
106 using ::com::sun::star::lang::XMultiServiceFactory;
107 using ::com::sun::star::util::XCloneable;
108 using ::com::sun::star::lang::Locale;
109 using ::com::sun::star::util::XChangesNotifier;
110 using ::com::sun::star::util::XChangesListener;
111 
112 namespace sd
113 {
114 class MainSequenceChangeGuard
115 {
116 public:
MainSequenceChangeGuard(EffectSequenceHelper * pSequence)117     MainSequenceChangeGuard( EffectSequenceHelper* pSequence )
118     {
119         mpMainSequence = dynamic_cast< MainSequence* >( pSequence );
120         if( mpMainSequence == 0 )
121         {
122             InteractiveSequence* pI = dynamic_cast< InteractiveSequence* >( pSequence );
123             if( pI )
124                 mpMainSequence = pI->mpMainSequence;
125         }
126         DBG_ASSERT( mpMainSequence, "sd::MainSequenceChangeGuard::MainSequenceChangeGuard(), no main sequence to guard!" );
127 
128         if( mpMainSequence )
129             mpMainSequence->mbIgnoreChanges++;
130     }
131 
~MainSequenceChangeGuard()132     ~MainSequenceChangeGuard()
133     {
134         if( mpMainSequence )
135             mpMainSequence->mbIgnoreChanges++;
136     }
137 
138 private:
139     MainSequence* mpMainSequence;
140 };
141 
CustomAnimationEffect(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode)142 CustomAnimationEffect::CustomAnimationEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
143 :   mnNodeType(-1),
144     mnPresetClass(-1),
145     mfBegin(-1.0),
146     mfDuration(-1.0),
147     mfAbsoluteDuration(-1.0),
148     mnGroupId(-1),
149     mnIterateType(0),
150     mfIterateInterval(0.0),
151     mnParaDepth( -1 ),
152     mbHasText(sal_False),
153     mfAcceleration( 1.0 ),
154     mfDecelerate( 1.0 ),
155     mbAutoReverse(false),
156     mnTargetSubItem(0),
157     mnCommand(0),
158     mpEffectSequence( 0 ),
159     mbHasAfterEffect(false),
160     mbAfterEffectOnNextEffect(false)
161 {
162     setNode( xNode );
163 }
164 
165 // --------------------------------------------------------------------
166 
setNode(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode)167 void CustomAnimationEffect::setNode( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
168 {
169     mxNode = xNode;
170     mxAudio.clear();
171 
172     Sequence< NamedValue > aUserData( mxNode->getUserData() );
173     sal_Int32 nLength = aUserData.getLength();
174     const NamedValue* p = aUserData.getConstArray();
175 
176     while( nLength-- )
177     {
178         if( p->Name.equalsAscii( "node-type" ) )
179         {
180             p->Value >>= mnNodeType;
181         }
182         else if( p->Name.equalsAscii( "preset-id" ) )
183         {
184             p->Value >>= maPresetId;
185         }
186         else if( p->Name.equalsAscii( "preset-sub-type" ) )
187         {
188             p->Value >>= maPresetSubType;
189         }
190         else if( p->Name.equalsAscii( "preset-class" ) )
191         {
192             p->Value >>= mnPresetClass;
193         }
194         else if( p->Name.equalsAscii( "preset-property" ) )
195         {
196             p->Value >>= maProperty;
197         }
198         else if( p->Name.equalsAscii( "group-id" ) )
199         {
200             p->Value >>= mnGroupId;
201         }
202 
203         p++;
204     }
205 
206     // get effect start time
207     mxNode->getBegin() >>= mfBegin;
208 
209     mfAcceleration = mxNode->getAcceleration();
210     mfDecelerate = mxNode->getDecelerate();
211     mbAutoReverse = mxNode->getAutoReverse();
212 
213     // get iteration data
214     Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
215     if( xIter.is() )
216     {
217         mfIterateInterval = xIter->getIterateInterval();
218         mnIterateType = xIter->getIterateType();
219         maTarget = xIter->getTarget();
220         mnTargetSubItem = xIter->getSubItem();
221     }
222     else
223     {
224         mfIterateInterval = 0.0f;
225         mnIterateType = 0;
226     }
227 
228     // calculate effect duration and get target shape
229     Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
230     if( xEnumerationAccess.is() )
231     {
232         Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
233         if( xEnumeration.is() )
234         {
235             while( xEnumeration->hasMoreElements() )
236             {
237                 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
238                 if( !xChildNode.is() )
239                     continue;
240 
241                 if( xChildNode->getType() == AnimationNodeType::AUDIO )
242                 {
243                     mxAudio.set( xChildNode, UNO_QUERY );
244                 }
245                 else if( xChildNode->getType() == AnimationNodeType::COMMAND )
246                 {
247                     Reference< XCommand > xCommand( xChildNode, UNO_QUERY );
248                     if( xCommand.is() )
249                     {
250                         mnCommand = xCommand->getCommand();
251                         if( !maTarget.hasValue() )
252                             maTarget = xCommand->getTarget();
253                     }
254                 }
255                 else
256                 {
257                     double fBegin = 0.0;
258                     double fDuration = 0.0;
259                     xChildNode->getBegin() >>= fBegin;
260                     xChildNode->getDuration() >>= fDuration;
261 
262                     fDuration += fBegin;
263                     if( fDuration > mfDuration )
264                         mfDuration = fDuration;
265 
266                     // no target shape yet?
267                     if( !maTarget.hasValue() )
268                     {
269                         // go get it boys!
270                         Reference< XAnimate > xAnimate( xChildNode, UNO_QUERY );
271                         if( xAnimate.is() )
272                         {
273                             maTarget = xAnimate->getTarget();
274                             mnTargetSubItem = xAnimate->getSubItem();
275                         }
276                     }
277                 }
278             }
279         }
280     }
281 
282     mfAbsoluteDuration = mfDuration;
283     checkForText();
284 }
285 
286 // --------------------------------------------------------------------
287 
getNumberOfSubitems(const Any & aTarget,sal_Int16 nIterateType)288 sal_Int32 CustomAnimationEffect::getNumberOfSubitems( const Any& aTarget, sal_Int16 nIterateType )
289 {
290     sal_Int32 nSubItems = 0;
291 
292     try
293     {
294         // first get target text
295         sal_Int32 nOnlyPara = -1;
296 
297         Reference< XText > xShape;
298         aTarget >>= xShape;
299         if( !xShape.is() )
300         {
301             ParagraphTarget aParaTarget;
302             if( aTarget >>= aParaTarget )
303             {
304                 xShape.set( aParaTarget.Shape, UNO_QUERY );
305                 nOnlyPara = aParaTarget.Paragraph;
306             }
307         }
308 
309         // now use the break iterator to iterate over the given text
310         // and count the sub items
311 
312         if( xShape.is() )
313         {
314             // TODO/LATER: Optimize this, don't create a break iterator each time
315             Reference< lang::XMultiServiceFactory > xMSF( ::comphelper::getProcessServiceFactory() );
316             Reference < i18n::XBreakIterator > xBI( xMSF->createInstance( OUString::createFromAscii( "com.sun.star.i18n.BreakIterator" ) ), UNO_QUERY );
317             DBG_ASSERT( xBI.is(), "sd::CustomAnimationEffect::getNumberOfSubitems(), could not create a 'com.sun.star.i18n.BreakIterator'!" );
318 
319             if( xBI.is() )
320             {
321                 Reference< XEnumerationAccess > xEA( xShape, UNO_QUERY_THROW );
322                 Reference< XEnumeration > xEnumeration( xEA->createEnumeration(), UNO_QUERY_THROW );
323                 Locale aLocale;
324                 const OUString aStrLocaleName( RTL_CONSTASCII_USTRINGPARAM("CharLocale") );
325                 Reference< XTextRange > xParagraph;
326 
327                 sal_Int32 nPara = 0;
328                 while( xEnumeration->hasMoreElements() )
329                 {
330                     xEnumeration->nextElement() >>= xParagraph;
331 
332                     // skip this if its not the only paragraph we want to count
333                     if( (nOnlyPara != -1) && (nOnlyPara != nPara ) )
334                         continue;
335 
336                     if( nIterateType == TextAnimationType::BY_PARAGRAPH )
337                     {
338                         nSubItems++;
339                     }
340                     else
341                     {
342                         const OUString aText( xParagraph->getString() );
343                         Reference< XPropertySet > xSet( xParagraph, UNO_QUERY_THROW );
344                         xSet->getPropertyValue( aStrLocaleName ) >>= aLocale;
345 
346                         sal_Int32 nPos;
347                         const sal_Int32 nEndPos = aText.getLength();
348 
349                         if( nIterateType == TextAnimationType::BY_WORD )
350                         {
351                             for( nPos = 0; nPos < nEndPos; nPos++ )
352                             {
353                                 nPos = xBI->getWordBoundary(aText, nPos, aLocale, i18n::WordType::ANY_WORD, sal_True).endPos;
354                                 nSubItems++;
355                             }
356                             break;
357                         }
358                         else
359                         {
360                             sal_Int32 nDone;
361                             for( nPos = 0; nPos < nEndPos; nPos++ )
362                             {
363                                 nPos = xBI->nextCharacters(aText, nPos, aLocale, i18n::CharacterIteratorMode::SKIPCELL, 0, nDone);
364                                 nSubItems++;
365                             }
366                         }
367                     }
368 
369                     if( nPara == nOnlyPara )
370                         break;
371 
372                     nPara++;
373                 }
374             }
375         }
376     }
377     catch( Exception& e )
378     {
379         (void)e;
380         nSubItems = 0;
381         DBG_ERROR( "sd::CustomAnimationEffect::getNumberOfSubitems(), exception caught!" );
382     }
383 
384     return nSubItems;
385 }
386 
387 // --------------------------------------------------------------------
388 
~CustomAnimationEffect()389 CustomAnimationEffect::~CustomAnimationEffect()
390 {
391 }
392 
393 // --------------------------------------------------------------------
394 
clone() const395 CustomAnimationEffectPtr CustomAnimationEffect::clone() const
396 {
397     Reference< XCloneable > xCloneable( mxNode, UNO_QUERY_THROW );
398     Reference< XAnimationNode > xNode( xCloneable->createClone(), UNO_QUERY_THROW );
399     CustomAnimationEffectPtr pEffect( new CustomAnimationEffect( xNode ) );
400     pEffect->setEffectSequence( getEffectSequence() );
401     return pEffect;
402 }
403 
404 // --------------------------------------------------------------------
405 
get_node_type(const Reference<XAnimationNode> & xNode)406 sal_Int32 CustomAnimationEffect::get_node_type( const Reference< XAnimationNode >& xNode )
407 {
408     sal_Int16 nNodeType = -1;
409 
410     if( xNode.is() )
411     {
412         Sequence< NamedValue > aUserData( xNode->getUserData() );
413         sal_Int32 nLength = aUserData.getLength();
414         if( nLength )
415         {
416             const NamedValue* p = aUserData.getConstArray();
417             while( nLength-- )
418             {
419                 if( p->Name.equalsAscii( "node-type" ) )
420                 {
421                     p->Value >>= nNodeType;
422                     break;
423                 }
424                 p++;
425             }
426         }
427     }
428 
429     return nNodeType;
430 }
431 
432 // --------------------------------------------------------------------
433 
setPresetClass(sal_Int16 nPresetClass)434 void CustomAnimationEffect::setPresetClass( sal_Int16 nPresetClass )
435 {
436     if( mnPresetClass != nPresetClass )
437     {
438         mnPresetClass = nPresetClass;
439         if( mxNode.is() )
440         {
441             // first try to find a "preset-class" entry in the user data
442             // and change it
443             Sequence< NamedValue > aUserData( mxNode->getUserData() );
444             sal_Int32 nLength = aUserData.getLength();
445             bool bFound = false;
446             if( nLength )
447             {
448                 NamedValue* p = aUserData.getArray();
449                 while( nLength-- )
450                 {
451                     if( p->Name.equalsAscii( "preset-class" ) )
452                     {
453                         p->Value <<= mnPresetClass;
454                         bFound = true;
455                         break;
456                     }
457                     p++;
458                 }
459             }
460 
461             // no "node-type" entry inside user data, so add it
462             if( !bFound )
463             {
464                 nLength = aUserData.getLength();
465                 aUserData.realloc( nLength + 1);
466                 aUserData[nLength].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "preset-class" ) );
467                 aUserData[nLength].Value <<= mnPresetClass;
468             }
469 
470             mxNode->setUserData( aUserData );
471         }
472     }
473 }
474 
setNodeType(sal_Int16 nNodeType)475 void CustomAnimationEffect::setNodeType( sal_Int16 nNodeType )
476 {
477     if( mnNodeType != nNodeType )
478     {
479         mnNodeType = nNodeType;
480         if( mxNode.is() )
481         {
482             // first try to find a "node-type" entry in the user data
483             // and change it
484             Sequence< NamedValue > aUserData( mxNode->getUserData() );
485             sal_Int32 nLength = aUserData.getLength();
486             bool bFound = false;
487             if( nLength )
488             {
489                 NamedValue* p = aUserData.getArray();
490                 while( nLength-- )
491                 {
492                     if( p->Name.equalsAscii( "node-type" ) )
493                     {
494                         p->Value <<= mnNodeType;
495                         bFound = true;
496                         break;
497                     }
498                     p++;
499                 }
500             }
501 
502             // no "node-type" entry inside user data, so add it
503             if( !bFound )
504             {
505                 nLength = aUserData.getLength();
506                 aUserData.realloc( nLength + 1);
507                 aUserData[nLength].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
508                 aUserData[nLength].Value <<= mnNodeType;
509             }
510 
511             mxNode->setUserData( aUserData );
512         }
513     }
514 }
515 
516 // --------------------------------------------------------------------
517 
setGroupId(sal_Int32 nGroupId)518 void CustomAnimationEffect::setGroupId( sal_Int32 nGroupId )
519 {
520     mnGroupId = nGroupId;
521     if( mxNode.is() )
522     {
523         // first try to find a "group-id" entry in the user data
524         // and change it
525         Sequence< NamedValue > aUserData( mxNode->getUserData() );
526         sal_Int32 nLength = aUserData.getLength();
527         bool bFound = false;
528         if( nLength )
529         {
530             NamedValue* p = aUserData.getArray();
531             while( nLength-- )
532             {
533                 if( p->Name.equalsAscii( "group-id" ) )
534                 {
535                     p->Value <<= mnGroupId;
536                     bFound = true;
537                     break;
538                 }
539                 p++;
540             }
541         }
542 
543         // no "node-type" entry inside user data, so add it
544         if( !bFound )
545         {
546             nLength = aUserData.getLength();
547             aUserData.realloc( nLength + 1);
548             aUserData[nLength].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "group-id" ) );
549             aUserData[nLength].Value <<= mnGroupId;
550         }
551 
552         mxNode->setUserData( aUserData );
553     }
554 }
555 
556 // --------------------------------------------------------------------
557 
558 /** checks if the text for this effect has changed and updates internal flags.
559     returns true if something changed.
560 */
checkForText()561 bool CustomAnimationEffect::checkForText()
562 {
563     bool bChange = false;
564 
565     Reference< XText > xText;
566 
567     if( maTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
568     {
569         // calc para depth
570         ParagraphTarget aParaTarget;
571         maTarget >>= aParaTarget;
572 
573         xText = Reference< XText >::query( aParaTarget.Shape );
574 
575         // get paragraph
576         if( xText.is() )
577         {
578             Reference< XEnumerationAccess > xEA( xText, UNO_QUERY );
579             if( xEA.is() )
580             {
581                 Reference< XEnumeration > xEnumeration( xEA->createEnumeration(), UNO_QUERY );
582                 if( xEnumeration.is() )
583                 {
584                     sal_Bool bHasText = xEnumeration->hasMoreElements();
585                     bChange |= bHasText != mbHasText;
586                     mbHasText = bHasText;
587 
588                     sal_Int32 nPara = aParaTarget.Paragraph;
589 
590                     while( xEnumeration->hasMoreElements() && nPara-- )
591                         xEnumeration->nextElement();
592 
593                     if( xEnumeration->hasMoreElements() )
594                     {
595                         Reference< XPropertySet > xParaSet;
596                         xEnumeration->nextElement() >>= xParaSet;
597                         if( xParaSet.is() )
598                         {
599                             sal_Int32 nParaDepth = 0;
600                             const OUString strNumberingLevel( RTL_CONSTASCII_USTRINGPARAM("NumberingLevel") );
601                             xParaSet->getPropertyValue( strNumberingLevel ) >>= nParaDepth;
602                             bChange |= nParaDepth != mnParaDepth;
603                             mnParaDepth = nParaDepth;
604                         }
605                     }
606                 }
607             }
608         }
609     }
610     else
611     {
612         maTarget >>= xText;
613         sal_Bool bHasText = xText.is() && xText->getString().getLength();
614         bChange |= bHasText != mbHasText;
615         mbHasText = bHasText;
616     }
617 
618     bChange |= calculateIterateDuration();
619     return bChange;
620 }
621 
calculateIterateDuration()622 bool CustomAnimationEffect::calculateIterateDuration()
623 {
624     bool bChange = false;
625 
626     // if we have an iteration, we must also calculate the
627     // 'true' container duration, that is
628     // ( ( is form animated ) ? [contained effects duration] : 0 ) +
629     // ( [number of animated children] - 1 ) * [interval-delay] + [contained effects duration]
630     Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
631     if( xIter.is() )
632     {
633         double fDuration = mfDuration;
634         const double fSubEffectDuration = mfDuration;
635 
636         if( mnTargetSubItem != ShapeAnimationSubType::ONLY_BACKGROUND ) // does not make sense for iterate container but better check
637         {
638             const sal_Int32 nSubItems = getNumberOfSubitems( maTarget, mnIterateType );
639             if( nSubItems )
640             {
641                 const double f = (nSubItems-1) * mfIterateInterval;
642                 fDuration += f;
643             }
644         }
645 
646         // if we also animate the form first, we have to add the
647         // sub effect duration to the whole effect duration
648         if( mnTargetSubItem == ShapeAnimationSubType::AS_WHOLE )
649             fDuration += fSubEffectDuration;
650 
651         bChange |= fDuration != mfAbsoluteDuration;
652         mfAbsoluteDuration = fDuration;
653     }
654 
655     return bChange;
656 }
657 
658 // --------------------------------------------------------------------
659 
setTarget(const::com::sun::star::uno::Any & rTarget)660 void CustomAnimationEffect::setTarget( const ::com::sun::star::uno::Any& rTarget )
661 {
662     try
663     {
664         maTarget = rTarget;
665 
666         // first, check special case for random node
667         Reference< XInitialization > xInit( mxNode, UNO_QUERY );
668         if( xInit.is() )
669         {
670             const Sequence< Any > aArgs( &maTarget, 1 );
671             xInit->initialize( aArgs );
672         }
673         else
674         {
675             Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
676             if( xIter.is() )
677             {
678                 xIter->setTarget(maTarget);
679             }
680             else
681             {
682                 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
683                 if( xEnumerationAccess.is() )
684                 {
685                     Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
686                     if( xEnumeration.is() )
687                     {
688                         while( xEnumeration->hasMoreElements() )
689                         {
690                             const Any aElem( xEnumeration->nextElement() );
691                             Reference< XAnimate > xAnimate( aElem, UNO_QUERY );
692                             if( xAnimate.is() )
693                                 xAnimate->setTarget( rTarget );
694                             else
695                             {
696                                 Reference< XCommand > xCommand( aElem, UNO_QUERY );
697                                 if( xCommand.is() )
698                                     xCommand->setTarget( rTarget );
699                             }
700                         }
701                     }
702                 }
703             }
704         }
705         checkForText();
706     }
707     catch( Exception& )
708     {
709         DBG_ERROR( "sd::CustomAnimationEffect::setTarget(), exception caught!" );
710     }
711 }
712 
713 // --------------------------------------------------------------------
714 
setTargetSubItem(sal_Int16 nSubItem)715 void CustomAnimationEffect::setTargetSubItem( sal_Int16 nSubItem )
716 {
717     try
718     {
719         mnTargetSubItem = nSubItem;
720 
721         Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
722         if( xIter.is() )
723         {
724             xIter->setSubItem(mnTargetSubItem);
725         }
726         else
727         {
728             Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
729             if( xEnumerationAccess.is() )
730             {
731                 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
732                 if( xEnumeration.is() )
733                 {
734                     while( xEnumeration->hasMoreElements() )
735                     {
736                         Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
737                         if( xAnimate.is() )
738                             xAnimate->setSubItem( mnTargetSubItem );
739                     }
740                 }
741             }
742         }
743     }
744     catch( Exception& )
745     {
746         DBG_ERROR( "sd::CustomAnimationEffect::setTargetSubItem(), exception caught!" );
747     }
748 }
749 
750 // --------------------------------------------------------------------
751 
setDuration(double fDuration)752 void CustomAnimationEffect::setDuration( double fDuration )
753 {
754     if( (mfDuration != -1.0) && (mfDuration != fDuration) ) try
755     {
756         double fScale = fDuration / mfDuration;
757         mfDuration = fDuration;
758         mfAbsoluteDuration = mfDuration;
759 
760         // calculate effect duration and get target shape
761         Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
762         if( xEnumerationAccess.is() )
763         {
764             Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
765             if( xEnumeration.is() )
766             {
767                 while( xEnumeration->hasMoreElements() )
768                 {
769                     Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
770                     if( !xChildNode.is() )
771                         continue;
772 
773 
774                     double fChildBegin = 0.0;
775                     xChildNode->getBegin() >>= fChildBegin;
776                     if(  fChildBegin != 0.0 )
777                     {
778                         fChildBegin *= fScale;
779                         xChildNode->setBegin( makeAny( fChildBegin ) );
780                     }
781 
782                     double fChildDuration = 0.0;
783                     xChildNode->getDuration() >>= fChildDuration;
784                     if( fChildDuration != 0.0 )
785                     {
786                         fChildDuration *= fScale;
787                         xChildNode->setDuration( makeAny( fChildDuration ) );
788                     }
789                 }
790             }
791         }
792         calculateIterateDuration();
793     }
794     catch( Exception& )
795     {
796         DBG_ERROR( "sd::CustomAnimationEffect::setDuration(), exception caught!" );
797     }
798 }
799 
800 // --------------------------------------------------------------------
801 
setBegin(double fBegin)802 void CustomAnimationEffect::setBegin( double fBegin )
803 {
804     if( mxNode.is() ) try
805     {
806         mfBegin = fBegin;
807         mxNode->setBegin( makeAny( fBegin ) );
808     }
809     catch( Exception& )
810     {
811         DBG_ERROR( "sd::CustomAnimationEffect::setBegin(), exception caught!" );
812     }
813 }
814 
815 // --------------------------------------------------------------------
816 
setAcceleration(double fAcceleration)817 void CustomAnimationEffect::setAcceleration( double fAcceleration )
818 {
819     if( mxNode.is() ) try
820     {
821         mfAcceleration = fAcceleration;
822         mxNode->setAcceleration( fAcceleration );
823     }
824     catch( Exception& )
825     {
826         DBG_ERROR( "sd::CustomAnimationEffect::setAcceleration(), exception caught!" );
827     }
828 }
829 // --------------------------------------------------------------------
830 
setDecelerate(double fDecelerate)831 void CustomAnimationEffect::setDecelerate( double fDecelerate )
832 {
833     if( mxNode.is() ) try
834     {
835         mfDecelerate = fDecelerate;
836         mxNode->setDecelerate( fDecelerate );
837     }
838     catch( Exception& )
839     {
840         DBG_ERROR( "sd::CustomAnimationEffect::setDecelerate(), exception caught!" );
841     }
842 }
843 
844 // --------------------------------------------------------------------
845 
setAutoReverse(sal_Bool bAutoReverse)846 void CustomAnimationEffect::setAutoReverse( sal_Bool bAutoReverse )
847 {
848     if( mxNode.is() ) try
849     {
850         mbAutoReverse = bAutoReverse;
851         mxNode->setAutoReverse( bAutoReverse );
852     }
853     catch( Exception& )
854     {
855         DBG_ERROR( "sd::CustomAnimationEffect::setAutoReverse(), exception caught!" );
856     }
857 }
858 
859 // --------------------------------------------------------------------
860 
replaceNode(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode)861 void CustomAnimationEffect::replaceNode( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
862 {
863     sal_Int16 nNodeType = mnNodeType;
864     Any aTarget = maTarget;
865 
866     double fBegin = mfBegin;
867     double fDuration = mfDuration;
868     double fAcceleration = mfAcceleration;
869     double fDecelerate = mfDecelerate ;
870     sal_Bool bAutoReverse = mbAutoReverse;
871     Reference< XAudio > xAudio( mxAudio );
872     sal_Int16 nIterateType = mnIterateType;
873     double fIterateInterval = mfIterateInterval;
874     sal_Int16 nSubItem = mnTargetSubItem;
875 
876     setNode( xNode );
877 
878     setAudio( xAudio );
879     setNodeType( nNodeType );
880     setTarget( aTarget );
881     setTargetSubItem( nSubItem );
882     setDuration( fDuration );
883     setBegin( fBegin );
884 
885     setAcceleration( fAcceleration );
886     setDecelerate( fDecelerate );
887     setAutoReverse( bAutoReverse );
888 
889     if( nIterateType != mnIterateType )
890         setIterateType( nIterateType );
891 
892     if( mnIterateType && ( fIterateInterval != mfIterateInterval ) )
893         setIterateInterval( fIterateInterval );
894 }
895 
896 // --------------------------------------------------------------------
897 
getTargetShape() const898 Reference< XShape > CustomAnimationEffect::getTargetShape() const
899 {
900     Reference< XShape > xShape;
901     maTarget >>= xShape;
902     if( !xShape.is() )
903     {
904         ParagraphTarget aParaTarget;
905         if( maTarget >>= aParaTarget )
906             xShape = aParaTarget.Shape;
907     }
908 
909     return xShape;
910 }
911 
912 // --------------------------------------------------------------------
913 
getRepeatCount() const914 Any CustomAnimationEffect::getRepeatCount() const
915 {
916     if( mxNode.is() )
917     {
918         return mxNode->getRepeatCount();
919     }
920     else
921     {
922         Any aAny;
923         return aAny;
924     }
925 }
926 
927 // --------------------------------------------------------------------
928 
getEnd() const929 Any CustomAnimationEffect::getEnd() const
930 {
931     if( mxNode.is() )
932     {
933         return mxNode->getEnd();
934     }
935     else
936     {
937         Any aAny;
938         return aAny;
939     }
940 }
941 
942 // --------------------------------------------------------------------
943 
getFill() const944 sal_Int16 CustomAnimationEffect::getFill() const
945 {
946     if( mxNode.is() )
947         return mxNode->getFill();
948     else
949         return 0;
950 }
951 
952 // --------------------------------------------------------------------
953 
setRepeatCount(const Any & rRepeatCount)954 void CustomAnimationEffect::setRepeatCount( const Any& rRepeatCount )
955 {
956     if( mxNode.is() )
957         mxNode->setRepeatCount( rRepeatCount );
958 }
959 
960 // --------------------------------------------------------------------
961 
setEnd(const Any & rEnd)962 void CustomAnimationEffect::setEnd( const Any& rEnd )
963 {
964     if( mxNode.is() )
965         mxNode->setEnd( rEnd );
966 }
967 
968 // --------------------------------------------------------------------
969 
setFill(sal_Int16 nFill)970 void CustomAnimationEffect::setFill( sal_Int16 nFill )
971 {
972     if( mxNode.is() )
973         mxNode->setFill( nFill );
974 }
975 
976 // --------------------------------------------------------------------
977 
createAfterEffectNode() const978 Reference< XAnimationNode > CustomAnimationEffect::createAfterEffectNode() const
979 {
980     DBG_ASSERT( mbHasAfterEffect, "sd::CustomAnimationEffect::createAfterEffectNode(), this node has no after effect!" );
981 
982     Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() );
983 
984     const char* pServiceName = maDimColor.hasValue() ?
985         "com.sun.star.animations.AnimateColor" : "com.sun.star.animations.AnimateSet";
986 
987     Reference< XAnimate > xAnimate( xMsf->createInstance(OUString::createFromAscii(pServiceName) ), UNO_QUERY_THROW );
988 
989     Any aTo;
990     OUString aAttributeName;
991 
992     if( maDimColor.hasValue() )
993     {
994         aTo = maDimColor;
995         aAttributeName = OUString( RTL_CONSTASCII_USTRINGPARAM( "DimColor" ) );
996     }
997     else
998     {
999         aTo = makeAny( (sal_Bool)sal_False );
1000         aAttributeName = OUString( RTL_CONSTASCII_USTRINGPARAM( "Visibility" ) );
1001     }
1002 
1003     Any aBegin;
1004     if( !mbAfterEffectOnNextEffect ) // sameClick
1005     {
1006         Event aEvent;
1007 
1008         aEvent.Source <<= getNode();
1009         aEvent.Trigger = EventTrigger::END_EVENT;
1010         aEvent.Repeat = 0;
1011 
1012         aBegin <<= aEvent;
1013     }
1014     else
1015     {
1016         aBegin <<= (double)0.0;
1017     }
1018 
1019     xAnimate->setBegin( aBegin );
1020     xAnimate->setTo( aTo );
1021     xAnimate->setAttributeName( aAttributeName );
1022 
1023     xAnimate->setDuration( makeAny( (double)0.001 ) );
1024     xAnimate->setFill( AnimationFill::HOLD );
1025     xAnimate->setTarget( maTarget );
1026 
1027     return Reference< XAnimationNode >( xAnimate, UNO_QUERY_THROW );
1028 }
1029 
1030 // --------------------------------------------------------------------
1031 
setIterateType(sal_Int16 nIterateType)1032 void CustomAnimationEffect::setIterateType( sal_Int16 nIterateType )
1033 {
1034     if( mnIterateType != nIterateType ) try
1035     {
1036         // do we need to exchange the container node?
1037         if( (mnIterateType == 0) || (nIterateType == 0) )
1038         {
1039             sal_Int16 nTargetSubItem = mnTargetSubItem;
1040 
1041             Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() );
1042             const char * pServiceName =
1043                 nIterateType ? "com.sun.star.animations.IterateContainer" : "com.sun.star.animations.ParallelTimeContainer";
1044             Reference< XTimeContainer > xNewContainer(
1045                 xMsf->createInstance( OUString::createFromAscii(pServiceName) ), UNO_QUERY_THROW );
1046 
1047             Reference< XTimeContainer > xOldContainer( mxNode, UNO_QUERY_THROW );
1048             Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW );
1049             Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1050             while( xEnumeration->hasMoreElements() )
1051             {
1052                 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
1053                 xOldContainer->removeChild( xChildNode );
1054                 xNewContainer->appendChild( xChildNode );
1055             }
1056 
1057             Reference< XAnimationNode > xNewNode( xNewContainer, UNO_QUERY_THROW );
1058 
1059             xNewNode->setBegin( mxNode->getBegin() );
1060             xNewNode->setDuration( mxNode->getDuration() );
1061             xNewNode->setEnd( mxNode->getEnd() );
1062             xNewNode->setEndSync( mxNode->getEndSync() );
1063             xNewNode->setRepeatCount( mxNode->getRepeatCount() );
1064             xNewNode->setFill( mxNode->getFill() );
1065             xNewNode->setFillDefault( mxNode->getFillDefault() );
1066             xNewNode->setRestart( mxNode->getRestart() );
1067             xNewNode->setRestartDefault( mxNode->getRestartDefault() );
1068             xNewNode->setAcceleration( mxNode->getAcceleration() );
1069             xNewNode->setDecelerate( mxNode->getDecelerate() );
1070             xNewNode->setAutoReverse( mxNode->getAutoReverse() );
1071             xNewNode->setRepeatDuration( mxNode->getRepeatDuration() );
1072             xNewNode->setEndSync( mxNode->getEndSync() );
1073             xNewNode->setRepeatCount( mxNode->getRepeatCount() );
1074             xNewNode->setUserData( mxNode->getUserData() );
1075 
1076             mxNode = xNewNode;
1077 
1078             Any aTarget;
1079             if( nIterateType )
1080             {
1081                 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY_THROW );
1082                 xIter->setTarget(maTarget);
1083                 xIter->setSubItem( nTargetSubItem );
1084             }
1085             else
1086             {
1087                 aTarget = maTarget;
1088             }
1089 
1090             Reference< XEnumerationAccess > xEA( mxNode, UNO_QUERY_THROW );
1091             Reference< XEnumeration > xE( xEA->createEnumeration(), UNO_QUERY_THROW );
1092             while( xE->hasMoreElements() )
1093             {
1094                 Reference< XAnimate > xAnimate( xE->nextElement(), UNO_QUERY );
1095                 if( xAnimate.is() )
1096                 {
1097                     xAnimate->setTarget( aTarget );
1098                     xAnimate->setSubItem( nTargetSubItem );
1099                 }
1100             }
1101         }
1102 
1103         mnIterateType = nIterateType;
1104 
1105         // if we have an iteration container, we must set its type
1106         if( mnIterateType )
1107         {
1108             Reference< XIterateContainer > xIter( mxNode, UNO_QUERY_THROW );
1109             xIter->setIterateType( nIterateType );
1110         }
1111 
1112         checkForText();
1113     }
1114     catch( Exception& e )
1115     {
1116         (void)e;
1117         DBG_ERROR( "sd::CustomAnimationEffect::setIterateType(), Exception caught!" );
1118     }
1119 }
1120 
1121 // --------------------------------------------------------------------
1122 
setIterateInterval(double fIterateInterval)1123 void CustomAnimationEffect::setIterateInterval( double fIterateInterval )
1124 {
1125     if( mfIterateInterval != fIterateInterval )
1126     {
1127         Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
1128 
1129         DBG_ASSERT( xIter.is(), "sd::CustomAnimationEffect::setIterateInterval(), not an iteration node" );
1130         if( xIter.is() )
1131         {
1132             mfIterateInterval = fIterateInterval;
1133             xIter->setIterateInterval( fIterateInterval );
1134         }
1135 
1136         calculateIterateDuration();
1137     }
1138 }
1139 
1140 // --------------------------------------------------------------------
1141 
getPath() const1142 ::rtl::OUString CustomAnimationEffect::getPath() const
1143 {
1144     ::rtl::OUString aPath;
1145 
1146     if( mxNode.is() ) try
1147     {
1148         Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW );
1149         Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1150         while( xEnumeration->hasMoreElements() )
1151         {
1152             Reference< XAnimateMotion > xMotion( xEnumeration->nextElement(), UNO_QUERY );
1153             if( xMotion.is() )
1154             {
1155                 xMotion->getPath() >>= aPath;
1156                 break;
1157             }
1158         }
1159     }
1160     catch( Exception& e )
1161     {
1162         (void)e;
1163         DBG_ERROR("sd::CustomAnimationEffect::getPath(), exception caught!" );
1164     }
1165 
1166     return aPath;
1167 }
1168 
1169 // --------------------------------------------------------------------
1170 
setPath(const::rtl::OUString & rPath)1171 void CustomAnimationEffect::setPath( const ::rtl::OUString& rPath )
1172 {
1173     if( mxNode.is() ) try
1174     {
1175         Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW );
1176         Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1177         while( xEnumeration->hasMoreElements() )
1178         {
1179             Reference< XAnimateMotion > xMotion( xEnumeration->nextElement(), UNO_QUERY );
1180             if( xMotion.is() )
1181             {
1182 
1183                 MainSequenceChangeGuard aGuard( mpEffectSequence );
1184                 xMotion->setPath( Any( rPath ) );
1185                 break;
1186             }
1187         }
1188     }
1189     catch( Exception& e )
1190     {
1191         (void)e;
1192         DBG_ERROR("sd::CustomAnimationEffect::setPath(), exception caught!" );
1193     }
1194 }
1195 
1196 // --------------------------------------------------------------------
1197 
getProperty(sal_Int32 nNodeType,const OUString & rAttributeName,EValue eValue)1198 Any CustomAnimationEffect::getProperty( sal_Int32 nNodeType, const OUString& rAttributeName, EValue eValue )
1199 {
1200     Any aProperty;
1201     if( mxNode.is() ) try
1202     {
1203         Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1204         if( xEnumerationAccess.is() )
1205         {
1206             Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1207             if( xEnumeration.is() )
1208             {
1209                 while( xEnumeration->hasMoreElements() && !aProperty.hasValue() )
1210                 {
1211                     Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1212                     if( !xAnimate.is() )
1213                         continue;
1214 
1215                     if( xAnimate->getType() == nNodeType )
1216                     {
1217                         if( xAnimate->getAttributeName() == rAttributeName )
1218                         {
1219                             switch( eValue )
1220                             {
1221                             case VALUE_FROM: aProperty = xAnimate->getFrom(); break;
1222                             case VALUE_TO:   aProperty = xAnimate->getTo(); break;
1223                             case VALUE_BY:   aProperty = xAnimate->getBy(); break;
1224                             case VALUE_FIRST:
1225                             case VALUE_LAST:
1226                                 {
1227                                     Sequence<Any> aValues( xAnimate->getValues() );
1228                                     if( aValues.hasElements() )
1229                                         aProperty =  aValues[ eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1 ];
1230                                 }
1231                                 break;
1232                             }
1233                         }
1234                     }
1235                 }
1236             }
1237         }
1238     }
1239     catch( Exception& e )
1240     {
1241         (void)e;
1242         DBG_ERROR("sd::CustomAnimationEffect::getProperty(), exception caught!" );
1243     }
1244 
1245     return aProperty;
1246 }
1247 
1248 // --------------------------------------------------------------------
1249 
setProperty(sal_Int32 nNodeType,const OUString & rAttributeName,EValue eValue,const Any & rValue)1250 bool CustomAnimationEffect::setProperty( sal_Int32 nNodeType, const OUString& rAttributeName, EValue eValue, const Any& rValue )
1251 {
1252     bool bChanged = false;
1253     if( mxNode.is() ) try
1254     {
1255         Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1256         if( xEnumerationAccess.is() )
1257         {
1258             Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1259             if( xEnumeration.is() )
1260             {
1261                 while( xEnumeration->hasMoreElements() )
1262                 {
1263                     Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1264                     if( !xAnimate.is() )
1265                         continue;
1266 
1267                     if( xAnimate->getType() == nNodeType )
1268                     {
1269                         if( xAnimate->getAttributeName() == rAttributeName )
1270                         {
1271                             switch( eValue )
1272                             {
1273                             case VALUE_FROM:
1274                                 if( xAnimate->getFrom() != rValue )
1275                                 {
1276                                     xAnimate->setFrom( rValue );
1277                                     bChanged = true;
1278                                 }
1279                                 break;
1280                             case VALUE_TO:
1281                                 if( xAnimate->getTo() != rValue )
1282                                 {
1283                                     xAnimate->setTo( rValue );
1284                                     bChanged = true;
1285                                 }
1286                                 break;
1287                             case VALUE_BY:
1288                                 if( xAnimate->getTo() != rValue )
1289                                 {
1290                                     xAnimate->setBy( rValue );
1291                                     bChanged = true;
1292                                 }
1293                                 break;
1294                             case VALUE_FIRST:
1295                             case VALUE_LAST:
1296                                 {
1297                                     Sequence<Any> aValues( xAnimate->getValues() );
1298                                     if( !aValues.hasElements() )
1299                                         aValues.realloc(1);
1300 
1301                                     sal_Int32 nIndex = eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1;
1302 
1303                                     if( aValues[ nIndex ] != rValue )
1304                                     {
1305                                         aValues[ nIndex ] = rValue;
1306                                         xAnimate->setValues( aValues );
1307                                         bChanged = true;
1308                                     }
1309                                 }
1310                             }
1311                         }
1312                     }
1313                 }
1314             }
1315         }
1316     }
1317     catch( Exception& e )
1318     {
1319         (void)e;
1320         DBG_ERROR("sd::CustomAnimationEffect::setProperty(), exception caught!" );
1321     }
1322 
1323     return bChanged;
1324 }
1325 
1326 // --------------------------------------------------------------------
1327 
implIsColorAttribute(const OUString & rAttributeName)1328 static bool implIsColorAttribute( const OUString& rAttributeName )
1329 {
1330     return rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("FillColor") ) ||
1331            rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("LineColor") ) ||
1332            rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("CharColor") );
1333 }
1334 
1335 // --------------------------------------------------------------------
1336 
getColor(sal_Int32 nIndex)1337 Any CustomAnimationEffect::getColor( sal_Int32 nIndex )
1338 {
1339     Any aColor;
1340     if( mxNode.is() ) try
1341     {
1342         Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1343         if( xEnumerationAccess.is() )
1344         {
1345             Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1346             if( xEnumeration.is() )
1347             {
1348                 while( xEnumeration->hasMoreElements() && !aColor.hasValue() )
1349                 {
1350                     Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1351                     if( !xAnimate.is() )
1352                         continue;
1353 
1354                     switch( xAnimate->getType() )
1355                     {
1356                     case AnimationNodeType::SET:
1357                     case AnimationNodeType::ANIMATE:
1358                         if( !implIsColorAttribute( xAnimate->getAttributeName() ) )
1359                             break;
1360                     case AnimationNodeType::ANIMATECOLOR:
1361                         Sequence<Any> aValues( xAnimate->getValues() );
1362                         if( aValues.hasElements() )
1363                         {
1364                             if( aValues.getLength() > nIndex )
1365                                 aColor = aValues[nIndex];
1366                         }
1367                         else if( nIndex == 0 )
1368                             aColor = xAnimate->getFrom();
1369                         else
1370                             aColor = xAnimate->getTo();
1371                     }
1372                 }
1373             }
1374         }
1375     }
1376     catch( Exception& e )
1377     {
1378         (void)e;
1379         DBG_ERROR("sd::CustomAnimationEffect::getColor(), exception caught!" );
1380     }
1381 
1382     return aColor;
1383 }
1384 
1385 // --------------------------------------------------------------------
1386 
setColor(sal_Int32 nIndex,const Any & rColor)1387 void CustomAnimationEffect::setColor( sal_Int32 nIndex, const Any& rColor )
1388 {
1389     if( mxNode.is() ) try
1390     {
1391         Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1392         if( xEnumerationAccess.is() )
1393         {
1394             Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1395             if( xEnumeration.is() )
1396             {
1397                 while( xEnumeration->hasMoreElements() )
1398                 {
1399                     Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1400                     if( !xAnimate.is() )
1401                         continue;
1402 
1403                     switch( xAnimate->getType() )
1404                     {
1405                     case AnimationNodeType::SET:
1406                     case AnimationNodeType::ANIMATE:
1407                         if( !implIsColorAttribute( xAnimate->getAttributeName() ) )
1408                             break;
1409                     case AnimationNodeType::ANIMATECOLOR:
1410                     {
1411                         Sequence<Any> aValues( xAnimate->getValues() );
1412                         if( aValues.hasElements() )
1413                         {
1414                             if( aValues.getLength() > nIndex )
1415                             {
1416                                 aValues[nIndex] = rColor;
1417                                 xAnimate->setValues( aValues );
1418                             }
1419                         }
1420                         else if( (nIndex == 0) && xAnimate->getFrom().hasValue() )
1421                             xAnimate->setFrom(rColor);
1422                         else if( (nIndex == 1) && xAnimate->getTo().hasValue() )
1423                             xAnimate->setTo(rColor);
1424                     }
1425                     break;
1426 
1427                     }
1428                 }
1429             }
1430         }
1431     }
1432     catch( Exception& e )
1433     {
1434         (void)e;
1435         DBG_ERROR("sd::CustomAnimationEffect::setColor(), exception caught!" );
1436     }
1437 }
1438 
1439 // --------------------------------------------------------------------
1440 
getTransformationProperty(sal_Int32 nTransformType,EValue eValue)1441 Any CustomAnimationEffect::getTransformationProperty( sal_Int32 nTransformType, EValue eValue )
1442 {
1443     Any aProperty;
1444     if( mxNode.is() ) try
1445     {
1446         Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1447         if( xEnumerationAccess.is() )
1448         {
1449             Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1450             if( xEnumeration.is() )
1451             {
1452                 while( xEnumeration->hasMoreElements() && !aProperty.hasValue() )
1453                 {
1454                     Reference< XAnimateTransform > xTransform( xEnumeration->nextElement(), UNO_QUERY );
1455                     if( !xTransform.is() )
1456                         continue;
1457 
1458                     if( xTransform->getTransformType() == nTransformType )
1459                     {
1460                         switch( eValue )
1461                         {
1462                         case VALUE_FROM: aProperty = xTransform->getFrom(); break;
1463                         case VALUE_TO:   aProperty = xTransform->getTo(); break;
1464                         case VALUE_BY:   aProperty = xTransform->getBy(); break;
1465                         case VALUE_FIRST:
1466                         case VALUE_LAST:
1467                             {
1468                                 Sequence<Any> aValues( xTransform->getValues() );
1469                                 if( aValues.hasElements() )
1470                                     aProperty =  aValues[ eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1 ];
1471                             }
1472                             break;
1473                         }
1474                     }
1475                 }
1476             }
1477         }
1478     }
1479     catch( Exception& e )
1480     {
1481         (void)e;
1482         DBG_ERROR("sd::CustomAnimationEffect::getTransformationProperty(), exception caught!" );
1483     }
1484 
1485     return aProperty;
1486 }
1487 
1488 // --------------------------------------------------------------------
1489 
setTransformationProperty(sal_Int32 nTransformType,EValue eValue,const Any & rValue)1490 bool CustomAnimationEffect::setTransformationProperty( sal_Int32 nTransformType, EValue eValue, const Any& rValue )
1491 {
1492     bool bChanged = false;
1493     if( mxNode.is() ) try
1494     {
1495         Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1496         if( xEnumerationAccess.is() )
1497         {
1498             Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1499             if( xEnumeration.is() )
1500             {
1501                 while( xEnumeration->hasMoreElements() )
1502                 {
1503                     Reference< XAnimateTransform > xTransform( xEnumeration->nextElement(), UNO_QUERY );
1504                     if( !xTransform.is() )
1505                         continue;
1506 
1507                     if( xTransform->getTransformType() == nTransformType )
1508                     {
1509                         switch( eValue )
1510                         {
1511                         case VALUE_FROM:
1512                             if( xTransform->getFrom() != rValue )
1513                             {
1514                                 xTransform->setFrom( rValue );
1515                                 bChanged = true;
1516                             }
1517                             break;
1518                         case VALUE_TO:
1519                             if( xTransform->getTo() != rValue )
1520                             {
1521                                 xTransform->setTo( rValue );
1522                                 bChanged = true;
1523                             }
1524                             break;
1525                         case VALUE_BY:
1526                             if( xTransform->getBy() != rValue )
1527                             {
1528                                 xTransform->setBy( rValue );
1529                                 bChanged = true;
1530                             }
1531                             break;
1532                         case VALUE_FIRST:
1533                         case VALUE_LAST:
1534                             {
1535                                 Sequence<Any> aValues( xTransform->getValues() );
1536                                 if( !aValues.hasElements() )
1537                                     aValues.realloc(1);
1538 
1539                                 sal_Int32 nIndex = eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1;
1540                                 if( aValues[nIndex] != rValue )
1541                                 {
1542                                     aValues[nIndex] = rValue;
1543                                     xTransform->setValues( aValues );
1544                                     bChanged = true;
1545                                 }
1546                             }
1547                         }
1548                     }
1549                 }
1550             }
1551         }
1552     }
1553     catch( Exception& e )
1554     {
1555         (void)e;
1556         DBG_ERROR("sd::CustomAnimationEffect::setTransformationProperty(), exception caught!" );
1557     }
1558 
1559     return bChanged;
1560 }
1561 
1562 // --------------------------------------------------------------------
1563 
createAudio(const::com::sun::star::uno::Any & rSource,double fVolume)1564 void CustomAnimationEffect::createAudio( const ::com::sun::star::uno::Any& rSource, double fVolume /* = 1.0 */ )
1565 {
1566     DBG_ASSERT( !mxAudio.is(), "sd::CustomAnimationEffect::createAudio(), node already has an audio!" );
1567 
1568     if( !mxAudio.is() ) try
1569     {
1570         Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() );
1571         Reference< XAudio > xAudio( xMsf->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.Audio") ) ), UNO_QUERY_THROW );
1572         xAudio->setSource( rSource );
1573         xAudio->setVolume( fVolume );
1574         setAudio( xAudio );
1575     }
1576     catch( Exception& e )
1577     {
1578         (void)e;
1579         DBG_ERROR("sd::CustomAnimationEffect::createAudio(), exception caught!" );
1580     }
1581 }
1582 
1583 // --------------------------------------------------------------------
1584 
findCommandNode(const Reference<XAnimationNode> & xRootNode)1585 static Reference< XCommand > findCommandNode( const Reference< XAnimationNode >& xRootNode )
1586 {
1587     Reference< XCommand > xCommand;
1588 
1589     if( xRootNode.is() ) try
1590     {
1591         Reference< XEnumerationAccess > xEnumerationAccess( xRootNode, UNO_QUERY_THROW );
1592         Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1593         while( !xCommand.is() && xEnumeration->hasMoreElements() )
1594         {
1595             Reference< XAnimationNode > xNode( xEnumeration->nextElement(), UNO_QUERY );
1596             if( xNode.is() && (xNode->getType() == AnimationNodeType::COMMAND) )
1597                 xCommand.set( xNode, UNO_QUERY_THROW );
1598         }
1599     }
1600     catch( Exception& e )
1601     {
1602         (void)e;
1603         DBG_ERROR("sd::findCommandNode(), exception caught!" );
1604     }
1605 
1606     return xCommand;
1607 }
1608 
removeAudio()1609 void CustomAnimationEffect::removeAudio()
1610 {
1611     try
1612     {
1613         Reference< XAnimationNode > xChild;
1614 
1615         if( mxAudio.is() )
1616         {
1617             xChild.set( mxAudio, UNO_QUERY );
1618             mxAudio.clear();
1619         }
1620         else if( mnCommand == EffectCommands::STOPAUDIO )
1621         {
1622             xChild.set( findCommandNode( mxNode ), UNO_QUERY );
1623             mnCommand = 0;
1624         }
1625 
1626         if( xChild.is() )
1627         {
1628             Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY );
1629             if( xContainer.is() )
1630                 xContainer->removeChild( xChild );
1631         }
1632     }
1633     catch( Exception& e )
1634     {
1635         (void)e;
1636         DBG_ERROR("sd::CustomAnimationEffect::removeAudio(), exception caught!" );
1637     }
1638 
1639 }
1640 
1641 // --------------------------------------------------------------------
1642 
setAudio(const Reference<::com::sun::star::animations::XAudio> & xAudio)1643 void CustomAnimationEffect::setAudio( const Reference< ::com::sun::star::animations::XAudio >& xAudio )
1644 {
1645     if( mxAudio != xAudio ) try
1646     {
1647         removeAudio();
1648         mxAudio = xAudio;
1649         Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY );
1650         Reference< XAnimationNode > xChild( mxAudio, UNO_QUERY );
1651         if( xContainer.is() && xChild.is() )
1652             xContainer->appendChild( xChild );
1653     }
1654     catch( Exception& e )
1655     {
1656         (void)e;
1657         DBG_ERROR("sd::CustomAnimationEffect::setAudio(), exception caught!" );
1658     }
1659 }
1660 
1661 // --------------------------------------------------------------------
1662 
setStopAudio()1663 void CustomAnimationEffect::setStopAudio()
1664 {
1665     if( mnCommand != EffectCommands::STOPAUDIO ) try
1666     {
1667         if( mxAudio.is() )
1668             removeAudio();
1669 
1670         Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() );
1671         Reference< XCommand > xCommand( xMsf->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.Command") ) ), UNO_QUERY_THROW );
1672 
1673         xCommand->setCommand( EffectCommands::STOPAUDIO );
1674 
1675         Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY_THROW );
1676         Reference< XAnimationNode > xChild( xCommand, UNO_QUERY_THROW );
1677         xContainer->appendChild( xChild );
1678 
1679         mnCommand = EffectCommands::STOPAUDIO;
1680     }
1681     catch( Exception& e )
1682     {
1683         (void)e;
1684         DBG_ERROR("sd::CustomAnimationEffect::setStopAudio(), exception caught!" );
1685     }
1686 }
1687 
1688 // --------------------------------------------------------------------
1689 
getStopAudio() const1690 bool CustomAnimationEffect::getStopAudio() const
1691 {
1692     return mnCommand == EffectCommands::STOPAUDIO;
1693 }
1694 
1695 // --------------------------------------------------------------------
1696 
createSdrPathObjFromPath()1697 SdrPathObj* CustomAnimationEffect::createSdrPathObjFromPath()
1698 {
1699     SdrPathObj * pPathObj = new SdrPathObj( OBJ_PATHLINE );
1700     updateSdrPathObjFromPath( *pPathObj );
1701     return pPathObj;
1702 }
1703 
1704 // --------------------------------------------------------------------
1705 
updateSdrPathObjFromPath(SdrPathObj & rPathObj)1706 void CustomAnimationEffect::updateSdrPathObjFromPath( SdrPathObj& rPathObj )
1707 {
1708     ::basegfx::B2DPolyPolygon xPolyPoly;
1709     if( ::basegfx::tools::importFromSvgD( xPolyPoly, getPath(), true, 0 ) )
1710     {
1711         SdrObject* pObj = GetSdrObjectFromXShape( getTargetShape() );
1712         if( pObj )
1713         {
1714             SdrPage* pPage = pObj->GetPage();
1715             if( pPage )
1716             {
1717                 const Size aPageSize( pPage->GetSize() );
1718                 xPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix((double)aPageSize.Width(), (double)aPageSize.Height()));
1719             }
1720 
1721             const Rectangle aBoundRect( pObj->GetCurrentBoundRect() );
1722             const Point aCenter( aBoundRect.Center() );
1723             xPolyPoly.transform(basegfx::tools::createTranslateB2DHomMatrix(aCenter.X(), aCenter.Y()));
1724         }
1725     }
1726 
1727     rPathObj.SetPathPoly( xPolyPoly );
1728 }
1729 
1730 // --------------------------------------------------------------------
1731 
updatePathFromSdrPathObj(const SdrPathObj & rPathObj)1732 void CustomAnimationEffect::updatePathFromSdrPathObj( const SdrPathObj& rPathObj )
1733 {
1734     ::basegfx::B2DPolyPolygon xPolyPoly( rPathObj.GetPathPoly() );
1735 
1736     SdrObject* pObj = GetSdrObjectFromXShape( getTargetShape() );
1737     if( pObj )
1738     {
1739         Rectangle aBoundRect(0,0,0,0);
1740 
1741         const drawinglayer::primitive2d::Primitive2DSequence xPrimitives(pObj->GetViewContact().getViewIndependentPrimitive2DSequence());
1742         const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
1743         const basegfx::B2DRange aRange(drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(xPrimitives, aViewInformation2D));
1744 
1745         if(!aRange.isEmpty())
1746         {
1747             aBoundRect = Rectangle(
1748                     (sal_Int32)floor(aRange.getMinX()), (sal_Int32)floor(aRange.getMinY()),
1749                     (sal_Int32)ceil(aRange.getMaxX()), (sal_Int32)ceil(aRange.getMaxY()));
1750         }
1751 
1752         const Point aCenter( aBoundRect.Center() );
1753 
1754         xPolyPoly.transform(basegfx::tools::createTranslateB2DHomMatrix(-aCenter.X(), -aCenter.Y()));
1755 
1756         SdrPage* pPage = pObj->GetPage();
1757         if( pPage )
1758         {
1759             const Size aPageSize( pPage->GetSize() );
1760             xPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(
1761                 1.0 / (double)aPageSize.Width(), 1.0 / (double)aPageSize.Height()));
1762         }
1763     }
1764 
1765     setPath( ::basegfx::tools::exportToSvgD( xPolyPoly, true, true, true) );
1766 }
1767 
1768 // ====================================================================
1769 
EffectSequenceHelper()1770 EffectSequenceHelper::EffectSequenceHelper()
1771 : mnSequenceType( EffectNodeType::DEFAULT )
1772 {
1773 }
1774 
1775 // --------------------------------------------------------------------
1776 
EffectSequenceHelper(const::com::sun::star::uno::Reference<::com::sun::star::animations::XTimeContainer> & xSequenceRoot)1777 EffectSequenceHelper::EffectSequenceHelper( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XTimeContainer >& xSequenceRoot )
1778 : mxSequenceRoot( xSequenceRoot ), mnSequenceType( EffectNodeType::DEFAULT )
1779 {
1780     Reference< XAnimationNode > xNode( mxSequenceRoot, UNO_QUERY_THROW );
1781     create( xNode );
1782 }
1783 
1784 // --------------------------------------------------------------------
1785 
~EffectSequenceHelper()1786 EffectSequenceHelper::~EffectSequenceHelper()
1787 {
1788     reset();
1789 }
1790 
1791 // --------------------------------------------------------------------
1792 
reset()1793 void EffectSequenceHelper::reset()
1794 {
1795     EffectSequence::iterator aIter( maEffects.begin() );
1796     EffectSequence::iterator aEnd( maEffects.end() );
1797     if( aIter != aEnd )
1798     {
1799         CustomAnimationEffectPtr pEffect = (*aIter++);
1800         pEffect->setEffectSequence(0);
1801     }
1802     maEffects.clear();
1803 }
1804 
getRootNode()1805 Reference< XAnimationNode > EffectSequenceHelper::getRootNode()
1806 {
1807     Reference< XAnimationNode > xRoot( mxSequenceRoot, UNO_QUERY );
1808     return xRoot;
1809 }
1810 
1811 // --------------------------------------------------------------------
1812 
append(const CustomAnimationEffectPtr & pEffect)1813 void EffectSequenceHelper::append( const CustomAnimationEffectPtr& pEffect )
1814 {
1815     pEffect->setEffectSequence( this );
1816     maEffects.push_back(pEffect);
1817     rebuild();
1818 }
1819 
1820 // --------------------------------------------------------------------
1821 
append(const CustomAnimationPresetPtr & pPreset,const Any & rTarget,double fDuration)1822 CustomAnimationEffectPtr EffectSequenceHelper::append( const CustomAnimationPresetPtr& pPreset, const Any& rTarget, double fDuration /* = -1.0 */ )
1823 {
1824     CustomAnimationEffectPtr pEffect;
1825 
1826     if( pPreset.get() )
1827     {
1828         OUString strEmpty;
1829         Reference< XAnimationNode > xNode( pPreset->create( strEmpty ) );
1830         if( xNode.is() )
1831         {
1832             // first, filter all only ui relevant user data
1833             std::vector< NamedValue > aNewUserData;
1834             Sequence< NamedValue > aUserData( xNode->getUserData() );
1835             sal_Int32 nLength = aUserData.getLength();
1836             const NamedValue* p = aUserData.getConstArray();
1837             bool bFilter = false;
1838 
1839             while( nLength-- )
1840             {
1841                 if( !p->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "text-only" ) ) &&
1842                     !p->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "preset-property" ) ) )
1843                 {
1844                     aNewUserData.push_back( *p );
1845                     bFilter = true;
1846                 }
1847                 p++;
1848             }
1849 
1850             if( bFilter )
1851             {
1852                 aUserData = ::comphelper::containerToSequence< NamedValue, std::vector< NamedValue > >( aNewUserData );
1853                 xNode->setUserData( aUserData );
1854             }
1855 
1856             // check target, maybe we need to force it to text
1857             Any aTarget( rTarget );
1858             sal_Int16 nSubItem = ShapeAnimationSubType::AS_WHOLE;
1859 
1860             if( aTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
1861             {
1862                 nSubItem = ShapeAnimationSubType::ONLY_TEXT;
1863             }
1864             else if( pPreset->isTextOnly() )
1865             {
1866                 Reference< XShape > xShape;
1867                 aTarget >>= xShape;
1868                 if( xShape.is() )
1869                 {
1870                     // that's bad, we target a shape here but the effect is only for text
1871                     // so change subitem
1872                     nSubItem = ShapeAnimationSubType::ONLY_TEXT;
1873                 }
1874             }
1875 
1876             // now create effect from preset
1877             pEffect.reset( new CustomAnimationEffect( xNode ) );
1878             pEffect->setEffectSequence( this );
1879             pEffect->setTarget( aTarget );
1880             pEffect->setTargetSubItem( nSubItem );
1881             if( fDuration != -1.0 )
1882                 pEffect->setDuration( fDuration );
1883 
1884             maEffects.push_back(pEffect);
1885 
1886             rebuild();
1887         }
1888     }
1889 
1890     DBG_ASSERT( pEffect.get(), "sd::EffectSequenceHelper::append(), failed!" );
1891     return pEffect;
1892 }
1893 
1894 // --------------------------------------------------------------------
1895 
append(const SdrPathObj & rPathObj,const Any & rTarget,double fDuration)1896 CustomAnimationEffectPtr EffectSequenceHelper::append( const SdrPathObj& rPathObj, const Any& rTarget, double fDuration /* = -1.0 */ )
1897 {
1898     CustomAnimationEffectPtr pEffect;
1899 
1900     if( fDuration <= 0.0 )
1901         fDuration = 2.0;
1902 
1903     try
1904     {
1905         Reference< XTimeContainer > xEffectContainer( createParallelTimeContainer() );
1906         const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.animations.AnimateMotion" ) );
1907         Reference< XAnimationNode > xAnimateMotion( ::comphelper::getProcessServiceFactory()->createInstance(aServiceName), UNO_QUERY_THROW );
1908 
1909         xAnimateMotion->setDuration( Any( fDuration ) );
1910         xAnimateMotion->setFill( AnimationFill::HOLD );
1911         xEffectContainer->appendChild( xAnimateMotion );
1912 
1913         sal_Int16 nSubItem = ShapeAnimationSubType::AS_WHOLE;
1914 
1915         if( rTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
1916             nSubItem = ShapeAnimationSubType::ONLY_TEXT;
1917 
1918         Reference< XAnimationNode > xEffectNode( xEffectContainer, UNO_QUERY_THROW );
1919         pEffect.reset( new CustomAnimationEffect( xEffectNode ) );
1920         pEffect->setEffectSequence( this );
1921         pEffect->setTarget( rTarget );
1922         pEffect->setTargetSubItem( nSubItem );
1923         pEffect->setNodeType( ::com::sun::star::presentation::EffectNodeType::ON_CLICK );
1924         pEffect->setPresetClass( ::com::sun::star::presentation::EffectPresetClass::MOTIONPATH );
1925         pEffect->setAcceleration( 0.5 );
1926         pEffect->setDecelerate( 0.5 );
1927         pEffect->setFill( AnimationFill::HOLD );
1928         pEffect->setBegin( 0.0 );
1929         pEffect->updatePathFromSdrPathObj( rPathObj );
1930         if( fDuration != -1.0 )
1931             pEffect->setDuration( fDuration );
1932 
1933         maEffects.push_back(pEffect);
1934 
1935         rebuild();
1936     }
1937     catch( Exception& )
1938     {
1939         DBG_ERROR( "sd::EffectSequenceHelper::append(), exception caught!" );
1940     }
1941 
1942     return pEffect;
1943 }
1944 
1945 // --------------------------------------------------------------------
1946 
replace(const CustomAnimationEffectPtr & pEffect,const CustomAnimationPresetPtr & pPreset,const OUString & rPresetSubType,double fDuration)1947 void EffectSequenceHelper::replace( const CustomAnimationEffectPtr& pEffect, const CustomAnimationPresetPtr& pPreset, const OUString& rPresetSubType, double fDuration /* = -1.0 */ )
1948 {
1949     if( pEffect.get() && pPreset.get() ) try
1950     {
1951         Reference< XAnimationNode > xNewNode( pPreset->create( rPresetSubType ) );
1952         if( xNewNode.is() )
1953         {
1954             pEffect->replaceNode( xNewNode );
1955             if( fDuration != -1.0 )
1956                 pEffect->setDuration( fDuration );
1957         }
1958 
1959         rebuild();
1960     }
1961     catch( Exception& e )
1962     {
1963         (void)e;
1964         DBG_ERROR( "sd::EffectSequenceHelper::replace(), exception caught!" );
1965     }
1966 }
1967 
1968 // --------------------------------------------------------------------
1969 
replace(const CustomAnimationEffectPtr & pEffect,const CustomAnimationPresetPtr & pPreset,double fDuration)1970 void EffectSequenceHelper::replace( const CustomAnimationEffectPtr& pEffect, const CustomAnimationPresetPtr& pPreset, double fDuration /* = -1.0 */ )
1971 {
1972     OUString strEmpty;
1973     replace( pEffect, pPreset, strEmpty, fDuration );
1974 }
1975 
1976 // --------------------------------------------------------------------
1977 
remove(const CustomAnimationEffectPtr & pEffect)1978 void EffectSequenceHelper::remove( const CustomAnimationEffectPtr& pEffect )
1979 {
1980     if( pEffect.get() )
1981     {
1982         pEffect->setEffectSequence( 0 );
1983         maEffects.remove( pEffect );
1984     }
1985 
1986     rebuild();
1987 }
1988 
1989 // --------------------------------------------------------------------
1990 
rebuild()1991 void EffectSequenceHelper::rebuild()
1992 {
1993     implRebuild();
1994 }
1995 
1996 // --------------------------------------------------------------------
1997 
implRebuild()1998 void EffectSequenceHelper::implRebuild()
1999 {
2000     try
2001     {
2002         // first we delete all time containers on the first two levels
2003         Reference< XEnumerationAccess > xEnumerationAccess( mxSequenceRoot, UNO_QUERY_THROW );
2004         Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
2005         while( xEnumeration->hasMoreElements() )
2006         {
2007             Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
2008             Reference< XTimeContainer > xChildContainer( xChildNode, UNO_QUERY_THROW );
2009 
2010             Reference< XEnumerationAccess > xChildEnumerationAccess( xChildNode, UNO_QUERY_THROW );
2011             Reference< XEnumeration > xChildEnumeration( xChildEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
2012             while( xChildEnumeration->hasMoreElements() )
2013             {
2014                 Reference< XAnimationNode > xNode( xChildEnumeration->nextElement(), UNO_QUERY_THROW );
2015                 xChildContainer->removeChild( xNode );
2016             }
2017 
2018             mxSequenceRoot->removeChild( xChildNode );
2019         }
2020 
2021         // second, rebuild main sequence
2022         EffectSequence::iterator aIter( maEffects.begin() );
2023         EffectSequence::iterator aEnd( maEffects.end() );
2024         if( aIter != aEnd )
2025         {
2026             AfterEffectNodeList aAfterEffects;
2027 
2028             CustomAnimationEffectPtr pEffect = (*aIter++);
2029 
2030             bool bFirst = true;
2031             do
2032             {
2033                 // create a par container for the next click node and all following with and after effects
2034                 Reference< XTimeContainer > xOnClickContainer( createParallelTimeContainer() );
2035 
2036                 Event aEvent;
2037                 if( mxEventSource.is() )
2038                 {
2039                     aEvent.Source <<= mxEventSource;
2040                     aEvent.Trigger = EventTrigger::ON_CLICK;
2041                 }
2042                 else
2043                 {
2044                     aEvent.Trigger = EventTrigger::ON_NEXT;
2045                 }
2046                 aEvent.Repeat = 0;
2047 
2048                 Any aBegin( makeAny( aEvent ) );
2049                 if( bFirst )
2050                 {
2051                     // if the first node is not a click action, this click container
2052                     // must not have INDEFINITE begin but start at 0s
2053                     bFirst = false;
2054                     if( pEffect->getNodeType() != EffectNodeType::ON_CLICK )
2055                         aBegin <<= (double)0.0;
2056                 }
2057 
2058                 xOnClickContainer->setBegin( aBegin );
2059 
2060                 Reference< XAnimationNode > xOnClickContainerNode( xOnClickContainer, UNO_QUERY_THROW );
2061                 mxSequenceRoot->appendChild( xOnClickContainerNode );
2062 
2063                 double fBegin = 0.0;
2064 
2065                 do
2066                 {
2067                     // create a par container for the current click or after effect node and all following with effects
2068                     Reference< XTimeContainer > xWithContainer( createParallelTimeContainer() );
2069                     Reference< XAnimationNode > xWithContainerNode( xWithContainer, UNO_QUERY_THROW );
2070                     xWithContainer->setBegin( makeAny( fBegin ) );
2071                     xOnClickContainer->appendChild( xWithContainerNode );
2072 
2073                     double fDuration = 0.0;
2074                     do
2075                     {
2076                         Reference< XAnimationNode > xEffectNode( pEffect->getNode() );
2077                         xWithContainer->appendChild( xEffectNode );
2078 
2079                         if( pEffect->hasAfterEffect() )
2080                         {
2081                             Reference< XAnimationNode > xAfterEffect( pEffect->createAfterEffectNode() );
2082                             AfterEffectNode a( xAfterEffect, xEffectNode, pEffect->IsAfterEffectOnNext() );
2083                             aAfterEffects.push_back( a );
2084                         }
2085 
2086                         double fTemp = pEffect->getBegin() + pEffect->getAbsoluteDuration();
2087                         if( fTemp > fDuration )
2088                             fDuration = fTemp;
2089 
2090                         if( aIter != aEnd )
2091                             pEffect = (*aIter++);
2092                         else
2093                             pEffect.reset();
2094                     }
2095                     while( pEffect.get() && (pEffect->getNodeType() == EffectNodeType::WITH_PREVIOUS) );
2096 
2097                     fBegin += fDuration;
2098                 }
2099                 while( pEffect.get() && (pEffect->getNodeType() != EffectNodeType::ON_CLICK) );
2100             }
2101             while( pEffect.get() );
2102 
2103             // process after effect nodes
2104             std::for_each( aAfterEffects.begin(), aAfterEffects.end(), stl_process_after_effect_node_func );
2105 
2106             updateTextGroups();
2107 
2108             // reset duration, might have been altered (see below)
2109             mxSequenceRoot->setDuration( Any() );
2110         }
2111         else
2112         {
2113             // empty sequence, set duration to 0.0 explicitly
2114             // (otherwise, this sequence will never end)
2115             mxSequenceRoot->setDuration( makeAny((double)0.0) );
2116         }
2117     }
2118     catch( Exception& e )
2119     {
2120         (void)e;
2121         DBG_ERROR( "sd::EffectSequenceHelper::rebuild(), exception caught!" );
2122     }
2123 }
2124 
2125 // --------------------------------------------------------------------
2126 
createParallelTimeContainer() const2127 Reference< XTimeContainer > EffectSequenceHelper::createParallelTimeContainer() const
2128 {
2129     const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.animations.ParallelTimeContainer" ) );
2130     return Reference< XTimeContainer >( ::comphelper::getProcessServiceFactory()->createInstance(aServiceName), UNO_QUERY );
2131 }
2132 
2133 // --------------------------------------------------------------------
2134 
stl_CustomAnimationEffect_search_node_predict(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xSearchNode)2135 stl_CustomAnimationEffect_search_node_predict::stl_CustomAnimationEffect_search_node_predict( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xSearchNode )
2136 : mxSearchNode( xSearchNode )
2137 {
2138 }
2139 
2140 // --------------------------------------------------------------------
2141 
operator ()(CustomAnimationEffectPtr pEffect) const2142 bool stl_CustomAnimationEffect_search_node_predict::operator()( CustomAnimationEffectPtr pEffect ) const
2143 {
2144     return pEffect->getNode() == mxSearchNode;
2145 }
2146 
2147 // --------------------------------------------------------------------
2148 
implFindNextContainer(Reference<XTimeContainer> & xParent,Reference<XTimeContainer> & xCurrent,Reference<XTimeContainer> & xNext)2149 static bool implFindNextContainer( Reference< XTimeContainer >& xParent, Reference< XTimeContainer >& xCurrent, Reference< XTimeContainer >& xNext )
2150 {
2151     Reference< XEnumerationAccess > xEnumerationAccess( xParent, UNO_QUERY_THROW );
2152     Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration() );
2153     if( xEnumeration.is() )
2154     {
2155         Reference< XInterface > x;
2156         while( xEnumeration->hasMoreElements() && !xNext.is() )
2157         {
2158             if( (xEnumeration->nextElement() >>= x) && (x == xCurrent) )
2159             {
2160                 if( xEnumeration->hasMoreElements() )
2161                     xEnumeration->nextElement() >>= xNext;
2162             }
2163         }
2164     }
2165     return xNext.is();
2166 }
2167 
2168 // --------------------------------------------------------------------
2169 
stl_process_after_effect_node_func(AfterEffectNode & rNode)2170 void stl_process_after_effect_node_func(AfterEffectNode& rNode)
2171 {
2172     try
2173     {
2174         if( rNode.mxNode.is() && rNode.mxMaster.is() )
2175         {
2176             // set master node
2177             Reference< XAnimationNode > xMasterNode( rNode.mxMaster, UNO_QUERY_THROW );
2178             Sequence< NamedValue > aUserData( rNode.mxNode->getUserData() );
2179             sal_Int32 nSize = aUserData.getLength();
2180             aUserData.realloc(nSize+1);
2181             aUserData[nSize].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "master-element" ) );
2182             aUserData[nSize].Value <<= xMasterNode;
2183             rNode.mxNode->setUserData( aUserData );
2184 
2185             // insert after effect node into timeline
2186             Reference< XTimeContainer > xContainer( rNode.mxMaster->getParent(), UNO_QUERY_THROW );
2187 
2188             if( !rNode.mbOnNextEffect ) // sameClick
2189             {
2190                 // insert the aftereffect after its effect is animated
2191                 xContainer->insertAfter( rNode.mxNode, rNode.mxMaster );
2192             }
2193             else // nextClick
2194             {
2195                 Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() );
2196                 // insert the aftereffect in the next group
2197 
2198                 Reference< XTimeContainer > xClickContainer( xContainer->getParent(), UNO_QUERY_THROW );
2199                 Reference< XTimeContainer > xSequenceContainer( xClickContainer->getParent(), UNO_QUERY_THROW );
2200 
2201                 Reference< XTimeContainer > xNextContainer;
2202 
2203                 // first try if we have an after effect container
2204                 if( !implFindNextContainer( xClickContainer, xContainer, xNextContainer ) )
2205                 {
2206                     Reference< XTimeContainer > xNextClickContainer;
2207                     // if not, try to find the next click effect container
2208                     if( implFindNextContainer( xSequenceContainer, xClickContainer, xNextClickContainer ) )
2209                     {
2210                         Reference< XEnumerationAccess > xEnumerationAccess( xNextClickContainer, UNO_QUERY_THROW );
2211                         Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
2212                         if( xEnumeration->hasMoreElements() )
2213                         {
2214                             // the next container is the first child container
2215                             xEnumeration->nextElement() >>= xNextContainer;
2216                         }
2217                         else
2218                         {
2219                             // this does not yet have a child container, create one
2220                             const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.ParallelTimeContainer") );
2221                             xNextContainer = Reference< XTimeContainer >::query( xMsf->createInstance(aServiceName) );
2222 
2223                             if( xNextContainer.is() )
2224                             {
2225                                 Reference< XAnimationNode > xNode( xNextContainer, UNO_QUERY_THROW );
2226                                 xNode->setBegin( makeAny( (double)0.0 ) );
2227 //                              xNode->setFill( AnimationFill::HOLD );
2228                                 xNextClickContainer->appendChild( xNode );
2229                             }
2230                         }
2231                         DBG_ASSERT( xNextContainer.is(), "ppt::stl_process_after_effect_node_func::operator(), could not find/create container!" );
2232                     }
2233                 }
2234 
2235                 // if we don't have a next container, we add one to the sequence container
2236                 if( !xNextContainer.is() )
2237                 {
2238                     const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.ParallelTimeContainer") );
2239                     Reference< XTimeContainer > xNewClickContainer( xMsf->createInstance(aServiceName), UNO_QUERY_THROW );
2240 
2241                     Reference< XAnimationNode > xNewClickNode( xNewClickContainer, UNO_QUERY_THROW );
2242 
2243                     Event aEvent;
2244                     aEvent.Trigger = EventTrigger::ON_NEXT;
2245                     aEvent.Repeat = 0;
2246                     xNewClickNode->setBegin( makeAny( aEvent ) );
2247 
2248                     Reference< XAnimationNode > xRefNode( xClickContainer, UNO_QUERY_THROW );
2249                     xSequenceContainer->insertAfter( xNewClickNode, xRefNode );
2250 
2251                     xNextContainer = Reference< XTimeContainer >::query( xMsf->createInstance(aServiceName) );
2252 
2253                     DBG_ASSERT( xNextContainer.is(), "ppt::stl_process_after_effect_node_func::operator(), could not create container!" );
2254                     if( xNextContainer.is() )
2255                     {
2256                         Reference< XAnimationNode > xNode( xNextContainer, UNO_QUERY_THROW );
2257                         xNode->setBegin( makeAny( (double)0.0 ) );
2258 //                      xNode->setFill( AnimationFill::HOLD );
2259                         xNewClickContainer->appendChild( xNode );
2260                     }
2261                 }
2262 
2263                 if( xNextContainer.is() )
2264                 {
2265                     // find begin time of first element
2266                     Reference< XEnumerationAccess > xEnumerationAccess( xNextContainer, UNO_QUERY_THROW );
2267                     Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
2268                     if( xEnumeration->hasMoreElements() )
2269                     {
2270                         Reference< XAnimationNode > xChild;
2271                         // the next container is the first child container
2272                         xEnumeration->nextElement() >>= xChild;
2273                         if( xChild.is() )
2274                         {
2275                             Any aBegin( xChild->getBegin() );
2276                             double fBegin = 0.0;
2277                             if( (aBegin >>= fBegin) && (fBegin >= 0.0))
2278                                 rNode.mxNode->setBegin( aBegin );
2279                         }
2280                     }
2281 
2282                     xNextContainer->appendChild( rNode.mxNode );
2283                 }
2284             }
2285         }
2286     }
2287     catch( Exception& e )
2288     {
2289         (void)e;
2290         DBG_ERROR( "ppt::stl_process_after_effect_node_func::operator(), exception caught!" );
2291     }
2292 }
2293 
2294 // --------------------------------------------------------------------
2295 
find(const CustomAnimationEffectPtr & pEffect)2296 EffectSequence::iterator EffectSequenceHelper::find( const CustomAnimationEffectPtr& pEffect )
2297 {
2298     return std::find( maEffects.begin(), maEffects.end(), pEffect );
2299 }
2300 
2301 // --------------------------------------------------------------------
2302 
findEffect(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode) const2303 CustomAnimationEffectPtr EffectSequenceHelper::findEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) const
2304 {
2305     CustomAnimationEffectPtr pEffect;
2306 
2307     EffectSequence::const_iterator aIter( maEffects.begin() );
2308     for( ; aIter != maEffects.end(); aIter++ )
2309     {
2310         if( (*aIter)->getNode() == xNode )
2311         {
2312             pEffect = (*aIter);
2313             break;
2314         }
2315     }
2316 
2317     return pEffect;
2318 }
2319 
2320 // --------------------------------------------------------------------
2321 
getOffsetFromEffect(const CustomAnimationEffectPtr & xEffect) const2322 sal_Int32 EffectSequenceHelper::getOffsetFromEffect( const CustomAnimationEffectPtr& xEffect ) const
2323 {
2324     sal_Int32 nOffset = 0;
2325 
2326     EffectSequence::const_iterator aIter( maEffects.begin() );
2327     for( ; aIter != maEffects.end(); aIter++, nOffset++ )
2328     {
2329         if( (*aIter) == xEffect )
2330             return nOffset;
2331     }
2332 
2333     return -1;
2334 }
2335 
2336 // --------------------------------------------------------------------
2337 
getEffectFromOffset(sal_Int32 nOffset) const2338 CustomAnimationEffectPtr EffectSequenceHelper::getEffectFromOffset( sal_Int32 nOffset ) const
2339 {
2340     EffectSequence::const_iterator aIter( maEffects.begin() );
2341     while( nOffset-- && aIter != maEffects.end() )
2342         aIter++;
2343 
2344     CustomAnimationEffectPtr pEffect;
2345     if( aIter != maEffects.end() )
2346         pEffect = (*aIter);
2347 
2348     return pEffect;
2349 }
2350 
2351 // --------------------------------------------------------------------
2352 
disposeShape(const Reference<XShape> & xShape)2353 bool EffectSequenceHelper::disposeShape( const Reference< XShape >& xShape )
2354 {
2355     bool bChanges = false;
2356 
2357     EffectSequence::iterator aIter( maEffects.begin() );
2358     while( aIter != maEffects.end() )
2359     {
2360         if( (*aIter)->getTargetShape() == xShape )
2361         {
2362             (*aIter)->setEffectSequence( 0 );
2363             bChanges = true;
2364             aIter = maEffects.erase( aIter );
2365         }
2366         else
2367         {
2368             aIter++;
2369         }
2370     }
2371 
2372     return bChanges;
2373 }
2374 
2375 // --------------------------------------------------------------------
2376 
hasEffect(const com::sun::star::uno::Reference<com::sun::star::drawing::XShape> & xShape)2377 bool EffectSequenceHelper::hasEffect( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape )
2378 {
2379     EffectSequence::iterator aIter( maEffects.begin() );
2380     while( aIter != maEffects.end() )
2381     {
2382         if( (*aIter)->getTargetShape() == xShape )
2383             return true;
2384         aIter++;
2385     }
2386 
2387     return false;
2388 }
2389 
2390 // --------------------------------------------------------------------
2391 
insertTextRange(const com::sun::star::uno::Any & aTarget)2392 void EffectSequenceHelper::insertTextRange( const com::sun::star::uno::Any& aTarget )
2393 {
2394     bool bChanges = false;
2395 
2396     ParagraphTarget aParaTarget;
2397     if( !(aTarget >>= aParaTarget ) )
2398         return;
2399 
2400     EffectSequence::iterator aIter( maEffects.begin() );
2401     while( aIter != maEffects.end() )
2402     {
2403         if( (*aIter)->getTargetShape() == aParaTarget.Shape )
2404             bChanges |= (*aIter)->checkForText();
2405         aIter++;
2406     }
2407 
2408     if( bChanges )
2409         rebuild();
2410 }
2411 
2412 // --------------------------------------------------------------------
2413 
disposeTextRange(const com::sun::star::uno::Any & aTarget)2414 void EffectSequenceHelper::disposeTextRange( const com::sun::star::uno::Any& aTarget )
2415 {
2416     ParagraphTarget aParaTarget;
2417     if( !(aTarget >>= aParaTarget ) )
2418         return;
2419 
2420     bool bChanges = false;
2421     bool bErased = false;
2422 
2423     EffectSequence::iterator aIter( maEffects.begin() );
2424     while( aIter != maEffects.end() )
2425     {
2426         Any aIterTarget( (*aIter)->getTarget() );
2427         if( aIterTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2428         {
2429             ParagraphTarget aIterParaTarget;
2430             if( (aIterTarget >>= aIterParaTarget) && (aIterParaTarget.Shape == aParaTarget.Shape) )
2431             {
2432                 if( aIterParaTarget.Paragraph == aParaTarget.Paragraph )
2433                 {
2434                     // delete this effect if it targets the disposed paragraph directly
2435                     (*aIter)->setEffectSequence( 0 );
2436                     aIter = maEffects.erase( aIter );
2437                     bChanges = true;
2438                     bErased = true;
2439                 }
2440                 else
2441                 {
2442                     if( aIterParaTarget.Paragraph > aParaTarget.Paragraph )
2443                     {
2444                         // shift all paragraphs after disposed paragraph
2445                         aIterParaTarget.Paragraph--;
2446                         (*aIter)->setTarget( makeAny( aIterParaTarget ) );
2447                     }
2448                 }
2449             }
2450         }
2451         else if( (*aIter)->getTargetShape() == aParaTarget.Shape )
2452         {
2453             bChanges |= (*aIter)->checkForText();
2454         }
2455 
2456         if( bErased )
2457             bErased = false;
2458         else
2459             aIter++;
2460     }
2461 
2462     if( bChanges )
2463         rebuild();
2464 }
2465 
2466 // --------------------------------------------------------------------
2467 
CustomAnimationTextGroup(const Reference<XShape> & rTarget,sal_Int32 nGroupId)2468 CustomAnimationTextGroup::CustomAnimationTextGroup( const Reference< XShape >& rTarget, sal_Int32 nGroupId )
2469 :   maTarget( rTarget ),
2470     mnGroupId( nGroupId )
2471 {
2472     reset();
2473 }
2474 
2475 // --------------------------------------------------------------------
2476 
reset()2477 void CustomAnimationTextGroup::reset()
2478 {
2479     mnTextGrouping = -1;
2480     mbAnimateForm = false;
2481     mbTextReverse = false;
2482     mfGroupingAuto = -1.0;
2483     mnLastPara = -1; // used to check for TextReverse
2484 
2485     int i = 5;
2486     while( i-- ) mnDepthFlags[i] = 0;
2487 
2488     maEffects.clear();
2489 }
2490 
2491 // --------------------------------------------------------------------
2492 
addEffect(CustomAnimationEffectPtr & pEffect)2493 void CustomAnimationTextGroup::addEffect( CustomAnimationEffectPtr& pEffect )
2494 {
2495     maEffects.push_back( pEffect );
2496 
2497     Any aTarget( pEffect->getTarget() );
2498     if( aTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2499     {
2500         // now look at the paragraph
2501         ParagraphTarget aParaTarget;
2502         aTarget >>= aParaTarget;
2503 
2504         if( mnLastPara != -1 )
2505             mbTextReverse = mnLastPara > aParaTarget.Paragraph;
2506 
2507         mnLastPara = aParaTarget.Paragraph;
2508 
2509         const sal_Int32 nParaDepth = pEffect->getParaDepth();
2510 
2511         // only look at the first 5 levels
2512         if( nParaDepth < 5 )
2513         {
2514             // our first paragraph with this level?
2515             if( mnDepthFlags[nParaDepth] == 0 )
2516             {
2517                 // so set it to the first found
2518                 mnDepthFlags[nParaDepth] = (sal_Int8)pEffect->getNodeType();
2519             }
2520             else if( mnDepthFlags[nParaDepth] != pEffect->getNodeType() )
2521             {
2522                 mnDepthFlags[nParaDepth] = -1;
2523             }
2524 
2525             if( pEffect->getNodeType() == EffectNodeType::AFTER_PREVIOUS )
2526                 mfGroupingAuto = pEffect->getBegin();
2527 
2528             mnTextGrouping = 0;
2529             while( (mnTextGrouping < 5) && (mnDepthFlags[mnTextGrouping] > 0) )
2530                 mnTextGrouping++;
2531         }
2532     }
2533     else
2534     {
2535         // if we have an effect with the shape as a target, we animate the background
2536         mbAnimateForm = pEffect->getTargetSubItem() != ShapeAnimationSubType::ONLY_TEXT;
2537     }
2538 }
2539 
2540 // --------------------------------------------------------------------
2541 
2542 class TextGroupMapImpl : public std::map< sal_Int32, CustomAnimationTextGroup* >
2543 {
2544 public:
2545     CustomAnimationTextGroup* findGroup( sal_Int32 nGroupId );
2546 };
2547 
2548 // --------------------------------------------------------------------
2549 
findGroup(sal_Int32 nGroupId)2550 CustomAnimationTextGroupPtr EffectSequenceHelper::findGroup( sal_Int32 nGroupId )
2551 {
2552     CustomAnimationTextGroupPtr aPtr;
2553 
2554     CustomAnimationTextGroupMap::iterator aIter( maGroupMap.find( nGroupId ) );
2555     if( aIter != maGroupMap.end() )
2556         aPtr = (*aIter).second;
2557 
2558     return aPtr;
2559 }
2560 
2561 // --------------------------------------------------------------------
2562 
updateTextGroups()2563 void EffectSequenceHelper::updateTextGroups()
2564 {
2565     maGroupMap.clear();
2566 
2567     // first create all the groups
2568     EffectSequence::iterator aIter( maEffects.begin() );
2569     const EffectSequence::iterator aEnd( maEffects.end() );
2570     while( aIter != aEnd )
2571     {
2572         CustomAnimationEffectPtr pEffect( (*aIter++) );
2573 
2574         const sal_Int32 nGroupId = pEffect->getGroupId();
2575 
2576         if( nGroupId == -1 )
2577             continue; // trivial case, no group
2578 
2579         CustomAnimationTextGroupPtr pGroup = findGroup( nGroupId );
2580         if( !pGroup.get() )
2581         {
2582             pGroup.reset( new CustomAnimationTextGroup( pEffect->getTargetShape(), nGroupId ) );
2583             maGroupMap[nGroupId] = pGroup;
2584         }
2585 
2586         pGroup->addEffect( pEffect );
2587     }
2588 }
2589 
2590 // --------------------------------------------------------------------
2591 
createTextGroup(CustomAnimationEffectPtr pEffect,sal_Int32 nTextGrouping,double fTextGroupingAuto,sal_Bool bAnimateForm,sal_Bool bTextReverse)2592 CustomAnimationTextGroupPtr EffectSequenceHelper::createTextGroup( CustomAnimationEffectPtr pEffect, sal_Int32 nTextGrouping, double fTextGroupingAuto, sal_Bool bAnimateForm, sal_Bool bTextReverse )
2593 {
2594     // first finde a free group-id
2595     sal_Int32 nGroupId = 0;
2596 
2597     CustomAnimationTextGroupMap::iterator aIter( maGroupMap.begin() );
2598     const CustomAnimationTextGroupMap::iterator aEnd( maGroupMap.end() );
2599     while( aIter != aEnd )
2600     {
2601         if( (*aIter).first == nGroupId )
2602         {
2603             nGroupId++;
2604             aIter = maGroupMap.begin();
2605         }
2606         else
2607         {
2608             aIter++;
2609         }
2610     }
2611 
2612     Reference< XShape > xTarget( pEffect->getTargetShape() );
2613 
2614     CustomAnimationTextGroupPtr pTextGroup( new CustomAnimationTextGroup( xTarget, nGroupId ) );
2615     maGroupMap[nGroupId] = pTextGroup;
2616 
2617     bool bUsed = false;
2618 
2619     // do we need to target the shape?
2620     if( (nTextGrouping == 0) || bAnimateForm )
2621     {
2622         sal_Int16 nSubItem;
2623         if( nTextGrouping == 0)
2624             nSubItem = bAnimateForm ? ShapeAnimationSubType::AS_WHOLE : ShapeAnimationSubType::ONLY_TEXT;
2625         else
2626             nSubItem = ShapeAnimationSubType::ONLY_BACKGROUND;
2627 
2628         pEffect->setTarget( makeAny( xTarget ) );
2629         pEffect->setTargetSubItem( nSubItem );
2630         pEffect->setEffectSequence( this );
2631         pEffect->setGroupId( nGroupId );
2632 
2633         pTextGroup->addEffect( pEffect );
2634         bUsed = true;
2635     }
2636 
2637     pTextGroup->mnTextGrouping = nTextGrouping;
2638     pTextGroup->mfGroupingAuto = fTextGroupingAuto;
2639     pTextGroup->mbTextReverse = bTextReverse;
2640 
2641     // now add an effect for each paragraph
2642     createTextGroupParagraphEffects( pTextGroup, pEffect, bUsed );
2643 
2644     notify_listeners();
2645 
2646     return pTextGroup;
2647 }
2648 
2649 // --------------------------------------------------------------------
2650 
createTextGroupParagraphEffects(CustomAnimationTextGroupPtr pTextGroup,CustomAnimationEffectPtr pEffect,bool bUsed)2651 void EffectSequenceHelper::createTextGroupParagraphEffects( CustomAnimationTextGroupPtr pTextGroup, CustomAnimationEffectPtr pEffect, bool bUsed )
2652 {
2653     Reference< XShape > xTarget( pTextGroup->maTarget );
2654 
2655     sal_Int32 nTextGrouping = pTextGroup->mnTextGrouping;
2656     double fTextGroupingAuto = pTextGroup->mfGroupingAuto;
2657     sal_Bool bTextReverse = pTextGroup->mbTextReverse;
2658 
2659     // now add an effect for each paragraph
2660     if( nTextGrouping >= 0 ) try
2661     {
2662         EffectSequence::iterator aInsertIter( find( pEffect ) );
2663 
2664         const OUString strNumberingLevel( RTL_CONSTASCII_USTRINGPARAM("NumberingLevel") );
2665         Reference< XEnumerationAccess > xText( xTarget, UNO_QUERY_THROW );
2666         Reference< XEnumeration > xEnumeration( xText->createEnumeration(), UNO_QUERY_THROW );
2667 
2668         std::list< sal_Int16 > aParaList;
2669         sal_Int16 nPara;
2670 
2671         // fill the list with all valid paragraphs
2672         for( nPara = 0; xEnumeration->hasMoreElements(); nPara++ )
2673         {
2674             Reference< XTextRange > xRange( xEnumeration->nextElement(), UNO_QUERY );
2675             if( xRange.is() && xRange->getString().getLength() )
2676             {
2677                 if( bTextReverse ) // sort them
2678                     aParaList.push_front( nPara );
2679                 else
2680                     aParaList.push_back( nPara );
2681             }
2682         }
2683 
2684         ParagraphTarget aTarget;
2685         aTarget.Shape = xTarget;
2686 
2687         std::list< sal_Int16 >::iterator aIter( aParaList.begin() );
2688         std::list< sal_Int16 >::iterator aEnd( aParaList.end() );
2689         while( aIter != aEnd )
2690         {
2691             aTarget.Paragraph = (*aIter++);
2692 
2693             CustomAnimationEffectPtr pNewEffect;
2694             if( bUsed )
2695             {
2696                 // clone a new effect from first effect
2697                 pNewEffect = pEffect->clone();
2698                 ++aInsertIter;
2699                 aInsertIter = maEffects.insert( aInsertIter, pNewEffect );
2700             }
2701             else
2702             {
2703                 // reuse first effect if its not yet used
2704                 pNewEffect = pEffect;
2705                 bUsed = true;
2706                 aInsertIter = find( pNewEffect );
2707             }
2708 
2709             // set target and group-id
2710             pNewEffect->setTarget( makeAny( aTarget ) );
2711             pNewEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT );
2712             pNewEffect->setGroupId( pTextGroup->mnGroupId );
2713             pNewEffect->setEffectSequence( this );
2714 
2715             // set correct node type
2716             if( pNewEffect->getParaDepth() < nTextGrouping )
2717             {
2718                 if( fTextGroupingAuto == -1.0 )
2719                 {
2720                     pNewEffect->setNodeType( EffectNodeType::ON_CLICK );
2721                     pNewEffect->setBegin( 0.0 );
2722                 }
2723                 else
2724                 {
2725                     pNewEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2726                     pNewEffect->setBegin( fTextGroupingAuto );
2727                 }
2728             }
2729             else
2730             {
2731                 pNewEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2732                 pNewEffect->setBegin( 0.0 );
2733             }
2734 
2735             pTextGroup->addEffect( pNewEffect );
2736         }
2737         notify_listeners();
2738     }
2739     catch( Exception& e )
2740     {
2741         (void)e;
2742         DBG_ERROR("sd::EffectSequenceHelper::createTextGroup(), exception caught!" );
2743     }
2744 }
2745 
2746 // --------------------------------------------------------------------
2747 
setTextGrouping(CustomAnimationTextGroupPtr pTextGroup,sal_Int32 nTextGrouping)2748 void EffectSequenceHelper::setTextGrouping( CustomAnimationTextGroupPtr pTextGroup, sal_Int32 nTextGrouping )
2749 {
2750     if( pTextGroup->mnTextGrouping == nTextGrouping )
2751     {
2752         // first case, trivial case, do nothing
2753     }
2754     else if( (pTextGroup->mnTextGrouping == -1) && (nTextGrouping >= 0) )
2755     {
2756         // second case, we need to add new effects for each paragraph
2757 
2758         CustomAnimationEffectPtr pEffect( pTextGroup->maEffects.front() );
2759 
2760         pTextGroup->mnTextGrouping = nTextGrouping;
2761         createTextGroupParagraphEffects( pTextGroup, pEffect, true );
2762         notify_listeners();
2763     }
2764     else if( (pTextGroup->mnTextGrouping >= 0) && (nTextGrouping == -1 ) )
2765     {
2766         // third case, we need to remove effects for each paragraph
2767 
2768         EffectSequence aEffects( pTextGroup->maEffects );
2769         pTextGroup->reset();
2770 
2771         EffectSequence::iterator aIter( aEffects.begin() );
2772         const EffectSequence::iterator aEnd( aEffects.end() );
2773         while( aIter != aEnd )
2774         {
2775             CustomAnimationEffectPtr pEffect( (*aIter++) );
2776 
2777             if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2778                 remove( pEffect );
2779             else
2780                 pTextGroup->addEffect( pEffect );
2781         }
2782         notify_listeners();
2783     }
2784     else
2785     {
2786         // fourth case, we need to change the node types for the text nodes
2787         double fTextGroupingAuto = pTextGroup->mfGroupingAuto;
2788 
2789         EffectSequence aEffects( pTextGroup->maEffects );
2790         pTextGroup->reset();
2791 
2792         EffectSequence::iterator aIter( aEffects.begin() );
2793         const EffectSequence::iterator aEnd( aEffects.end() );
2794         while( aIter != aEnd )
2795         {
2796             CustomAnimationEffectPtr pEffect( (*aIter++) );
2797 
2798             if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2799             {
2800                 // set correct node type
2801                 if( pEffect->getParaDepth() < nTextGrouping )
2802                 {
2803                     if( fTextGroupingAuto == -1.0 )
2804                     {
2805                         pEffect->setNodeType( EffectNodeType::ON_CLICK );
2806                         pEffect->setBegin( 0.0 );
2807                     }
2808                     else
2809                     {
2810                         pEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2811                         pEffect->setBegin( fTextGroupingAuto );
2812                     }
2813                 }
2814                 else
2815                 {
2816                     pEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2817                     pEffect->setBegin( 0.0 );
2818                 }
2819             }
2820 
2821             pTextGroup->addEffect( pEffect );
2822 
2823         }
2824         notify_listeners();
2825     }
2826 }
2827 
2828 // --------------------------------------------------------------------
2829 
setAnimateForm(CustomAnimationTextGroupPtr pTextGroup,sal_Bool bAnimateForm)2830 void EffectSequenceHelper::setAnimateForm( CustomAnimationTextGroupPtr pTextGroup, sal_Bool bAnimateForm )
2831 {
2832     if( pTextGroup->mbAnimateForm == bAnimateForm )
2833     {
2834         // trivial case, do nothing
2835     }
2836     else
2837     {
2838         EffectSequence aEffects( pTextGroup->maEffects );
2839         pTextGroup->reset();
2840 
2841         EffectSequence::iterator aIter( aEffects.begin() );
2842         const EffectSequence::iterator aEnd( aEffects.end() );
2843 
2844         // first insert if we have to
2845         if( bAnimateForm )
2846         {
2847             EffectSequence::iterator aInsertIter( find( (*aIter) ) );
2848 
2849             CustomAnimationEffectPtr pEffect;
2850             if( (aEffects.size() == 1) && ((*aIter)->getTarget().getValueType() != ::getCppuType((const ParagraphTarget*)0) ) )
2851             {
2852                 // special case, only one effect and that targets whole text,
2853                 // convert this to target whole shape
2854                 pEffect = (*aIter++);
2855                 pEffect->setTargetSubItem( ShapeAnimationSubType::AS_WHOLE );
2856             }
2857             else
2858             {
2859                 pEffect = (*aIter)->clone();
2860                 pEffect->setTarget( makeAny( (*aIter)->getTargetShape() ) );
2861                 pEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_BACKGROUND );
2862                 maEffects.insert( aInsertIter, pEffect );
2863             }
2864 
2865             pTextGroup->addEffect( pEffect );
2866         }
2867 
2868         if( !bAnimateForm && (aEffects.size() == 1) )
2869         {
2870             CustomAnimationEffectPtr pEffect( (*aIter) );
2871             pEffect->setTarget( makeAny( (*aIter)->getTargetShape() ) );
2872             pEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT );
2873             pTextGroup->addEffect( pEffect );
2874         }
2875         else
2876         {
2877             // readd the rest to the group again
2878             while( aIter != aEnd )
2879             {
2880                 CustomAnimationEffectPtr pEffect( (*aIter++) );
2881 
2882                 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2883                 {
2884                     pTextGroup->addEffect( pEffect );
2885                 }
2886                 else
2887                 {
2888                     DBG_ASSERT( !bAnimateForm, "sd::EffectSequenceHelper::setAnimateForm(), something is wrong here!" );
2889                     remove( pEffect );
2890                 }
2891             }
2892         }
2893         notify_listeners();
2894     }
2895 }
2896 
2897 // --------------------------------------------------------------------
2898 
setTextGroupingAuto(CustomAnimationTextGroupPtr pTextGroup,double fTextGroupingAuto)2899 void EffectSequenceHelper::setTextGroupingAuto( CustomAnimationTextGroupPtr pTextGroup, double fTextGroupingAuto )
2900 {
2901     sal_Int32 nTextGrouping = pTextGroup->mnTextGrouping;
2902 
2903     EffectSequence aEffects( pTextGroup->maEffects );
2904     pTextGroup->reset();
2905 
2906     EffectSequence::iterator aIter( aEffects.begin() );
2907     const EffectSequence::iterator aEnd( aEffects.end() );
2908     while( aIter != aEnd )
2909     {
2910         CustomAnimationEffectPtr pEffect( (*aIter++) );
2911 
2912         if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2913         {
2914             // set correct node type
2915             if( pEffect->getParaDepth() < nTextGrouping )
2916             {
2917                 if( fTextGroupingAuto == -1.0 )
2918                 {
2919                     pEffect->setNodeType( EffectNodeType::ON_CLICK );
2920                     pEffect->setBegin( 0.0 );
2921                 }
2922                 else
2923                 {
2924                     pEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2925                     pEffect->setBegin( fTextGroupingAuto );
2926                 }
2927             }
2928             else
2929             {
2930                 pEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2931                 pEffect->setBegin( 0.0 );
2932             }
2933         }
2934 
2935         pTextGroup->addEffect( pEffect );
2936 
2937     }
2938     notify_listeners();
2939 }
2940 
2941 // --------------------------------------------------------------------
2942 
2943 struct ImplStlTextGroupSortHelper
2944 {
ImplStlTextGroupSortHelpersd::ImplStlTextGroupSortHelper2945     ImplStlTextGroupSortHelper( bool bReverse ) : mbReverse( bReverse ) {};
2946     bool operator()( const CustomAnimationEffectPtr& p1, const CustomAnimationEffectPtr& p2 );
2947     bool mbReverse;
2948     sal_Int32 getTargetParagraph( const CustomAnimationEffectPtr& p1 );
2949 };
2950 
2951 // --------------------------------------------------------------------
2952 
getTargetParagraph(const CustomAnimationEffectPtr & p1)2953 sal_Int32 ImplStlTextGroupSortHelper::getTargetParagraph( const CustomAnimationEffectPtr& p1 )
2954 {
2955     const Any aTarget(p1->getTarget());
2956     if( aTarget.hasValue() && aTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2957     {
2958         ParagraphTarget aParaTarget;
2959         aTarget >>= aParaTarget;
2960         return aParaTarget.Paragraph;
2961     }
2962     else
2963     {
2964         return mbReverse ? 0x7fffffff : -1;
2965     }
2966 }
2967 
2968 // --------------------------------------------------------------------
2969 
operator ()(const CustomAnimationEffectPtr & p1,const CustomAnimationEffectPtr & p2)2970 bool ImplStlTextGroupSortHelper::operator()( const CustomAnimationEffectPtr& p1, const CustomAnimationEffectPtr& p2 )
2971 {
2972     if( mbReverse )
2973     {
2974         return getTargetParagraph( p2 ) < getTargetParagraph( p1 );
2975     }
2976     else
2977     {
2978         return getTargetParagraph( p1 ) < getTargetParagraph( p2 );
2979     }
2980 }
2981 
2982 // --------------------------------------------------------------------
2983 
setTextReverse(CustomAnimationTextGroupPtr pTextGroup,sal_Bool bTextReverse)2984 void EffectSequenceHelper::setTextReverse( CustomAnimationTextGroupPtr pTextGroup, sal_Bool bTextReverse )
2985 {
2986     if( pTextGroup->mbTextReverse == bTextReverse )
2987     {
2988         // do nothing
2989     }
2990     else
2991     {
2992         std::vector< CustomAnimationEffectPtr > aSortedVector(pTextGroup->maEffects.size());
2993         std::copy( pTextGroup->maEffects.begin(), pTextGroup->maEffects.end(), aSortedVector.begin() );
2994         ImplStlTextGroupSortHelper aSortHelper( bTextReverse );
2995         std::sort( aSortedVector.begin(), aSortedVector.end(), aSortHelper );
2996 
2997         pTextGroup->reset();
2998 
2999         std::vector< CustomAnimationEffectPtr >::iterator aIter( aSortedVector.begin() );
3000         const std::vector< CustomAnimationEffectPtr >::iterator aEnd( aSortedVector.end() );
3001 
3002         if( aIter != aEnd )
3003         {
3004             pTextGroup->addEffect( (*aIter ) );
3005             EffectSequence::iterator aInsertIter( find( (*aIter++) ) );
3006             while( aIter != aEnd )
3007             {
3008                 CustomAnimationEffectPtr pEffect( (*aIter++) );
3009                 maEffects.erase( find( pEffect ) );
3010                 aInsertIter = maEffects.insert( ++aInsertIter, pEffect );
3011                 pTextGroup->addEffect( pEffect );
3012             }
3013         }
3014         notify_listeners();
3015     }
3016 }
3017 
3018 // --------------------------------------------------------------------
3019 
addListener(ISequenceListener * pListener)3020 void EffectSequenceHelper::addListener( ISequenceListener* pListener )
3021 {
3022     if( std::find( maListeners.begin(), maListeners.end(), pListener ) == maListeners.end() )
3023         maListeners.push_back( pListener );
3024 }
3025 
3026 // --------------------------------------------------------------------
3027 
removeListener(ISequenceListener * pListener)3028 void EffectSequenceHelper::removeListener( ISequenceListener* pListener )
3029 {
3030     maListeners.remove( pListener );
3031 }
3032 
3033 // --------------------------------------------------------------------
3034 
3035 struct stl_notify_listeners_func : public std::unary_function<ISequenceListener*, void>
3036 {
stl_notify_listeners_funcsd::stl_notify_listeners_func3037     stl_notify_listeners_func() {}
operator ()sd::stl_notify_listeners_func3038     void operator()(ISequenceListener* pListener) { pListener->notify_change(); }
3039 };
3040 
3041 // --------------------------------------------------------------------
3042 
notify_listeners()3043 void EffectSequenceHelper::notify_listeners()
3044 {
3045     stl_notify_listeners_func aFunc;
3046     std::for_each( maListeners.begin(), maListeners.end(), aFunc );
3047 }
3048 
3049 // --------------------------------------------------------------------
3050 
create(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode)3051 void EffectSequenceHelper::create( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
3052 {
3053     DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::create(), illegal argument" );
3054 
3055     if( xNode.is() ) try
3056     {
3057         Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
3058         Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3059         while( xEnumeration->hasMoreElements() )
3060         {
3061             Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3062             createEffectsequence( xChildNode );
3063         }
3064     }
3065     catch( Exception& )
3066     {
3067         DBG_ERROR( "sd::EffectSequenceHelper::create(), exception caught!" );
3068     }
3069 }
3070 
3071 // --------------------------------------------------------------------
3072 
createEffectsequence(const Reference<XAnimationNode> & xNode)3073 void EffectSequenceHelper::createEffectsequence( const Reference< XAnimationNode >& xNode )
3074 {
3075     DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::createEffectsequence(), illegal argument" );
3076 
3077     if( xNode.is() ) try
3078     {
3079         Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
3080         Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3081         while( xEnumeration->hasMoreElements() )
3082         {
3083             Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3084 
3085             createEffects( xChildNode );
3086         }
3087     }
3088     catch( Exception& )
3089     {
3090         DBG_ERROR( "sd::EffectSequenceHelper::createEffectsequence(), exception caught!" );
3091     }
3092 }
3093 
3094 // --------------------------------------------------------------------
3095 
createEffects(const Reference<XAnimationNode> & xNode)3096 void EffectSequenceHelper::createEffects( const Reference< XAnimationNode >& xNode )
3097 {
3098     DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::createEffects(), illegal argument" );
3099 
3100     if( xNode.is() ) try
3101     {
3102         Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
3103         Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3104         while( xEnumeration->hasMoreElements() )
3105         {
3106             Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3107 
3108             switch( xChildNode->getType() )
3109             {
3110             // found an effect
3111             case AnimationNodeType::PAR:
3112             case AnimationNodeType::ITERATE:
3113                 {
3114                     CustomAnimationEffectPtr pEffect( new CustomAnimationEffect( xChildNode ) );
3115 
3116                     if( pEffect->mnNodeType != -1 )
3117                     {
3118                         pEffect->setEffectSequence( this );
3119                         maEffects.push_back(pEffect);
3120                     }
3121                 }
3122                 break;
3123 
3124             // found an after effect
3125             case AnimationNodeType::SET:
3126             case AnimationNodeType::ANIMATECOLOR:
3127                 {
3128                     processAfterEffect( xChildNode );
3129                 }
3130                 break;
3131             }
3132         }
3133     }
3134     catch( Exception& e )
3135     {
3136         (void)e;
3137         DBG_ERROR( "sd::EffectSequenceHelper::createEffects(), exception caught!" );
3138     }
3139 }
3140 
3141 // --------------------------------------------------------------------
3142 
processAfterEffect(const Reference<XAnimationNode> & xNode)3143 void EffectSequenceHelper::processAfterEffect( const Reference< XAnimationNode >& xNode )
3144 {
3145     try
3146     {
3147         Reference< XAnimationNode > xMaster;
3148 
3149         Sequence< NamedValue > aUserData( xNode->getUserData() );
3150         sal_Int32 nLength = aUserData.getLength();
3151         const NamedValue* p = aUserData.getConstArray();
3152 
3153         while( nLength-- )
3154         {
3155             if( p->Name.equalsAscii( "master-element" ) )
3156             {
3157                 p->Value >>= xMaster;
3158                 break;
3159             }
3160             p++;
3161         }
3162 
3163         // only process if this is a valid after effect
3164         if( xMaster.is() )
3165         {
3166             CustomAnimationEffectPtr pMasterEffect;
3167 
3168             // find the master effect
3169             stl_CustomAnimationEffect_search_node_predict aSearchPredict( xMaster );
3170             EffectSequence::iterator aIter( std::find_if( maEffects.begin(), maEffects.end(), aSearchPredict ) );
3171             if( aIter != maEffects.end() )
3172                 pMasterEffect = (*aIter );
3173 
3174             if( pMasterEffect.get() )
3175             {
3176                 pMasterEffect->setHasAfterEffect( true );
3177 
3178                 // find out what kind of after effect this is
3179                 if( xNode->getType() == AnimationNodeType::ANIMATECOLOR )
3180                 {
3181                     // its a dim
3182                     Reference< XAnimate > xAnimate( xNode, UNO_QUERY_THROW );
3183                     pMasterEffect->setDimColor( xAnimate->getTo() );
3184                     pMasterEffect->setAfterEffectOnNext( true );
3185                 }
3186                 else
3187                 {
3188                     // its a hide
3189                     Reference< XChild > xNodeChild( xNode, UNO_QUERY_THROW );
3190                     Reference< XChild > xMasterChild( xMaster, UNO_QUERY_THROW );
3191                     pMasterEffect->setAfterEffectOnNext( xNodeChild->getParent() != xMasterChild->getParent() );
3192                 }
3193             }
3194         }
3195     }
3196     catch( Exception& e )
3197     {
3198         (void)e;
3199         DBG_ERROR( "sd::EffectSequenceHelper::processAfterEffect(), exception caught!" );
3200     }
3201 }
3202 
3203 /*
3204 double EffectSequenceHelper::calculateIterateNodeDuration(
3205 {
3206     Reference< i18n::XBreakIterator > xBI( ImplGetBreakIterator() );
3207 
3208     sal_Int32 nDone;
3209     sal_Int32 nNextCellBreak( xBI->nextCharacters(rTxt, nIdx, rLocale, i18n::CharacterIteratorMode::SKIPCELL, 0, nDone) );
3210     i18n::Boundary nNextWordBoundary( xBI->getWordBoundary(rTxt, nIdx, rLocale, i18n::WordType::ANY_WORD, sal_True) );
3211     sal_Int32 nNextSentenceBreak( xBI->endOfSentence(rTxt, nIdx, rLocale) );
3212 
3213     const sal_Int32 nEndPos( nIdx + nLen );
3214     sal_Int32 i, currOffset(0);
3215     for( i=nIdx; i<nEndPos; ++i )
3216     {
3217         // TODO: Check whether position update is valid for CTL/BiDi
3218         rOutDev.DrawText( rPos + Point(currOffset,0), rTxt, i, 1 );
3219         currOffset = *pDXArray++;
3220 
3221         // issue the comments at the respective break positions
3222         if( i == nNextCellBreak )
3223         {
3224             rMtf.AddAction( new MetaCommentAction( "XTEXT_EOC" ) );
3225             nNextCellBreak = xBI->nextCharacters(rTxt, i, rLocale, i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
3226         }
3227         if( i == nNextWordBoundary.endPos )
3228         {
3229             rMtf.AddAction( new MetaCommentAction( "XTEXT_EOW" ) );
3230             nNextWordBoundary = xBI->getWordBoundary(rTxt, i+1, rLocale, i18n::WordType::ANY_WORD, sal_True);
3231         }
3232         if( i == nNextSentenceBreak )
3233         {
3234             rMtf.AddAction( new MetaCommentAction( "XTEXT_EOS" ) );
3235             nNextSentenceBreak = xBI->endOfSentence(rTxt, i+1, rLocale);
3236         }
3237     }
3238 }
3239 
3240 */
3241 // ====================================================================
3242 
3243 class AnimationChangeListener : public cppu::WeakImplHelper1< XChangesListener >
3244 {
3245 public:
AnimationChangeListener(MainSequence * pMainSequence)3246     AnimationChangeListener( MainSequence* pMainSequence ) : mpMainSequence( pMainSequence ) {}
3247 
3248     virtual void SAL_CALL changesOccurred( const ::com::sun::star::util::ChangesEvent& Event );
3249     virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source );
3250 private:
3251     MainSequence* mpMainSequence;
3252 };
3253 
changesOccurred(const::com::sun::star::util::ChangesEvent &)3254 void SAL_CALL AnimationChangeListener::changesOccurred( const ::com::sun::star::util::ChangesEvent& )
3255 {
3256     if( mpMainSequence )
3257         mpMainSequence->startRecreateTimer();
3258 }
3259 
disposing(const::com::sun::star::lang::EventObject &)3260 void SAL_CALL AnimationChangeListener::disposing( const ::com::sun::star::lang::EventObject& )
3261 {
3262 }
3263 
3264 // ====================================================================
3265 
MainSequence()3266 MainSequence::MainSequence()
3267 : mxTimingRootNode( ::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.SequenceTimeContainer"))), UNO_QUERY )
3268 , mbRebuilding( false )
3269 , mnRebuildLockGuard( 0 )
3270 , mbPendingRebuildRequest( false )
3271 {
3272     if( mxTimingRootNode.is() )
3273     {
3274         Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
3275         aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
3276         aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::MAIN_SEQUENCE;
3277         mxTimingRootNode->setUserData( aUserData );
3278     }
3279     init();
3280 }
3281 
3282 // --------------------------------------------------------------------
3283 
MainSequence(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode)3284 MainSequence::MainSequence( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
3285 : mxTimingRootNode( xNode, UNO_QUERY )
3286 , mbRebuilding( false )
3287 , mnRebuildLockGuard( 0 )
3288 , mbPendingRebuildRequest( false )
3289 , mbIgnoreChanges( 0 )
3290 {
3291     init();
3292 }
3293 
3294 // --------------------------------------------------------------------
3295 
~MainSequence()3296 MainSequence::~MainSequence()
3297 {
3298     reset();
3299 }
3300 
3301 // --------------------------------------------------------------------
3302 
init()3303 void MainSequence::init()
3304 {
3305     mnSequenceType = EffectNodeType::MAIN_SEQUENCE;
3306 
3307     maTimer.SetTimeoutHdl( LINK(this, MainSequence, onTimerHdl) );
3308     maTimer.SetTimeout(500);
3309 
3310     mxChangesListener.set( new AnimationChangeListener( this ) );
3311 
3312     createMainSequence();
3313 }
3314 
3315 // --------------------------------------------------------------------
3316 
reset(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xTimingRootNode)3317 void MainSequence::reset( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xTimingRootNode )
3318 {
3319     reset();
3320 
3321     mxTimingRootNode.set( xTimingRootNode, UNO_QUERY );
3322 
3323     createMainSequence();
3324 }
3325 
3326 // --------------------------------------------------------------------
3327 
getRootNode()3328 Reference< ::com::sun::star::animations::XAnimationNode > MainSequence::getRootNode()
3329 {
3330     DBG_ASSERT( mnRebuildLockGuard == 0, "MainSequence::getRootNode(), rebuild is locked, ist this really what you want?" );
3331 
3332     if( maTimer.IsActive() && mbTimerMode )
3333     {
3334         // force a rebuild NOW if one is pending
3335         maTimer.Stop();
3336         implRebuild();
3337     }
3338 
3339     return EffectSequenceHelper::getRootNode();
3340 }
3341 
3342 // --------------------------------------------------------------------
3343 
createMainSequence()3344 void MainSequence::createMainSequence()
3345 {
3346     if( mxTimingRootNode.is() ) try
3347     {
3348         Reference< XEnumerationAccess > xEnumerationAccess( mxTimingRootNode, UNO_QUERY_THROW );
3349         Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3350         while( xEnumeration->hasMoreElements() )
3351         {
3352             Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3353             sal_Int32 nNodeType = CustomAnimationEffect::get_node_type( xChildNode );
3354             if( nNodeType == EffectNodeType::MAIN_SEQUENCE )
3355             {
3356                 mxSequenceRoot.set( xChildNode, UNO_QUERY );
3357                 EffectSequenceHelper::create( xChildNode );
3358             }
3359             else if( nNodeType == EffectNodeType::INTERACTIVE_SEQUENCE )
3360             {
3361                 Reference< XTimeContainer > xInteractiveRoot( xChildNode, UNO_QUERY_THROW );
3362                 InteractiveSequencePtr pIS( new InteractiveSequence( xInteractiveRoot, this ) );
3363                 pIS->addListener( this );
3364                 maInteractiveSequenceList.push_back( pIS );
3365             }
3366         }
3367 
3368         // see if we have a mainsequence at all. if not, create one...
3369         if( !mxSequenceRoot.is() )
3370         {
3371             mxSequenceRoot = Reference< XTimeContainer >::query(::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.SequenceTimeContainer"))));
3372             if( mxSequenceRoot.is() )
3373             {
3374                 uno::Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
3375                 aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
3376                 aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::MAIN_SEQUENCE;
3377                 mxSequenceRoot->setUserData( aUserData );
3378 
3379                 // empty sequence until now, set duration to 0.0
3380                 // explicitly (otherwise, this sequence will never
3381                 // end)
3382                 mxSequenceRoot->setDuration( makeAny((double)0.0) );
3383 
3384                 Reference< XAnimationNode > xMainSequenceNode( mxSequenceRoot, UNO_QUERY_THROW );
3385                 mxTimingRootNode->appendChild( xMainSequenceNode );
3386             }
3387         }
3388 
3389         updateTextGroups();
3390 
3391         notify_listeners();
3392 
3393         Reference< XChangesNotifier > xNotifier( mxTimingRootNode, UNO_QUERY );
3394         if( xNotifier.is() )
3395             xNotifier->addChangesListener( mxChangesListener );
3396     }
3397     catch( Exception& e )
3398     {
3399         (void)e;
3400         DBG_ERROR( "sd::MainSequence::create(), exception caught!" );
3401         return;
3402     }
3403 
3404     DBG_ASSERT( mxSequenceRoot.is(), "sd::MainSequence::create(), found no main sequence!" );
3405 }
3406 
3407 // --------------------------------------------------------------------
3408 
reset()3409 void MainSequence::reset()
3410 {
3411     EffectSequenceHelper::reset();
3412 
3413     InteractiveSequenceList::iterator aIter;
3414     for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3415         (*aIter)->reset();
3416     maInteractiveSequenceList.clear();
3417 
3418     try
3419     {
3420         Reference< XChangesNotifier > xNotifier( mxTimingRootNode, UNO_QUERY );
3421         if( xNotifier.is() )
3422             xNotifier->removeChangesListener( mxChangesListener );
3423     }
3424     catch( Exception& )
3425     {
3426         // ...
3427     }
3428 }
3429 
3430 // --------------------------------------------------------------------
3431 
createInteractiveSequence(const::com::sun::star::uno::Reference<::com::sun::star::drawing::XShape> & xShape)3432 InteractiveSequencePtr MainSequence::createInteractiveSequence( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xShape )
3433 {
3434     InteractiveSequencePtr pIS;
3435 
3436     // create a new interactive sequence container
3437     Reference< XTimeContainer > xISRoot( ::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.SequenceTimeContainer"))), UNO_QUERY );
3438     DBG_ASSERT( xISRoot.is(), "sd::MainSequence::createInteractiveSequence(), could not create \"com.sun.star.animations.SequenceTimeContainer\"!");
3439     if( xISRoot.is() )
3440     {
3441         uno::Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
3442         aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
3443         aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::INTERACTIVE_SEQUENCE ;
3444         xISRoot->setUserData( aUserData );
3445 
3446         Reference< XChild > xChild( mxSequenceRoot, UNO_QUERY_THROW );
3447         Reference< XAnimationNode > xISNode( xISRoot, UNO_QUERY_THROW );
3448         Reference< XTimeContainer > xParent( xChild->getParent(), UNO_QUERY_THROW );
3449         xParent->appendChild( xISNode );
3450     }
3451     pIS.reset( new InteractiveSequence( xISRoot, this) );
3452     pIS->setTriggerShape( xShape );
3453     pIS->addListener( this );
3454     maInteractiveSequenceList.push_back( pIS );
3455     return pIS;
3456 }
3457 
3458 // --------------------------------------------------------------------
3459 
findEffect(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode) const3460 CustomAnimationEffectPtr MainSequence::findEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) const
3461 {
3462     CustomAnimationEffectPtr pEffect = EffectSequenceHelper::findEffect( xNode );
3463 
3464     if( pEffect.get() == 0 )
3465     {
3466         InteractiveSequenceList::const_iterator aIter;
3467         for( aIter = maInteractiveSequenceList.begin(); (aIter != maInteractiveSequenceList.end()) && (pEffect.get() == 0); aIter++ )
3468         {
3469             pEffect = (*aIter)->findEffect( xNode );
3470         }
3471     }
3472     return pEffect;
3473 }
3474 
3475 // --------------------------------------------------------------------
3476 
getOffsetFromEffect(const CustomAnimationEffectPtr & pEffect) const3477 sal_Int32 MainSequence::getOffsetFromEffect( const CustomAnimationEffectPtr& pEffect ) const
3478 {
3479     sal_Int32 nOffset = EffectSequenceHelper::getOffsetFromEffect( pEffect );
3480 
3481     if( nOffset != -1 )
3482         return nOffset;
3483 
3484     nOffset = EffectSequenceHelper::getCount();
3485 
3486     InteractiveSequenceList::const_iterator aIter;
3487     for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3488     {
3489         sal_Int32 nTemp = (*aIter)->getOffsetFromEffect( pEffect );
3490         if( nTemp != -1 )
3491             return nOffset + nTemp;
3492 
3493         nOffset += (*aIter)->getCount();
3494     }
3495 
3496     return -1;
3497 }
3498 
3499 // --------------------------------------------------------------------
3500 
getEffectFromOffset(sal_Int32 nOffset) const3501 CustomAnimationEffectPtr MainSequence::getEffectFromOffset( sal_Int32 nOffset ) const
3502 {
3503     if( nOffset >= 0 )
3504     {
3505         if( nOffset < getCount() )
3506             return EffectSequenceHelper::getEffectFromOffset( nOffset );
3507 
3508         nOffset -= getCount();
3509 
3510         InteractiveSequenceList::const_iterator aIter( maInteractiveSequenceList.begin() );
3511 
3512         while( (aIter != maInteractiveSequenceList.end()) && (nOffset > (*aIter)->getCount()) )
3513             nOffset -= (*aIter++)->getCount();
3514 
3515         if( (aIter != maInteractiveSequenceList.end()) && (nOffset >= 0) )
3516             return (*aIter)->getEffectFromOffset( nOffset );
3517     }
3518 
3519     CustomAnimationEffectPtr pEffect;
3520     return pEffect;
3521 }
3522 
3523 // --------------------------------------------------------------------
3524 
disposeShape(const Reference<XShape> & xShape)3525 bool MainSequence::disposeShape( const Reference< XShape >& xShape )
3526 {
3527     bool bChanges = EffectSequenceHelper::disposeShape( xShape );
3528 
3529     InteractiveSequenceList::iterator aIter;
3530     for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end();  )
3531     {
3532             bChanges |= (*aIter++)->disposeShape( xShape );
3533     }
3534 
3535     if( bChanges )
3536         startRebuildTimer();
3537 
3538     return bChanges;
3539 }
3540 
3541 // --------------------------------------------------------------------
3542 
hasEffect(const com::sun::star::uno::Reference<com::sun::star::drawing::XShape> & xShape)3543 bool MainSequence::hasEffect( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape )
3544 {
3545     if( EffectSequenceHelper::hasEffect( xShape ) )
3546         return true;
3547 
3548     InteractiveSequenceList::iterator aIter;
3549     for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end();  )
3550     {
3551         if( (*aIter)->getTriggerShape() == xShape )
3552             return true;
3553 
3554         if( (*aIter++)->hasEffect( xShape ) )
3555             return true;
3556     }
3557 
3558     return false;
3559 }
3560 
3561 // --------------------------------------------------------------------
3562 
insertTextRange(const com::sun::star::uno::Any & aTarget)3563 void MainSequence::insertTextRange( const com::sun::star::uno::Any& aTarget )
3564 {
3565     EffectSequenceHelper::insertTextRange( aTarget );
3566 
3567     InteractiveSequenceList::iterator aIter;
3568     for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3569     {
3570         (*aIter)->insertTextRange( aTarget );
3571     }
3572 }
3573 // --------------------------------------------------------------------
3574 
disposeTextRange(const com::sun::star::uno::Any & aTarget)3575 void MainSequence::disposeTextRange( const com::sun::star::uno::Any& aTarget )
3576 {
3577     EffectSequenceHelper::disposeTextRange( aTarget );
3578 
3579     InteractiveSequenceList::iterator aIter;
3580     for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3581     {
3582         (*aIter)->disposeTextRange( aTarget );
3583     }
3584 }
3585 
3586 // --------------------------------------------------------------------
3587 
3588 /** callback from the sd::View when an object just left text edit mode */
onTextChanged(const Reference<XShape> & xShape)3589 void MainSequence::onTextChanged( const Reference< XShape >& xShape )
3590 {
3591     EffectSequenceHelper::onTextChanged( xShape );
3592 
3593     InteractiveSequenceList::iterator aIter;
3594     for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3595     {
3596         (*aIter)->onTextChanged( xShape );
3597     }
3598 }
3599 
3600 // --------------------------------------------------------------------
3601 
onTextChanged(const Reference<XShape> & xShape)3602 void EffectSequenceHelper::onTextChanged( const Reference< XShape >& xShape )
3603 {
3604     bool bChanges = false;
3605 
3606     EffectSequence::iterator aIter;
3607     for( aIter = maEffects.begin(); aIter != maEffects.end(); aIter++ )
3608     {
3609         if( (*aIter)->getTargetShape() == xShape )
3610             bChanges |= (*aIter)->checkForText();
3611     }
3612 
3613     if( bChanges )
3614         EffectSequenceHelper::implRebuild();
3615 }
3616 
3617 // --------------------------------------------------------------------
3618 
rebuild()3619 void MainSequence::rebuild()
3620 {
3621     startRebuildTimer();
3622 }
3623 
3624 // --------------------------------------------------------------------
3625 
lockRebuilds()3626 void MainSequence::lockRebuilds()
3627 {
3628     mnRebuildLockGuard++;
3629 }
3630 
3631 // --------------------------------------------------------------------
3632 
unlockRebuilds()3633 void MainSequence::unlockRebuilds()
3634 {
3635     DBG_ASSERT( mnRebuildLockGuard, "sd::MainSequence::unlockRebuilds(), no corresponding lockRebuilds() call!" );
3636     if( mnRebuildLockGuard )
3637         mnRebuildLockGuard--;
3638 
3639     if( (mnRebuildLockGuard == 0) && mbPendingRebuildRequest )
3640     {
3641         mbPendingRebuildRequest = false;
3642         startRebuildTimer();
3643     }
3644 }
3645 
3646 // --------------------------------------------------------------------
3647 
implRebuild()3648 void MainSequence::implRebuild()
3649 {
3650     if( mnRebuildLockGuard )
3651     {
3652         mbPendingRebuildRequest = true;
3653         return;
3654     }
3655 
3656     mbRebuilding = true;
3657 
3658     EffectSequenceHelper::implRebuild();
3659 
3660     InteractiveSequenceList::iterator aIter( maInteractiveSequenceList.begin() );
3661     const InteractiveSequenceList::iterator aEnd( maInteractiveSequenceList.end() );
3662     while( aIter != aEnd )
3663     {
3664         InteractiveSequencePtr pIS( (*aIter) );
3665         if( pIS->maEffects.empty() )
3666         {
3667             // remove empty interactive sequences
3668             aIter = maInteractiveSequenceList.erase( aIter );
3669 
3670             Reference< XChild > xChild( mxSequenceRoot, UNO_QUERY_THROW );
3671             Reference< XTimeContainer > xParent( xChild->getParent(), UNO_QUERY_THROW );
3672             Reference< XAnimationNode > xISNode( pIS->mxSequenceRoot, UNO_QUERY_THROW );
3673             xParent->removeChild( xISNode );
3674         }
3675         else
3676         {
3677             pIS->implRebuild();
3678             aIter++;
3679         }
3680     }
3681 
3682     notify_listeners();
3683     mbRebuilding = false;
3684 }
3685 
3686 // --------------------------------------------------------------------
3687 
notify_change()3688 void MainSequence::notify_change()
3689 {
3690     notify_listeners();
3691 }
3692 
3693 // --------------------------------------------------------------------
3694 
setTrigger(const CustomAnimationEffectPtr & pEffect,const::com::sun::star::uno::Reference<::com::sun::star::drawing::XShape> & xTriggerShape)3695 bool MainSequence::setTrigger( const CustomAnimationEffectPtr& pEffect, const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xTriggerShape )
3696 {
3697     EffectSequenceHelper* pOldSequence = pEffect->getEffectSequence();
3698 
3699     EffectSequenceHelper* pNewSequence = 0;
3700     if( xTriggerShape.is() )
3701     {
3702         InteractiveSequenceList::iterator aIter( maInteractiveSequenceList.begin() );
3703         const InteractiveSequenceList::iterator aEnd( maInteractiveSequenceList.end() );
3704         while( aIter != aEnd )
3705         {
3706             InteractiveSequencePtr pIS( (*aIter++) );
3707             if( pIS->getTriggerShape() == xTriggerShape )
3708             {
3709                 pNewSequence = pIS.get();
3710                 break;
3711             }
3712         }
3713 
3714         if( !pNewSequence )
3715             pNewSequence = createInteractiveSequence( xTriggerShape ).get();
3716     }
3717     else
3718     {
3719         pNewSequence = this;
3720     }
3721 
3722     if( pOldSequence != pNewSequence )
3723     {
3724         if( pOldSequence )
3725             pOldSequence->maEffects.remove( pEffect );
3726         if( pNewSequence )
3727             pNewSequence->maEffects.push_back( pEffect );
3728         pEffect->setEffectSequence( pNewSequence );
3729         return true;
3730     }
3731     else
3732     {
3733         return false;
3734     }
3735 
3736 }
3737 
3738 // --------------------------------------------------------------------
3739 
IMPL_LINK(MainSequence,onTimerHdl,Timer *,EMPTYARG)3740 IMPL_LINK( MainSequence, onTimerHdl, Timer *, EMPTYARG )
3741 {
3742     if( mbTimerMode )
3743     {
3744         implRebuild();
3745     }
3746     else
3747     {
3748         reset();
3749         createMainSequence();
3750     }
3751 
3752     return 0;
3753 }
3754 
3755 // --------------------------------------------------------------------
3756 
3757 /** starts a timer that recreates the internal structure from the API core after 1 second */
startRecreateTimer()3758 void MainSequence::startRecreateTimer()
3759 {
3760     if( !mbRebuilding && (mbIgnoreChanges == 0) )
3761     {
3762         mbTimerMode = false;
3763         maTimer.Start();
3764     }
3765 }
3766 
3767 // --------------------------------------------------------------------
3768 
3769 /** starts a timer that rebuilds the API core from the internal structure after 1 second */
startRebuildTimer()3770 void MainSequence::startRebuildTimer()
3771 {
3772     mbTimerMode = true;
3773     maTimer.Start();
3774 }
3775 
3776 // ====================================================================
3777 
InteractiveSequence(const Reference<XTimeContainer> & xSequenceRoot,MainSequence * pMainSequence)3778 InteractiveSequence::InteractiveSequence( const Reference< XTimeContainer >& xSequenceRoot, MainSequence* pMainSequence )
3779 : EffectSequenceHelper( xSequenceRoot ), mpMainSequence( pMainSequence )
3780 {
3781     mnSequenceType = EffectNodeType::INTERACTIVE_SEQUENCE;
3782 
3783     try
3784     {
3785         if( mxSequenceRoot.is() )
3786         {
3787             Reference< XEnumerationAccess > xEnumerationAccess( mxSequenceRoot, UNO_QUERY_THROW );
3788             Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3789             while( !mxEventSource.is() && xEnumeration->hasMoreElements() )
3790             {
3791                 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3792 
3793                 Event aEvent;
3794                 if( (xChildNode->getBegin() >>= aEvent) && (aEvent.Trigger == EventTrigger::ON_CLICK) )
3795                     aEvent.Source >>= mxEventSource;
3796             }
3797         }
3798     }
3799     catch( Exception& e )
3800     {
3801         (void)e;
3802         DBG_ERROR( "sd::InteractiveSequence::InteractiveSequence(), exception caught!" );
3803         return;
3804     }
3805 }
3806 
3807 // --------------------------------------------------------------------
3808 
rebuild()3809 void InteractiveSequence::rebuild()
3810 {
3811     mpMainSequence->rebuild();
3812 }
3813 
implRebuild()3814 void InteractiveSequence::implRebuild()
3815 {
3816     EffectSequenceHelper::implRebuild();
3817 }
3818 
3819 // --------------------------------------------------------------------
3820 
MainSequenceRebuildGuard(const MainSequencePtr & pMainSequence)3821 MainSequenceRebuildGuard::MainSequenceRebuildGuard( const MainSequencePtr& pMainSequence )
3822 : mpMainSequence( pMainSequence )
3823 {
3824     if( mpMainSequence.get() )
3825         mpMainSequence->lockRebuilds();
3826 }
3827 
~MainSequenceRebuildGuard()3828 MainSequenceRebuildGuard::~MainSequenceRebuildGuard()
3829 {
3830     if( mpMainSequence.get() )
3831         mpMainSequence->unlockRebuilds();
3832 }
3833 
3834 
3835 }
3836