1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "oox/ppt/timenodelistcontext.hxx"
29 
30 #include "comphelper/anytostring.hxx"
31 #include "cppuhelper/exc_hlp.hxx"
32 #include <osl/diagnose.h>
33 #include <rtl/math.hxx>
34 
35 #include <com/sun/star/animations/XTimeContainer.hpp>
36 #include <com/sun/star/animations/XAnimationNode.hpp>
37 #include <com/sun/star/animations/XAnimateColor.hpp>
38 #include <com/sun/star/animations/XAnimateSet.hpp>
39 #include <com/sun/star/animations/XAnimateTransform.hpp>
40 #include <com/sun/star/animations/AnimationTransformType.hpp>
41 #include <com/sun/star/animations/AnimationCalcMode.hpp>
42 #include <com/sun/star/animations/AnimationColorSpace.hpp>
43 #include <com/sun/star/animations/AnimationNodeType.hpp>
44 #include <com/sun/star/animations/XCommand.hpp>
45 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
46 #include <com/sun/star/presentation/EffectCommands.hpp>
47 #include <com/sun/star/beans/NamedValue.hpp>
48 
49 #include "oox/helper/attributelist.hxx"
50 #include "oox/core/xmlfilterbase.hxx"
51 #include "oox/drawingml/drawingmltypes.hxx"
52 #include "oox/drawingml/colorchoicecontext.hxx"
53 #include "oox/ppt/slidetransition.hxx"
54 
55 #include "animvariantcontext.hxx"
56 #include "commonbehaviorcontext.hxx"
57 #include "conditioncontext.hxx"
58 #include "commontimenodecontext.hxx"
59 #include "timeanimvaluecontext.hxx"
60 #include "animationtypes.hxx"
61 
62 using namespace ::oox::core;
63 using namespace ::oox::drawingml;
64 using namespace ::com::sun::star::uno;
65 using namespace ::com::sun::star::lang;
66 using namespace ::com::sun::star::animations;
67 using namespace ::com::sun::star::presentation;
68 using namespace ::com::sun::star::xml::sax;
69 using namespace ::com::sun::star::awt;
70 using ::com::sun::star::beans::NamedValue;
71 
72 using ::rtl::OUString;
73 
74 namespace oox { namespace ppt {
75 
76 	struct AnimColor
77 	{
78 		AnimColor(sal_Int16 cs, sal_Int32 o, sal_Int32 t, sal_Int32 th )
79 			: colorSpace( cs ), one( o ), two( t ), three( th )
80 			{
81 			}
82 
83 		sal_Int32 get()
84 			{
85 				sal_Int32 nColor;
86 
87 				switch( colorSpace )
88 				{
89 				case AnimationColorSpace::HSL:
90 					nColor = ( ( ( one * 128 ) / 360 ) & 0xff ) << 16
91 						| ( ( ( two * 128 ) / 1000 ) & 0xff ) << 8
92 						| ( ( ( three * 128 ) / 1000 )  & 0xff );
93 					break;
94 				case AnimationColorSpace::RGB:
95 					nColor = ( ( ( one * 128 ) / 1000 ) & 0xff ) << 16
96 						| ( ( ( two * 128 ) / 1000 ) & 0xff ) << 8
97 						| ( ( ( three * 128 ) / 1000 )  & 0xff );
98 					break;
99 				default:
100 					nColor = 0;
101 					break;
102 				}
103 				return  nColor;
104 			}
105 
106 		sal_Int16 colorSpace;
107 		sal_Int32 one;
108 		sal_Int32 two;
109 		sal_Int32 three;
110 	};
111 
112 
113 	/** CT_TLMediaNodeAudio
114 			CT_TLMediaNodeVideo */
115 	class MediaNodeContext
116 		: public TimeNodeContext
117 	{
118 	public:
119         MediaNodeContext( ContextHandler& rParent, sal_Int32  aElement,
120                             const Reference< XFastAttributeList >& xAttribs,
121                             const TimeNodePtr & pNode )
122             : TimeNodeContext( rParent, aElement, xAttribs, pNode )
123 				, mbIsNarration( false )
124 				, mbFullScrn( false )
125 			{
126 				AttributeList attribs( xAttribs );
127 
128 				switch( aElement )
129 				{
130 				case PPT_TOKEN( audio ):
131 					mbIsNarration = attribs.getBool( XML_isNarration, false );
132 					break;
133 				case PPT_TOKEN( video ):
134 					mbFullScrn = attribs.getBool( XML_fullScrn, false );
135 					break;
136 				default:
137 					break;
138 				}
139 			}
140 
141 		virtual void SAL_CALL endFastElement( sal_Int32 aElement )
142 			throw ( SAXException, RuntimeException)
143 			{
144 				if( aElement == PPT_TOKEN( audio ) )
145 				{
146 					// TODO deal with mbIsNarration
147 				}
148 				else if( aElement == PPT_TOKEN( video ) )
149 				{
150 					// TODO deal with mbFullScrn
151 				}
152 			}
153 
154 		virtual Reference< XFastContextHandler > SAL_CALL createFastChildContext( ::sal_Int32 aElementToken,
155 																																							const Reference< XFastAttributeList >& xAttribs )
156 			throw ( SAXException, RuntimeException )
157 			{
158 				Reference< XFastContextHandler > xRet;
159 
160 				switch ( aElementToken )
161 				{
162 				case PPT_TOKEN( cBhvr ):
163                     xRet.set( new CommonBehaviorContext ( *this, xAttribs, mpNode ) );
164 					break;
165 				default:
166 					break;
167 				}
168 
169 				if( !xRet.is() )
170 					xRet.set( this );
171 
172 				return xRet;
173 			}
174 
175 	private:
176 		bool mbIsNarration;
177 		bool mbFullScrn;
178 	};
179 
180 
181 	/** CT_TLSetBehavior
182 	 */
183 	class SetTimeNodeContext
184 		: public TimeNodeContext
185 	{
186 	public:
187         SetTimeNodeContext( ContextHandler& rParent, sal_Int32  aElement,
188                             const Reference< XFastAttributeList >& xAttribs,
189                             const TimeNodePtr & pNode )
190             : TimeNodeContext( rParent, aElement, xAttribs, pNode )
191 			{
192 
193 			}
194 
195 		~SetTimeNodeContext() throw ()
196 			{
197 				if( maTo.hasValue() )
198 				{
199 					// TODO
200 					// HACK !!! discard and refactor
201 					OUString aString;
202 					if( maTo >>= aString )
203 					{
204 						OSL_TRACE( "Magic conversion %s", OUSTRING_TO_CSTR( aString ) );
205 						maTo = makeAny( aString.equalsAscii( "visible" ) ? sal_True : sal_False );
206 						if( !maTo.has<sal_Bool>() )
207 							OSL_TRACE( "conversion failed" );
208 					}
209 					mpNode->setTo( maTo );
210 				}
211 
212 			}
213 
214 		virtual void SAL_CALL endFastElement( sal_Int32 /*aElement*/ )
215 			throw ( SAXException, RuntimeException)
216 			{
217 			}
218 
219 
220 		virtual Reference< XFastContextHandler > SAL_CALL createFastChildContext( ::sal_Int32 aElementToken,
221 																																							const Reference< XFastAttributeList >& xAttribs )
222 			throw ( SAXException, RuntimeException )
223 			{
224 				Reference< XFastContextHandler > xRet;
225 
226 				switch ( aElementToken )
227 				{
228 				case PPT_TOKEN( cBhvr ):
229                     xRet.set( new CommonBehaviorContext ( *this, xAttribs, mpNode ) );
230 					break;
231 				case PPT_TOKEN( to ):
232 					// CT_TLAnimVariant
233                     xRet.set( new AnimVariantContext( *this, aElementToken, maTo ) );
234 					break;
235 				default:
236 					break;
237 				}
238 
239 				if( !xRet.is() )
240 					xRet.set( this );
241 
242 				return xRet;
243 			}
244 	private:
245 		Any  maTo;
246 	};
247 
248 	/** CT_TLCommandBehavior
249 	 */
250 	class CmdTimeNodeContext
251 		: public TimeNodeContext
252 	{
253 	public:
254         CmdTimeNodeContext( ContextHandler& rParent, sal_Int32  aElement,
255                             const Reference< XFastAttributeList >& xAttribs,
256                             const TimeNodePtr & pNode )
257             : TimeNodeContext( rParent, aElement, xAttribs, pNode )
258 				, maType(0)
259 			{
260 				switch ( aElement )
261 				{
262 				case PPT_TOKEN( cmd ):
263 					msCommand = xAttribs->getOptionalValue( XML_cmd );
264 					maType = xAttribs->getOptionalValueToken( XML_type, 0 );
265 					break;
266 				default:
267 					break;
268 				}
269 			}
270 
271 		~CmdTimeNodeContext() throw ()
272 			{
273 			}
274 
275 		virtual void SAL_CALL endFastElement( sal_Int32 aElement )
276 			throw ( SAXException, RuntimeException)
277 			{
278 				if( aElement == PPT_TOKEN( cmd ) )
279 				{
280 					try {
281 						// see sd/source/filter/ppt/pptinanimations.cxx
282 						// in AnimationImporter::importCommandContainer()
283 						// REFACTOR?
284 						// a good chunk of this code has been copied verbatim *sigh*
285 						sal_Int16 nCommand = EffectCommands::CUSTOM;
286 						NamedValue aParamValue;
287 
288 						switch( maType )
289 						{
290 						case XML_verb:
291 							aParamValue.Name = OUString(RTL_CONSTASCII_USTRINGPARAM("Verb"));
292 							// TODO make sure msCommand has what we want
293 							aParamValue.Value <<= msCommand.toInt32();
294 							nCommand = EffectCommands::VERB;
295 							break;
296 						case XML_evt:
297 						case XML_call:
298 							if( msCommand.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "onstopaudio" ) ) )
299 							{
300 								nCommand = EffectCommands::STOPAUDIO;
301 							}
302 							else if( msCommand.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("play") ) )
303 							{
304 								nCommand = EffectCommands::PLAY;
305 							}
306 							else if( msCommand.compareToAscii( RTL_CONSTASCII_STRINGPARAM("playFrom") ) == 0 )
307 							{
308 								const OUString aMediaTime( msCommand.copy( 9, msCommand.getLength() - 10 ) );
309 								rtl_math_ConversionStatus eStatus;
310 								double fMediaTime = ::rtl::math::stringToDouble( aMediaTime, (sal_Unicode)('.'), (sal_Unicode)(','), &eStatus, NULL );
311 								if( eStatus == rtl_math_ConversionStatus_Ok )
312 								{
313 									aParamValue.Name = CREATE_OUSTRING("MediaTime");
314 									aParamValue.Value <<= fMediaTime;
315 								}
316 								nCommand = EffectCommands::PLAY;
317 							}
318 							else if( msCommand.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("togglePause") ) )
319 							{
320 								nCommand = EffectCommands::TOGGLEPAUSE;
321 							}
322 							else if( msCommand.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("stop") ) )
323 							{
324 								nCommand = EffectCommands::STOP;
325 							}
326 							break;
327 						}
328 						mpNode->getNodeProperties()[ NP_COMMAND ] = makeAny((sal_Int16)nCommand);
329 						if( nCommand == EffectCommands::CUSTOM )
330 						{
331 							OSL_TRACE("OOX: CmdTimeNodeContext::endFastElement(), unknown command!");
332 							aParamValue.Name = CREATE_OUSTRING("UserDefined");
333 							aParamValue.Value <<= msCommand;
334 						}
335 						if( aParamValue.Value.hasValue() )
336 						{
337 							Sequence< NamedValue > aParamSeq( &aParamValue, 1 );
338 							mpNode->getNodeProperties()[ NP_PARAMETER ] = makeAny( aParamSeq );
339 						}
340 					}
341 					catch( RuntimeException& )
342 					{
343 						OSL_TRACE( "OOX: Exception in CmdTimeNodeContext::endFastElement()" );
344 					}
345 				}
346 			}
347 
348 
349 		virtual Reference< XFastContextHandler > SAL_CALL createFastChildContext( ::sal_Int32 aElementToken,
350 																																							const Reference< XFastAttributeList >& xAttribs )
351 			throw ( SAXException, RuntimeException )
352 			{
353 				Reference< XFastContextHandler > xRet;
354 
355 				switch ( aElementToken )
356 				{
357 				case PPT_TOKEN( cBhvr ):
358                     xRet.set( new CommonBehaviorContext ( *this, xAttribs, mpNode ) );
359 					break;
360 				default:
361 					break;
362 				}
363 
364 				if( !xRet.is() )
365 					xRet.set( this );
366 
367 				return xRet;
368 			}
369 
370 	private:
371 		OUString msCommand;
372 		sal_Int32 maType;
373 	};
374 
375 
376 	/** CT_TLTimeNodeSequence
377 	 */
378 	class SequenceTimeNodeContext
379 		: public TimeNodeContext
380 	{
381 	public:
382         SequenceTimeNodeContext( ContextHandler& rParent, sal_Int32  aElement,
383                                  const Reference< XFastAttributeList >& xAttribs,
384                                  const TimeNodePtr & pNode )
385             : TimeNodeContext( rParent, aElement, xAttribs, pNode )
386 				, mnNextAc(0)
387 				, mnPrevAc(0)
388 			{
389 				AttributeList attribs(xAttribs);
390 				mbConcurrent = attribs.getBool( XML_concurrent, false );
391 				// ST_TLNextActionType { none, seek }
392 				mnNextAc = xAttribs->getOptionalValueToken( XML_nextAc, 0 );
393 				// ST_TLPreviousActionType { none, skipTimed }
394 				mnPrevAc = xAttribs->getOptionalValueToken( XML_prevAc, 0 );
395 			}
396 
397 		~SequenceTimeNodeContext() throw()
398 			{
399 			}
400 
401 
402 		virtual Reference< XFastContextHandler > SAL_CALL createFastChildContext( ::sal_Int32 aElementToken,
403 																																							const Reference< XFastAttributeList >& xAttribs )
404 			throw ( SAXException, RuntimeException )
405 			{
406 				Reference< XFastContextHandler > xRet;
407 
408 				switch ( aElementToken )
409 				{
410 				case PPT_TOKEN( cTn ):
411                     xRet.set( new CommonTimeNodeContext( *this, aElementToken, xAttribs, mpNode ) );
412 					break;
413 				case PPT_TOKEN( nextCondLst ):
414                     xRet.set( new CondListContext( *this, aElementToken, xAttribs, mpNode,
415 												   mpNode->getNextCondition() ) );
416 					break;
417 				case PPT_TOKEN( prevCondLst ):
418                     xRet.set( new CondListContext( *this, aElementToken, xAttribs, mpNode,
419 												   mpNode->getPrevCondition() ) );
420 					break;
421 				default:
422 					break;
423 				}
424 
425 				if( !xRet.is() )
426 					xRet.set( this );
427 
428 				return xRet;
429 			}
430 	private:
431 		bool mbConcurrent;
432 		sal_Int32 mnNextAc, mnPrevAc;
433 	};
434 
435 
436 	/** CT_TLTimeNodeParallel
437 	 *  CT_TLTimeNodeExclusive
438 	 */
439 	class ParallelExclTimeNodeContext
440 		: public TimeNodeContext
441 	{
442 	public:
443         ParallelExclTimeNodeContext( ContextHandler& rParent, sal_Int32  aElement,
444                                      const Reference< XFastAttributeList >& xAttribs,
445                                      const TimeNodePtr & pNode )
446             : TimeNodeContext( rParent, aElement, xAttribs, pNode )
447 			{
448 			}
449 
450 		virtual Reference< XFastContextHandler > SAL_CALL createFastChildContext( ::sal_Int32 aElementToken,
451 																																							const Reference< XFastAttributeList >& xAttribs )
452 			throw ( SAXException, RuntimeException )
453 			{
454 				Reference< XFastContextHandler > xRet;
455 
456 				switch ( aElementToken )
457 				{
458 				case PPT_TOKEN( cTn ):
459                     xRet.set( new CommonTimeNodeContext( *this, aElementToken, xAttribs, mpNode ) );
460 					break;
461 				default:
462 					break;
463 				}
464 
465 				if( !xRet.is() )
466 					xRet.set( this );
467 
468 				return xRet;
469 			}
470 
471 	protected:
472 
473 	};
474 
475 
476 	/** CT_TLAnimateColorBehavior */
477 	class AnimColorContext
478 		: public TimeNodeContext
479 	{
480 	public:
481         AnimColorContext( ContextHandler& rParent, sal_Int32  aElement,
482                             const Reference< XFastAttributeList >& xAttribs,
483                             const TimeNodePtr & pNode ) throw()
484             : TimeNodeContext( rParent, aElement, xAttribs, pNode )
485 				// ST_TLAnimateColorSpace ( XML_rgb, XML_hsl }
486 			, mnColorSpace( xAttribs->getOptionalValueToken( XML_clrSpc, 0 ) )
487 				// ST_TLAnimateColorDirection { XML_cw, XML_ccw }
488 			, mnDir( xAttribs->getOptionalValueToken( XML_dir, 0 ) )
489 			, mbHasByColor( false )
490 			, m_byColor( AnimationColorSpace::RGB, 0, 0, 0)
491 			{
492 			}
493 		~AnimColorContext() throw()
494 			{
495 			}
496 
497 		virtual void SAL_CALL endFastElement( sal_Int32 aElement ) throw ( SAXException, RuntimeException)
498 			{
499 				//xParentNode
500 				if( aElement == mnElement )
501 				{
502 					NodePropertyMap & pProps(mpNode->getNodeProperties());
503 					pProps[ NP_DIRECTION ] = makeAny( mnDir == XML_cw );
504 					pProps[ NP_COLORINTERPOLATION ] = makeAny( mnColorSpace == XML_hsl ? AnimationColorSpace::HSL : AnimationColorSpace::RGB );
505                     const GraphicHelper& rGraphicHelper = getFilter().getGraphicHelper();
506 					if( maToClr.isUsed() )
507                         mpNode->setTo( Any( maToClr.getColor( rGraphicHelper ) ) );
508 					if( maFromClr.isUsed() )
509                         mpNode->setFrom( Any( maFromClr.getColor( rGraphicHelper ) ) );
510 					if( mbHasByColor )
511 						mpNode->setBy( Any ( m_byColor.get() ) );
512 				}
513 			}
514 
515 
516 		virtual Reference< XFastContextHandler > SAL_CALL createFastChildContext( ::sal_Int32 aElementToken, const Reference< XFastAttributeList >& xAttribs ) throw ( SAXException, RuntimeException )
517 			{
518 				Reference< XFastContextHandler > xRet;
519 
520 				switch ( aElementToken )
521 				{
522 				case PPT_TOKEN( hsl ):
523 					// CT_TLByHslColorTransform
524 				{
525 					if( mbHasByColor )
526 					{
527 						m_byColor.colorSpace = AnimationColorSpace::HSL;
528 						m_byColor.one = xAttribs->getOptionalValue( XML_h ).toInt32( );
529 						m_byColor.two = xAttribs->getOptionalValue( XML_s ).toInt32( );
530 						m_byColor.three = xAttribs->getOptionalValue( XML_l ).toInt32( );
531 					}
532 					xRet.set(this);
533 					break;
534 				}
535 				case PPT_TOKEN( rgb ):
536 				{
537 					if( mbHasByColor )
538 					{
539 						// CT_TLByRgbColorTransform
540 						m_byColor.colorSpace = AnimationColorSpace::RGB;
541 						m_byColor.one = xAttribs->getOptionalValue( XML_r ).toInt32();
542 						m_byColor.two = xAttribs->getOptionalValue( XML_g ).toInt32();
543 						m_byColor.three = xAttribs->getOptionalValue( XML_b ).toInt32();
544 					}
545 					xRet.set(this);
546 					break;
547 				}
548 				case PPT_TOKEN( by ):
549 					// CT_TLByAnimateColorTransform
550 					mbHasByColor = true;
551 					xRet.set(this);
552 					break;
553 				case PPT_TOKEN( cBhvr ):
554                     xRet.set( new CommonBehaviorContext ( *this, xAttribs, mpNode ) );
555 					break;
556 				case PPT_TOKEN( to ):
557 					// CT_Color
558                     xRet.set( new ColorContext( *this, maToClr ) );
559 					break;
560 				case PPT_TOKEN( from ):
561 					// CT_Color
562                     xRet.set( new ColorContext( *this, maFromClr ) );
563 					break;
564 
565 				default:
566 					break;
567 				}
568 
569 				if( !xRet.is() )
570 					xRet.set( this );
571 
572 				return xRet;
573 			}
574 
575 
576 	private:
577 		sal_Int32 mnColorSpace;
578 		sal_Int32 mnDir;
579 		bool mbHasByColor;
580 		AnimColor m_byColor;
581 		oox::drawingml::Color maToClr;
582 		oox::drawingml::Color maFromClr;
583 	};
584 
585 
586 	/** CT_TLAnimateBehavior */
587 	class AnimContext
588 		: public TimeNodeContext
589 	{
590 	public:
591         AnimContext( ContextHandler& rParent, sal_Int32  aElement,
592                      const Reference< XFastAttributeList >& xAttribs,
593                       const TimeNodePtr & pNode ) throw()
594             : TimeNodeContext( rParent, aElement, xAttribs, pNode )
595 			{
596 				NodePropertyMap & aProps( pNode->getNodeProperties() );
597 				sal_Int32 nCalcMode = xAttribs->getOptionalValueToken( XML_calcmode, 0 );
598 				if(nCalcMode)
599 				{
600 					sal_Int16 nEnum = 0;
601 					switch(nCalcMode)
602 					{
603 					case XML_discrete:
604 						nEnum = AnimationCalcMode::DISCRETE;
605 						break;
606 					case XML_lin:
607 						nEnum = AnimationCalcMode::LINEAR;
608 						break;
609 					case XML_fmla:
610 					default:
611 						// TODO what value is good ?
612 						nEnum = AnimationCalcMode::DISCRETE;
613 						break;
614 					}
615 					aProps[ NP_CALCMODE ] = makeAny(nEnum);
616 				}
617 				OUString aStr;
618 				aStr = xAttribs->getOptionalValue( XML_from );
619 				if( aStr.getLength() )
620 				{
621 					pNode->setFrom( makeAny( aStr ) );
622 				}
623 				aStr = xAttribs->getOptionalValue( XML_by );
624 				if( aStr.getLength() )
625 				{
626 					pNode->setBy( makeAny( aStr ) );
627 				}
628 				aStr = xAttribs->getOptionalValue( XML_to );
629 				if( aStr.getLength() )
630 				{
631 					pNode->setTo( makeAny( aStr ) );
632 				}
633 				mnValueType = xAttribs->getOptionalValueToken( XML_valueType, 0 );
634 			}
635 
636 
637 		~AnimContext() throw ()
638 			{
639 				::std::list< TimeAnimationValue >::iterator iter, end;
640 				int nKeyTimes = maTavList.size();
641 				if( nKeyTimes > 0)
642 				{
643 					int i;
644 					Sequence< double > aKeyTimes( nKeyTimes );
645 					Sequence< Any > aValues( nKeyTimes );
646 
647 					NodePropertyMap & aProps( mpNode->getNodeProperties() );
648 					end = maTavList.end();
649 					for(iter = maTavList.begin(), i=0; iter != end; iter++,i++)
650 					{
651 						// TODO what to do if it is Timing_INFINITE ?
652 						Any aTime = GetTimeAnimateValueTime( iter->msTime );
653 						aTime >>= aKeyTimes[i];
654 						aValues[i] = iter->maValue;
655 
656 						OUString aTest;
657 						iter->maValue >>= aTest;
658 						if( aTest.getLength() != 0 )
659 						{
660 							aValues[i] = iter->maValue;
661 						}
662 						else
663 						{
664 							aProps[ NP_FORMULA ] <<= iter->msFormula;
665 						}
666 					}
667 					aProps[ NP_VALUES ] <<= aValues;
668 					aProps[ NP_KEYTIMES ] <<= aKeyTimes;
669 				}
670 			}
671 
672 
673 		virtual Reference< XFastContextHandler > SAL_CALL createFastChildContext( ::sal_Int32 aElementToken, const Reference< XFastAttributeList >& xAttribs ) throw ( SAXException, RuntimeException )
674 			{
675 				Reference< XFastContextHandler > xRet;
676 
677 				switch ( aElementToken )
678 				{
679 				case PPT_TOKEN( cBhvr ):
680                     xRet.set( new CommonBehaviorContext ( *this, xAttribs, mpNode ) );
681 					break;
682 				case PPT_TOKEN( tavLst ):
683                     xRet.set( new TimeAnimValueListContext ( *this, xAttribs, maTavList ) );
684 					break;
685 				default:
686 					break;
687 				}
688 
689 				if( !xRet.is() )
690 					xRet.set( this );
691 
692 				return xRet;
693 			}
694 	private:
695 		sal_Int32              mnValueType;
696 		TimeAnimationValueList maTavList;
697 	};
698 
699 
700 	/** CT_TLAnimateScaleBehavior */
701 	class AnimScaleContext
702 		: public TimeNodeContext
703 	{
704 	public:
705         AnimScaleContext( ContextHandler& rParent, sal_Int32  aElement,
706                             const Reference< XFastAttributeList >& xAttribs,
707                             const TimeNodePtr & pNode ) throw()
708             : TimeNodeContext( rParent, aElement, xAttribs, pNode )
709 				, mbZoomContents( false )
710 			{
711 				AttributeList attribs( xAttribs );
712 				// TODO what to do with mbZoomContents
713 				mbZoomContents = attribs.getBool( XML_zoomContents, false );
714 				pNode->getNodeProperties()[ NP_TRANSFORMTYPE ]
715 					= makeAny((sal_Int16)AnimationTransformType::SCALE);
716 			}
717 
718 		~AnimScaleContext( ) throw( )
719 			{
720 			}
721 
722 		virtual void SAL_CALL endFastElement( sal_Int32 aElement ) throw ( SAXException, RuntimeException)
723 			{
724 				if( aElement == mnElement )
725 				{
726 					if( maTo.hasValue() )
727 					{
728 						mpNode->setTo( maTo );
729 					}
730 					if( maBy.hasValue() )
731 					{
732 						mpNode->setBy( maBy );
733 					}
734 					if( maFrom.hasValue() )
735 					{
736 						mpNode->setFrom( maFrom );
737 					}
738 				}
739 			}
740 
741 		virtual Reference< XFastContextHandler > SAL_CALL createFastChildContext( ::sal_Int32 aElementToken,
742 																																							const Reference< XFastAttributeList >& xAttribs )
743 			throw ( SAXException, RuntimeException )
744 			{
745 				Reference< XFastContextHandler > xRet;
746 
747 				switch ( aElementToken )
748 				{
749 				case PPT_TOKEN( cBhvr ):
750                     xRet.set( new CommonBehaviorContext ( *this, xAttribs, mpNode ) );
751 					break;
752 				case PPT_TOKEN( to ):
753 				{
754 					// CT_TLPoint
755 					Point p = GetPointPercent( xAttribs );
756 					maTo <<= p.X;
757 					maTo <<= p.Y;
758 					break;
759 				}
760 				case PPT_TOKEN( from ):
761 				{
762 					// CT_TLPoint
763 					Point p = GetPointPercent( xAttribs );
764 					maFrom <<= p.X;
765 					maFrom <<= p.Y;
766 					break;
767 				}
768 				case PPT_TOKEN( by ):
769 				{
770 					// CT_TLPoint
771 					Point p = GetPointPercent( xAttribs );
772 					maBy <<= p.X;
773 					maBy <<= p.Y;
774 					break;
775 				}
776 				default:
777 					break;
778 				}
779 
780 				if( !xRet.is() )
781 					xRet.set( this );
782 
783 				return xRet;
784 			}
785 	private:
786 		Any maBy;
787 		Any maFrom;
788 		Any maTo;
789 		bool mbZoomContents;
790 	};
791 
792 
793 	/** CT_TLAnimateRotationBehavior */
794 	class AnimRotContext
795 		: public TimeNodeContext
796 	{
797 	public:
798         AnimRotContext( ContextHandler& rParent, sal_Int32  aElement,
799                         const Reference< XFastAttributeList >& xAttribs,
800                          const TimeNodePtr & pNode ) throw()
801             : TimeNodeContext( rParent, aElement, xAttribs, pNode )
802 			{
803 				AttributeList attribs( xAttribs );
804 
805 				pNode->getNodeProperties()[ NP_TRANSFORMTYPE ]
806 					= makeAny((sal_Int16)AnimationTransformType::ROTATE);
807 				// TODO make sure the units are OK
808 				if(attribs.hasAttribute( XML_by ) )
809 				{
810 					sal_Int32 nBy = attribs.getInteger( XML_by, 0 );
811 					pNode->setBy( makeAny( nBy ) );
812 				}
813 				if(attribs.hasAttribute( XML_from ) )
814 				{
815 					sal_Int32 nFrom = attribs.getInteger( XML_from, 0 );
816 					pNode->setFrom( makeAny( nFrom ) );
817 				}
818 				if(attribs.hasAttribute( XML_to ) )
819 				{
820 					sal_Int32 nTo = attribs.getInteger( XML_to, 0 );
821 					pNode->setTo( makeAny( nTo ) );
822 				}
823 			}
824 
825 		~AnimRotContext( ) throw( )
826 			{
827 			}
828 
829 		virtual Reference< XFastContextHandler > SAL_CALL createFastChildContext( ::sal_Int32 aElementToken, const Reference< XFastAttributeList >& xAttribs ) throw ( SAXException, RuntimeException )
830 			{
831 				Reference< XFastContextHandler > xRet;
832 
833 				switch ( aElementToken )
834 				{
835 				case PPT_TOKEN( cBhvr ):
836                     xRet.set( new CommonBehaviorContext ( *this, xAttribs, mpNode ) );
837 					break;
838 				default:
839 					break;
840 				}
841 
842 				if( !xRet.is() )
843 					xRet.set( this );
844 
845 				return xRet;
846 			}
847 	};
848 
849 
850 
851 	/** CT_TLAnimateMotionBehavior */
852 	class AnimMotionContext
853 		: public TimeNodeContext
854 	{
855 	public:
856         AnimMotionContext( ContextHandler& rParent, sal_Int32  aElement,
857                          const Reference< XFastAttributeList >& xAttribs,
858                           const TimeNodePtr & pNode ) throw()
859             : TimeNodeContext( rParent, aElement, xAttribs, pNode )
860 			{
861 				pNode->getNodeProperties()[ NP_TRANSFORMTYPE ]
862 					= makeAny((sal_Int16)AnimationTransformType::TRANSLATE);
863 
864 				AttributeList attribs( xAttribs );
865 				// ST_TLAnimateMotionBehaviorOrigin { parent, layour }
866 				sal_Int32 nOrigin = xAttribs->getOptionalValueToken( XML_origin, 0 );
867 				if( nOrigin != 0 )
868 				{
869 					switch(nOrigin)
870 					{
871 					case XML_layout:
872 					case XML_parent:
873 						break;
874 					}
875 					// TODO
876 				}
877 
878 				OUString aStr = xAttribs->getOptionalValue( XML_path );
879 				aStr = aStr.replace( 'E', ' ' );
880 				aStr = aStr.trim();
881 				pNode->getNodeProperties()[ NP_PATH ] = makeAny(aStr);
882 
883 				// ST_TLAnimateMotionPathEditMode{ fixed, relative }
884 				mnPathEditMode = xAttribs->getOptionalValueToken( XML_pathEditMode, 0 );
885 				msPtsTypes = xAttribs->getOptionalValue( XML_ptsTypes );
886 				mnAngle = attribs.getInteger( XML_rAng, 0 );
887 				// TODO make sure the units are right. Likely not.
888 			}
889 
890 		~AnimMotionContext( ) throw()
891 			{
892 			}
893 
894 
895 		virtual Reference< XFastContextHandler > SAL_CALL createFastChildContext( ::sal_Int32 aElementToken,
896 																																							const Reference< XFastAttributeList >& xAttribs )
897 			throw ( SAXException, RuntimeException )
898 			{
899 				Reference< XFastContextHandler > xRet;
900 
901 				switch ( aElementToken )
902 				{
903 				case PPT_TOKEN( cBhvr ):
904                     xRet.set( new CommonBehaviorContext ( *this, xAttribs, mpNode ) );
905 					break;
906 				case PPT_TOKEN( to ):
907 				{
908 					// CT_TLPoint
909 					Point p = GetPointPercent( xAttribs );
910 					Any rAny;
911 					rAny <<= p.X;
912 					rAny <<= p.Y;
913 					mpNode->setTo( rAny );
914 					break;
915 				}
916 				case PPT_TOKEN( from ):
917 				{
918 					// CT_TLPoint
919 					Point p = GetPointPercent( xAttribs );
920 					Any rAny;
921 					rAny <<= p.X;
922 					rAny <<= p.Y;
923 					mpNode->setFrom( rAny );
924 					break;
925 				}
926 				case PPT_TOKEN( by ):
927 				{
928 					// CT_TLPoint
929 					Point p = GetPointPercent( xAttribs );
930 					Any rAny;
931 					rAny <<= p.X;
932 					rAny <<= p.Y;
933 					mpNode->setBy( rAny );
934 					break;
935 				}
936 				case PPT_TOKEN( rCtr ):
937 				{
938 					// CT_TLPoint
939 					Point p = GetPointPercent( xAttribs );
940 					// TODO push
941 					break;
942 				}
943 				default:
944 					break;
945 				}
946 
947 				if( !xRet.is() )
948 					xRet.set( this );
949 
950 				return xRet;
951 			}
952 	private:
953 		OUString msPtsTypes;
954 		sal_Int32 mnPathEditMode;
955 		sal_Int32 mnAngle;
956 	};
957 
958 
959 	/** CT_TLAnimateEffectBehavior */
960 	class AnimEffectContext
961 		: public TimeNodeContext
962 	{
963 	public:
964         AnimEffectContext( ContextHandler& rParent, sal_Int32  aElement,
965                              const Reference< XFastAttributeList >& xAttribs,
966                              const TimeNodePtr & pNode ) throw()
967             : TimeNodeContext( rParent, aElement, xAttribs, pNode )
968 			{
969 				sal_Int32 nDir = xAttribs->getOptionalValueToken( XML_transition, 0 );
970 				OUString sFilter = xAttribs->getOptionalValue( XML_filter );
971 				// TODO
972 //				OUString sPrList = xAttribs->getOptionalValue( XML_prLst );
973 
974 				if( sFilter.getLength() )
975 				{
976 					SlideTransition aFilter( sFilter );
977 					aFilter.setMode( nDir == XML_out ? false : true );
978 					pNode->setTransitionFilter( aFilter );
979 				}
980 			}
981 
982 
983 		~AnimEffectContext( ) throw()
984 			{
985 			}
986 
987 
988 		virtual Reference< XFastContextHandler > SAL_CALL createFastChildContext( ::sal_Int32 aElementToken, const Reference< XFastAttributeList >& xAttribs ) throw ( SAXException, RuntimeException )
989 			{
990 				Reference< XFastContextHandler > xRet;
991 
992 				switch ( aElementToken )
993 				{
994 				case PPT_TOKEN( cBhvr ):
995                     xRet.set( new CommonBehaviorContext ( *this, xAttribs, mpNode ) );
996 					break;
997 				case PPT_TOKEN( progress ):
998                     xRet.set( new AnimVariantContext( *this, aElementToken, maProgress ) );
999 					// TODO handle it.
1000 					break;
1001 				default:
1002 					break;
1003 				}
1004 
1005 				if( !xRet.is() )
1006 					xRet.set( this );
1007 
1008 				return xRet;
1009 			}
1010 	private:
1011 		Any maProgress;
1012 		OUString msFilter;
1013 		OUString msPrList;
1014 	};
1015 
1016 
1017 
1018     TimeNodeContext * TimeNodeContext::makeContext(
1019             ContextHandler& rParent, sal_Int32  aElement,
1020             const Reference< XFastAttributeList >& xAttribs,
1021             const TimeNodePtr & pNode )
1022 	{
1023 		TimeNodeContext *pCtx = NULL;
1024 		switch( aElement )
1025 		{
1026 		case PPT_TOKEN( animClr ):
1027             pCtx = new AnimColorContext( rParent, aElement, xAttribs, pNode );
1028 			break;
1029 		case PPT_TOKEN( par ):
1030             pCtx = new ParallelExclTimeNodeContext( rParent, aElement, xAttribs, pNode );
1031 			break;
1032 		case PPT_TOKEN( seq ):
1033             pCtx = new SequenceTimeNodeContext( rParent, aElement, xAttribs, pNode );
1034 			break;
1035 		case PPT_TOKEN( excl ):
1036             pCtx = new ParallelExclTimeNodeContext( rParent, aElement, xAttribs, pNode );
1037 			break;
1038 		case PPT_TOKEN( anim ):
1039             pCtx = new AnimContext ( rParent, aElement, xAttribs, pNode );
1040 			break;
1041 		case PPT_TOKEN( animEffect ):
1042             pCtx = new AnimEffectContext( rParent, aElement, xAttribs, pNode );
1043 			break;
1044 		case PPT_TOKEN( animMotion ):
1045             pCtx = new AnimMotionContext( rParent, aElement, xAttribs, pNode );
1046 			break;
1047 		case PPT_TOKEN( animRot ):
1048             pCtx = new AnimRotContext( rParent, aElement, xAttribs, pNode );
1049 			break;
1050 		case PPT_TOKEN( animScale ):
1051             pCtx = new AnimScaleContext( rParent, aElement, xAttribs, pNode );
1052 			break;
1053 		case PPT_TOKEN( cmd ):
1054             pCtx = new CmdTimeNodeContext( rParent, aElement, xAttribs, pNode );
1055 			break;
1056 		case PPT_TOKEN( set ):
1057             pCtx = new SetTimeNodeContext( rParent, aElement, xAttribs, pNode );
1058 			break;
1059 		case PPT_TOKEN( audio ):
1060 		case PPT_TOKEN( video ):
1061             pCtx = new MediaNodeContext( rParent, aElement, xAttribs, pNode );
1062 			break;
1063 		default:
1064 			break;
1065 		}
1066 		return pCtx;
1067 	}
1068 
1069 
1070     TimeNodeContext::TimeNodeContext( ContextHandler& rParent, sal_Int32 aElement,
1071             const Reference< XFastAttributeList >& /*xAttribs*/,
1072             const TimeNodePtr & pNode ) throw()
1073         : ContextHandler( rParent )
1074 		, mnElement( aElement )
1075 		, mpNode( pNode )
1076 	{
1077 	}
1078 
1079 
1080 	TimeNodeContext::~TimeNodeContext( ) throw()
1081 	{
1082 
1083 	}
1084 
1085 
1086     TimeNodeListContext::TimeNodeListContext( ContextHandler& rParent, TimeNodePtrList & aList )
1087 		throw()
1088         : ContextHandler( rParent )
1089 			, maList( aList )
1090 	{
1091 	}
1092 
1093 
1094 	TimeNodeListContext::~TimeNodeListContext( ) throw()
1095 	{
1096 	}
1097 
1098 
1099 	Reference< XFastContextHandler > SAL_CALL TimeNodeListContext::createFastChildContext( ::sal_Int32 aElementToken, const Reference< XFastAttributeList >& xAttribs ) throw (SAXException, RuntimeException)
1100 	{
1101 		Reference< XFastContextHandler > xRet;
1102 
1103 		sal_Int16 nNodeType;
1104 
1105 		switch( aElementToken )
1106 		{
1107 		case PPT_TOKEN( par ):
1108 			nNodeType = AnimationNodeType::PAR;
1109 			break;
1110 		case PPT_TOKEN( seq ):
1111 			nNodeType = AnimationNodeType::SEQ;
1112 			break;
1113 		case PPT_TOKEN( excl ):
1114 			// TODO pick the right type. We choose parallel for now as
1115 			// there does not seem to be an "Exclusive"
1116 			nNodeType = AnimationNodeType::PAR;
1117 			break;
1118 		case PPT_TOKEN( anim ):
1119 			nNodeType = AnimationNodeType::ANIMATE;
1120 			break;
1121 		case PPT_TOKEN( animClr ):
1122 			nNodeType = AnimationNodeType::ANIMATECOLOR;
1123 			break;
1124 		case PPT_TOKEN( animEffect ):
1125 			nNodeType = AnimationNodeType::TRANSITIONFILTER;
1126 			break;
1127 		case PPT_TOKEN( animMotion ):
1128 			nNodeType = AnimationNodeType::ANIMATEMOTION;
1129 			break;
1130 		case PPT_TOKEN( animRot ):
1131 		case PPT_TOKEN( animScale ):
1132 			nNodeType = AnimationNodeType::ANIMATETRANSFORM;
1133 			break;
1134 		case PPT_TOKEN( cmd ):
1135 			nNodeType = AnimationNodeType::COMMAND;
1136 			break;
1137 		case PPT_TOKEN( set ):
1138 			nNodeType = AnimationNodeType::SET;
1139 			break;
1140 		case PPT_TOKEN( audio ):
1141 			nNodeType = AnimationNodeType::AUDIO;
1142 			break;
1143 		case PPT_TOKEN( video ):
1144 			nNodeType = AnimationNodeType::AUDIO;
1145 			OSL_TRACE( "OOX: video requested, gave Audio instead" );
1146 			break;
1147 
1148 		default:
1149 			nNodeType = AnimationNodeType::CUSTOM;
1150 			OSL_TRACE( "OOX: uhandled token %x", aElementToken );
1151 			break;
1152 		}
1153 
1154 		TimeNodePtr pNode(new TimeNode(nNodeType));
1155 		maList.push_back( pNode );
1156         ContextHandler * pContext = TimeNodeContext::makeContext( *this, aElementToken, xAttribs, pNode );
1157         xRet.set( pContext ? pContext : this );
1158 
1159 		return xRet;
1160 	}
1161 
1162 
1163 } }
1164