xref: /trunk/main/oox/source/ppt/timenode.cxx (revision cdf0e10c)
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/timenode.hxx"
29 
30 #include <boost/bind.hpp>
31 
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/beans/NamedValue.hpp>
34 #include <com/sun/star/container/XEnumerationAccess.hpp>
35 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
36 #include <com/sun/star/frame/XModel.hpp>
37 #include <com/sun/star/animations/XAnimateColor.hpp>
38 #include <com/sun/star/animations/XAnimateMotion.hpp>
39 #include <com/sun/star/animations/XAnimateTransform.hpp>
40 #include <com/sun/star/animations/XCommand.hpp>
41 #include <com/sun/star/animations/XIterateContainer.hpp>
42 #include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
43 #include <com/sun/star/animations/XTimeContainer.hpp>
44 #include <com/sun/star/animations/AnimationNodeType.hpp>
45 #include <com/sun/star/animations/Event.hpp>
46 #include <com/sun/star/animations/EventTrigger.hpp>
47 #include <com/sun/star/presentation/EffectNodeType.hpp>
48 
49 #include "oox/helper/helper.hxx"
50 #include "oox/core/xmlfilterbase.hxx"
51 
52 using ::rtl::OUString;
53 using namespace ::oox::core;
54 using namespace ::com::sun::star::beans;
55 using namespace ::com::sun::star::container;
56 using namespace ::com::sun::star::uno;
57 using namespace ::com::sun::star::lang;
58 using namespace ::com::sun::star::animations;
59 using namespace ::com::sun::star::frame;
60 using namespace ::com::sun::star::presentation;
61 
62 namespace oox { namespace ppt {
63 
64 		OUString TimeNode::getServiceName( sal_Int16 nNodeType )
65 		{
66 			OUString sServiceName;
67 			switch( nNodeType )
68 			{
69 			case AnimationNodeType::PAR:
70 //				sServiceName = CREATE_OUSTRING("com.sun.star.animations.IterateContainer");
71 				sServiceName = CREATE_OUSTRING("com.sun.star.animations.ParallelTimeContainer");
72 				break;
73 			case AnimationNodeType::SEQ:
74 				sServiceName = CREATE_OUSTRING("com.sun.star.animations.SequenceTimeContainer");
75 				break;
76 			case AnimationNodeType::ANIMATE:
77 				sServiceName = CREATE_OUSTRING("com.sun.star.animations.Animate");
78 				break;
79 			case AnimationNodeType::ANIMATECOLOR:
80 				sServiceName = CREATE_OUSTRING("com.sun.star.animations.AnimateColor");
81 				break;
82 			case AnimationNodeType::TRANSITIONFILTER:
83 				sServiceName = CREATE_OUSTRING("com.sun.star.animations.TransitionFilter");
84 				break;
85 			case AnimationNodeType::ANIMATEMOTION:
86 				sServiceName = CREATE_OUSTRING("com.sun.star.animations.AnimateMotion");
87 				break;
88 			case AnimationNodeType::ANIMATETRANSFORM:
89 				sServiceName = CREATE_OUSTRING("com.sun.star.animations.AnimateTransform");
90 				break;
91 			case AnimationNodeType::COMMAND:
92 				sServiceName = CREATE_OUSTRING("com.sun.star.animations.Command");
93 				break;
94 			case AnimationNodeType::SET:
95 				sServiceName = CREATE_OUSTRING("com.sun.star.animations.AnimateSet");
96 				break;
97 			case AnimationNodeType::AUDIO:
98 				sServiceName = CREATE_OUSTRING("com.sun.star.animations.Audio");
99 				break;
100 			default:
101 				OSL_TRACE( "OOX: uhandled type %x", nNodeType );
102 				break;
103 			}
104 			return sServiceName;
105 		}
106 
107 
108 
109 	TimeNode::TimeNode( sal_Int16 nNodeType )
110 		: mnNodeType( nNodeType )
111 		, mbHasEndSyncValue( false )
112 	{
113 	}
114 
115 
116 	TimeNode::~TimeNode()
117 	{
118 	}
119 
120 // BEGIN CUT&PASTE from sd/source/filter/ppt/pptinanimations.hxx
121 // --------------------------------------------------------------------
122 	static void fixMainSequenceTiming( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
123 	{
124 		try
125 		{
126 			bool bFirst = true;
127 			Reference< XEnumerationAccess > xEA( xNode, UNO_QUERY_THROW );
128 			Reference< XEnumeration > xE( xEA->createEnumeration(), UNO_QUERY_THROW );
129 			while( xE->hasMoreElements() )
130 			{
131 				// click node
132 				Reference< XAnimationNode > xClickNode( xE->nextElement(), UNO_QUERY );
133 
134 				Event aEvent;
135 				aEvent.Trigger = EventTrigger::ON_NEXT;
136 				aEvent.Repeat = 0;
137 				xClickNode->setBegin( makeAny( aEvent ) );
138 
139 				if( bFirst )
140 				{
141 					bFirst = false;
142 					Reference< XEnumerationAccess > xEA2( xClickNode, UNO_QUERY_THROW );
143 					Reference< XEnumeration > xE2( xEA2->createEnumeration(), UNO_QUERY_THROW );
144 					if( xE2->hasMoreElements() )
145 					{
146 						// with node
147 						xE2->nextElement() >>= xEA2;
148 						if( xEA2.is() )
149 							xE2.query( xEA2->createEnumeration() );
150 						else
151 							xE2.clear();
152 
153 						if( xE2.is() && xE2->hasMoreElements() )
154 						{
155 							Reference< XAnimationNode > xEffectNode( xE2->nextElement(), UNO_QUERY_THROW );
156 							const Sequence< NamedValue > aUserData( xEffectNode->getUserData() );
157 							const NamedValue* p = aUserData.getConstArray();
158 							sal_Int32 nLength = aUserData.getLength();
159 							while( nLength-- )
160 							{
161 								if( p->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "node-type" ) ) )
162 								{
163 									sal_Int16 nNodeType = 0;
164 									p->Value >>= nNodeType;
165 									if( nNodeType != ::com::sun::star::presentation::EffectNodeType::ON_CLICK )
166 									{
167 										// first effect does not start on click, so correct
168 										// first click nodes begin to 0s
169 										xClickNode->setBegin( makeAny( (double)0.0 ) );
170 										break;
171 									}
172 								}
173 								p++;
174 							}
175 						}
176 					}
177 				}
178 			}
179 		}
180 		catch( Exception& e )
181 		{
182 			(void)e;
183 			OSL_TRACE("fixMainSequenceTiming(), exception caught!" );
184 		}
185 	}
186 
187 // --------------------------------------------------------------------
188 
189 	static void fixInteractiveSequenceTiming( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
190 	{
191 		try
192 		{
193 			Any aBegin( xNode->getBegin() );
194 			Any aEmpty;
195 			xNode->setBegin( aEmpty );
196 
197 			Reference< XEnumerationAccess > xEA( xNode, UNO_QUERY_THROW );
198 			Reference< XEnumeration > xE( xEA->createEnumeration(), UNO_QUERY_THROW );
199 			while( xE->hasMoreElements() )
200 			{
201 				// click node
202 				Reference< XAnimationNode > xClickNode( xE->nextElement(), UNO_QUERY );
203 				xClickNode->setBegin( aBegin );
204 			}
205 		}
206 		catch( Exception& e )
207 		{
208 			(void)e;
209 			OSL_TRACE("fixInteractiveSequenceTiming(), exception caught!" );
210 		}
211 	}
212 
213 // END CUT&PASTE
214 
215     void TimeNode::addNode( const XmlFilterBase& rFilter, const Reference< XAnimationNode >& rxNode, const SlidePersistPtr & pSlide )
216 	{
217 		try {
218 			OUString sServiceName = getServiceName( mnNodeType );
219             Reference< XAnimationNode > xNode = createAndInsert( rFilter, sServiceName, rxNode );
220             setNode( rFilter, xNode, pSlide );
221 		}
222 		catch( const Exception& e )
223 		{
224 			OSL_TRACE( "OOX: exception raised in TimeNode::addNode() - %s",
225 								 OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
226 		}
227 	}
228 
229     void TimeNode::setNode( const XmlFilterBase& rFilter, const Reference< XAnimationNode >& xNode, const SlidePersistPtr & pSlide )
230 	{
231 		OSL_ENSURE( xNode.is(), "null node passed" );
232 
233 		try {
234 			if( msId.getLength() )
235 			{
236 				pSlide->getAnimNodesMap()[ msId ] = xNode;
237 			}
238 
239 			if( mpTarget )
240 			{
241 				sal_Int16 nSubType;
242 				maNodeProperties[ NP_TARGET ] = mpTarget->convert( pSlide, nSubType );
243 				if( mpTarget->mnType == XML_spTgt )
244 				{
245 					maNodeProperties[ NP_SUBITEM ] <<= nSubType;
246 				}
247 			}
248 
249 			if( !maStCondList.empty() )
250 			{
251 				Any aAny = AnimationCondition::convertList( pSlide, maStCondList );
252  				if( aAny.hasValue() )
253 				{
254 					xNode->setBegin( aAny );
255 				}
256 
257 			}
258 			if( !maEndCondList.empty() )
259 			{
260 				Any aAny = AnimationCondition::convertList( pSlide, maEndCondList );
261 				if( aAny.hasValue() )
262 				{
263 					xNode->setEnd( aAny );
264 				}
265 			}
266 #if 0  // FIXME even the binary filter has this disabled.
267 			if( !maNextCondList.empty() )
268 			{
269 				Any aAny = AnimationCondition::convertList( pSlide, maNextCondList );
270 				if( aAny.hasValue() )
271 				{
272 					xNode->setNext( aAny );
273 				}
274 			}
275 			if( !maPrevCondList.empty() )
276 			{
277 				Any aAny = AnimationCondition::convertList( pSlide, maPrevCondList );
278 				if( aAny.hasValue() )
279 				{
280 					xNode->setPrev( aAny );
281 				}
282 			}
283 #endif
284 			if( mbHasEndSyncValue )
285 			{
286 				Any aValue = maEndSyncValue.convert( pSlide );
287 				xNode->setEndSync(aValue);
288 			}
289 
290             if( !maUserData.empty() )
291             {
292                 Sequence< NamedValue > aUserDataSeq( static_cast< sal_Int32 >( maUserData.size() ) );
293                 NamedValue* pValues = aUserDataSeq.getArray();
294                 for( UserDataMap::const_iterator aIt = maUserData.begin(), aEnd = maUserData.end(); aIt != aEnd; ++aIt, ++pValues )
295                 {
296                     pValues->Name = aIt->first;
297                     pValues->Value = aIt->second;
298                 }
299                 maNodeProperties[ NP_USERDATA ] <<= aUserDataSeq;
300 			}
301 
302 			Reference< XAnimate > xAnimate( xNode, UNO_QUERY );
303 			Reference< XAnimateColor > xAnimateColor( xNode, UNO_QUERY );
304 			Reference< XAnimateMotion > xAnimateMotion( xNode, UNO_QUERY );
305 			Reference< XAnimateTransform > xAnimateTransform( xNode, UNO_QUERY );
306 			Reference< XCommand > xCommand( xNode, UNO_QUERY );
307 			Reference< XIterateContainer > xIterateContainer( xNode, UNO_QUERY );
308 			sal_Int16 nInt16 = 0;
309 			sal_Bool bBool = sal_False;
310 			double fDouble = 0;
311 			OUString sString;
312 			Sequence< NamedValue > aSeq;
313 
314 			for( int i = 0; i < _NP_SIZE; i++)
315 			{
316 				Any & aValue( maNodeProperties[ i ] );
317 				if( aValue.hasValue() )
318 				{
319 					switch( i )
320 					{
321 					case NP_TO:
322 						if( xAnimate.is() )
323 							xAnimate->setTo( aValue );
324 						break;
325 					case NP_FROM:
326 						if( xAnimate.is() )
327 							xAnimate->setFrom( aValue );
328 						break;
329 					case NP_BY:
330 						if( xAnimate.is() )
331 							xAnimate->setBy( aValue );
332 						break;
333 					case NP_TARGET:
334 						if( xAnimate.is() )
335 							xAnimate->setTarget( aValue );
336 						break;
337 					case NP_SUBITEM:
338 						if( xAnimate.is() )
339 						{
340 							if( aValue >>= nInt16 )
341 								xAnimate->setSubItem( nInt16 );
342 							else
343 							{
344 								OSL_TRACE( "any >>= failed %d", __LINE__ );
345 							}
346 						}
347 						break;
348 					case NP_ATTRIBUTENAME:
349 						if( xAnimate.is() )
350 						{
351 							if(	aValue >>= sString )
352 								xAnimate->setAttributeName( sString );
353 							else
354 							{
355 								OSL_TRACE( "any >>= failed %d", __LINE__ );
356 							}
357 						}
358 						break;
359 					case NP_CALCMODE:
360 						if( xAnimate.is() )
361 						{
362 							if( aValue >>= nInt16 )
363 								xAnimate->setCalcMode( nInt16 );
364 							else
365 							{
366 								OSL_TRACE( "any >>= failed %d", __LINE__ );
367 							}
368 						}
369 						break;
370 					case NP_KEYTIMES:
371 						if( xAnimate.is() )
372 						{
373 							Sequence<double> aKeyTimes;
374 							if( aValue >>= aKeyTimes )
375 								xAnimate->setKeyTimes(aKeyTimes);
376 							else
377 							{
378 								OSL_TRACE( "any >>= failed %d", __LINE__ );
379 							}
380 						}
381 						break;
382 					case NP_VALUES:
383 						if( xAnimate.is() )
384 						{
385 							Sequence<Any> aValues;
386 							if( aValue >>= aValues )
387 								xAnimate->setValues(aValues);
388 							else
389 							{
390 								OSL_TRACE( "any >>= failed %d", __LINE__ );
391 							}
392 						}
393 						break;
394 					case NP_FORMULA:
395 						if( xAnimate.is() )
396 						{
397 							if( aValue >>= sString )
398 								xAnimate->setFormula(sString);
399 							else
400 							{
401 								OSL_TRACE( "any >>= failed %d", __LINE__ );
402 							}
403 						}
404 						break;
405 					case NP_COLORINTERPOLATION:
406 						if( xAnimateColor.is() )
407 						{
408 							if( aValue >>= nInt16 )
409 								xAnimateColor->setColorInterpolation( nInt16 );
410 							else
411 							{
412 								OSL_TRACE( "any >>= failed %d", __LINE__ );
413 							}
414 						}
415 						break;
416 					case NP_DIRECTION:
417 						if( xAnimateColor.is() )
418 						{
419 							if( aValue >>= bBool )
420 								xAnimateColor->setDirection( bBool );
421 							else
422 							{
423 								OSL_TRACE( "any >>= failed %d", __LINE__ );
424 							}
425 						}
426 						break;
427 					case NP_PATH:
428 						if( xAnimateMotion.is() )
429 							xAnimateMotion->setPath( aValue );
430 						break;
431 					case NP_TRANSFORMTYPE:
432 						if( xAnimateTransform.is() )
433 						{
434 							if( aValue >>= nInt16 )
435 								xAnimateTransform->setTransformType( nInt16 );
436 							else
437 							{
438 								OSL_TRACE( "any >>= failed %d", __LINE__ );
439 							}
440 						}
441 						break;
442 					case NP_USERDATA:
443 						if( aValue >>= aSeq )
444 							xNode->setUserData( aSeq );
445 						else
446 						{
447 							OSL_TRACE( "any >>= failed %d", __LINE__ );
448 						}
449 						break;
450 					case NP_ACCELERATION:
451 						if( aValue >>= fDouble )
452 							xNode->setAcceleration( fDouble );
453 						else
454 						{
455 							OSL_TRACE( "any >>= failed %d", __LINE__ );
456 						}
457 						break;
458 					case NP_DECELERATE:
459 						if( aValue >>= fDouble )
460 							xNode->setDecelerate( fDouble );
461 						else
462 						{
463 							OSL_TRACE( "any >>= failed %d", __LINE__ );
464 						}
465 						break;
466 					case NP_AUTOREVERSE:
467 						if( aValue >>= bBool )
468 							xNode->setAutoReverse( bBool );
469 						else
470 						{
471 							OSL_TRACE( "any >>= failed %d", __LINE__ );
472 						}
473 						break;
474 					case NP_DURATION:
475 						xNode->setDuration( aValue );
476 						break;
477 					case NP_FILL:
478 						if( aValue >>= nInt16 )
479 							xNode->setFill( nInt16 );
480 						else
481 						{
482 							OSL_TRACE( "any >>= failed %d", __LINE__ );
483 						}
484 						break;
485 					case NP_REPEATCOUNT:
486 						xNode->setRepeatCount( aValue );
487 						break;
488 					case NP_REPEATDURATION:
489 						xNode->setRepeatDuration( aValue );
490 						break;
491 					case NP_RESTART:
492 						if( aValue >>= nInt16 )
493 							xNode->setRestart( nInt16 );
494 						else
495 						{
496 							OSL_TRACE( "any >>= failed %d", __LINE__ );
497 						}
498 						break;
499 					case NP_COMMAND:
500 						if( xCommand.is() )
501 						{
502 							if( aValue >>= nInt16 )
503 								xCommand->setCommand( nInt16 );
504 							else
505 							{
506 								OSL_TRACE( "any >>= failed %d", __LINE__ );
507 							}
508 						}
509 						break;
510 					case NP_PARAMETER:
511 						if( xCommand.is() )
512 							xCommand->setParameter( aValue );
513 						break;
514 					case NP_ITERATETYPE:
515 						if( xIterateContainer.is() )
516 						{
517 							if( aValue >>= nInt16 )
518 								xIterateContainer->setIterateType( nInt16 );
519 							else
520 							{
521 								OSL_TRACE( "any >>= failed %d", __LINE__ );
522 							}
523 						}
524 						break;
525 					case NP_ITERATEINTERVAL:
526 						if( xIterateContainer.is() )
527 						{
528 							if( aValue >>= fDouble )
529 								xIterateContainer->setIterateInterval( fDouble );
530 							else
531 							{
532 								OSL_TRACE( "any >>= failed %d", __LINE__ );
533 							}
534 						}
535 						break;
536 					default:
537 						OSL_TRACE( "ERR-OOX: unknown prop index %d", i );
538 						break;
539 					}
540 				}
541 			}
542 
543 			if( mnNodeType == AnimationNodeType::TRANSITIONFILTER )
544 			{
545 
546 				Reference< XTransitionFilter > xFilter( xNode, UNO_QUERY );
547 				maTransitionFilter.setTransitionFilterProperties( xFilter );
548 			}
549 
550             std::for_each( maChildren.begin(), maChildren.end(),
551                            boost::bind(&TimeNode::addNode, _1, boost::cref(rFilter), boost::ref(xNode),
552 									   boost::ref(pSlide) ) );
553 
554 			switch( mnNodeType )
555 			{
556 			case AnimationNodeType::SEQ:
557 			{
558 				sal_Int16 nEnum = 0;
559 				if( maUserData[ CREATE_OUSTRING( "node-type" ) ] >>= nEnum )
560 				{
561 					if( nEnum == EffectNodeType::MAIN_SEQUENCE )
562 					{
563 						fixMainSequenceTiming( xNode );
564 					}
565 					else if( nEnum ==  EffectNodeType::INTERACTIVE_SEQUENCE )
566 					{
567 						fixInteractiveSequenceTiming( xNode );
568 					}
569 				}
570 				break;
571 			}
572 			case AnimationNodeType::PAR:
573 				// some other cut&paste... from AnimationImporter::importAnimationContainer()
574 				break;
575 			}
576 		}
577 		catch( const Exception& e )
578 		{
579 			OSL_TRACE( "OOX: exception raised in TimeNode::setNode() - %s",
580 								 OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
581 		}
582 	}
583 
584 
585     Reference< XAnimationNode > TimeNode::createAndInsert(
586             const XmlFilterBase& rFilter,
587             const OUString& rServiceName,
588             const Reference< XAnimationNode >& rxNode )
589 	{
590 		try {
591             Reference< XAnimationNode > xNode ( rFilter.getServiceFactory()->createInstance( rServiceName ), UNO_QUERY_THROW );
592 			Reference< XTimeContainer > xParentContainer( rxNode, UNO_QUERY_THROW );
593 
594 			xParentContainer->appendChild( xNode );
595 			return xNode;
596 		}
597 		catch( const Exception& e )
598 		{
599 			OSL_TRACE( "OOX: exception raised in TimeNode::createAndInsert() trying to create a service %s = %s",
600 								 OUStringToOString( rServiceName, RTL_TEXTENCODING_ASCII_US ).getStr(),
601 								 OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
602 		}
603 
604 		return Reference< XAnimationNode >();
605 	}
606 
607 
608 	void 	TimeNode::setId( sal_Int32 nId )
609 	{
610 		msId = OUString::valueOf(nId);
611 	}
612 
613 	void TimeNode::setTo( const Any & aTo )
614 	{
615 		maNodeProperties[ NP_TO ] = aTo;
616 	}
617 
618 
619 	void TimeNode::setFrom( const Any & aFrom )
620 	{
621 		maNodeProperties[ NP_FROM ] = aFrom;
622 	}
623 
624 	void TimeNode::setBy( const Any & aBy )
625 	{
626 		maNodeProperties[ NP_BY ] = aBy;
627 	}
628 
629 
630 } }
631