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:
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 
132 	~MainSequenceChangeGuard()
133 	{
134 		if( mpMainSequence )
135 			mpMainSequence->mbIgnoreChanges++;
136 	}
137 
138 private:
139 	MainSequence* mpMainSequence;
140 };
141 
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 
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 
288 sal_Int32 CustomAnimationEffect::getNumberOfSubitems( const Any& aTarget, sal_Int16 nIterateType )
289 {
290 	sal_Int32 nSubItems = 0;
291 
292 	try
293 	{
294 		// first get target text
295 		sal_Int32 nOnlyPara = -1;
296 
297 		Reference< XText > xShape;
298 		aTarget >>= xShape;
299 		if( !xShape.is() )
300 		{
301 			ParagraphTarget aParaTarget;
302 			if( aTarget >>= aParaTarget )
303 			{
304 				xShape.set( aParaTarget.Shape, UNO_QUERY );
305 				nOnlyPara = aParaTarget.Paragraph;
306 			}
307 		}
308 
309 		// now use the break iterator to iterate over the given text
310 		// and count the sub items
311 
312 		if( xShape.is() )
313 		{
314 			// TODO/LATER: Optimize this, don't create a break iterator each time
315 			Reference< lang::XMultiServiceFactory > xMSF( ::comphelper::getProcessServiceFactory() );
316 			Reference < i18n::XBreakIterator > xBI( xMSF->createInstance( OUString::createFromAscii( "com.sun.star.i18n.BreakIterator" ) ), UNO_QUERY );
317 			DBG_ASSERT( xBI.is(), "sd::CustomAnimationEffect::getNumberOfSubitems(), could not create a 'com.sun.star.i18n.BreakIterator'!" );
318 
319 			if( xBI.is() )
320 			{
321 				Reference< XEnumerationAccess > xEA( xShape, UNO_QUERY_THROW );
322 				Reference< XEnumeration > xEnumeration( xEA->createEnumeration(), UNO_QUERY_THROW );
323 				Locale aLocale;
324 				const OUString aStrLocaleName( RTL_CONSTASCII_USTRINGPARAM("CharLocale") );
325 				Reference< XTextRange > xParagraph;
326 
327 				sal_Int32 nPara = 0;
328 				while( xEnumeration->hasMoreElements() )
329 				{
330 					xEnumeration->nextElement() >>= xParagraph;
331 
332 					// skip this if its not the only paragraph we want to count
333 					if( (nOnlyPara != -1) && (nOnlyPara != nPara ) )
334 						continue;
335 
336 					if( nIterateType == TextAnimationType::BY_PARAGRAPH )
337 					{
338 						nSubItems++;
339 					}
340 					else
341 					{
342 						const OUString aText( xParagraph->getString() );
343 						Reference< XPropertySet > xSet( xParagraph, UNO_QUERY_THROW );
344 						xSet->getPropertyValue( aStrLocaleName ) >>= aLocale;
345 
346 						sal_Int32 nPos;
347 						const sal_Int32 nEndPos = aText.getLength();
348 
349 						if( nIterateType == TextAnimationType::BY_WORD )
350 						{
351 							for( nPos = 0; nPos < nEndPos; nPos++ )
352 							{
353 								nPos = xBI->getWordBoundary(aText, nPos, aLocale, i18n::WordType::ANY_WORD, sal_True).endPos;
354 								nSubItems++;
355 							}
356 							break;
357 						}
358 						else
359 						{
360 							sal_Int32 nDone;
361 							for( nPos = 0; nPos < nEndPos; nPos++ )
362 							{
363 								nPos = xBI->nextCharacters(aText, nPos, aLocale, i18n::CharacterIteratorMode::SKIPCELL, 0, nDone);
364 								nSubItems++;
365 							}
366 						}
367 					}
368 
369 					if( nPara == nOnlyPara )
370 						break;
371 
372 					nPara++;
373 				}
374 			}
375 		}
376 	}
377 	catch( Exception& e )
378 	{
379 		(void)e;
380 		nSubItems = 0;
381 		DBG_ERROR( "sd::CustomAnimationEffect::getNumberOfSubitems(), exception caught!" );
382 	}
383 
384 	return nSubItems;
385 }
386 
387 // --------------------------------------------------------------------
388 
389 CustomAnimationEffect::~CustomAnimationEffect()
390 {
391 }
392 
393 // --------------------------------------------------------------------
394 
395 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 
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 
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 
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 
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 */
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 
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 
660 void CustomAnimationEffect::setTarget( const ::com::sun::star::uno::Any& rTarget )
661 {
662 	try
663 	{
664 		maTarget = rTarget;
665 
666 		// first, check special case for random node
667 		Reference< XInitialization > xInit( mxNode, UNO_QUERY );
668 		if( xInit.is() )
669 		{
670 			const Sequence< Any > aArgs( &maTarget, 1 );
671 			xInit->initialize( aArgs );
672 		}
673 		else
674 		{
675 			Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
676 			if( xIter.is() )
677 			{
678 				xIter->setTarget(maTarget);
679 			}
680 			else
681 			{
682 				Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
683 				if( xEnumerationAccess.is() )
684 				{
685 					Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
686 					if( xEnumeration.is() )
687 					{
688 						while( xEnumeration->hasMoreElements() )
689 						{
690 							const Any aElem( xEnumeration->nextElement() );
691 							Reference< XAnimate > xAnimate( aElem, UNO_QUERY );
692 							if( xAnimate.is() )
693 								xAnimate->setTarget( rTarget );
694                             else
695                             {
696                                 Reference< XCommand > xCommand( aElem, UNO_QUERY );
697                                 if( xCommand.is() )
698                                     xCommand->setTarget( rTarget );
699                             }
700 						}
701 					}
702 				}
703 			}
704 		}
705 		checkForText();
706 	}
707 	catch( Exception& )
708 	{
709 		DBG_ERROR( "sd::CustomAnimationEffect::setTarget(), exception caught!" );
710 	}
711 }
712 
713 // --------------------------------------------------------------------
714 
715 void CustomAnimationEffect::setTargetSubItem( sal_Int16 nSubItem )
716 {
717 	try
718 	{
719 		mnTargetSubItem = nSubItem;
720 
721 		Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
722 		if( xIter.is() )
723 		{
724 			xIter->setSubItem(mnTargetSubItem);
725 		}
726 		else
727 		{
728 			Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
729 			if( xEnumerationAccess.is() )
730 			{
731 				Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
732 				if( xEnumeration.is() )
733 				{
734 					while( xEnumeration->hasMoreElements() )
735 					{
736 						Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
737 						if( xAnimate.is() )
738 							xAnimate->setSubItem( mnTargetSubItem );
739 					}
740 				}
741 			}
742 		}
743 	}
744 	catch( Exception& )
745 	{
746 		DBG_ERROR( "sd::CustomAnimationEffect::setTargetSubItem(), exception caught!" );
747 	}
748 }
749 
750 // --------------------------------------------------------------------
751 
752 void CustomAnimationEffect::setDuration( double fDuration )
753 {
754 	if( (mfDuration != -1.0) && (mfDuration != fDuration) ) try
755 	{
756 		double fScale = fDuration / mfDuration;
757 		mfDuration = fDuration;
758 		mfAbsoluteDuration = mfDuration;
759 
760 		// calculate effect duration and get target shape
761 		Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
762 		if( xEnumerationAccess.is() )
763 		{
764 			Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
765 			if( xEnumeration.is() )
766 			{
767 				while( xEnumeration->hasMoreElements() )
768 				{
769 					Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
770 					if( !xChildNode.is() )
771 						continue;
772 
773 
774 					double fChildBegin = 0.0;
775 					xChildNode->getBegin() >>= fChildBegin;
776 					if(  fChildBegin != 0.0 )
777 					{
778 						fChildBegin *= fScale;
779 						xChildNode->setBegin( makeAny( fChildBegin ) );
780 					}
781 
782 					double fChildDuration = 0.0;
783 					xChildNode->getDuration() >>= fChildDuration;
784 					if( fChildDuration != 0.0 )
785 					{
786 						fChildDuration *= fScale;
787 						xChildNode->setDuration( makeAny( fChildDuration ) );
788 					}
789 				}
790 			}
791 		}
792 		calculateIterateDuration();
793 	}
794 	catch( Exception& )
795 	{
796 		DBG_ERROR( "sd::CustomAnimationEffect::setDuration(), exception caught!" );
797 	}
798 }
799 
800 // --------------------------------------------------------------------
801 
802 void CustomAnimationEffect::setBegin( double fBegin )
803 {
804 	if( mxNode.is() ) try
805 	{
806 		mfBegin = fBegin;
807 		mxNode->setBegin( makeAny( fBegin ) );
808 	}
809 	catch( Exception& )
810 	{
811 		DBG_ERROR( "sd::CustomAnimationEffect::setBegin(), exception caught!" );
812 	}
813 }
814 
815 // --------------------------------------------------------------------
816 
817 void CustomAnimationEffect::setAcceleration( double fAcceleration )
818 {
819 	if( mxNode.is() ) try
820 	{
821 		mfAcceleration = fAcceleration;
822 		mxNode->setAcceleration( fAcceleration );
823 	}
824 	catch( Exception& )
825 	{
826 		DBG_ERROR( "sd::CustomAnimationEffect::setAcceleration(), exception caught!" );
827 	}
828 }
829 // --------------------------------------------------------------------
830 
831 void CustomAnimationEffect::setDecelerate( double fDecelerate )
832 {
833 	if( mxNode.is() ) try
834 	{
835 		mfDecelerate = fDecelerate;
836 		mxNode->setDecelerate( fDecelerate );
837 	}
838 	catch( Exception& )
839 	{
840 		DBG_ERROR( "sd::CustomAnimationEffect::setDecelerate(), exception caught!" );
841 	}
842 }
843 
844 // --------------------------------------------------------------------
845 
846 void CustomAnimationEffect::setAutoReverse( sal_Bool bAutoReverse )
847 {
848 	if( mxNode.is() ) try
849 	{
850 		mbAutoReverse = bAutoReverse;
851 		mxNode->setAutoReverse( bAutoReverse );
852 	}
853 	catch( Exception& )
854 	{
855 		DBG_ERROR( "sd::CustomAnimationEffect::setAutoReverse(), exception caught!" );
856 	}
857 }
858 
859 // --------------------------------------------------------------------
860 
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 
898 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 
914 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 
929 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 
944 sal_Int16 CustomAnimationEffect::getFill() const
945 {
946 	if( mxNode.is() )
947 		return mxNode->getFill();
948 	else
949 		return 0;
950 }
951 
952 // --------------------------------------------------------------------
953 
954 void CustomAnimationEffect::setRepeatCount( const Any& rRepeatCount )
955 {
956 	if( mxNode.is() )
957 		mxNode->setRepeatCount( rRepeatCount );
958 }
959 
960 // --------------------------------------------------------------------
961 
962 void CustomAnimationEffect::setEnd( const Any& rEnd )
963 {
964 	if( mxNode.is() )
965 		mxNode->setEnd( rEnd );
966 }
967 
968 // --------------------------------------------------------------------
969 
970 void CustomAnimationEffect::setFill( sal_Int16 nFill )
971 {
972 	if( mxNode.is() )
973 		mxNode->setFill( nFill );
974 }
975 
976 // --------------------------------------------------------------------
977 
978 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 
1032 void CustomAnimationEffect::setIterateType( sal_Int16 nIterateType )
1033 {
1034 	if( mnIterateType != nIterateType ) try
1035 	{
1036 		// do we need to exchange the container node?
1037 		if( (mnIterateType == 0) || (nIterateType == 0) )
1038 		{
1039 			sal_Int16 nTargetSubItem = mnTargetSubItem;
1040 
1041 			Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() );
1042 			const char * pServiceName =
1043 				nIterateType ? "com.sun.star.animations.IterateContainer" : "com.sun.star.animations.ParallelTimeContainer";
1044 			Reference< XTimeContainer > xNewContainer(
1045 				xMsf->createInstance( OUString::createFromAscii(pServiceName) ), UNO_QUERY_THROW );
1046 
1047 			Reference< XTimeContainer > xOldContainer( mxNode, UNO_QUERY_THROW );
1048 			Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW );
1049 			Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1050 			while( xEnumeration->hasMoreElements() )
1051 			{
1052 				Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
1053 				xOldContainer->removeChild( xChildNode );
1054 				xNewContainer->appendChild( xChildNode );
1055 			}
1056 
1057 			Reference< XAnimationNode > xNewNode( xNewContainer, UNO_QUERY_THROW );
1058 
1059 			xNewNode->setBegin( mxNode->getBegin() );
1060 			xNewNode->setDuration( mxNode->getDuration() );
1061 			xNewNode->setEnd( mxNode->getEnd() );
1062 			xNewNode->setEndSync( mxNode->getEndSync() );
1063 			xNewNode->setRepeatCount( mxNode->getRepeatCount() );
1064 			xNewNode->setFill( mxNode->getFill() );
1065 			xNewNode->setFillDefault( mxNode->getFillDefault() );
1066 			xNewNode->setRestart( mxNode->getRestart() );
1067 			xNewNode->setRestartDefault( mxNode->getRestartDefault() );
1068 			xNewNode->setAcceleration( mxNode->getAcceleration() );
1069 			xNewNode->setDecelerate( mxNode->getDecelerate() );
1070 			xNewNode->setAutoReverse( mxNode->getAutoReverse() );
1071 			xNewNode->setRepeatDuration( mxNode->getRepeatDuration() );
1072 			xNewNode->setEndSync( mxNode->getEndSync() );
1073 			xNewNode->setRepeatCount( mxNode->getRepeatCount() );
1074 			xNewNode->setUserData( mxNode->getUserData() );
1075 
1076 			mxNode = xNewNode;
1077 
1078 			Any aTarget;
1079 			if( nIterateType )
1080 			{
1081 				Reference< XIterateContainer > xIter( mxNode, UNO_QUERY_THROW );
1082 				xIter->setTarget(maTarget);
1083 				xIter->setSubItem( nTargetSubItem );
1084 			}
1085 			else
1086 			{
1087 				aTarget = maTarget;
1088 			}
1089 
1090 			Reference< XEnumerationAccess > xEA( mxNode, UNO_QUERY_THROW );
1091 			Reference< XEnumeration > xE( xEA->createEnumeration(), UNO_QUERY_THROW );
1092 			while( xE->hasMoreElements() )
1093 			{
1094 				Reference< XAnimate > xAnimate( xE->nextElement(), UNO_QUERY );
1095 				if( xAnimate.is() )
1096 				{
1097 					xAnimate->setTarget( aTarget );
1098 					xAnimate->setSubItem( nTargetSubItem );
1099 				}
1100 			}
1101 		}
1102 
1103 		mnIterateType = nIterateType;
1104 
1105 		// if we have an iteration container, we must set its type
1106 		if( mnIterateType )
1107 		{
1108 			Reference< XIterateContainer > xIter( mxNode, UNO_QUERY_THROW );
1109 			xIter->setIterateType( nIterateType );
1110 		}
1111 
1112 		checkForText();
1113 	}
1114 	catch( Exception& e )
1115 	{
1116 		(void)e;
1117 		DBG_ERROR( "sd::CustomAnimationEffect::setIterateType(), Exception caught!" );
1118 	}
1119 }
1120 
1121 // --------------------------------------------------------------------
1122 
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 
1142 ::rtl::OUString	CustomAnimationEffect::getPath() const
1143 {
1144 	::rtl::OUString aPath;
1145 
1146 	if( mxNode.is() ) try
1147 	{
1148 		Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW );
1149 		Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1150 		while( xEnumeration->hasMoreElements() )
1151 		{
1152 			Reference< XAnimateMotion > xMotion( xEnumeration->nextElement(), UNO_QUERY );
1153 			if( xMotion.is() )
1154 			{
1155 				xMotion->getPath() >>= aPath;
1156 				break;
1157 			}
1158 		}
1159 	}
1160 	catch( Exception& e )
1161 	{
1162 		(void)e;
1163 		DBG_ERROR("sd::CustomAnimationEffect::getPath(), exception caught!" );
1164 	}
1165 
1166 	return aPath;
1167 }
1168 
1169 // --------------------------------------------------------------------
1170 
1171 void CustomAnimationEffect::setPath( const ::rtl::OUString& rPath )
1172 {
1173 	if( mxNode.is() ) try
1174 	{
1175 		Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW );
1176 		Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1177 		while( xEnumeration->hasMoreElements() )
1178 		{
1179 			Reference< XAnimateMotion > xMotion( xEnumeration->nextElement(), UNO_QUERY );
1180 			if( xMotion.is() )
1181 			{
1182 
1183 				MainSequenceChangeGuard aGuard( mpEffectSequence );
1184 				xMotion->setPath( Any( rPath ) );
1185 				break;
1186 			}
1187 		}
1188 	}
1189 	catch( Exception& e )
1190 	{
1191 		(void)e;
1192 		DBG_ERROR("sd::CustomAnimationEffect::setPath(), exception caught!" );
1193 	}
1194 }
1195 
1196 // --------------------------------------------------------------------
1197 
1198 Any CustomAnimationEffect::getProperty( sal_Int32 nNodeType, const OUString& rAttributeName, EValue eValue )
1199 {
1200 	Any aProperty;
1201 	if( mxNode.is() ) try
1202 	{
1203 		Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1204 		if( xEnumerationAccess.is() )
1205 		{
1206 			Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1207 			if( xEnumeration.is() )
1208 			{
1209 				while( xEnumeration->hasMoreElements() && !aProperty.hasValue() )
1210 				{
1211 					Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1212 					if( !xAnimate.is() )
1213 						continue;
1214 
1215 					if( xAnimate->getType() == nNodeType )
1216 					{
1217 						if( xAnimate->getAttributeName() == rAttributeName )
1218 						{
1219 							switch( eValue )
1220 							{
1221 							case VALUE_FROM: aProperty = xAnimate->getFrom(); break;
1222 							case VALUE_TO:   aProperty = xAnimate->getTo(); break;
1223 							case VALUE_BY:   aProperty = xAnimate->getBy(); break;
1224 							case VALUE_FIRST:
1225 							case VALUE_LAST:
1226 								{
1227 									Sequence<Any> aValues( xAnimate->getValues() );
1228 									if( aValues.hasElements() )
1229 										aProperty =  aValues[ eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1 ];
1230 								}
1231 								break;
1232 							}
1233 						}
1234 					}
1235 				}
1236 			}
1237 		}
1238 	}
1239 	catch( Exception& e )
1240 	{
1241 		(void)e;
1242 		DBG_ERROR("sd::CustomAnimationEffect::getProperty(), exception caught!" );
1243 	}
1244 
1245 	return aProperty;
1246 }
1247 
1248 // --------------------------------------------------------------------
1249 
1250 bool CustomAnimationEffect::setProperty( sal_Int32 nNodeType, const OUString& rAttributeName, EValue eValue, const Any& rValue )
1251 {
1252 	bool bChanged = false;
1253 	if( mxNode.is() ) try
1254 	{
1255 		Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1256 		if( xEnumerationAccess.is() )
1257 		{
1258 			Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1259 			if( xEnumeration.is() )
1260 			{
1261 				while( xEnumeration->hasMoreElements() )
1262 				{
1263 					Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1264 					if( !xAnimate.is() )
1265 						continue;
1266 
1267 					if( xAnimate->getType() == nNodeType )
1268 					{
1269 						if( xAnimate->getAttributeName() == rAttributeName )
1270 						{
1271 							switch( eValue )
1272 							{
1273 							case VALUE_FROM:
1274 								if( xAnimate->getFrom() != rValue )
1275 								{
1276 									xAnimate->setFrom( rValue );
1277 									bChanged = true;
1278 								}
1279 								break;
1280 							case VALUE_TO:
1281 								if( xAnimate->getTo() != rValue )
1282 								{
1283 									xAnimate->setTo( rValue );
1284 									bChanged = true;
1285 								}
1286 								break;
1287 							case VALUE_BY:
1288 								if( xAnimate->getTo() != rValue )
1289 								{
1290 									xAnimate->setBy( rValue );
1291 									bChanged = true;
1292 								}
1293 								break;
1294 							case VALUE_FIRST:
1295 							case VALUE_LAST:
1296 								{
1297 									Sequence<Any> aValues( xAnimate->getValues() );
1298 									if( !aValues.hasElements() )
1299 										aValues.realloc(1);
1300 
1301 									sal_Int32 nIndex = eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1;
1302 
1303 									if( aValues[ nIndex ] != rValue )
1304 									{
1305 										aValues[ nIndex ] = rValue;
1306 										xAnimate->setValues( aValues );
1307 										bChanged = true;
1308 									}
1309 								}
1310 							}
1311 						}
1312 					}
1313 				}
1314 			}
1315 		}
1316 	}
1317 	catch( Exception& e )
1318 	{
1319 		(void)e;
1320 		DBG_ERROR("sd::CustomAnimationEffect::setProperty(), exception caught!" );
1321 	}
1322 
1323 	return bChanged;
1324 }
1325 
1326 // --------------------------------------------------------------------
1327 
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 
1337 Any CustomAnimationEffect::getColor( sal_Int32 nIndex )
1338 {
1339 	Any aColor;
1340 	if( mxNode.is() ) try
1341 	{
1342 		Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1343 		if( xEnumerationAccess.is() )
1344 		{
1345 			Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1346 			if( xEnumeration.is() )
1347 			{
1348 				while( xEnumeration->hasMoreElements() && !aColor.hasValue() )
1349 				{
1350 					Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1351 					if( !xAnimate.is() )
1352 						continue;
1353 
1354 					switch( xAnimate->getType() )
1355 					{
1356 					case AnimationNodeType::SET:
1357 					case AnimationNodeType::ANIMATE:
1358 						if( !implIsColorAttribute( xAnimate->getAttributeName() ) )
1359 							break;
1360 					case AnimationNodeType::ANIMATECOLOR:
1361 						Sequence<Any> aValues( xAnimate->getValues() );
1362 						if( aValues.hasElements() )
1363 						{
1364 							if( aValues.getLength() > nIndex )
1365 								aColor = aValues[nIndex];
1366 						}
1367 						else if( nIndex == 0 )
1368 							aColor = xAnimate->getFrom();
1369 						else
1370 							aColor = xAnimate->getTo();
1371 					}
1372 				}
1373 			}
1374 		}
1375 	}
1376 	catch( Exception& e )
1377 	{
1378 		(void)e;
1379 		DBG_ERROR("sd::CustomAnimationEffect::getColor(), exception caught!" );
1380 	}
1381 
1382 	return aColor;
1383 }
1384 
1385 // --------------------------------------------------------------------
1386 
1387 void CustomAnimationEffect::setColor( sal_Int32 nIndex, const Any& rColor )
1388 {
1389 	if( mxNode.is() ) try
1390 	{
1391 		Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1392 		if( xEnumerationAccess.is() )
1393 		{
1394 			Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1395 			if( xEnumeration.is() )
1396 			{
1397 				while( xEnumeration->hasMoreElements() )
1398 				{
1399 					Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1400 					if( !xAnimate.is() )
1401 						continue;
1402 
1403 					switch( xAnimate->getType() )
1404 					{
1405 					case AnimationNodeType::SET:
1406 					case AnimationNodeType::ANIMATE:
1407 						if( !implIsColorAttribute( xAnimate->getAttributeName() ) )
1408 							break;
1409 					case AnimationNodeType::ANIMATECOLOR:
1410 					{
1411 						Sequence<Any> aValues( xAnimate->getValues() );
1412 						if( aValues.hasElements() )
1413 						{
1414 							if( aValues.getLength() > nIndex )
1415 							{
1416 								aValues[nIndex] = rColor;
1417 								xAnimate->setValues( aValues );
1418 							}
1419 						}
1420 						else if( (nIndex == 0) && xAnimate->getFrom().hasValue() )
1421 							xAnimate->setFrom(rColor);
1422 						else if( (nIndex == 1) && xAnimate->getTo().hasValue() )
1423 							xAnimate->setTo(rColor);
1424 					}
1425 					break;
1426 
1427 					}
1428 				}
1429 			}
1430 		}
1431 	}
1432 	catch( Exception& e )
1433 	{
1434 		(void)e;
1435 		DBG_ERROR("sd::CustomAnimationEffect::setColor(), exception caught!" );
1436 	}
1437 }
1438 
1439 // --------------------------------------------------------------------
1440 
1441 Any CustomAnimationEffect::getTransformationProperty( sal_Int32 nTransformType, EValue eValue )
1442 {
1443 	Any aProperty;
1444 	if( mxNode.is() ) try
1445 	{
1446 		Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1447 		if( xEnumerationAccess.is() )
1448 		{
1449 			Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1450 			if( xEnumeration.is() )
1451 			{
1452 				while( xEnumeration->hasMoreElements() && !aProperty.hasValue() )
1453 				{
1454 					Reference< XAnimateTransform > xTransform( xEnumeration->nextElement(), UNO_QUERY );
1455 					if( !xTransform.is() )
1456 						continue;
1457 
1458 					if( xTransform->getTransformType() == nTransformType )
1459 					{
1460 						switch( eValue )
1461 						{
1462 						case VALUE_FROM: aProperty = xTransform->getFrom(); break;
1463 						case VALUE_TO:   aProperty = xTransform->getTo(); break;
1464 						case VALUE_BY:   aProperty = xTransform->getBy(); break;
1465 						case VALUE_FIRST:
1466 						case VALUE_LAST:
1467 							{
1468 								Sequence<Any> aValues( xTransform->getValues() );
1469 								if( aValues.hasElements() )
1470 									aProperty =  aValues[ eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1 ];
1471 							}
1472 							break;
1473 						}
1474 					}
1475 				}
1476 			}
1477 		}
1478 	}
1479 	catch( Exception& e )
1480 	{
1481 		(void)e;
1482 		DBG_ERROR("sd::CustomAnimationEffect::getTransformationProperty(), exception caught!" );
1483 	}
1484 
1485 	return aProperty;
1486 }
1487 
1488 // --------------------------------------------------------------------
1489 
1490 bool CustomAnimationEffect::setTransformationProperty( sal_Int32 nTransformType, EValue eValue, const Any& rValue )
1491 {
1492 	bool bChanged = false;
1493 	if( mxNode.is() ) try
1494 	{
1495 		Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1496 		if( xEnumerationAccess.is() )
1497 		{
1498 			Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1499 			if( xEnumeration.is() )
1500 			{
1501 				while( xEnumeration->hasMoreElements() )
1502 				{
1503 					Reference< XAnimateTransform > xTransform( xEnumeration->nextElement(), UNO_QUERY );
1504 					if( !xTransform.is() )
1505 						continue;
1506 
1507 					if( xTransform->getTransformType() == nTransformType )
1508 					{
1509 						switch( eValue )
1510 						{
1511 						case VALUE_FROM:
1512 							if( xTransform->getFrom() != rValue )
1513 							{
1514 								xTransform->setFrom( rValue );
1515 								bChanged = true;
1516 							}
1517 							break;
1518 						case VALUE_TO:
1519 							if( xTransform->getTo() != rValue )
1520 							{
1521 								xTransform->setTo( rValue );
1522 								bChanged = true;
1523 							}
1524 							break;
1525 						case VALUE_BY:
1526 							if( xTransform->getBy() != rValue )
1527 							{
1528 								xTransform->setBy( rValue );
1529 								bChanged = true;
1530 							}
1531 							break;
1532 						case VALUE_FIRST:
1533 						case VALUE_LAST:
1534 							{
1535 								Sequence<Any> aValues( xTransform->getValues() );
1536 								if( !aValues.hasElements() )
1537 									aValues.realloc(1);
1538 
1539 								sal_Int32 nIndex = eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1;
1540 								if( aValues[nIndex] != rValue )
1541 								{
1542 									aValues[nIndex] = rValue;
1543 									xTransform->setValues( aValues );
1544 									bChanged = true;
1545 								}
1546 							}
1547 						}
1548 					}
1549 				}
1550 			}
1551 		}
1552 	}
1553 	catch( Exception& e )
1554 	{
1555 		(void)e;
1556 		DBG_ERROR("sd::CustomAnimationEffect::setTransformationProperty(), exception caught!" );
1557 	}
1558 
1559 	return bChanged;
1560 }
1561 
1562 // --------------------------------------------------------------------
1563 
1564 void CustomAnimationEffect::createAudio( const ::com::sun::star::uno::Any& rSource, double fVolume /* = 1.0 */ )
1565 {
1566 	DBG_ASSERT( !mxAudio.is(), "sd::CustomAnimationEffect::createAudio(), node already has an audio!" );
1567 
1568 	if( !mxAudio.is() ) try
1569 	{
1570 		Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() );
1571 		Reference< XAudio > xAudio( xMsf->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.Audio") ) ), UNO_QUERY_THROW );
1572 		xAudio->setSource( rSource );
1573 		xAudio->setVolume( fVolume );
1574 		setAudio( xAudio );
1575 	}
1576 	catch( Exception& e )
1577 	{
1578 		(void)e;
1579 		DBG_ERROR("sd::CustomAnimationEffect::createAudio(), exception caught!" );
1580 	}
1581 }
1582 
1583 // --------------------------------------------------------------------
1584 
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 
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 
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 
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 
1690 bool CustomAnimationEffect::getStopAudio() const
1691 {
1692 	return mnCommand == EffectCommands::STOPAUDIO;
1693 }
1694 
1695 // --------------------------------------------------------------------
1696 
1697 SdrPathObj* CustomAnimationEffect::createSdrPathObjFromPath()
1698 {
1699 	SdrPathObj * pPathObj = new SdrPathObj( OBJ_PATHLINE );
1700 	updateSdrPathObjFromPath( *pPathObj );
1701 	return pPathObj;
1702 }
1703 
1704 // --------------------------------------------------------------------
1705 
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 
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 
1770 EffectSequenceHelper::EffectSequenceHelper()
1771 : mnSequenceType( EffectNodeType::DEFAULT )
1772 {
1773 }
1774 
1775 // --------------------------------------------------------------------
1776 
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 
1786 EffectSequenceHelper::~EffectSequenceHelper()
1787 {
1788 	reset();
1789 }
1790 
1791 // --------------------------------------------------------------------
1792 
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 
1805 Reference< XAnimationNode > EffectSequenceHelper::getRootNode()
1806 {
1807 	Reference< XAnimationNode > xRoot( mxSequenceRoot, UNO_QUERY );
1808 	return xRoot;
1809 }
1810 
1811 // --------------------------------------------------------------------
1812 
1813 void EffectSequenceHelper::append( const CustomAnimationEffectPtr& pEffect )
1814 {
1815 	pEffect->setEffectSequence( this );
1816 	maEffects.push_back(pEffect);
1817 	rebuild();
1818 }
1819 
1820 // --------------------------------------------------------------------
1821 
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 
1896 CustomAnimationEffectPtr EffectSequenceHelper::append( const SdrPathObj& rPathObj, const Any& rTarget, double fDuration /* = -1.0 */ )
1897 {
1898 	CustomAnimationEffectPtr pEffect;
1899 
1900 	if( fDuration <= 0.0 )
1901 		fDuration = 2.0;
1902 
1903 	try
1904 	{
1905 		Reference< XTimeContainer > xEffectContainer( createParallelTimeContainer() );
1906 		const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.animations.AnimateMotion" ) );
1907 		Reference< XAnimationNode > xAnimateMotion( ::comphelper::getProcessServiceFactory()->createInstance(aServiceName), UNO_QUERY_THROW );
1908 
1909 		xAnimateMotion->setDuration( Any( fDuration ) );
1910 		xAnimateMotion->setFill( AnimationFill::HOLD );
1911 		xEffectContainer->appendChild( xAnimateMotion );
1912 
1913 		sal_Int16 nSubItem = ShapeAnimationSubType::AS_WHOLE;
1914 
1915 		if(	rTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
1916 			nSubItem = ShapeAnimationSubType::ONLY_TEXT;
1917 
1918 		Reference< XAnimationNode > xEffectNode( xEffectContainer, UNO_QUERY_THROW );
1919 		pEffect.reset( new CustomAnimationEffect( xEffectNode ) );
1920 		pEffect->setEffectSequence( this );
1921 		pEffect->setTarget( rTarget );
1922 		pEffect->setTargetSubItem( nSubItem );
1923 		pEffect->setNodeType( ::com::sun::star::presentation::EffectNodeType::ON_CLICK );
1924 		pEffect->setPresetClass( ::com::sun::star::presentation::EffectPresetClass::MOTIONPATH );
1925 		pEffect->setAcceleration( 0.5 );
1926 		pEffect->setDecelerate( 0.5 );
1927 		pEffect->setFill( AnimationFill::HOLD );
1928 		pEffect->setBegin( 0.0 );
1929 		pEffect->updatePathFromSdrPathObj( rPathObj );
1930 		if( fDuration != -1.0 )
1931 			pEffect->setDuration( fDuration );
1932 
1933 		maEffects.push_back(pEffect);
1934 
1935 		rebuild();
1936 	}
1937 	catch( Exception& )
1938 	{
1939 		DBG_ERROR( "sd::EffectSequenceHelper::append(), exception caught!" );
1940 	}
1941 
1942 	return pEffect;
1943 }
1944 
1945 // --------------------------------------------------------------------
1946 
1947 void EffectSequenceHelper::replace( const CustomAnimationEffectPtr& pEffect, const CustomAnimationPresetPtr& pPreset, const OUString& rPresetSubType, double fDuration /* = -1.0 */ )
1948 {
1949 	if( pEffect.get() && pPreset.get() ) try
1950 	{
1951 		Reference< XAnimationNode > xNewNode( pPreset->create( rPresetSubType ) );
1952 		if( xNewNode.is() )
1953 		{
1954 			pEffect->replaceNode( xNewNode );
1955 			if( fDuration != -1.0 )
1956 				pEffect->setDuration( fDuration );
1957 		}
1958 
1959 		rebuild();
1960 	}
1961 	catch( Exception& e )
1962 	{
1963 		(void)e;
1964 		DBG_ERROR( "sd::EffectSequenceHelper::replace(), exception caught!" );
1965 	}
1966 }
1967 
1968 // --------------------------------------------------------------------
1969 
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 
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 
1991 void EffectSequenceHelper::rebuild()
1992 {
1993 	implRebuild();
1994 }
1995 
1996 // --------------------------------------------------------------------
1997 
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 caught!" );
2122 	}
2123 }
2124 
2125 // --------------------------------------------------------------------
2126 
2127 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 
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 
2142 bool stl_CustomAnimationEffect_search_node_predict::operator()( CustomAnimationEffectPtr pEffect ) const
2143 {
2144 	return pEffect->getNode() == mxSearchNode;
2145 }
2146 
2147 // --------------------------------------------------------------------
2148 
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 
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 caught!" );
2292 	}
2293 }
2294 
2295 // --------------------------------------------------------------------
2296 
2297 EffectSequence::iterator EffectSequenceHelper::find( const CustomAnimationEffectPtr& pEffect )
2298 {
2299 	return std::find( maEffects.begin(), maEffects.end(), pEffect );
2300 }
2301 
2302 // --------------------------------------------------------------------
2303 
2304 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 
2323 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 
2339 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 
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 
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 
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 
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 
2469 CustomAnimationTextGroup::CustomAnimationTextGroup( const Reference< XShape >& rTarget, sal_Int32 nGroupId )
2470 :	maTarget( rTarget ),
2471 	mnGroupId( nGroupId )
2472 {
2473 	reset();
2474 }
2475 
2476 // --------------------------------------------------------------------
2477 
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 
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 
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 
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 
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 
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 caught!" );
2744 	}
2745 }
2746 
2747 // --------------------------------------------------------------------
2748 
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 
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 
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 {
2946 	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 
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 
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 
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 
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 
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 {
3038 	stl_notify_listeners_func() {}
3039 	void operator()(ISequenceListener* pListener) { pListener->notify_change(); }
3040 };
3041 
3042 // --------------------------------------------------------------------
3043 
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 
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 caught!" );
3069 	}
3070 }
3071 
3072 // --------------------------------------------------------------------
3073 
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 caught!" );
3092 	}
3093 }
3094 
3095 // --------------------------------------------------------------------
3096 
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 caught!" );
3139 	}
3140 }
3141 
3142 // --------------------------------------------------------------------
3143 
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 caught!" );
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:
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 
3255 void SAL_CALL AnimationChangeListener::changesOccurred( const ::com::sun::star::util::ChangesEvent& ) throw (RuntimeException)
3256 {
3257 	if( mpMainSequence )
3258 		mpMainSequence->startRecreateTimer();
3259 }
3260 
3261 void SAL_CALL AnimationChangeListener::disposing( const ::com::sun::star::lang::EventObject& ) throw (RuntimeException)
3262 {
3263 }
3264 
3265 // ====================================================================
3266 
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 
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 
3297 MainSequence::~MainSequence()
3298 {
3299 	reset();
3300 }
3301 
3302 // --------------------------------------------------------------------
3303 
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 
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 
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 
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 caught!" );
3402 		return;
3403 	}
3404 
3405 	DBG_ASSERT( mxSequenceRoot.is(), "sd::MainSequence::create(), found no main sequence!" );
3406 }
3407 
3408 // --------------------------------------------------------------------
3409 
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 
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 
3461 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 
3478 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 
3502 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 
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 
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 
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 
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 */
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 
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 
3620 void MainSequence::rebuild()
3621 {
3622 	startRebuildTimer();
3623 }
3624 
3625 // --------------------------------------------------------------------
3626 
3627 void MainSequence::lockRebuilds()
3628 {
3629 	mnRebuildLockGuard++;
3630 }
3631 
3632 // --------------------------------------------------------------------
3633 
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 
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 
3689 void MainSequence::notify_change()
3690 {
3691 	notify_listeners();
3692 }
3693 
3694 // --------------------------------------------------------------------
3695 
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 
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 */
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 */
3771 void MainSequence::startRebuildTimer()
3772 {
3773 	mbTimerMode = true;
3774 	maTimer.Start();
3775 }
3776 
3777 // ====================================================================
3778 
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 caught!" );
3804 		return;
3805 	}
3806 }
3807 
3808 // --------------------------------------------------------------------
3809 
3810 void InteractiveSequence::rebuild()
3811 {
3812 	mpMainSequence->rebuild();
3813 }
3814 
3815 void InteractiveSequence::implRebuild()
3816 {
3817 	EffectSequenceHelper::implRebuild();
3818 }
3819 
3820 // --------------------------------------------------------------------
3821 
3822 MainSequenceRebuildGuard::MainSequenceRebuildGuard( const MainSequencePtr& pMainSequence )
3823 : mpMainSequence( pMainSequence )
3824 {
3825 	if( mpMainSequence.get() )
3826 		mpMainSequence->lockRebuilds();
3827 }
3828 
3829 MainSequenceRebuildGuard::~MainSequenceRebuildGuard()
3830 {
3831 	if( mpMainSequence.get() )
3832 		mpMainSequence->unlockRebuilds();
3833 }
3834 
3835 
3836 }
3837