xref: /AOO41X/main/sd/source/core/CustomAnimationEffect.cxx (revision fe22d2cfc602815794415026f1317bd625db6f83)
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 cought!" );
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 cought!" );
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 cought!" );
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 cought!" );
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 cought!" );
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 cought!" );
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 cought!" );
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 cought!" );
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 throw (Exception)
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 cought!" );
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 cought!" );
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 cought!" );
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 cought!" );
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 cought!" );
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 cought!" );
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 cought!" );
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 cought!" );
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 cought!" );
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 cought!" );
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                     // thats 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 cought!" );
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 cought!" );
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 explicitely
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 cought!" );
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  throw(Exception)
2151 {
2152     Reference< XEnumerationAccess > xEnumerationAccess( xParent, UNO_QUERY_THROW );
2153     Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration() );
2154     if( xEnumeration.is() )
2155     {
2156         Reference< XInterface > x;
2157         while( xEnumeration->hasMoreElements() && !xNext.is() )
2158         {
2159             if( (xEnumeration->nextElement() >>= x) && (x == xCurrent) )
2160             {
2161                 if( xEnumeration->hasMoreElements() )
2162                     xEnumeration->nextElement() >>= xNext;
2163             }
2164         }
2165     }
2166     return xNext.is();
2167 }
2168 
2169 // --------------------------------------------------------------------
2170 
stl_process_after_effect_node_func(AfterEffectNode & rNode)2171 void stl_process_after_effect_node_func(AfterEffectNode& rNode)
2172 {
2173     try
2174     {
2175         if( rNode.mxNode.is() && rNode.mxMaster.is() )
2176         {
2177             // set master node
2178             Reference< XAnimationNode > xMasterNode( rNode.mxMaster, UNO_QUERY_THROW );
2179             Sequence< NamedValue > aUserData( rNode.mxNode->getUserData() );
2180             sal_Int32 nSize = aUserData.getLength();
2181             aUserData.realloc(nSize+1);
2182             aUserData[nSize].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "master-element" ) );
2183             aUserData[nSize].Value <<= xMasterNode;
2184             rNode.mxNode->setUserData( aUserData );
2185 
2186             // insert after effect node into timeline
2187             Reference< XTimeContainer > xContainer( rNode.mxMaster->getParent(), UNO_QUERY_THROW );
2188 
2189             if( !rNode.mbOnNextEffect ) // sameClick
2190             {
2191                 // insert the aftereffect after its effect is animated
2192                 xContainer->insertAfter( rNode.mxNode, rNode.mxMaster );
2193             }
2194             else // nextClick
2195             {
2196                 Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() );
2197                 // insert the aftereffect in the next group
2198 
2199                 Reference< XTimeContainer > xClickContainer( xContainer->getParent(), UNO_QUERY_THROW );
2200                 Reference< XTimeContainer > xSequenceContainer( xClickContainer->getParent(), UNO_QUERY_THROW );
2201 
2202                 Reference< XTimeContainer > xNextContainer;
2203 
2204                 // first try if we have an after effect container
2205                 if( !implFindNextContainer( xClickContainer, xContainer, xNextContainer ) )
2206                 {
2207                     Reference< XTimeContainer > xNextClickContainer;
2208                     // if not, try to find the next click effect container
2209                     if( implFindNextContainer( xSequenceContainer, xClickContainer, xNextClickContainer ) )
2210                     {
2211                         Reference< XEnumerationAccess > xEnumerationAccess( xNextClickContainer, UNO_QUERY_THROW );
2212                         Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
2213                         if( xEnumeration->hasMoreElements() )
2214                         {
2215                             // the next container is the first child container
2216                             xEnumeration->nextElement() >>= xNextContainer;
2217                         }
2218                         else
2219                         {
2220                             // this does not yet have a child container, create one
2221                             const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.ParallelTimeContainer") );
2222                             xNextContainer = Reference< XTimeContainer >::query( xMsf->createInstance(aServiceName) );
2223 
2224                             if( xNextContainer.is() )
2225                             {
2226                                 Reference< XAnimationNode > xNode( xNextContainer, UNO_QUERY_THROW );
2227                                 xNode->setBegin( makeAny( (double)0.0 ) );
2228 //                              xNode->setFill( AnimationFill::HOLD );
2229                                 xNextClickContainer->appendChild( xNode );
2230                             }
2231                         }
2232                         DBG_ASSERT( xNextContainer.is(), "ppt::stl_process_after_effect_node_func::operator(), could not find/create container!" );
2233                     }
2234                 }
2235 
2236                 // if we don't have a next container, we add one to the sequence container
2237                 if( !xNextContainer.is() )
2238                 {
2239                     const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.ParallelTimeContainer") );
2240                     Reference< XTimeContainer > xNewClickContainer( xMsf->createInstance(aServiceName), UNO_QUERY_THROW );
2241 
2242                     Reference< XAnimationNode > xNewClickNode( xNewClickContainer, UNO_QUERY_THROW );
2243 
2244                     Event aEvent;
2245                     aEvent.Trigger = EventTrigger::ON_NEXT;
2246                     aEvent.Repeat = 0;
2247                     xNewClickNode->setBegin( makeAny( aEvent ) );
2248 
2249                     Reference< XAnimationNode > xRefNode( xClickContainer, UNO_QUERY_THROW );
2250                     xSequenceContainer->insertAfter( xNewClickNode, xRefNode );
2251 
2252                     xNextContainer = Reference< XTimeContainer >::query( xMsf->createInstance(aServiceName) );
2253 
2254                     DBG_ASSERT( xNextContainer.is(), "ppt::stl_process_after_effect_node_func::operator(), could not create container!" );
2255                     if( xNextContainer.is() )
2256                     {
2257                         Reference< XAnimationNode > xNode( xNextContainer, UNO_QUERY_THROW );
2258                         xNode->setBegin( makeAny( (double)0.0 ) );
2259 //                      xNode->setFill( AnimationFill::HOLD );
2260                         xNewClickContainer->appendChild( xNode );
2261                     }
2262                 }
2263 
2264                 if( xNextContainer.is() )
2265                 {
2266                     // find begin time of first element
2267                     Reference< XEnumerationAccess > xEnumerationAccess( xNextContainer, UNO_QUERY_THROW );
2268                     Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
2269                     if( xEnumeration->hasMoreElements() )
2270                     {
2271                         Reference< XAnimationNode > xChild;
2272                         // the next container is the first child container
2273                         xEnumeration->nextElement() >>= xChild;
2274                         if( xChild.is() )
2275                         {
2276                             Any aBegin( xChild->getBegin() );
2277                             double fBegin = 0.0;
2278                             if( (aBegin >>= fBegin) && (fBegin >= 0.0))
2279                                 rNode.mxNode->setBegin( aBegin );
2280                         }
2281                     }
2282 
2283                     xNextContainer->appendChild( rNode.mxNode );
2284                 }
2285             }
2286         }
2287     }
2288     catch( Exception& e )
2289     {
2290         (void)e;
2291         DBG_ERROR( "ppt::stl_process_after_effect_node_func::operator(), exception cought!" );
2292     }
2293 }
2294 
2295 // --------------------------------------------------------------------
2296 
find(const CustomAnimationEffectPtr & pEffect)2297 EffectSequence::iterator EffectSequenceHelper::find( const CustomAnimationEffectPtr& pEffect )
2298 {
2299     return std::find( maEffects.begin(), maEffects.end(), pEffect );
2300 }
2301 
2302 // --------------------------------------------------------------------
2303 
findEffect(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode) const2304 CustomAnimationEffectPtr EffectSequenceHelper::findEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) const
2305 {
2306     CustomAnimationEffectPtr pEffect;
2307 
2308     EffectSequence::const_iterator aIter( maEffects.begin() );
2309     for( ; aIter != maEffects.end(); aIter++ )
2310     {
2311         if( (*aIter)->getNode() == xNode )
2312         {
2313             pEffect = (*aIter);
2314             break;
2315         }
2316     }
2317 
2318     return pEffect;
2319 }
2320 
2321 // --------------------------------------------------------------------
2322 
getOffsetFromEffect(const CustomAnimationEffectPtr & xEffect) const2323 sal_Int32 EffectSequenceHelper::getOffsetFromEffect( const CustomAnimationEffectPtr& xEffect ) const
2324 {
2325     sal_Int32 nOffset = 0;
2326 
2327     EffectSequence::const_iterator aIter( maEffects.begin() );
2328     for( ; aIter != maEffects.end(); aIter++, nOffset++ )
2329     {
2330         if( (*aIter) == xEffect )
2331             return nOffset;
2332     }
2333 
2334     return -1;
2335 }
2336 
2337 // --------------------------------------------------------------------
2338 
getEffectFromOffset(sal_Int32 nOffset) const2339 CustomAnimationEffectPtr EffectSequenceHelper::getEffectFromOffset( sal_Int32 nOffset ) const
2340 {
2341     EffectSequence::const_iterator aIter( maEffects.begin() );
2342     while( nOffset-- && aIter != maEffects.end() )
2343         aIter++;
2344 
2345     CustomAnimationEffectPtr pEffect;
2346     if( aIter != maEffects.end() )
2347         pEffect = (*aIter);
2348 
2349     return pEffect;
2350 }
2351 
2352 // --------------------------------------------------------------------
2353 
disposeShape(const Reference<XShape> & xShape)2354 bool EffectSequenceHelper::disposeShape( const Reference< XShape >& xShape )
2355 {
2356     bool bChanges = false;
2357 
2358     EffectSequence::iterator aIter( maEffects.begin() );
2359     while( aIter != maEffects.end() )
2360     {
2361         if( (*aIter)->getTargetShape() == xShape )
2362         {
2363             (*aIter)->setEffectSequence( 0 );
2364             bChanges = true;
2365             aIter = maEffects.erase( aIter );
2366         }
2367         else
2368         {
2369             aIter++;
2370         }
2371     }
2372 
2373     return bChanges;
2374 }
2375 
2376 // --------------------------------------------------------------------
2377 
hasEffect(const com::sun::star::uno::Reference<com::sun::star::drawing::XShape> & xShape)2378 bool EffectSequenceHelper::hasEffect( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape )
2379 {
2380     EffectSequence::iterator aIter( maEffects.begin() );
2381     while( aIter != maEffects.end() )
2382     {
2383         if( (*aIter)->getTargetShape() == xShape )
2384             return true;
2385         aIter++;
2386     }
2387 
2388     return false;
2389 }
2390 
2391 // --------------------------------------------------------------------
2392 
insertTextRange(const com::sun::star::uno::Any & aTarget)2393 void EffectSequenceHelper::insertTextRange( const com::sun::star::uno::Any& aTarget )
2394 {
2395     bool bChanges = false;
2396 
2397     ParagraphTarget aParaTarget;
2398     if( !(aTarget >>= aParaTarget ) )
2399         return;
2400 
2401     EffectSequence::iterator aIter( maEffects.begin() );
2402     while( aIter != maEffects.end() )
2403     {
2404         if( (*aIter)->getTargetShape() == aParaTarget.Shape )
2405             bChanges |= (*aIter)->checkForText();
2406         aIter++;
2407     }
2408 
2409     if( bChanges )
2410         rebuild();
2411 }
2412 
2413 // --------------------------------------------------------------------
2414 
disposeTextRange(const com::sun::star::uno::Any & aTarget)2415 void EffectSequenceHelper::disposeTextRange( const com::sun::star::uno::Any& aTarget )
2416 {
2417     ParagraphTarget aParaTarget;
2418     if( !(aTarget >>= aParaTarget ) )
2419         return;
2420 
2421     bool bChanges = false;
2422     bool bErased = false;
2423 
2424     EffectSequence::iterator aIter( maEffects.begin() );
2425     while( aIter != maEffects.end() )
2426     {
2427         Any aIterTarget( (*aIter)->getTarget() );
2428         if( aIterTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2429         {
2430             ParagraphTarget aIterParaTarget;
2431             if( (aIterTarget >>= aIterParaTarget) && (aIterParaTarget.Shape == aParaTarget.Shape) )
2432             {
2433                 if( aIterParaTarget.Paragraph == aParaTarget.Paragraph )
2434                 {
2435                     // delete this effect if it targets the disposed paragraph directly
2436                     (*aIter)->setEffectSequence( 0 );
2437                     aIter = maEffects.erase( aIter );
2438                     bChanges = true;
2439                     bErased = true;
2440                 }
2441                 else
2442                 {
2443                     if( aIterParaTarget.Paragraph > aParaTarget.Paragraph )
2444                     {
2445                         // shift all paragraphs after disposed paragraph
2446                         aIterParaTarget.Paragraph--;
2447                         (*aIter)->setTarget( makeAny( aIterParaTarget ) );
2448                     }
2449                 }
2450             }
2451         }
2452         else if( (*aIter)->getTargetShape() == aParaTarget.Shape )
2453         {
2454             bChanges |= (*aIter)->checkForText();
2455         }
2456 
2457         if( bErased )
2458             bErased = false;
2459         else
2460             aIter++;
2461     }
2462 
2463     if( bChanges )
2464         rebuild();
2465 }
2466 
2467 // --------------------------------------------------------------------
2468 
CustomAnimationTextGroup(const Reference<XShape> & rTarget,sal_Int32 nGroupId)2469 CustomAnimationTextGroup::CustomAnimationTextGroup( const Reference< XShape >& rTarget, sal_Int32 nGroupId )
2470 :   maTarget( rTarget ),
2471     mnGroupId( nGroupId )
2472 {
2473     reset();
2474 }
2475 
2476 // --------------------------------------------------------------------
2477 
reset()2478 void CustomAnimationTextGroup::reset()
2479 {
2480     mnTextGrouping = -1;
2481     mbAnimateForm = false;
2482     mbTextReverse = false;
2483     mfGroupingAuto = -1.0;
2484     mnLastPara = -1; // used to check for TextReverse
2485 
2486     int i = 5;
2487     while( i-- ) mnDepthFlags[i] = 0;
2488 
2489     maEffects.clear();
2490 }
2491 
2492 // --------------------------------------------------------------------
2493 
addEffect(CustomAnimationEffectPtr & pEffect)2494 void CustomAnimationTextGroup::addEffect( CustomAnimationEffectPtr& pEffect )
2495 {
2496     maEffects.push_back( pEffect );
2497 
2498     Any aTarget( pEffect->getTarget() );
2499     if( aTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2500     {
2501         // now look at the paragraph
2502         ParagraphTarget aParaTarget;
2503         aTarget >>= aParaTarget;
2504 
2505         if( mnLastPara != -1 )
2506             mbTextReverse = mnLastPara > aParaTarget.Paragraph;
2507 
2508         mnLastPara = aParaTarget.Paragraph;
2509 
2510         const sal_Int32 nParaDepth = pEffect->getParaDepth();
2511 
2512         // only look at the first 5 levels
2513         if( nParaDepth < 5 )
2514         {
2515             // our first paragraph with this level?
2516             if( mnDepthFlags[nParaDepth] == 0 )
2517             {
2518                 // so set it to the first found
2519                 mnDepthFlags[nParaDepth] = (sal_Int8)pEffect->getNodeType();
2520             }
2521             else if( mnDepthFlags[nParaDepth] != pEffect->getNodeType() )
2522             {
2523                 mnDepthFlags[nParaDepth] = -1;
2524             }
2525 
2526             if( pEffect->getNodeType() == EffectNodeType::AFTER_PREVIOUS )
2527                 mfGroupingAuto = pEffect->getBegin();
2528 
2529             mnTextGrouping = 0;
2530             while( (mnTextGrouping < 5) && (mnDepthFlags[mnTextGrouping] > 0) )
2531                 mnTextGrouping++;
2532         }
2533     }
2534     else
2535     {
2536         // if we have an effect with the shape as a target, we animate the background
2537         mbAnimateForm = pEffect->getTargetSubItem() != ShapeAnimationSubType::ONLY_TEXT;
2538     }
2539 }
2540 
2541 // --------------------------------------------------------------------
2542 
2543 class TextGroupMapImpl : public std::map< sal_Int32, CustomAnimationTextGroup* >
2544 {
2545 public:
2546     CustomAnimationTextGroup* findGroup( sal_Int32 nGroupId );
2547 };
2548 
2549 // --------------------------------------------------------------------
2550 
findGroup(sal_Int32 nGroupId)2551 CustomAnimationTextGroupPtr EffectSequenceHelper::findGroup( sal_Int32 nGroupId )
2552 {
2553     CustomAnimationTextGroupPtr aPtr;
2554 
2555     CustomAnimationTextGroupMap::iterator aIter( maGroupMap.find( nGroupId ) );
2556     if( aIter != maGroupMap.end() )
2557         aPtr = (*aIter).second;
2558 
2559     return aPtr;
2560 }
2561 
2562 // --------------------------------------------------------------------
2563 
updateTextGroups()2564 void EffectSequenceHelper::updateTextGroups()
2565 {
2566     maGroupMap.clear();
2567 
2568     // first create all the groups
2569     EffectSequence::iterator aIter( maEffects.begin() );
2570     const EffectSequence::iterator aEnd( maEffects.end() );
2571     while( aIter != aEnd )
2572     {
2573         CustomAnimationEffectPtr pEffect( (*aIter++) );
2574 
2575         const sal_Int32 nGroupId = pEffect->getGroupId();
2576 
2577         if( nGroupId == -1 )
2578             continue; // trivial case, no group
2579 
2580         CustomAnimationTextGroupPtr pGroup = findGroup( nGroupId );
2581         if( !pGroup.get() )
2582         {
2583             pGroup.reset( new CustomAnimationTextGroup( pEffect->getTargetShape(), nGroupId ) );
2584             maGroupMap[nGroupId] = pGroup;
2585         }
2586 
2587         pGroup->addEffect( pEffect );
2588     }
2589 }
2590 
2591 // --------------------------------------------------------------------
2592 
createTextGroup(CustomAnimationEffectPtr pEffect,sal_Int32 nTextGrouping,double fTextGroupingAuto,sal_Bool bAnimateForm,sal_Bool bTextReverse)2593 CustomAnimationTextGroupPtr EffectSequenceHelper::createTextGroup( CustomAnimationEffectPtr pEffect, sal_Int32 nTextGrouping, double fTextGroupingAuto, sal_Bool bAnimateForm, sal_Bool bTextReverse )
2594 {
2595     // first finde a free group-id
2596     sal_Int32 nGroupId = 0;
2597 
2598     CustomAnimationTextGroupMap::iterator aIter( maGroupMap.begin() );
2599     const CustomAnimationTextGroupMap::iterator aEnd( maGroupMap.end() );
2600     while( aIter != aEnd )
2601     {
2602         if( (*aIter).first == nGroupId )
2603         {
2604             nGroupId++;
2605             aIter = maGroupMap.begin();
2606         }
2607         else
2608         {
2609             aIter++;
2610         }
2611     }
2612 
2613     Reference< XShape > xTarget( pEffect->getTargetShape() );
2614 
2615     CustomAnimationTextGroupPtr pTextGroup( new CustomAnimationTextGroup( xTarget, nGroupId ) );
2616     maGroupMap[nGroupId] = pTextGroup;
2617 
2618     bool bUsed = false;
2619 
2620     // do we need to target the shape?
2621     if( (nTextGrouping == 0) || bAnimateForm )
2622     {
2623         sal_Int16 nSubItem;
2624         if( nTextGrouping == 0)
2625             nSubItem = bAnimateForm ? ShapeAnimationSubType::AS_WHOLE : ShapeAnimationSubType::ONLY_TEXT;
2626         else
2627             nSubItem = ShapeAnimationSubType::ONLY_BACKGROUND;
2628 
2629         pEffect->setTarget( makeAny( xTarget ) );
2630         pEffect->setTargetSubItem( nSubItem );
2631         pEffect->setEffectSequence( this );
2632         pEffect->setGroupId( nGroupId );
2633 
2634         pTextGroup->addEffect( pEffect );
2635         bUsed = true;
2636     }
2637 
2638     pTextGroup->mnTextGrouping = nTextGrouping;
2639     pTextGroup->mfGroupingAuto = fTextGroupingAuto;
2640     pTextGroup->mbTextReverse = bTextReverse;
2641 
2642     // now add an effect for each paragraph
2643     createTextGroupParagraphEffects( pTextGroup, pEffect, bUsed );
2644 
2645     notify_listeners();
2646 
2647     return pTextGroup;
2648 }
2649 
2650 // --------------------------------------------------------------------
2651 
createTextGroupParagraphEffects(CustomAnimationTextGroupPtr pTextGroup,CustomAnimationEffectPtr pEffect,bool bUsed)2652 void EffectSequenceHelper::createTextGroupParagraphEffects( CustomAnimationTextGroupPtr pTextGroup, CustomAnimationEffectPtr pEffect, bool bUsed )
2653 {
2654     Reference< XShape > xTarget( pTextGroup->maTarget );
2655 
2656     sal_Int32 nTextGrouping = pTextGroup->mnTextGrouping;
2657     double fTextGroupingAuto = pTextGroup->mfGroupingAuto;
2658     sal_Bool bTextReverse = pTextGroup->mbTextReverse;
2659 
2660     // now add an effect for each paragraph
2661     if( nTextGrouping >= 0 ) try
2662     {
2663         EffectSequence::iterator aInsertIter( find( pEffect ) );
2664 
2665         const OUString strNumberingLevel( RTL_CONSTASCII_USTRINGPARAM("NumberingLevel") );
2666         Reference< XEnumerationAccess > xText( xTarget, UNO_QUERY_THROW );
2667         Reference< XEnumeration > xEnumeration( xText->createEnumeration(), UNO_QUERY_THROW );
2668 
2669         std::list< sal_Int16 > aParaList;
2670         sal_Int16 nPara;
2671 
2672         // fill the list with all valid paragraphs
2673         for( nPara = 0; xEnumeration->hasMoreElements(); nPara++ )
2674         {
2675             Reference< XTextRange > xRange( xEnumeration->nextElement(), UNO_QUERY );
2676             if( xRange.is() && xRange->getString().getLength() )
2677             {
2678                 if( bTextReverse ) // sort them
2679                     aParaList.push_front( nPara );
2680                 else
2681                     aParaList.push_back( nPara );
2682             }
2683         }
2684 
2685         ParagraphTarget aTarget;
2686         aTarget.Shape = xTarget;
2687 
2688         std::list< sal_Int16 >::iterator aIter( aParaList.begin() );
2689         std::list< sal_Int16 >::iterator aEnd( aParaList.end() );
2690         while( aIter != aEnd )
2691         {
2692             aTarget.Paragraph = (*aIter++);
2693 
2694             CustomAnimationEffectPtr pNewEffect;
2695             if( bUsed )
2696             {
2697                 // clone a new effect from first effect
2698                 pNewEffect = pEffect->clone();
2699                 ++aInsertIter;
2700                 aInsertIter = maEffects.insert( aInsertIter, pNewEffect );
2701             }
2702             else
2703             {
2704                 // reuse first effect if its not yet used
2705                 pNewEffect = pEffect;
2706                 bUsed = true;
2707                 aInsertIter = find( pNewEffect );
2708             }
2709 
2710             // set target and group-id
2711             pNewEffect->setTarget( makeAny( aTarget ) );
2712             pNewEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT );
2713             pNewEffect->setGroupId( pTextGroup->mnGroupId );
2714             pNewEffect->setEffectSequence( this );
2715 
2716             // set correct node type
2717             if( pNewEffect->getParaDepth() < nTextGrouping )
2718             {
2719                 if( fTextGroupingAuto == -1.0 )
2720                 {
2721                     pNewEffect->setNodeType( EffectNodeType::ON_CLICK );
2722                     pNewEffect->setBegin( 0.0 );
2723                 }
2724                 else
2725                 {
2726                     pNewEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2727                     pNewEffect->setBegin( fTextGroupingAuto );
2728                 }
2729             }
2730             else
2731             {
2732                 pNewEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2733                 pNewEffect->setBegin( 0.0 );
2734             }
2735 
2736             pTextGroup->addEffect( pNewEffect );
2737         }
2738         notify_listeners();
2739     }
2740     catch( Exception& e )
2741     {
2742         (void)e;
2743         DBG_ERROR("sd::EffectSequenceHelper::createTextGroup(), exception cought!" );
2744     }
2745 }
2746 
2747 // --------------------------------------------------------------------
2748 
setTextGrouping(CustomAnimationTextGroupPtr pTextGroup,sal_Int32 nTextGrouping)2749 void EffectSequenceHelper::setTextGrouping( CustomAnimationTextGroupPtr pTextGroup, sal_Int32 nTextGrouping )
2750 {
2751     if( pTextGroup->mnTextGrouping == nTextGrouping )
2752     {
2753         // first case, trivial case, do nothing
2754     }
2755     else if( (pTextGroup->mnTextGrouping == -1) && (nTextGrouping >= 0) )
2756     {
2757         // second case, we need to add new effects for each paragraph
2758 
2759         CustomAnimationEffectPtr pEffect( pTextGroup->maEffects.front() );
2760 
2761         pTextGroup->mnTextGrouping = nTextGrouping;
2762         createTextGroupParagraphEffects( pTextGroup, pEffect, true );
2763         notify_listeners();
2764     }
2765     else if( (pTextGroup->mnTextGrouping >= 0) && (nTextGrouping == -1 ) )
2766     {
2767         // third case, we need to remove effects for each paragraph
2768 
2769         EffectSequence aEffects( pTextGroup->maEffects );
2770         pTextGroup->reset();
2771 
2772         EffectSequence::iterator aIter( aEffects.begin() );
2773         const EffectSequence::iterator aEnd( aEffects.end() );
2774         while( aIter != aEnd )
2775         {
2776             CustomAnimationEffectPtr pEffect( (*aIter++) );
2777 
2778             if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2779                 remove( pEffect );
2780             else
2781                 pTextGroup->addEffect( pEffect );
2782         }
2783         notify_listeners();
2784     }
2785     else
2786     {
2787         // fourth case, we need to change the node types for the text nodes
2788         double fTextGroupingAuto = pTextGroup->mfGroupingAuto;
2789 
2790         EffectSequence aEffects( pTextGroup->maEffects );
2791         pTextGroup->reset();
2792 
2793         EffectSequence::iterator aIter( aEffects.begin() );
2794         const EffectSequence::iterator aEnd( aEffects.end() );
2795         while( aIter != aEnd )
2796         {
2797             CustomAnimationEffectPtr pEffect( (*aIter++) );
2798 
2799             if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2800             {
2801                 // set correct node type
2802                 if( pEffect->getParaDepth() < nTextGrouping )
2803                 {
2804                     if( fTextGroupingAuto == -1.0 )
2805                     {
2806                         pEffect->setNodeType( EffectNodeType::ON_CLICK );
2807                         pEffect->setBegin( 0.0 );
2808                     }
2809                     else
2810                     {
2811                         pEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2812                         pEffect->setBegin( fTextGroupingAuto );
2813                     }
2814                 }
2815                 else
2816                 {
2817                     pEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2818                     pEffect->setBegin( 0.0 );
2819                 }
2820             }
2821 
2822             pTextGroup->addEffect( pEffect );
2823 
2824         }
2825         notify_listeners();
2826     }
2827 }
2828 
2829 // --------------------------------------------------------------------
2830 
setAnimateForm(CustomAnimationTextGroupPtr pTextGroup,sal_Bool bAnimateForm)2831 void EffectSequenceHelper::setAnimateForm( CustomAnimationTextGroupPtr pTextGroup, sal_Bool bAnimateForm )
2832 {
2833     if( pTextGroup->mbAnimateForm == bAnimateForm )
2834     {
2835         // trivial case, do nothing
2836     }
2837     else
2838     {
2839         EffectSequence aEffects( pTextGroup->maEffects );
2840         pTextGroup->reset();
2841 
2842         EffectSequence::iterator aIter( aEffects.begin() );
2843         const EffectSequence::iterator aEnd( aEffects.end() );
2844 
2845         // first insert if we have to
2846         if( bAnimateForm )
2847         {
2848             EffectSequence::iterator aInsertIter( find( (*aIter) ) );
2849 
2850             CustomAnimationEffectPtr pEffect;
2851             if( (aEffects.size() == 1) && ((*aIter)->getTarget().getValueType() != ::getCppuType((const ParagraphTarget*)0) ) )
2852             {
2853                 // special case, only one effect and that targets whole text,
2854                 // convert this to target whole shape
2855                 pEffect = (*aIter++);
2856                 pEffect->setTargetSubItem( ShapeAnimationSubType::AS_WHOLE );
2857             }
2858             else
2859             {
2860                 pEffect = (*aIter)->clone();
2861                 pEffect->setTarget( makeAny( (*aIter)->getTargetShape() ) );
2862                 pEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_BACKGROUND );
2863                 maEffects.insert( aInsertIter, pEffect );
2864             }
2865 
2866             pTextGroup->addEffect( pEffect );
2867         }
2868 
2869         if( !bAnimateForm && (aEffects.size() == 1) )
2870         {
2871             CustomAnimationEffectPtr pEffect( (*aIter) );
2872             pEffect->setTarget( makeAny( (*aIter)->getTargetShape() ) );
2873             pEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT );
2874             pTextGroup->addEffect( pEffect );
2875         }
2876         else
2877         {
2878             // readd the rest to the group again
2879             while( aIter != aEnd )
2880             {
2881                 CustomAnimationEffectPtr pEffect( (*aIter++) );
2882 
2883                 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2884                 {
2885                     pTextGroup->addEffect( pEffect );
2886                 }
2887                 else
2888                 {
2889                     DBG_ASSERT( !bAnimateForm, "sd::EffectSequenceHelper::setAnimateForm(), something is wrong here!" );
2890                     remove( pEffect );
2891                 }
2892             }
2893         }
2894         notify_listeners();
2895     }
2896 }
2897 
2898 // --------------------------------------------------------------------
2899 
setTextGroupingAuto(CustomAnimationTextGroupPtr pTextGroup,double fTextGroupingAuto)2900 void EffectSequenceHelper::setTextGroupingAuto( CustomAnimationTextGroupPtr pTextGroup, double fTextGroupingAuto )
2901 {
2902     sal_Int32 nTextGrouping = pTextGroup->mnTextGrouping;
2903 
2904     EffectSequence aEffects( pTextGroup->maEffects );
2905     pTextGroup->reset();
2906 
2907     EffectSequence::iterator aIter( aEffects.begin() );
2908     const EffectSequence::iterator aEnd( aEffects.end() );
2909     while( aIter != aEnd )
2910     {
2911         CustomAnimationEffectPtr pEffect( (*aIter++) );
2912 
2913         if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2914         {
2915             // set correct node type
2916             if( pEffect->getParaDepth() < nTextGrouping )
2917             {
2918                 if( fTextGroupingAuto == -1.0 )
2919                 {
2920                     pEffect->setNodeType( EffectNodeType::ON_CLICK );
2921                     pEffect->setBegin( 0.0 );
2922                 }
2923                 else
2924                 {
2925                     pEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2926                     pEffect->setBegin( fTextGroupingAuto );
2927                 }
2928             }
2929             else
2930             {
2931                 pEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2932                 pEffect->setBegin( 0.0 );
2933             }
2934         }
2935 
2936         pTextGroup->addEffect( pEffect );
2937 
2938     }
2939     notify_listeners();
2940 }
2941 
2942 // --------------------------------------------------------------------
2943 
2944 struct ImplStlTextGroupSortHelper
2945 {
ImplStlTextGroupSortHelpersd::ImplStlTextGroupSortHelper2946     ImplStlTextGroupSortHelper( bool bReverse ) : mbReverse( bReverse ) {};
2947     bool operator()( const CustomAnimationEffectPtr& p1, const CustomAnimationEffectPtr& p2 );
2948     bool mbReverse;
2949     sal_Int32 getTargetParagraph( const CustomAnimationEffectPtr& p1 );
2950 };
2951 
2952 // --------------------------------------------------------------------
2953 
getTargetParagraph(const CustomAnimationEffectPtr & p1)2954 sal_Int32 ImplStlTextGroupSortHelper::getTargetParagraph( const CustomAnimationEffectPtr& p1 )
2955 {
2956     const Any aTarget(p1->getTarget());
2957     if( aTarget.hasValue() && aTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2958     {
2959         ParagraphTarget aParaTarget;
2960         aTarget >>= aParaTarget;
2961         return aParaTarget.Paragraph;
2962     }
2963     else
2964     {
2965         return mbReverse ? 0x7fffffff : -1;
2966     }
2967 }
2968 
2969 // --------------------------------------------------------------------
2970 
operator ()(const CustomAnimationEffectPtr & p1,const CustomAnimationEffectPtr & p2)2971 bool ImplStlTextGroupSortHelper::operator()( const CustomAnimationEffectPtr& p1, const CustomAnimationEffectPtr& p2 )
2972 {
2973     if( mbReverse )
2974     {
2975         return getTargetParagraph( p2 ) < getTargetParagraph( p1 );
2976     }
2977     else
2978     {
2979         return getTargetParagraph( p1 ) < getTargetParagraph( p2 );
2980     }
2981 }
2982 
2983 // --------------------------------------------------------------------
2984 
setTextReverse(CustomAnimationTextGroupPtr pTextGroup,sal_Bool bTextReverse)2985 void EffectSequenceHelper::setTextReverse( CustomAnimationTextGroupPtr pTextGroup, sal_Bool bTextReverse )
2986 {
2987     if( pTextGroup->mbTextReverse == bTextReverse )
2988     {
2989         // do nothing
2990     }
2991     else
2992     {
2993         std::vector< CustomAnimationEffectPtr > aSortedVector(pTextGroup->maEffects.size());
2994         std::copy( pTextGroup->maEffects.begin(), pTextGroup->maEffects.end(), aSortedVector.begin() );
2995         ImplStlTextGroupSortHelper aSortHelper( bTextReverse );
2996         std::sort( aSortedVector.begin(), aSortedVector.end(), aSortHelper );
2997 
2998         pTextGroup->reset();
2999 
3000         std::vector< CustomAnimationEffectPtr >::iterator aIter( aSortedVector.begin() );
3001         const std::vector< CustomAnimationEffectPtr >::iterator aEnd( aSortedVector.end() );
3002 
3003         if( aIter != aEnd )
3004         {
3005             pTextGroup->addEffect( (*aIter ) );
3006             EffectSequence::iterator aInsertIter( find( (*aIter++) ) );
3007             while( aIter != aEnd )
3008             {
3009                 CustomAnimationEffectPtr pEffect( (*aIter++) );
3010                 maEffects.erase( find( pEffect ) );
3011                 aInsertIter = maEffects.insert( ++aInsertIter, pEffect );
3012                 pTextGroup->addEffect( pEffect );
3013             }
3014         }
3015         notify_listeners();
3016     }
3017 }
3018 
3019 // --------------------------------------------------------------------
3020 
addListener(ISequenceListener * pListener)3021 void EffectSequenceHelper::addListener( ISequenceListener* pListener )
3022 {
3023     if( std::find( maListeners.begin(), maListeners.end(), pListener ) == maListeners.end() )
3024         maListeners.push_back( pListener );
3025 }
3026 
3027 // --------------------------------------------------------------------
3028 
removeListener(ISequenceListener * pListener)3029 void EffectSequenceHelper::removeListener( ISequenceListener* pListener )
3030 {
3031     maListeners.remove( pListener );
3032 }
3033 
3034 // --------------------------------------------------------------------
3035 
3036 struct stl_notify_listeners_func : public std::unary_function<ISequenceListener*, void>
3037 {
stl_notify_listeners_funcsd::stl_notify_listeners_func3038     stl_notify_listeners_func() {}
operator ()sd::stl_notify_listeners_func3039     void operator()(ISequenceListener* pListener) { pListener->notify_change(); }
3040 };
3041 
3042 // --------------------------------------------------------------------
3043 
notify_listeners()3044 void EffectSequenceHelper::notify_listeners()
3045 {
3046     stl_notify_listeners_func aFunc;
3047     std::for_each( maListeners.begin(), maListeners.end(), aFunc );
3048 }
3049 
3050 // --------------------------------------------------------------------
3051 
create(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode)3052 void EffectSequenceHelper::create( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
3053 {
3054     DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::create(), illegal argument" );
3055 
3056     if( xNode.is() ) try
3057     {
3058         Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
3059         Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3060         while( xEnumeration->hasMoreElements() )
3061         {
3062             Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3063             createEffectsequence( xChildNode );
3064         }
3065     }
3066     catch( Exception& )
3067     {
3068         DBG_ERROR( "sd::EffectSequenceHelper::create(), exception cought!" );
3069     }
3070 }
3071 
3072 // --------------------------------------------------------------------
3073 
createEffectsequence(const Reference<XAnimationNode> & xNode)3074 void EffectSequenceHelper::createEffectsequence( const Reference< XAnimationNode >& xNode )
3075 {
3076     DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::createEffectsequence(), illegal argument" );
3077 
3078     if( xNode.is() ) try
3079     {
3080         Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
3081         Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3082         while( xEnumeration->hasMoreElements() )
3083         {
3084             Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3085 
3086             createEffects( xChildNode );
3087         }
3088     }
3089     catch( Exception& )
3090     {
3091         DBG_ERROR( "sd::EffectSequenceHelper::createEffectsequence(), exception cought!" );
3092     }
3093 }
3094 
3095 // --------------------------------------------------------------------
3096 
createEffects(const Reference<XAnimationNode> & xNode)3097 void EffectSequenceHelper::createEffects( const Reference< XAnimationNode >& xNode )
3098 {
3099     DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::createEffects(), illegal argument" );
3100 
3101     if( xNode.is() ) try
3102     {
3103         Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
3104         Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3105         while( xEnumeration->hasMoreElements() )
3106         {
3107             Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3108 
3109             switch( xChildNode->getType() )
3110             {
3111             // found an effect
3112             case AnimationNodeType::PAR:
3113             case AnimationNodeType::ITERATE:
3114                 {
3115                     CustomAnimationEffectPtr pEffect( new CustomAnimationEffect( xChildNode ) );
3116 
3117                     if( pEffect->mnNodeType != -1 )
3118                     {
3119                         pEffect->setEffectSequence( this );
3120                         maEffects.push_back(pEffect);
3121                     }
3122                 }
3123                 break;
3124 
3125             // found an after effect
3126             case AnimationNodeType::SET:
3127             case AnimationNodeType::ANIMATECOLOR:
3128                 {
3129                     processAfterEffect( xChildNode );
3130                 }
3131                 break;
3132             }
3133         }
3134     }
3135     catch( Exception& e )
3136     {
3137         (void)e;
3138         DBG_ERROR( "sd::EffectSequenceHelper::createEffects(), exception cought!" );
3139     }
3140 }
3141 
3142 // --------------------------------------------------------------------
3143 
processAfterEffect(const Reference<XAnimationNode> & xNode)3144 void EffectSequenceHelper::processAfterEffect( const Reference< XAnimationNode >& xNode )
3145 {
3146     try
3147     {
3148         Reference< XAnimationNode > xMaster;
3149 
3150         Sequence< NamedValue > aUserData( xNode->getUserData() );
3151         sal_Int32 nLength = aUserData.getLength();
3152         const NamedValue* p = aUserData.getConstArray();
3153 
3154         while( nLength-- )
3155         {
3156             if( p->Name.equalsAscii( "master-element" ) )
3157             {
3158                 p->Value >>= xMaster;
3159                 break;
3160             }
3161             p++;
3162         }
3163 
3164         // only process if this is a valid after effect
3165         if( xMaster.is() )
3166         {
3167             CustomAnimationEffectPtr pMasterEffect;
3168 
3169             // find the master effect
3170             stl_CustomAnimationEffect_search_node_predict aSearchPredict( xMaster );
3171             EffectSequence::iterator aIter( std::find_if( maEffects.begin(), maEffects.end(), aSearchPredict ) );
3172             if( aIter != maEffects.end() )
3173                 pMasterEffect = (*aIter );
3174 
3175             if( pMasterEffect.get() )
3176             {
3177                 pMasterEffect->setHasAfterEffect( true );
3178 
3179                 // find out what kind of after effect this is
3180                 if( xNode->getType() == AnimationNodeType::ANIMATECOLOR )
3181                 {
3182                     // its a dim
3183                     Reference< XAnimate > xAnimate( xNode, UNO_QUERY_THROW );
3184                     pMasterEffect->setDimColor( xAnimate->getTo() );
3185                     pMasterEffect->setAfterEffectOnNext( true );
3186                 }
3187                 else
3188                 {
3189                     // its a hide
3190                     Reference< XChild > xNodeChild( xNode, UNO_QUERY_THROW );
3191                     Reference< XChild > xMasterChild( xMaster, UNO_QUERY_THROW );
3192                     pMasterEffect->setAfterEffectOnNext( xNodeChild->getParent() != xMasterChild->getParent() );
3193                 }
3194             }
3195         }
3196     }
3197     catch( Exception& e )
3198     {
3199         (void)e;
3200         DBG_ERROR( "sd::EffectSequenceHelper::processAfterEffect(), exception cought!" );
3201     }
3202 }
3203 
3204 /*
3205 double EffectSequenceHelper::calculateIterateNodeDuration(
3206 {
3207     Reference< i18n::XBreakIterator > xBI( ImplGetBreakIterator() );
3208 
3209     sal_Int32 nDone;
3210     sal_Int32 nNextCellBreak( xBI->nextCharacters(rTxt, nIdx, rLocale, i18n::CharacterIteratorMode::SKIPCELL, 0, nDone) );
3211     i18n::Boundary nNextWordBoundary( xBI->getWordBoundary(rTxt, nIdx, rLocale, i18n::WordType::ANY_WORD, sal_True) );
3212     sal_Int32 nNextSentenceBreak( xBI->endOfSentence(rTxt, nIdx, rLocale) );
3213 
3214     const sal_Int32 nEndPos( nIdx + nLen );
3215     sal_Int32 i, currOffset(0);
3216     for( i=nIdx; i<nEndPos; ++i )
3217     {
3218         // TODO: Check whether position update is valid for CTL/BiDi
3219         rOutDev.DrawText( rPos + Point(currOffset,0), rTxt, i, 1 );
3220         currOffset = *pDXArray++;
3221 
3222         // issue the comments at the respective break positions
3223         if( i == nNextCellBreak )
3224         {
3225             rMtf.AddAction( new MetaCommentAction( "XTEXT_EOC" ) );
3226             nNextCellBreak = xBI->nextCharacters(rTxt, i, rLocale, i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
3227         }
3228         if( i == nNextWordBoundary.endPos )
3229         {
3230             rMtf.AddAction( new MetaCommentAction( "XTEXT_EOW" ) );
3231             nNextWordBoundary = xBI->getWordBoundary(rTxt, i+1, rLocale, i18n::WordType::ANY_WORD, sal_True);
3232         }
3233         if( i == nNextSentenceBreak )
3234         {
3235             rMtf.AddAction( new MetaCommentAction( "XTEXT_EOS" ) );
3236             nNextSentenceBreak = xBI->endOfSentence(rTxt, i+1, rLocale);
3237         }
3238     }
3239 }
3240 
3241 */
3242 // ====================================================================
3243 
3244 class AnimationChangeListener : public cppu::WeakImplHelper1< XChangesListener >
3245 {
3246 public:
AnimationChangeListener(MainSequence * pMainSequence)3247     AnimationChangeListener( MainSequence* pMainSequence ) : mpMainSequence( pMainSequence ) {}
3248 
3249     virtual void SAL_CALL changesOccurred( const ::com::sun::star::util::ChangesEvent& Event ) throw (RuntimeException);
3250     virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (RuntimeException);
3251 private:
3252     MainSequence* mpMainSequence;
3253 };
3254 
changesOccurred(const::com::sun::star::util::ChangesEvent &)3255 void SAL_CALL AnimationChangeListener::changesOccurred( const ::com::sun::star::util::ChangesEvent& ) throw (RuntimeException)
3256 {
3257     if( mpMainSequence )
3258         mpMainSequence->startRecreateTimer();
3259 }
3260 
disposing(const::com::sun::star::lang::EventObject &)3261 void SAL_CALL AnimationChangeListener::disposing( const ::com::sun::star::lang::EventObject& ) throw (RuntimeException)
3262 {
3263 }
3264 
3265 // ====================================================================
3266 
MainSequence()3267 MainSequence::MainSequence()
3268 : mxTimingRootNode( ::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.SequenceTimeContainer"))), UNO_QUERY )
3269 , mbRebuilding( false )
3270 , mnRebuildLockGuard( 0 )
3271 , mbPendingRebuildRequest( false )
3272 {
3273     if( mxTimingRootNode.is() )
3274     {
3275         Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
3276         aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
3277         aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::MAIN_SEQUENCE;
3278         mxTimingRootNode->setUserData( aUserData );
3279     }
3280     init();
3281 }
3282 
3283 // --------------------------------------------------------------------
3284 
MainSequence(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode)3285 MainSequence::MainSequence( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
3286 : mxTimingRootNode( xNode, UNO_QUERY )
3287 , mbRebuilding( false )
3288 , mnRebuildLockGuard( 0 )
3289 , mbPendingRebuildRequest( false )
3290 , mbIgnoreChanges( 0 )
3291 {
3292     init();
3293 }
3294 
3295 // --------------------------------------------------------------------
3296 
~MainSequence()3297 MainSequence::~MainSequence()
3298 {
3299     reset();
3300 }
3301 
3302 // --------------------------------------------------------------------
3303 
init()3304 void MainSequence::init()
3305 {
3306     mnSequenceType = EffectNodeType::MAIN_SEQUENCE;
3307 
3308     maTimer.SetTimeoutHdl( LINK(this, MainSequence, onTimerHdl) );
3309     maTimer.SetTimeout(500);
3310 
3311     mxChangesListener.set( new AnimationChangeListener( this ) );
3312 
3313     createMainSequence();
3314 }
3315 
3316 // --------------------------------------------------------------------
3317 
reset(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xTimingRootNode)3318 void MainSequence::reset( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xTimingRootNode )
3319 {
3320     reset();
3321 
3322     mxTimingRootNode.set( xTimingRootNode, UNO_QUERY );
3323 
3324     createMainSequence();
3325 }
3326 
3327 // --------------------------------------------------------------------
3328 
getRootNode()3329 Reference< ::com::sun::star::animations::XAnimationNode > MainSequence::getRootNode()
3330 {
3331     DBG_ASSERT( mnRebuildLockGuard == 0, "MainSequence::getRootNode(), rebuild is locked, ist this really what you want?" );
3332 
3333     if( maTimer.IsActive() && mbTimerMode )
3334     {
3335         // force a rebuild NOW if one is pending
3336         maTimer.Stop();
3337         implRebuild();
3338     }
3339 
3340     return EffectSequenceHelper::getRootNode();
3341 }
3342 
3343 // --------------------------------------------------------------------
3344 
createMainSequence()3345 void MainSequence::createMainSequence()
3346 {
3347     if( mxTimingRootNode.is() ) try
3348     {
3349         Reference< XEnumerationAccess > xEnumerationAccess( mxTimingRootNode, UNO_QUERY_THROW );
3350         Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3351         while( xEnumeration->hasMoreElements() )
3352         {
3353             Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3354             sal_Int32 nNodeType = CustomAnimationEffect::get_node_type( xChildNode );
3355             if( nNodeType == EffectNodeType::MAIN_SEQUENCE )
3356             {
3357                 mxSequenceRoot.set( xChildNode, UNO_QUERY );
3358                 EffectSequenceHelper::create( xChildNode );
3359             }
3360             else if( nNodeType == EffectNodeType::INTERACTIVE_SEQUENCE )
3361             {
3362                 Reference< XTimeContainer > xInteractiveRoot( xChildNode, UNO_QUERY_THROW );
3363                 InteractiveSequencePtr pIS( new InteractiveSequence( xInteractiveRoot, this ) );
3364                 pIS->addListener( this );
3365                 maInteractiveSequenceList.push_back( pIS );
3366             }
3367         }
3368 
3369         // see if we have a mainsequence at all. if not, create one...
3370         if( !mxSequenceRoot.is() )
3371         {
3372             mxSequenceRoot = Reference< XTimeContainer >::query(::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.SequenceTimeContainer"))));
3373             if( mxSequenceRoot.is() )
3374             {
3375                 uno::Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
3376                 aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
3377                 aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::MAIN_SEQUENCE;
3378                 mxSequenceRoot->setUserData( aUserData );
3379 
3380                 // empty sequence until now, set duration to 0.0
3381                 // explicitely (otherwise, this sequence will never
3382                 // end)
3383                 mxSequenceRoot->setDuration( makeAny((double)0.0) );
3384 
3385                 Reference< XAnimationNode > xMainSequenceNode( mxSequenceRoot, UNO_QUERY_THROW );
3386                 mxTimingRootNode->appendChild( xMainSequenceNode );
3387             }
3388         }
3389 
3390         updateTextGroups();
3391 
3392         notify_listeners();
3393 
3394         Reference< XChangesNotifier > xNotifier( mxTimingRootNode, UNO_QUERY );
3395         if( xNotifier.is() )
3396             xNotifier->addChangesListener( mxChangesListener );
3397     }
3398     catch( Exception& e )
3399     {
3400         (void)e;
3401         DBG_ERROR( "sd::MainSequence::create(), exception cought!" );
3402         return;
3403     }
3404 
3405     DBG_ASSERT( mxSequenceRoot.is(), "sd::MainSequence::create(), found no main sequence!" );
3406 }
3407 
3408 // --------------------------------------------------------------------
3409 
reset()3410 void MainSequence::reset()
3411 {
3412     EffectSequenceHelper::reset();
3413 
3414     InteractiveSequenceList::iterator aIter;
3415     for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3416         (*aIter)->reset();
3417     maInteractiveSequenceList.clear();
3418 
3419     try
3420     {
3421         Reference< XChangesNotifier > xNotifier( mxTimingRootNode, UNO_QUERY );
3422         if( xNotifier.is() )
3423             xNotifier->removeChangesListener( mxChangesListener );
3424     }
3425     catch( Exception& )
3426     {
3427         // ...
3428     }
3429 }
3430 
3431 // --------------------------------------------------------------------
3432 
createInteractiveSequence(const::com::sun::star::uno::Reference<::com::sun::star::drawing::XShape> & xShape)3433 InteractiveSequencePtr MainSequence::createInteractiveSequence( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xShape )
3434 {
3435     InteractiveSequencePtr pIS;
3436 
3437     // create a new interactive sequence container
3438     Reference< XTimeContainer > xISRoot( ::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.SequenceTimeContainer"))), UNO_QUERY );
3439     DBG_ASSERT( xISRoot.is(), "sd::MainSequence::createInteractiveSequence(), could not create \"com.sun.star.animations.SequenceTimeContainer\"!");
3440     if( xISRoot.is() )
3441     {
3442         uno::Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
3443         aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
3444         aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::INTERACTIVE_SEQUENCE ;
3445         xISRoot->setUserData( aUserData );
3446 
3447         Reference< XChild > xChild( mxSequenceRoot, UNO_QUERY_THROW );
3448         Reference< XAnimationNode > xISNode( xISRoot, UNO_QUERY_THROW );
3449         Reference< XTimeContainer > xParent( xChild->getParent(), UNO_QUERY_THROW );
3450         xParent->appendChild( xISNode );
3451     }
3452     pIS.reset( new InteractiveSequence( xISRoot, this) );
3453     pIS->setTriggerShape( xShape );
3454     pIS->addListener( this );
3455     maInteractiveSequenceList.push_back( pIS );
3456     return pIS;
3457 }
3458 
3459 // --------------------------------------------------------------------
3460 
findEffect(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode) const3461 CustomAnimationEffectPtr MainSequence::findEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) const
3462 {
3463     CustomAnimationEffectPtr pEffect = EffectSequenceHelper::findEffect( xNode );
3464 
3465     if( pEffect.get() == 0 )
3466     {
3467         InteractiveSequenceList::const_iterator aIter;
3468         for( aIter = maInteractiveSequenceList.begin(); (aIter != maInteractiveSequenceList.end()) && (pEffect.get() == 0); aIter++ )
3469         {
3470             pEffect = (*aIter)->findEffect( xNode );
3471         }
3472     }
3473     return pEffect;
3474 }
3475 
3476 // --------------------------------------------------------------------
3477 
getOffsetFromEffect(const CustomAnimationEffectPtr & pEffect) const3478 sal_Int32 MainSequence::getOffsetFromEffect( const CustomAnimationEffectPtr& pEffect ) const
3479 {
3480     sal_Int32 nOffset = EffectSequenceHelper::getOffsetFromEffect( pEffect );
3481 
3482     if( nOffset != -1 )
3483         return nOffset;
3484 
3485     nOffset = EffectSequenceHelper::getCount();
3486 
3487     InteractiveSequenceList::const_iterator aIter;
3488     for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3489     {
3490         sal_Int32 nTemp = (*aIter)->getOffsetFromEffect( pEffect );
3491         if( nTemp != -1 )
3492             return nOffset + nTemp;
3493 
3494         nOffset += (*aIter)->getCount();
3495     }
3496 
3497     return -1;
3498 }
3499 
3500 // --------------------------------------------------------------------
3501 
getEffectFromOffset(sal_Int32 nOffset) const3502 CustomAnimationEffectPtr MainSequence::getEffectFromOffset( sal_Int32 nOffset ) const
3503 {
3504     if( nOffset >= 0 )
3505     {
3506         if( nOffset < getCount() )
3507             return EffectSequenceHelper::getEffectFromOffset( nOffset );
3508 
3509         nOffset -= getCount();
3510 
3511         InteractiveSequenceList::const_iterator aIter( maInteractiveSequenceList.begin() );
3512 
3513         while( (aIter != maInteractiveSequenceList.end()) && (nOffset > (*aIter)->getCount()) )
3514             nOffset -= (*aIter++)->getCount();
3515 
3516         if( (aIter != maInteractiveSequenceList.end()) && (nOffset >= 0) )
3517             return (*aIter)->getEffectFromOffset( nOffset );
3518     }
3519 
3520     CustomAnimationEffectPtr pEffect;
3521     return pEffect;
3522 }
3523 
3524 // --------------------------------------------------------------------
3525 
disposeShape(const Reference<XShape> & xShape)3526 bool MainSequence::disposeShape( const Reference< XShape >& xShape )
3527 {
3528     bool bChanges = EffectSequenceHelper::disposeShape( xShape );
3529 
3530     InteractiveSequenceList::iterator aIter;
3531     for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end();  )
3532     {
3533             bChanges |= (*aIter++)->disposeShape( xShape );
3534     }
3535 
3536     if( bChanges )
3537         startRebuildTimer();
3538 
3539     return bChanges;
3540 }
3541 
3542 // --------------------------------------------------------------------
3543 
hasEffect(const com::sun::star::uno::Reference<com::sun::star::drawing::XShape> & xShape)3544 bool MainSequence::hasEffect( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape )
3545 {
3546     if( EffectSequenceHelper::hasEffect( xShape ) )
3547         return true;
3548 
3549     InteractiveSequenceList::iterator aIter;
3550     for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end();  )
3551     {
3552         if( (*aIter)->getTriggerShape() == xShape )
3553             return true;
3554 
3555         if( (*aIter++)->hasEffect( xShape ) )
3556             return true;
3557     }
3558 
3559     return false;
3560 }
3561 
3562 // --------------------------------------------------------------------
3563 
insertTextRange(const com::sun::star::uno::Any & aTarget)3564 void MainSequence::insertTextRange( const com::sun::star::uno::Any& aTarget )
3565 {
3566     EffectSequenceHelper::insertTextRange( aTarget );
3567 
3568     InteractiveSequenceList::iterator aIter;
3569     for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3570     {
3571         (*aIter)->insertTextRange( aTarget );
3572     }
3573 }
3574 // --------------------------------------------------------------------
3575 
disposeTextRange(const com::sun::star::uno::Any & aTarget)3576 void MainSequence::disposeTextRange( const com::sun::star::uno::Any& aTarget )
3577 {
3578     EffectSequenceHelper::disposeTextRange( aTarget );
3579 
3580     InteractiveSequenceList::iterator aIter;
3581     for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3582     {
3583         (*aIter)->disposeTextRange( aTarget );
3584     }
3585 }
3586 
3587 // --------------------------------------------------------------------
3588 
3589 /** callback from the sd::View when an object just left text edit mode */
onTextChanged(const Reference<XShape> & xShape)3590 void MainSequence::onTextChanged( const Reference< XShape >& xShape )
3591 {
3592     EffectSequenceHelper::onTextChanged( xShape );
3593 
3594     InteractiveSequenceList::iterator aIter;
3595     for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3596     {
3597         (*aIter)->onTextChanged( xShape );
3598     }
3599 }
3600 
3601 // --------------------------------------------------------------------
3602 
onTextChanged(const Reference<XShape> & xShape)3603 void EffectSequenceHelper::onTextChanged( const Reference< XShape >& xShape )
3604 {
3605     bool bChanges = false;
3606 
3607     EffectSequence::iterator aIter;
3608     for( aIter = maEffects.begin(); aIter != maEffects.end(); aIter++ )
3609     {
3610         if( (*aIter)->getTargetShape() == xShape )
3611             bChanges |= (*aIter)->checkForText();
3612     }
3613 
3614     if( bChanges )
3615         EffectSequenceHelper::implRebuild();
3616 }
3617 
3618 // --------------------------------------------------------------------
3619 
rebuild()3620 void MainSequence::rebuild()
3621 {
3622     startRebuildTimer();
3623 }
3624 
3625 // --------------------------------------------------------------------
3626 
lockRebuilds()3627 void MainSequence::lockRebuilds()
3628 {
3629     mnRebuildLockGuard++;
3630 }
3631 
3632 // --------------------------------------------------------------------
3633 
unlockRebuilds()3634 void MainSequence::unlockRebuilds()
3635 {
3636     DBG_ASSERT( mnRebuildLockGuard, "sd::MainSequence::unlockRebuilds(), no corresponding lockRebuilds() call!" );
3637     if( mnRebuildLockGuard )
3638         mnRebuildLockGuard--;
3639 
3640     if( (mnRebuildLockGuard == 0) && mbPendingRebuildRequest )
3641     {
3642         mbPendingRebuildRequest = false;
3643         startRebuildTimer();
3644     }
3645 }
3646 
3647 // --------------------------------------------------------------------
3648 
implRebuild()3649 void MainSequence::implRebuild()
3650 {
3651     if( mnRebuildLockGuard )
3652     {
3653         mbPendingRebuildRequest = true;
3654         return;
3655     }
3656 
3657     mbRebuilding = true;
3658 
3659     EffectSequenceHelper::implRebuild();
3660 
3661     InteractiveSequenceList::iterator aIter( maInteractiveSequenceList.begin() );
3662     const InteractiveSequenceList::iterator aEnd( maInteractiveSequenceList.end() );
3663     while( aIter != aEnd )
3664     {
3665         InteractiveSequencePtr pIS( (*aIter) );
3666         if( pIS->maEffects.empty() )
3667         {
3668             // remove empty interactive sequences
3669             aIter = maInteractiveSequenceList.erase( aIter );
3670 
3671             Reference< XChild > xChild( mxSequenceRoot, UNO_QUERY_THROW );
3672             Reference< XTimeContainer > xParent( xChild->getParent(), UNO_QUERY_THROW );
3673             Reference< XAnimationNode > xISNode( pIS->mxSequenceRoot, UNO_QUERY_THROW );
3674             xParent->removeChild( xISNode );
3675         }
3676         else
3677         {
3678             pIS->implRebuild();
3679             aIter++;
3680         }
3681     }
3682 
3683     notify_listeners();
3684     mbRebuilding = false;
3685 }
3686 
3687 // --------------------------------------------------------------------
3688 
notify_change()3689 void MainSequence::notify_change()
3690 {
3691     notify_listeners();
3692 }
3693 
3694 // --------------------------------------------------------------------
3695 
setTrigger(const CustomAnimationEffectPtr & pEffect,const::com::sun::star::uno::Reference<::com::sun::star::drawing::XShape> & xTriggerShape)3696 bool MainSequence::setTrigger( const CustomAnimationEffectPtr& pEffect, const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xTriggerShape )
3697 {
3698     EffectSequenceHelper* pOldSequence = pEffect->getEffectSequence();
3699 
3700     EffectSequenceHelper* pNewSequence = 0;
3701     if( xTriggerShape.is() )
3702     {
3703         InteractiveSequenceList::iterator aIter( maInteractiveSequenceList.begin() );
3704         const InteractiveSequenceList::iterator aEnd( maInteractiveSequenceList.end() );
3705         while( aIter != aEnd )
3706         {
3707             InteractiveSequencePtr pIS( (*aIter++) );
3708             if( pIS->getTriggerShape() == xTriggerShape )
3709             {
3710                 pNewSequence = pIS.get();
3711                 break;
3712             }
3713         }
3714 
3715         if( !pNewSequence )
3716             pNewSequence = createInteractiveSequence( xTriggerShape ).get();
3717     }
3718     else
3719     {
3720         pNewSequence = this;
3721     }
3722 
3723     if( pOldSequence != pNewSequence )
3724     {
3725         if( pOldSequence )
3726             pOldSequence->maEffects.remove( pEffect );
3727         if( pNewSequence )
3728             pNewSequence->maEffects.push_back( pEffect );
3729         pEffect->setEffectSequence( pNewSequence );
3730         return true;
3731     }
3732     else
3733     {
3734         return false;
3735     }
3736 
3737 }
3738 
3739 // --------------------------------------------------------------------
3740 
IMPL_LINK(MainSequence,onTimerHdl,Timer *,EMPTYARG)3741 IMPL_LINK( MainSequence, onTimerHdl, Timer *, EMPTYARG )
3742 {
3743     if( mbTimerMode )
3744     {
3745         implRebuild();
3746     }
3747     else
3748     {
3749         reset();
3750         createMainSequence();
3751     }
3752 
3753     return 0;
3754 }
3755 
3756 // --------------------------------------------------------------------
3757 
3758 /** starts a timer that recreates the internal structure from the API core after 1 second */
startRecreateTimer()3759 void MainSequence::startRecreateTimer()
3760 {
3761     if( !mbRebuilding && (mbIgnoreChanges == 0) )
3762     {
3763         mbTimerMode = false;
3764         maTimer.Start();
3765     }
3766 }
3767 
3768 // --------------------------------------------------------------------
3769 
3770 /** starts a timer that rebuilds the API core from the internal structure after 1 second */
startRebuildTimer()3771 void MainSequence::startRebuildTimer()
3772 {
3773     mbTimerMode = true;
3774     maTimer.Start();
3775 }
3776 
3777 // ====================================================================
3778 
InteractiveSequence(const Reference<XTimeContainer> & xSequenceRoot,MainSequence * pMainSequence)3779 InteractiveSequence::InteractiveSequence( const Reference< XTimeContainer >& xSequenceRoot, MainSequence* pMainSequence )
3780 : EffectSequenceHelper( xSequenceRoot ), mpMainSequence( pMainSequence )
3781 {
3782     mnSequenceType = EffectNodeType::INTERACTIVE_SEQUENCE;
3783 
3784     try
3785     {
3786         if( mxSequenceRoot.is() )
3787         {
3788             Reference< XEnumerationAccess > xEnumerationAccess( mxSequenceRoot, UNO_QUERY_THROW );
3789             Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3790             while( !mxEventSource.is() && xEnumeration->hasMoreElements() )
3791             {
3792                 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3793 
3794                 Event aEvent;
3795                 if( (xChildNode->getBegin() >>= aEvent) && (aEvent.Trigger == EventTrigger::ON_CLICK) )
3796                     aEvent.Source >>= mxEventSource;
3797             }
3798         }
3799     }
3800     catch( Exception& e )
3801     {
3802         (void)e;
3803         DBG_ERROR( "sd::InteractiveSequence::InteractiveSequence(), exception cought!" );
3804         return;
3805     }
3806 }
3807 
3808 // --------------------------------------------------------------------
3809 
rebuild()3810 void InteractiveSequence::rebuild()
3811 {
3812     mpMainSequence->rebuild();
3813 }
3814 
implRebuild()3815 void InteractiveSequence::implRebuild()
3816 {
3817     EffectSequenceHelper::implRebuild();
3818 }
3819 
3820 // --------------------------------------------------------------------
3821 
MainSequenceRebuildGuard(const MainSequencePtr & pMainSequence)3822 MainSequenceRebuildGuard::MainSequenceRebuildGuard( const MainSequencePtr& pMainSequence )
3823 : mpMainSequence( pMainSequence )
3824 {
3825     if( mpMainSequence.get() )
3826         mpMainSequence->lockRebuilds();
3827 }
3828 
~MainSequenceRebuildGuard()3829 MainSequenceRebuildGuard::~MainSequenceRebuildGuard()
3830 {
3831     if( mpMainSequence.get() )
3832         mpMainSequence->unlockRebuilds();
3833 }
3834 
3835 
3836 }
3837