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