1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sd.hxx"
26 #include <tools/debug.hxx>
27 #include <com/sun/star/util/XCloneable.hpp>
28 #include <com/sun/star/animations/AnimationFill.hpp>
29 #include <com/sun/star/container/XEnumerationAccess.hpp>
30 #include <com/sun/star/presentation/EffectNodeType.hpp>
31 #include <com/sun/star/presentation/EffectCommands.hpp>
32 #include <com/sun/star/presentation/EffectPresetClass.hpp>
33 #include <com/sun/star/presentation/ParagraphTarget.hpp>
34 #include <com/sun/star/lang/XInitialization.hpp>
35 #include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
36 #include <com/sun/star/animations/AnimationNodeType.hpp>
37 #include <com/sun/star/animations/XCommand.hpp>
38 #include <com/sun/star/animations/AnimationTransformType.hpp>
39 #include <com/sun/star/animations/XIterateContainer.hpp>
40 #include <com/sun/star/animations/XAnimateTransform.hpp>
41 #include <com/sun/star/animations/Event.hpp>
42 #include <com/sun/star/animations/EventTrigger.hpp>
43 #include <com/sun/star/animations/Timing.hpp>
44 #include <com/sun/star/drawing/XDrawPage.hpp>
45 #include <com/sun/star/text/XText.hpp>
46 #include <com/sun/star/animations/XAnimate.hpp>
47 #include <com/sun/star/beans/NamedValue.hpp>
48 #include <com/sun/star/beans/XPropertySet.hpp>
49 #include <com/sun/star/util/XChangesNotifier.hpp>
50 #include <com/sun/star/animations/XAnimateMotion.hpp>
51 #include <comphelper/processfactory.hxx>
52 #include <comphelper/sequence.hxx>
53 #include <com/sun/star/lang/Locale.hpp>
54 #include <com/sun/star/i18n/XBreakIterator.hpp>
55 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
56 #ifndef _COM_SUN_STAR_TEXT_WORDTYPE_HPP_
57 #include <com/sun/star/i18n/WordType.hpp>
58 #endif
59 #include <com/sun/star/presentation/TextAnimationType.hpp>
60
61 #include <basegfx/polygon/b2dpolypolygon.hxx>
62 #include <basegfx/polygon/b2dpolypolygontools.hxx>
63 #include <basegfx/matrix/b2dhommatrix.hxx>
64 #include <basegfx/range/b2drange.hxx>
65 #include <basegfx/matrix/b2dhommatrixtools.hxx>
66
67 #include <algorithm>
68
69 #include <cppuhelper/implbase1.hxx>
70
71 #include <drawinglayer/geometry/viewinformation2d.hxx>
72 #include <svx/sdr/contact/viewcontact.hxx>
73 #include <svx/svdopath.hxx>
74 #include <svx/svdpage.hxx>
75 #include <svx/unoapi.hxx>
76 #include "CustomAnimationEffect.hxx"
77 #include <CustomAnimationPreset.hxx>
78 #include "animations.hxx"
79
80 using namespace ::com::sun::star;
81 using namespace ::com::sun::star::presentation;
82 using namespace ::com::sun::star::animations;
83
84 using ::rtl::OUString;
85 using ::com::sun::star::uno::Reference;
86 using ::com::sun::star::uno::Sequence;
87 using ::com::sun::star::uno::XInterface;
88 using ::com::sun::star::uno::UNO_QUERY;
89 using ::com::sun::star::uno::UNO_QUERY_THROW;
90 using ::com::sun::star::uno::Any;
91 using ::com::sun::star::uno::makeAny;
92 using ::com::sun::star::uno::Exception;
93 using ::com::sun::star::uno::RuntimeException;
94 using ::com::sun::star::container::XEnumerationAccess;
95 using ::com::sun::star::container::XEnumeration;
96 using ::com::sun::star::beans::NamedValue;
97 using ::com::sun::star::container::XChild;
98 using ::com::sun::star::container::XElementAccess;
99 using ::com::sun::star::drawing::XShape;
100 using ::com::sun::star::lang::XInitialization;
101 using ::com::sun::star::drawing::XShapes;
102 using ::com::sun::star::drawing::XDrawPage;
103 using ::com::sun::star::text::XText;
104 using ::com::sun::star::text::XTextRange;
105 using ::com::sun::star::beans::XPropertySet;
106 using ::com::sun::star::lang::XMultiServiceFactory;
107 using ::com::sun::star::util::XCloneable;
108 using ::com::sun::star::lang::Locale;
109 using ::com::sun::star::util::XChangesNotifier;
110 using ::com::sun::star::util::XChangesListener;
111
112 namespace sd
113 {
114 class MainSequenceChangeGuard
115 {
116 public:
MainSequenceChangeGuard(EffectSequenceHelper * pSequence)117 MainSequenceChangeGuard( EffectSequenceHelper* pSequence )
118 {
119 mpMainSequence = dynamic_cast< MainSequence* >( pSequence );
120 if( mpMainSequence == 0 )
121 {
122 InteractiveSequence* pI = dynamic_cast< InteractiveSequence* >( pSequence );
123 if( pI )
124 mpMainSequence = pI->mpMainSequence;
125 }
126 DBG_ASSERT( mpMainSequence, "sd::MainSequenceChangeGuard::MainSequenceChangeGuard(), no main sequence to guard!" );
127
128 if( mpMainSequence )
129 mpMainSequence->mbIgnoreChanges++;
130 }
131
~MainSequenceChangeGuard()132 ~MainSequenceChangeGuard()
133 {
134 if( mpMainSequence )
135 mpMainSequence->mbIgnoreChanges++;
136 }
137
138 private:
139 MainSequence* mpMainSequence;
140 };
141
CustomAnimationEffect(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode)142 CustomAnimationEffect::CustomAnimationEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
143 : mnNodeType(-1),
144 mnPresetClass(-1),
145 mfBegin(-1.0),
146 mfDuration(-1.0),
147 mfAbsoluteDuration(-1.0),
148 mnGroupId(-1),
149 mnIterateType(0),
150 mfIterateInterval(0.0),
151 mnParaDepth( -1 ),
152 mbHasText(sal_False),
153 mfAcceleration( 1.0 ),
154 mfDecelerate( 1.0 ),
155 mbAutoReverse(false),
156 mnTargetSubItem(0),
157 mnCommand(0),
158 mpEffectSequence( 0 ),
159 mbHasAfterEffect(false),
160 mbAfterEffectOnNextEffect(false)
161 {
162 setNode( xNode );
163 }
164
165 // --------------------------------------------------------------------
166
setNode(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode)167 void CustomAnimationEffect::setNode( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
168 {
169 mxNode = xNode;
170 mxAudio.clear();
171
172 Sequence< NamedValue > aUserData( mxNode->getUserData() );
173 sal_Int32 nLength = aUserData.getLength();
174 const NamedValue* p = aUserData.getConstArray();
175
176 while( nLength-- )
177 {
178 if( p->Name.equalsAscii( "node-type" ) )
179 {
180 p->Value >>= mnNodeType;
181 }
182 else if( p->Name.equalsAscii( "preset-id" ) )
183 {
184 p->Value >>= maPresetId;
185 }
186 else if( p->Name.equalsAscii( "preset-sub-type" ) )
187 {
188 p->Value >>= maPresetSubType;
189 }
190 else if( p->Name.equalsAscii( "preset-class" ) )
191 {
192 p->Value >>= mnPresetClass;
193 }
194 else if( p->Name.equalsAscii( "preset-property" ) )
195 {
196 p->Value >>= maProperty;
197 }
198 else if( p->Name.equalsAscii( "group-id" ) )
199 {
200 p->Value >>= mnGroupId;
201 }
202
203 p++;
204 }
205
206 // get effect start time
207 mxNode->getBegin() >>= mfBegin;
208
209 mfAcceleration = mxNode->getAcceleration();
210 mfDecelerate = mxNode->getDecelerate();
211 mbAutoReverse = mxNode->getAutoReverse();
212
213 // get iteration data
214 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
215 if( xIter.is() )
216 {
217 mfIterateInterval = xIter->getIterateInterval();
218 mnIterateType = xIter->getIterateType();
219 maTarget = xIter->getTarget();
220 mnTargetSubItem = xIter->getSubItem();
221 }
222 else
223 {
224 mfIterateInterval = 0.0f;
225 mnIterateType = 0;
226 }
227
228 // calculate effect duration and get target shape
229 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
230 if( xEnumerationAccess.is() )
231 {
232 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
233 if( xEnumeration.is() )
234 {
235 while( xEnumeration->hasMoreElements() )
236 {
237 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
238 if( !xChildNode.is() )
239 continue;
240
241 if( xChildNode->getType() == AnimationNodeType::AUDIO )
242 {
243 mxAudio.set( xChildNode, UNO_QUERY );
244 }
245 else if( xChildNode->getType() == AnimationNodeType::COMMAND )
246 {
247 Reference< XCommand > xCommand( xChildNode, UNO_QUERY );
248 if( xCommand.is() )
249 {
250 mnCommand = xCommand->getCommand();
251 if( !maTarget.hasValue() )
252 maTarget = xCommand->getTarget();
253 }
254 }
255 else
256 {
257 double fBegin = 0.0;
258 double fDuration = 0.0;
259 xChildNode->getBegin() >>= fBegin;
260 xChildNode->getDuration() >>= fDuration;
261
262 fDuration += fBegin;
263 if( fDuration > mfDuration )
264 mfDuration = fDuration;
265
266 // no target shape yet?
267 if( !maTarget.hasValue() )
268 {
269 // go get it boys!
270 Reference< XAnimate > xAnimate( xChildNode, UNO_QUERY );
271 if( xAnimate.is() )
272 {
273 maTarget = xAnimate->getTarget();
274 mnTargetSubItem = xAnimate->getSubItem();
275 }
276 }
277 }
278 }
279 }
280 }
281
282 mfAbsoluteDuration = mfDuration;
283 checkForText();
284 }
285
286 // --------------------------------------------------------------------
287
getNumberOfSubitems(const Any & aTarget,sal_Int16 nIterateType)288 sal_Int32 CustomAnimationEffect::getNumberOfSubitems( const Any& aTarget, sal_Int16 nIterateType )
289 {
290 sal_Int32 nSubItems = 0;
291
292 try
293 {
294 // first get target text
295 sal_Int32 nOnlyPara = -1;
296
297 Reference< XText > xShape;
298 aTarget >>= xShape;
299 if( !xShape.is() )
300 {
301 ParagraphTarget aParaTarget;
302 if( aTarget >>= aParaTarget )
303 {
304 xShape.set( aParaTarget.Shape, UNO_QUERY );
305 nOnlyPara = aParaTarget.Paragraph;
306 }
307 }
308
309 // now use the break iterator to iterate over the given text
310 // and count the sub items
311
312 if( xShape.is() )
313 {
314 // TODO/LATER: Optimize this, don't create a break iterator each time
315 Reference< lang::XMultiServiceFactory > xMSF( ::comphelper::getProcessServiceFactory() );
316 Reference < i18n::XBreakIterator > xBI( xMSF->createInstance( OUString::createFromAscii( "com.sun.star.i18n.BreakIterator" ) ), UNO_QUERY );
317 DBG_ASSERT( xBI.is(), "sd::CustomAnimationEffect::getNumberOfSubitems(), could not create a 'com.sun.star.i18n.BreakIterator'!" );
318
319 if( xBI.is() )
320 {
321 Reference< XEnumerationAccess > xEA( xShape, UNO_QUERY_THROW );
322 Reference< XEnumeration > xEnumeration( xEA->createEnumeration(), UNO_QUERY_THROW );
323 Locale aLocale;
324 const OUString aStrLocaleName( RTL_CONSTASCII_USTRINGPARAM("CharLocale") );
325 Reference< XTextRange > xParagraph;
326
327 sal_Int32 nPara = 0;
328 while( xEnumeration->hasMoreElements() )
329 {
330 xEnumeration->nextElement() >>= xParagraph;
331
332 // skip this if its not the only paragraph we want to count
333 if( (nOnlyPara != -1) && (nOnlyPara != nPara ) )
334 continue;
335
336 if( nIterateType == TextAnimationType::BY_PARAGRAPH )
337 {
338 nSubItems++;
339 }
340 else
341 {
342 const OUString aText( xParagraph->getString() );
343 Reference< XPropertySet > xSet( xParagraph, UNO_QUERY_THROW );
344 xSet->getPropertyValue( aStrLocaleName ) >>= aLocale;
345
346 sal_Int32 nPos;
347 const sal_Int32 nEndPos = aText.getLength();
348
349 if( nIterateType == TextAnimationType::BY_WORD )
350 {
351 for( nPos = 0; nPos < nEndPos; nPos++ )
352 {
353 nPos = xBI->getWordBoundary(aText, nPos, aLocale, i18n::WordType::ANY_WORD, sal_True).endPos;
354 nSubItems++;
355 }
356 break;
357 }
358 else
359 {
360 sal_Int32 nDone;
361 for( nPos = 0; nPos < nEndPos; nPos++ )
362 {
363 nPos = xBI->nextCharacters(aText, nPos, aLocale, i18n::CharacterIteratorMode::SKIPCELL, 0, nDone);
364 nSubItems++;
365 }
366 }
367 }
368
369 if( nPara == nOnlyPara )
370 break;
371
372 nPara++;
373 }
374 }
375 }
376 }
377 catch( Exception& e )
378 {
379 (void)e;
380 nSubItems = 0;
381 DBG_ERROR( "sd::CustomAnimationEffect::getNumberOfSubitems(), exception caught!" );
382 }
383
384 return nSubItems;
385 }
386
387 // --------------------------------------------------------------------
388
~CustomAnimationEffect()389 CustomAnimationEffect::~CustomAnimationEffect()
390 {
391 }
392
393 // --------------------------------------------------------------------
394
clone() const395 CustomAnimationEffectPtr CustomAnimationEffect::clone() const
396 {
397 Reference< XCloneable > xCloneable( mxNode, UNO_QUERY_THROW );
398 Reference< XAnimationNode > xNode( xCloneable->createClone(), UNO_QUERY_THROW );
399 CustomAnimationEffectPtr pEffect( new CustomAnimationEffect( xNode ) );
400 pEffect->setEffectSequence( getEffectSequence() );
401 return pEffect;
402 }
403
404 // --------------------------------------------------------------------
405
get_node_type(const Reference<XAnimationNode> & xNode)406 sal_Int32 CustomAnimationEffect::get_node_type( const Reference< XAnimationNode >& xNode )
407 {
408 sal_Int16 nNodeType = -1;
409
410 if( xNode.is() )
411 {
412 Sequence< NamedValue > aUserData( xNode->getUserData() );
413 sal_Int32 nLength = aUserData.getLength();
414 if( nLength )
415 {
416 const NamedValue* p = aUserData.getConstArray();
417 while( nLength-- )
418 {
419 if( p->Name.equalsAscii( "node-type" ) )
420 {
421 p->Value >>= nNodeType;
422 break;
423 }
424 p++;
425 }
426 }
427 }
428
429 return nNodeType;
430 }
431
432 // --------------------------------------------------------------------
433
setPresetClass(sal_Int16 nPresetClass)434 void CustomAnimationEffect::setPresetClass( sal_Int16 nPresetClass )
435 {
436 if( mnPresetClass != nPresetClass )
437 {
438 mnPresetClass = nPresetClass;
439 if( mxNode.is() )
440 {
441 // first try to find a "preset-class" entry in the user data
442 // and change it
443 Sequence< NamedValue > aUserData( mxNode->getUserData() );
444 sal_Int32 nLength = aUserData.getLength();
445 bool bFound = false;
446 if( nLength )
447 {
448 NamedValue* p = aUserData.getArray();
449 while( nLength-- )
450 {
451 if( p->Name.equalsAscii( "preset-class" ) )
452 {
453 p->Value <<= mnPresetClass;
454 bFound = true;
455 break;
456 }
457 p++;
458 }
459 }
460
461 // no "node-type" entry inside user data, so add it
462 if( !bFound )
463 {
464 nLength = aUserData.getLength();
465 aUserData.realloc( nLength + 1);
466 aUserData[nLength].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "preset-class" ) );
467 aUserData[nLength].Value <<= mnPresetClass;
468 }
469
470 mxNode->setUserData( aUserData );
471 }
472 }
473 }
474
setNodeType(sal_Int16 nNodeType)475 void CustomAnimationEffect::setNodeType( sal_Int16 nNodeType )
476 {
477 if( mnNodeType != nNodeType )
478 {
479 mnNodeType = nNodeType;
480 if( mxNode.is() )
481 {
482 // first try to find a "node-type" entry in the user data
483 // and change it
484 Sequence< NamedValue > aUserData( mxNode->getUserData() );
485 sal_Int32 nLength = aUserData.getLength();
486 bool bFound = false;
487 if( nLength )
488 {
489 NamedValue* p = aUserData.getArray();
490 while( nLength-- )
491 {
492 if( p->Name.equalsAscii( "node-type" ) )
493 {
494 p->Value <<= mnNodeType;
495 bFound = true;
496 break;
497 }
498 p++;
499 }
500 }
501
502 // no "node-type" entry inside user data, so add it
503 if( !bFound )
504 {
505 nLength = aUserData.getLength();
506 aUserData.realloc( nLength + 1);
507 aUserData[nLength].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
508 aUserData[nLength].Value <<= mnNodeType;
509 }
510
511 mxNode->setUserData( aUserData );
512 }
513 }
514 }
515
516 // --------------------------------------------------------------------
517
setGroupId(sal_Int32 nGroupId)518 void CustomAnimationEffect::setGroupId( sal_Int32 nGroupId )
519 {
520 mnGroupId = nGroupId;
521 if( mxNode.is() )
522 {
523 // first try to find a "group-id" entry in the user data
524 // and change it
525 Sequence< NamedValue > aUserData( mxNode->getUserData() );
526 sal_Int32 nLength = aUserData.getLength();
527 bool bFound = false;
528 if( nLength )
529 {
530 NamedValue* p = aUserData.getArray();
531 while( nLength-- )
532 {
533 if( p->Name.equalsAscii( "group-id" ) )
534 {
535 p->Value <<= mnGroupId;
536 bFound = true;
537 break;
538 }
539 p++;
540 }
541 }
542
543 // no "node-type" entry inside user data, so add it
544 if( !bFound )
545 {
546 nLength = aUserData.getLength();
547 aUserData.realloc( nLength + 1);
548 aUserData[nLength].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "group-id" ) );
549 aUserData[nLength].Value <<= mnGroupId;
550 }
551
552 mxNode->setUserData( aUserData );
553 }
554 }
555
556 // --------------------------------------------------------------------
557
558 /** checks if the text for this effect has changed and updates internal flags.
559 returns true if something changed.
560 */
checkForText()561 bool CustomAnimationEffect::checkForText()
562 {
563 bool bChange = false;
564
565 Reference< XText > xText;
566
567 if( maTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
568 {
569 // calc para depth
570 ParagraphTarget aParaTarget;
571 maTarget >>= aParaTarget;
572
573 xText = Reference< XText >::query( aParaTarget.Shape );
574
575 // get paragraph
576 if( xText.is() )
577 {
578 Reference< XEnumerationAccess > xEA( xText, UNO_QUERY );
579 if( xEA.is() )
580 {
581 Reference< XEnumeration > xEnumeration( xEA->createEnumeration(), UNO_QUERY );
582 if( xEnumeration.is() )
583 {
584 sal_Bool bHasText = xEnumeration->hasMoreElements();
585 bChange |= bHasText != mbHasText;
586 mbHasText = bHasText;
587
588 sal_Int32 nPara = aParaTarget.Paragraph;
589
590 while( xEnumeration->hasMoreElements() && nPara-- )
591 xEnumeration->nextElement();
592
593 if( xEnumeration->hasMoreElements() )
594 {
595 Reference< XPropertySet > xParaSet;
596 xEnumeration->nextElement() >>= xParaSet;
597 if( xParaSet.is() )
598 {
599 sal_Int32 nParaDepth = 0;
600 const OUString strNumberingLevel( RTL_CONSTASCII_USTRINGPARAM("NumberingLevel") );
601 xParaSet->getPropertyValue( strNumberingLevel ) >>= nParaDepth;
602 bChange |= nParaDepth != mnParaDepth;
603 mnParaDepth = nParaDepth;
604 }
605 }
606 }
607 }
608 }
609 }
610 else
611 {
612 maTarget >>= xText;
613 sal_Bool bHasText = xText.is() && xText->getString().getLength();
614 bChange |= bHasText != mbHasText;
615 mbHasText = bHasText;
616 }
617
618 bChange |= calculateIterateDuration();
619 return bChange;
620 }
621
calculateIterateDuration()622 bool CustomAnimationEffect::calculateIterateDuration()
623 {
624 bool bChange = false;
625
626 // if we have an iteration, we must also calculate the
627 // 'true' container duration, that is
628 // ( ( is form animated ) ? [contained effects duration] : 0 ) +
629 // ( [number of animated children] - 1 ) * [interval-delay] + [contained effects duration]
630 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
631 if( xIter.is() )
632 {
633 double fDuration = mfDuration;
634 const double fSubEffectDuration = mfDuration;
635
636 if( mnTargetSubItem != ShapeAnimationSubType::ONLY_BACKGROUND ) // does not make sense for iterate container but better check
637 {
638 const sal_Int32 nSubItems = getNumberOfSubitems( maTarget, mnIterateType );
639 if( nSubItems )
640 {
641 const double f = (nSubItems-1) * mfIterateInterval;
642 fDuration += f;
643 }
644 }
645
646 // if we also animate the form first, we have to add the
647 // sub effect duration to the whole effect duration
648 if( mnTargetSubItem == ShapeAnimationSubType::AS_WHOLE )
649 fDuration += fSubEffectDuration;
650
651 bChange |= fDuration != mfAbsoluteDuration;
652 mfAbsoluteDuration = fDuration;
653 }
654
655 return bChange;
656 }
657
658 // --------------------------------------------------------------------
659
setTarget(const::com::sun::star::uno::Any & rTarget)660 void CustomAnimationEffect::setTarget( const ::com::sun::star::uno::Any& rTarget )
661 {
662 try
663 {
664 maTarget = rTarget;
665
666 // first, check special case for random node
667 Reference< XInitialization > xInit( mxNode, UNO_QUERY );
668 if( xInit.is() )
669 {
670 const Sequence< Any > aArgs( &maTarget, 1 );
671 xInit->initialize( aArgs );
672 }
673 else
674 {
675 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
676 if( xIter.is() )
677 {
678 xIter->setTarget(maTarget);
679 }
680 else
681 {
682 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
683 if( xEnumerationAccess.is() )
684 {
685 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
686 if( xEnumeration.is() )
687 {
688 while( xEnumeration->hasMoreElements() )
689 {
690 const Any aElem( xEnumeration->nextElement() );
691 Reference< XAnimate > xAnimate( aElem, UNO_QUERY );
692 if( xAnimate.is() )
693 xAnimate->setTarget( rTarget );
694 else
695 {
696 Reference< XCommand > xCommand( aElem, UNO_QUERY );
697 if( xCommand.is() )
698 xCommand->setTarget( rTarget );
699 }
700 }
701 }
702 }
703 }
704 }
705 checkForText();
706 }
707 catch( Exception& )
708 {
709 DBG_ERROR( "sd::CustomAnimationEffect::setTarget(), exception caught!" );
710 }
711 }
712
713 // --------------------------------------------------------------------
714
setTargetSubItem(sal_Int16 nSubItem)715 void CustomAnimationEffect::setTargetSubItem( sal_Int16 nSubItem )
716 {
717 try
718 {
719 mnTargetSubItem = nSubItem;
720
721 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
722 if( xIter.is() )
723 {
724 xIter->setSubItem(mnTargetSubItem);
725 }
726 else
727 {
728 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
729 if( xEnumerationAccess.is() )
730 {
731 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
732 if( xEnumeration.is() )
733 {
734 while( xEnumeration->hasMoreElements() )
735 {
736 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
737 if( xAnimate.is() )
738 xAnimate->setSubItem( mnTargetSubItem );
739 }
740 }
741 }
742 }
743 }
744 catch( Exception& )
745 {
746 DBG_ERROR( "sd::CustomAnimationEffect::setTargetSubItem(), exception caught!" );
747 }
748 }
749
750 // --------------------------------------------------------------------
751
setDuration(double fDuration)752 void CustomAnimationEffect::setDuration( double fDuration )
753 {
754 if( (mfDuration != -1.0) && (mfDuration != fDuration) ) try
755 {
756 double fScale = fDuration / mfDuration;
757 mfDuration = fDuration;
758 mfAbsoluteDuration = mfDuration;
759
760 // calculate effect duration and get target shape
761 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
762 if( xEnumerationAccess.is() )
763 {
764 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
765 if( xEnumeration.is() )
766 {
767 while( xEnumeration->hasMoreElements() )
768 {
769 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
770 if( !xChildNode.is() )
771 continue;
772
773
774 double fChildBegin = 0.0;
775 xChildNode->getBegin() >>= fChildBegin;
776 if( fChildBegin != 0.0 )
777 {
778 fChildBegin *= fScale;
779 xChildNode->setBegin( makeAny( fChildBegin ) );
780 }
781
782 double fChildDuration = 0.0;
783 xChildNode->getDuration() >>= fChildDuration;
784 if( fChildDuration != 0.0 )
785 {
786 fChildDuration *= fScale;
787 xChildNode->setDuration( makeAny( fChildDuration ) );
788 }
789 }
790 }
791 }
792 calculateIterateDuration();
793 }
794 catch( Exception& )
795 {
796 DBG_ERROR( "sd::CustomAnimationEffect::setDuration(), exception caught!" );
797 }
798 }
799
800 // --------------------------------------------------------------------
801
setBegin(double fBegin)802 void CustomAnimationEffect::setBegin( double fBegin )
803 {
804 if( mxNode.is() ) try
805 {
806 mfBegin = fBegin;
807 mxNode->setBegin( makeAny( fBegin ) );
808 }
809 catch( Exception& )
810 {
811 DBG_ERROR( "sd::CustomAnimationEffect::setBegin(), exception caught!" );
812 }
813 }
814
815 // --------------------------------------------------------------------
816
setAcceleration(double fAcceleration)817 void CustomAnimationEffect::setAcceleration( double fAcceleration )
818 {
819 if( mxNode.is() ) try
820 {
821 mfAcceleration = fAcceleration;
822 mxNode->setAcceleration( fAcceleration );
823 }
824 catch( Exception& )
825 {
826 DBG_ERROR( "sd::CustomAnimationEffect::setAcceleration(), exception caught!" );
827 }
828 }
829 // --------------------------------------------------------------------
830
setDecelerate(double fDecelerate)831 void CustomAnimationEffect::setDecelerate( double fDecelerate )
832 {
833 if( mxNode.is() ) try
834 {
835 mfDecelerate = fDecelerate;
836 mxNode->setDecelerate( fDecelerate );
837 }
838 catch( Exception& )
839 {
840 DBG_ERROR( "sd::CustomAnimationEffect::setDecelerate(), exception caught!" );
841 }
842 }
843
844 // --------------------------------------------------------------------
845
setAutoReverse(sal_Bool bAutoReverse)846 void CustomAnimationEffect::setAutoReverse( sal_Bool bAutoReverse )
847 {
848 if( mxNode.is() ) try
849 {
850 mbAutoReverse = bAutoReverse;
851 mxNode->setAutoReverse( bAutoReverse );
852 }
853 catch( Exception& )
854 {
855 DBG_ERROR( "sd::CustomAnimationEffect::setAutoReverse(), exception caught!" );
856 }
857 }
858
859 // --------------------------------------------------------------------
860
replaceNode(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode)861 void CustomAnimationEffect::replaceNode( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
862 {
863 sal_Int16 nNodeType = mnNodeType;
864 Any aTarget = maTarget;
865
866 double fBegin = mfBegin;
867 double fDuration = mfDuration;
868 double fAcceleration = mfAcceleration;
869 double fDecelerate = mfDecelerate ;
870 sal_Bool bAutoReverse = mbAutoReverse;
871 Reference< XAudio > xAudio( mxAudio );
872 sal_Int16 nIterateType = mnIterateType;
873 double fIterateInterval = mfIterateInterval;
874 sal_Int16 nSubItem = mnTargetSubItem;
875
876 setNode( xNode );
877
878 setAudio( xAudio );
879 setNodeType( nNodeType );
880 setTarget( aTarget );
881 setTargetSubItem( nSubItem );
882 setDuration( fDuration );
883 setBegin( fBegin );
884
885 setAcceleration( fAcceleration );
886 setDecelerate( fDecelerate );
887 setAutoReverse( bAutoReverse );
888
889 if( nIterateType != mnIterateType )
890 setIterateType( nIterateType );
891
892 if( mnIterateType && ( fIterateInterval != mfIterateInterval ) )
893 setIterateInterval( fIterateInterval );
894 }
895
896 // --------------------------------------------------------------------
897
getTargetShape() const898 Reference< XShape > CustomAnimationEffect::getTargetShape() const
899 {
900 Reference< XShape > xShape;
901 maTarget >>= xShape;
902 if( !xShape.is() )
903 {
904 ParagraphTarget aParaTarget;
905 if( maTarget >>= aParaTarget )
906 xShape = aParaTarget.Shape;
907 }
908
909 return xShape;
910 }
911
912 // --------------------------------------------------------------------
913
getRepeatCount() const914 Any CustomAnimationEffect::getRepeatCount() const
915 {
916 if( mxNode.is() )
917 {
918 return mxNode->getRepeatCount();
919 }
920 else
921 {
922 Any aAny;
923 return aAny;
924 }
925 }
926
927 // --------------------------------------------------------------------
928
getEnd() const929 Any CustomAnimationEffect::getEnd() const
930 {
931 if( mxNode.is() )
932 {
933 return mxNode->getEnd();
934 }
935 else
936 {
937 Any aAny;
938 return aAny;
939 }
940 }
941
942 // --------------------------------------------------------------------
943
getFill() const944 sal_Int16 CustomAnimationEffect::getFill() const
945 {
946 if( mxNode.is() )
947 return mxNode->getFill();
948 else
949 return 0;
950 }
951
952 // --------------------------------------------------------------------
953
setRepeatCount(const Any & rRepeatCount)954 void CustomAnimationEffect::setRepeatCount( const Any& rRepeatCount )
955 {
956 if( mxNode.is() )
957 mxNode->setRepeatCount( rRepeatCount );
958 }
959
960 // --------------------------------------------------------------------
961
setEnd(const Any & rEnd)962 void CustomAnimationEffect::setEnd( const Any& rEnd )
963 {
964 if( mxNode.is() )
965 mxNode->setEnd( rEnd );
966 }
967
968 // --------------------------------------------------------------------
969
setFill(sal_Int16 nFill)970 void CustomAnimationEffect::setFill( sal_Int16 nFill )
971 {
972 if( mxNode.is() )
973 mxNode->setFill( nFill );
974 }
975
976 // --------------------------------------------------------------------
977
createAfterEffectNode() const978 Reference< XAnimationNode > CustomAnimationEffect::createAfterEffectNode() const throw (Exception)
979 {
980 DBG_ASSERT( mbHasAfterEffect, "sd::CustomAnimationEffect::createAfterEffectNode(), this node has no after effect!" );
981
982 Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() );
983
984 const char* pServiceName = maDimColor.hasValue() ?
985 "com.sun.star.animations.AnimateColor" : "com.sun.star.animations.AnimateSet";
986
987 Reference< XAnimate > xAnimate( xMsf->createInstance(OUString::createFromAscii(pServiceName) ), UNO_QUERY_THROW );
988
989 Any aTo;
990 OUString aAttributeName;
991
992 if( maDimColor.hasValue() )
993 {
994 aTo = maDimColor;
995 aAttributeName = OUString( RTL_CONSTASCII_USTRINGPARAM( "DimColor" ) );
996 }
997 else
998 {
999 aTo = makeAny( (sal_Bool)sal_False );
1000 aAttributeName = OUString( RTL_CONSTASCII_USTRINGPARAM( "Visibility" ) );
1001 }
1002
1003 Any aBegin;
1004 if( !mbAfterEffectOnNextEffect ) // sameClick
1005 {
1006 Event aEvent;
1007
1008 aEvent.Source <<= getNode();
1009 aEvent.Trigger = EventTrigger::END_EVENT;
1010 aEvent.Repeat = 0;
1011
1012 aBegin <<= aEvent;
1013 }
1014 else
1015 {
1016 aBegin <<= (double)0.0;
1017 }
1018
1019 xAnimate->setBegin( aBegin );
1020 xAnimate->setTo( aTo );
1021 xAnimate->setAttributeName( aAttributeName );
1022
1023 xAnimate->setDuration( makeAny( (double)0.001 ) );
1024 xAnimate->setFill( AnimationFill::HOLD );
1025 xAnimate->setTarget( maTarget );
1026
1027 return Reference< XAnimationNode >( xAnimate, UNO_QUERY_THROW );
1028 }
1029
1030 // --------------------------------------------------------------------
1031
setIterateType(sal_Int16 nIterateType)1032 void CustomAnimationEffect::setIterateType( sal_Int16 nIterateType )
1033 {
1034 if( mnIterateType != nIterateType ) try
1035 {
1036 // do we need to exchange the container node?
1037 if( (mnIterateType == 0) || (nIterateType == 0) )
1038 {
1039 sal_Int16 nTargetSubItem = mnTargetSubItem;
1040
1041 Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() );
1042 const char * pServiceName =
1043 nIterateType ? "com.sun.star.animations.IterateContainer" : "com.sun.star.animations.ParallelTimeContainer";
1044 Reference< XTimeContainer > xNewContainer(
1045 xMsf->createInstance( OUString::createFromAscii(pServiceName) ), UNO_QUERY_THROW );
1046
1047 Reference< XTimeContainer > xOldContainer( mxNode, UNO_QUERY_THROW );
1048 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW );
1049 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1050 while( xEnumeration->hasMoreElements() )
1051 {
1052 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
1053 xOldContainer->removeChild( xChildNode );
1054 xNewContainer->appendChild( xChildNode );
1055 }
1056
1057 Reference< XAnimationNode > xNewNode( xNewContainer, UNO_QUERY_THROW );
1058
1059 xNewNode->setBegin( mxNode->getBegin() );
1060 xNewNode->setDuration( mxNode->getDuration() );
1061 xNewNode->setEnd( mxNode->getEnd() );
1062 xNewNode->setEndSync( mxNode->getEndSync() );
1063 xNewNode->setRepeatCount( mxNode->getRepeatCount() );
1064 xNewNode->setFill( mxNode->getFill() );
1065 xNewNode->setFillDefault( mxNode->getFillDefault() );
1066 xNewNode->setRestart( mxNode->getRestart() );
1067 xNewNode->setRestartDefault( mxNode->getRestartDefault() );
1068 xNewNode->setAcceleration( mxNode->getAcceleration() );
1069 xNewNode->setDecelerate( mxNode->getDecelerate() );
1070 xNewNode->setAutoReverse( mxNode->getAutoReverse() );
1071 xNewNode->setRepeatDuration( mxNode->getRepeatDuration() );
1072 xNewNode->setEndSync( mxNode->getEndSync() );
1073 xNewNode->setRepeatCount( mxNode->getRepeatCount() );
1074 xNewNode->setUserData( mxNode->getUserData() );
1075
1076 mxNode = xNewNode;
1077
1078 Any aTarget;
1079 if( nIterateType )
1080 {
1081 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY_THROW );
1082 xIter->setTarget(maTarget);
1083 xIter->setSubItem( nTargetSubItem );
1084 }
1085 else
1086 {
1087 aTarget = maTarget;
1088 }
1089
1090 Reference< XEnumerationAccess > xEA( mxNode, UNO_QUERY_THROW );
1091 Reference< XEnumeration > xE( xEA->createEnumeration(), UNO_QUERY_THROW );
1092 while( xE->hasMoreElements() )
1093 {
1094 Reference< XAnimate > xAnimate( xE->nextElement(), UNO_QUERY );
1095 if( xAnimate.is() )
1096 {
1097 xAnimate->setTarget( aTarget );
1098 xAnimate->setSubItem( nTargetSubItem );
1099 }
1100 }
1101 }
1102
1103 mnIterateType = nIterateType;
1104
1105 // if we have an iteration container, we must set its type
1106 if( mnIterateType )
1107 {
1108 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY_THROW );
1109 xIter->setIterateType( nIterateType );
1110 }
1111
1112 checkForText();
1113 }
1114 catch( Exception& e )
1115 {
1116 (void)e;
1117 DBG_ERROR( "sd::CustomAnimationEffect::setIterateType(), Exception caught!" );
1118 }
1119 }
1120
1121 // --------------------------------------------------------------------
1122
setIterateInterval(double fIterateInterval)1123 void CustomAnimationEffect::setIterateInterval( double fIterateInterval )
1124 {
1125 if( mfIterateInterval != fIterateInterval )
1126 {
1127 Reference< XIterateContainer > xIter( mxNode, UNO_QUERY );
1128
1129 DBG_ASSERT( xIter.is(), "sd::CustomAnimationEffect::setIterateInterval(), not an iteration node" );
1130 if( xIter.is() )
1131 {
1132 mfIterateInterval = fIterateInterval;
1133 xIter->setIterateInterval( fIterateInterval );
1134 }
1135
1136 calculateIterateDuration();
1137 }
1138 }
1139
1140 // --------------------------------------------------------------------
1141
getPath() const1142 ::rtl::OUString CustomAnimationEffect::getPath() const
1143 {
1144 ::rtl::OUString aPath;
1145
1146 if( mxNode.is() ) try
1147 {
1148 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW );
1149 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1150 while( xEnumeration->hasMoreElements() )
1151 {
1152 Reference< XAnimateMotion > xMotion( xEnumeration->nextElement(), UNO_QUERY );
1153 if( xMotion.is() )
1154 {
1155 xMotion->getPath() >>= aPath;
1156 break;
1157 }
1158 }
1159 }
1160 catch( Exception& e )
1161 {
1162 (void)e;
1163 DBG_ERROR("sd::CustomAnimationEffect::getPath(), exception caught!" );
1164 }
1165
1166 return aPath;
1167 }
1168
1169 // --------------------------------------------------------------------
1170
setPath(const::rtl::OUString & rPath)1171 void CustomAnimationEffect::setPath( const ::rtl::OUString& rPath )
1172 {
1173 if( mxNode.is() ) try
1174 {
1175 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY_THROW );
1176 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1177 while( xEnumeration->hasMoreElements() )
1178 {
1179 Reference< XAnimateMotion > xMotion( xEnumeration->nextElement(), UNO_QUERY );
1180 if( xMotion.is() )
1181 {
1182
1183 MainSequenceChangeGuard aGuard( mpEffectSequence );
1184 xMotion->setPath( Any( rPath ) );
1185 break;
1186 }
1187 }
1188 }
1189 catch( Exception& e )
1190 {
1191 (void)e;
1192 DBG_ERROR("sd::CustomAnimationEffect::setPath(), exception caught!" );
1193 }
1194 }
1195
1196 // --------------------------------------------------------------------
1197
getProperty(sal_Int32 nNodeType,const OUString & rAttributeName,EValue eValue)1198 Any CustomAnimationEffect::getProperty( sal_Int32 nNodeType, const OUString& rAttributeName, EValue eValue )
1199 {
1200 Any aProperty;
1201 if( mxNode.is() ) try
1202 {
1203 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1204 if( xEnumerationAccess.is() )
1205 {
1206 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1207 if( xEnumeration.is() )
1208 {
1209 while( xEnumeration->hasMoreElements() && !aProperty.hasValue() )
1210 {
1211 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1212 if( !xAnimate.is() )
1213 continue;
1214
1215 if( xAnimate->getType() == nNodeType )
1216 {
1217 if( xAnimate->getAttributeName() == rAttributeName )
1218 {
1219 switch( eValue )
1220 {
1221 case VALUE_FROM: aProperty = xAnimate->getFrom(); break;
1222 case VALUE_TO: aProperty = xAnimate->getTo(); break;
1223 case VALUE_BY: aProperty = xAnimate->getBy(); break;
1224 case VALUE_FIRST:
1225 case VALUE_LAST:
1226 {
1227 Sequence<Any> aValues( xAnimate->getValues() );
1228 if( aValues.hasElements() )
1229 aProperty = aValues[ eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1 ];
1230 }
1231 break;
1232 }
1233 }
1234 }
1235 }
1236 }
1237 }
1238 }
1239 catch( Exception& e )
1240 {
1241 (void)e;
1242 DBG_ERROR("sd::CustomAnimationEffect::getProperty(), exception caught!" );
1243 }
1244
1245 return aProperty;
1246 }
1247
1248 // --------------------------------------------------------------------
1249
setProperty(sal_Int32 nNodeType,const OUString & rAttributeName,EValue eValue,const Any & rValue)1250 bool CustomAnimationEffect::setProperty( sal_Int32 nNodeType, const OUString& rAttributeName, EValue eValue, const Any& rValue )
1251 {
1252 bool bChanged = false;
1253 if( mxNode.is() ) try
1254 {
1255 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1256 if( xEnumerationAccess.is() )
1257 {
1258 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1259 if( xEnumeration.is() )
1260 {
1261 while( xEnumeration->hasMoreElements() )
1262 {
1263 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1264 if( !xAnimate.is() )
1265 continue;
1266
1267 if( xAnimate->getType() == nNodeType )
1268 {
1269 if( xAnimate->getAttributeName() == rAttributeName )
1270 {
1271 switch( eValue )
1272 {
1273 case VALUE_FROM:
1274 if( xAnimate->getFrom() != rValue )
1275 {
1276 xAnimate->setFrom( rValue );
1277 bChanged = true;
1278 }
1279 break;
1280 case VALUE_TO:
1281 if( xAnimate->getTo() != rValue )
1282 {
1283 xAnimate->setTo( rValue );
1284 bChanged = true;
1285 }
1286 break;
1287 case VALUE_BY:
1288 if( xAnimate->getTo() != rValue )
1289 {
1290 xAnimate->setBy( rValue );
1291 bChanged = true;
1292 }
1293 break;
1294 case VALUE_FIRST:
1295 case VALUE_LAST:
1296 {
1297 Sequence<Any> aValues( xAnimate->getValues() );
1298 if( !aValues.hasElements() )
1299 aValues.realloc(1);
1300
1301 sal_Int32 nIndex = eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1;
1302
1303 if( aValues[ nIndex ] != rValue )
1304 {
1305 aValues[ nIndex ] = rValue;
1306 xAnimate->setValues( aValues );
1307 bChanged = true;
1308 }
1309 }
1310 }
1311 }
1312 }
1313 }
1314 }
1315 }
1316 }
1317 catch( Exception& e )
1318 {
1319 (void)e;
1320 DBG_ERROR("sd::CustomAnimationEffect::setProperty(), exception caught!" );
1321 }
1322
1323 return bChanged;
1324 }
1325
1326 // --------------------------------------------------------------------
1327
implIsColorAttribute(const OUString & rAttributeName)1328 static bool implIsColorAttribute( const OUString& rAttributeName )
1329 {
1330 return rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("FillColor") ) ||
1331 rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("LineColor") ) ||
1332 rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("CharColor") );
1333 }
1334
1335 // --------------------------------------------------------------------
1336
getColor(sal_Int32 nIndex)1337 Any CustomAnimationEffect::getColor( sal_Int32 nIndex )
1338 {
1339 Any aColor;
1340 if( mxNode.is() ) try
1341 {
1342 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1343 if( xEnumerationAccess.is() )
1344 {
1345 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1346 if( xEnumeration.is() )
1347 {
1348 while( xEnumeration->hasMoreElements() && !aColor.hasValue() )
1349 {
1350 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1351 if( !xAnimate.is() )
1352 continue;
1353
1354 switch( xAnimate->getType() )
1355 {
1356 case AnimationNodeType::SET:
1357 case AnimationNodeType::ANIMATE:
1358 if( !implIsColorAttribute( xAnimate->getAttributeName() ) )
1359 break;
1360 case AnimationNodeType::ANIMATECOLOR:
1361 Sequence<Any> aValues( xAnimate->getValues() );
1362 if( aValues.hasElements() )
1363 {
1364 if( aValues.getLength() > nIndex )
1365 aColor = aValues[nIndex];
1366 }
1367 else if( nIndex == 0 )
1368 aColor = xAnimate->getFrom();
1369 else
1370 aColor = xAnimate->getTo();
1371 }
1372 }
1373 }
1374 }
1375 }
1376 catch( Exception& e )
1377 {
1378 (void)e;
1379 DBG_ERROR("sd::CustomAnimationEffect::getColor(), exception caught!" );
1380 }
1381
1382 return aColor;
1383 }
1384
1385 // --------------------------------------------------------------------
1386
setColor(sal_Int32 nIndex,const Any & rColor)1387 void CustomAnimationEffect::setColor( sal_Int32 nIndex, const Any& rColor )
1388 {
1389 if( mxNode.is() ) try
1390 {
1391 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1392 if( xEnumerationAccess.is() )
1393 {
1394 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1395 if( xEnumeration.is() )
1396 {
1397 while( xEnumeration->hasMoreElements() )
1398 {
1399 Reference< XAnimate > xAnimate( xEnumeration->nextElement(), UNO_QUERY );
1400 if( !xAnimate.is() )
1401 continue;
1402
1403 switch( xAnimate->getType() )
1404 {
1405 case AnimationNodeType::SET:
1406 case AnimationNodeType::ANIMATE:
1407 if( !implIsColorAttribute( xAnimate->getAttributeName() ) )
1408 break;
1409 case AnimationNodeType::ANIMATECOLOR:
1410 {
1411 Sequence<Any> aValues( xAnimate->getValues() );
1412 if( aValues.hasElements() )
1413 {
1414 if( aValues.getLength() > nIndex )
1415 {
1416 aValues[nIndex] = rColor;
1417 xAnimate->setValues( aValues );
1418 }
1419 }
1420 else if( (nIndex == 0) && xAnimate->getFrom().hasValue() )
1421 xAnimate->setFrom(rColor);
1422 else if( (nIndex == 1) && xAnimate->getTo().hasValue() )
1423 xAnimate->setTo(rColor);
1424 }
1425 break;
1426
1427 }
1428 }
1429 }
1430 }
1431 }
1432 catch( Exception& e )
1433 {
1434 (void)e;
1435 DBG_ERROR("sd::CustomAnimationEffect::setColor(), exception caught!" );
1436 }
1437 }
1438
1439 // --------------------------------------------------------------------
1440
getTransformationProperty(sal_Int32 nTransformType,EValue eValue)1441 Any CustomAnimationEffect::getTransformationProperty( sal_Int32 nTransformType, EValue eValue )
1442 {
1443 Any aProperty;
1444 if( mxNode.is() ) try
1445 {
1446 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1447 if( xEnumerationAccess.is() )
1448 {
1449 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1450 if( xEnumeration.is() )
1451 {
1452 while( xEnumeration->hasMoreElements() && !aProperty.hasValue() )
1453 {
1454 Reference< XAnimateTransform > xTransform( xEnumeration->nextElement(), UNO_QUERY );
1455 if( !xTransform.is() )
1456 continue;
1457
1458 if( xTransform->getTransformType() == nTransformType )
1459 {
1460 switch( eValue )
1461 {
1462 case VALUE_FROM: aProperty = xTransform->getFrom(); break;
1463 case VALUE_TO: aProperty = xTransform->getTo(); break;
1464 case VALUE_BY: aProperty = xTransform->getBy(); break;
1465 case VALUE_FIRST:
1466 case VALUE_LAST:
1467 {
1468 Sequence<Any> aValues( xTransform->getValues() );
1469 if( aValues.hasElements() )
1470 aProperty = aValues[ eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1 ];
1471 }
1472 break;
1473 }
1474 }
1475 }
1476 }
1477 }
1478 }
1479 catch( Exception& e )
1480 {
1481 (void)e;
1482 DBG_ERROR("sd::CustomAnimationEffect::getTransformationProperty(), exception caught!" );
1483 }
1484
1485 return aProperty;
1486 }
1487
1488 // --------------------------------------------------------------------
1489
setTransformationProperty(sal_Int32 nTransformType,EValue eValue,const Any & rValue)1490 bool CustomAnimationEffect::setTransformationProperty( sal_Int32 nTransformType, EValue eValue, const Any& rValue )
1491 {
1492 bool bChanged = false;
1493 if( mxNode.is() ) try
1494 {
1495 Reference< XEnumerationAccess > xEnumerationAccess( mxNode, UNO_QUERY );
1496 if( xEnumerationAccess.is() )
1497 {
1498 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
1499 if( xEnumeration.is() )
1500 {
1501 while( xEnumeration->hasMoreElements() )
1502 {
1503 Reference< XAnimateTransform > xTransform( xEnumeration->nextElement(), UNO_QUERY );
1504 if( !xTransform.is() )
1505 continue;
1506
1507 if( xTransform->getTransformType() == nTransformType )
1508 {
1509 switch( eValue )
1510 {
1511 case VALUE_FROM:
1512 if( xTransform->getFrom() != rValue )
1513 {
1514 xTransform->setFrom( rValue );
1515 bChanged = true;
1516 }
1517 break;
1518 case VALUE_TO:
1519 if( xTransform->getTo() != rValue )
1520 {
1521 xTransform->setTo( rValue );
1522 bChanged = true;
1523 }
1524 break;
1525 case VALUE_BY:
1526 if( xTransform->getBy() != rValue )
1527 {
1528 xTransform->setBy( rValue );
1529 bChanged = true;
1530 }
1531 break;
1532 case VALUE_FIRST:
1533 case VALUE_LAST:
1534 {
1535 Sequence<Any> aValues( xTransform->getValues() );
1536 if( !aValues.hasElements() )
1537 aValues.realloc(1);
1538
1539 sal_Int32 nIndex = eValue == VALUE_FIRST ? 0 : aValues.getLength() - 1;
1540 if( aValues[nIndex] != rValue )
1541 {
1542 aValues[nIndex] = rValue;
1543 xTransform->setValues( aValues );
1544 bChanged = true;
1545 }
1546 }
1547 }
1548 }
1549 }
1550 }
1551 }
1552 }
1553 catch( Exception& e )
1554 {
1555 (void)e;
1556 DBG_ERROR("sd::CustomAnimationEffect::setTransformationProperty(), exception caught!" );
1557 }
1558
1559 return bChanged;
1560 }
1561
1562 // --------------------------------------------------------------------
1563
createAudio(const::com::sun::star::uno::Any & rSource,double fVolume)1564 void CustomAnimationEffect::createAudio( const ::com::sun::star::uno::Any& rSource, double fVolume /* = 1.0 */ )
1565 {
1566 DBG_ASSERT( !mxAudio.is(), "sd::CustomAnimationEffect::createAudio(), node already has an audio!" );
1567
1568 if( !mxAudio.is() ) try
1569 {
1570 Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() );
1571 Reference< XAudio > xAudio( xMsf->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.Audio") ) ), UNO_QUERY_THROW );
1572 xAudio->setSource( rSource );
1573 xAudio->setVolume( fVolume );
1574 setAudio( xAudio );
1575 }
1576 catch( Exception& e )
1577 {
1578 (void)e;
1579 DBG_ERROR("sd::CustomAnimationEffect::createAudio(), exception caught!" );
1580 }
1581 }
1582
1583 // --------------------------------------------------------------------
1584
findCommandNode(const Reference<XAnimationNode> & xRootNode)1585 static Reference< XCommand > findCommandNode( const Reference< XAnimationNode >& xRootNode )
1586 {
1587 Reference< XCommand > xCommand;
1588
1589 if( xRootNode.is() ) try
1590 {
1591 Reference< XEnumerationAccess > xEnumerationAccess( xRootNode, UNO_QUERY_THROW );
1592 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
1593 while( !xCommand.is() && xEnumeration->hasMoreElements() )
1594 {
1595 Reference< XAnimationNode > xNode( xEnumeration->nextElement(), UNO_QUERY );
1596 if( xNode.is() && (xNode->getType() == AnimationNodeType::COMMAND) )
1597 xCommand.set( xNode, UNO_QUERY_THROW );
1598 }
1599 }
1600 catch( Exception& e )
1601 {
1602 (void)e;
1603 DBG_ERROR("sd::findCommandNode(), exception caught!" );
1604 }
1605
1606 return xCommand;
1607 }
1608
removeAudio()1609 void CustomAnimationEffect::removeAudio()
1610 {
1611 try
1612 {
1613 Reference< XAnimationNode > xChild;
1614
1615 if( mxAudio.is() )
1616 {
1617 xChild.set( mxAudio, UNO_QUERY );
1618 mxAudio.clear();
1619 }
1620 else if( mnCommand == EffectCommands::STOPAUDIO )
1621 {
1622 xChild.set( findCommandNode( mxNode ), UNO_QUERY );
1623 mnCommand = 0;
1624 }
1625
1626 if( xChild.is() )
1627 {
1628 Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY );
1629 if( xContainer.is() )
1630 xContainer->removeChild( xChild );
1631 }
1632 }
1633 catch( Exception& e )
1634 {
1635 (void)e;
1636 DBG_ERROR("sd::CustomAnimationEffect::removeAudio(), exception caught!" );
1637 }
1638
1639 }
1640
1641 // --------------------------------------------------------------------
1642
setAudio(const Reference<::com::sun::star::animations::XAudio> & xAudio)1643 void CustomAnimationEffect::setAudio( const Reference< ::com::sun::star::animations::XAudio >& xAudio )
1644 {
1645 if( mxAudio != xAudio ) try
1646 {
1647 removeAudio();
1648 mxAudio = xAudio;
1649 Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY );
1650 Reference< XAnimationNode > xChild( mxAudio, UNO_QUERY );
1651 if( xContainer.is() && xChild.is() )
1652 xContainer->appendChild( xChild );
1653 }
1654 catch( Exception& e )
1655 {
1656 (void)e;
1657 DBG_ERROR("sd::CustomAnimationEffect::setAudio(), exception caught!" );
1658 }
1659 }
1660
1661 // --------------------------------------------------------------------
1662
setStopAudio()1663 void CustomAnimationEffect::setStopAudio()
1664 {
1665 if( mnCommand != EffectCommands::STOPAUDIO ) try
1666 {
1667 if( mxAudio.is() )
1668 removeAudio();
1669
1670 Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() );
1671 Reference< XCommand > xCommand( xMsf->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.Command") ) ), UNO_QUERY_THROW );
1672
1673 xCommand->setCommand( EffectCommands::STOPAUDIO );
1674
1675 Reference< XTimeContainer > xContainer( mxNode, UNO_QUERY_THROW );
1676 Reference< XAnimationNode > xChild( xCommand, UNO_QUERY_THROW );
1677 xContainer->appendChild( xChild );
1678
1679 mnCommand = EffectCommands::STOPAUDIO;
1680 }
1681 catch( Exception& e )
1682 {
1683 (void)e;
1684 DBG_ERROR("sd::CustomAnimationEffect::setStopAudio(), exception caught!" );
1685 }
1686 }
1687
1688 // --------------------------------------------------------------------
1689
getStopAudio() const1690 bool CustomAnimationEffect::getStopAudio() const
1691 {
1692 return mnCommand == EffectCommands::STOPAUDIO;
1693 }
1694
1695 // --------------------------------------------------------------------
1696
createSdrPathObjFromPath()1697 SdrPathObj* CustomAnimationEffect::createSdrPathObjFromPath()
1698 {
1699 SdrPathObj * pPathObj = new SdrPathObj( OBJ_PATHLINE );
1700 updateSdrPathObjFromPath( *pPathObj );
1701 return pPathObj;
1702 }
1703
1704 // --------------------------------------------------------------------
1705
updateSdrPathObjFromPath(SdrPathObj & rPathObj)1706 void CustomAnimationEffect::updateSdrPathObjFromPath( SdrPathObj& rPathObj )
1707 {
1708 ::basegfx::B2DPolyPolygon xPolyPoly;
1709 if( ::basegfx::tools::importFromSvgD( xPolyPoly, getPath(), true, 0 ) )
1710 {
1711 SdrObject* pObj = GetSdrObjectFromXShape( getTargetShape() );
1712 if( pObj )
1713 {
1714 SdrPage* pPage = pObj->GetPage();
1715 if( pPage )
1716 {
1717 const Size aPageSize( pPage->GetSize() );
1718 xPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix((double)aPageSize.Width(), (double)aPageSize.Height()));
1719 }
1720
1721 const Rectangle aBoundRect( pObj->GetCurrentBoundRect() );
1722 const Point aCenter( aBoundRect.Center() );
1723 xPolyPoly.transform(basegfx::tools::createTranslateB2DHomMatrix(aCenter.X(), aCenter.Y()));
1724 }
1725 }
1726
1727 rPathObj.SetPathPoly( xPolyPoly );
1728 }
1729
1730 // --------------------------------------------------------------------
1731
updatePathFromSdrPathObj(const SdrPathObj & rPathObj)1732 void CustomAnimationEffect::updatePathFromSdrPathObj( const SdrPathObj& rPathObj )
1733 {
1734 ::basegfx::B2DPolyPolygon xPolyPoly( rPathObj.GetPathPoly() );
1735
1736 SdrObject* pObj = GetSdrObjectFromXShape( getTargetShape() );
1737 if( pObj )
1738 {
1739 Rectangle aBoundRect(0,0,0,0);
1740
1741 const drawinglayer::primitive2d::Primitive2DSequence xPrimitives(pObj->GetViewContact().getViewIndependentPrimitive2DSequence());
1742 const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
1743 const basegfx::B2DRange aRange(drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(xPrimitives, aViewInformation2D));
1744
1745 if(!aRange.isEmpty())
1746 {
1747 aBoundRect = Rectangle(
1748 (sal_Int32)floor(aRange.getMinX()), (sal_Int32)floor(aRange.getMinY()),
1749 (sal_Int32)ceil(aRange.getMaxX()), (sal_Int32)ceil(aRange.getMaxY()));
1750 }
1751
1752 const Point aCenter( aBoundRect.Center() );
1753
1754 xPolyPoly.transform(basegfx::tools::createTranslateB2DHomMatrix(-aCenter.X(), -aCenter.Y()));
1755
1756 SdrPage* pPage = pObj->GetPage();
1757 if( pPage )
1758 {
1759 const Size aPageSize( pPage->GetSize() );
1760 xPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(
1761 1.0 / (double)aPageSize.Width(), 1.0 / (double)aPageSize.Height()));
1762 }
1763 }
1764
1765 setPath( ::basegfx::tools::exportToSvgD( xPolyPoly, true, true, true) );
1766 }
1767
1768 // ====================================================================
1769
EffectSequenceHelper()1770 EffectSequenceHelper::EffectSequenceHelper()
1771 : mnSequenceType( EffectNodeType::DEFAULT )
1772 {
1773 }
1774
1775 // --------------------------------------------------------------------
1776
EffectSequenceHelper(const::com::sun::star::uno::Reference<::com::sun::star::animations::XTimeContainer> & xSequenceRoot)1777 EffectSequenceHelper::EffectSequenceHelper( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XTimeContainer >& xSequenceRoot )
1778 : mxSequenceRoot( xSequenceRoot ), mnSequenceType( EffectNodeType::DEFAULT )
1779 {
1780 Reference< XAnimationNode > xNode( mxSequenceRoot, UNO_QUERY_THROW );
1781 create( xNode );
1782 }
1783
1784 // --------------------------------------------------------------------
1785
~EffectSequenceHelper()1786 EffectSequenceHelper::~EffectSequenceHelper()
1787 {
1788 reset();
1789 }
1790
1791 // --------------------------------------------------------------------
1792
reset()1793 void EffectSequenceHelper::reset()
1794 {
1795 EffectSequence::iterator aIter( maEffects.begin() );
1796 EffectSequence::iterator aEnd( maEffects.end() );
1797 if( aIter != aEnd )
1798 {
1799 CustomAnimationEffectPtr pEffect = (*aIter++);
1800 pEffect->setEffectSequence(0);
1801 }
1802 maEffects.clear();
1803 }
1804
getRootNode()1805 Reference< XAnimationNode > EffectSequenceHelper::getRootNode()
1806 {
1807 Reference< XAnimationNode > xRoot( mxSequenceRoot, UNO_QUERY );
1808 return xRoot;
1809 }
1810
1811 // --------------------------------------------------------------------
1812
append(const CustomAnimationEffectPtr & pEffect)1813 void EffectSequenceHelper::append( const CustomAnimationEffectPtr& pEffect )
1814 {
1815 pEffect->setEffectSequence( this );
1816 maEffects.push_back(pEffect);
1817 rebuild();
1818 }
1819
1820 // --------------------------------------------------------------------
1821
append(const CustomAnimationPresetPtr & pPreset,const Any & rTarget,double fDuration)1822 CustomAnimationEffectPtr EffectSequenceHelper::append( const CustomAnimationPresetPtr& pPreset, const Any& rTarget, double fDuration /* = -1.0 */ )
1823 {
1824 CustomAnimationEffectPtr pEffect;
1825
1826 if( pPreset.get() )
1827 {
1828 OUString strEmpty;
1829 Reference< XAnimationNode > xNode( pPreset->create( strEmpty ) );
1830 if( xNode.is() )
1831 {
1832 // first, filter all only ui relevant user data
1833 std::vector< NamedValue > aNewUserData;
1834 Sequence< NamedValue > aUserData( xNode->getUserData() );
1835 sal_Int32 nLength = aUserData.getLength();
1836 const NamedValue* p = aUserData.getConstArray();
1837 bool bFilter = false;
1838
1839 while( nLength-- )
1840 {
1841 if( !p->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "text-only" ) ) &&
1842 !p->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "preset-property" ) ) )
1843 {
1844 aNewUserData.push_back( *p );
1845 bFilter = true;
1846 }
1847 p++;
1848 }
1849
1850 if( bFilter )
1851 {
1852 aUserData = ::comphelper::containerToSequence< NamedValue, std::vector< NamedValue > >( aNewUserData );
1853 xNode->setUserData( aUserData );
1854 }
1855
1856 // check target, maybe we need to force it to text
1857 Any aTarget( rTarget );
1858 sal_Int16 nSubItem = ShapeAnimationSubType::AS_WHOLE;
1859
1860 if( aTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
1861 {
1862 nSubItem = ShapeAnimationSubType::ONLY_TEXT;
1863 }
1864 else if( pPreset->isTextOnly() )
1865 {
1866 Reference< XShape > xShape;
1867 aTarget >>= xShape;
1868 if( xShape.is() )
1869 {
1870 // that's bad, we target a shape here but the effect is only for text
1871 // so change subitem
1872 nSubItem = ShapeAnimationSubType::ONLY_TEXT;
1873 }
1874 }
1875
1876 // now create effect from preset
1877 pEffect.reset( new CustomAnimationEffect( xNode ) );
1878 pEffect->setEffectSequence( this );
1879 pEffect->setTarget( aTarget );
1880 pEffect->setTargetSubItem( nSubItem );
1881 if( fDuration != -1.0 )
1882 pEffect->setDuration( fDuration );
1883
1884 maEffects.push_back(pEffect);
1885
1886 rebuild();
1887 }
1888 }
1889
1890 DBG_ASSERT( pEffect.get(), "sd::EffectSequenceHelper::append(), failed!" );
1891 return pEffect;
1892 }
1893
1894 // --------------------------------------------------------------------
1895
append(const SdrPathObj & rPathObj,const Any & rTarget,double fDuration)1896 CustomAnimationEffectPtr EffectSequenceHelper::append( const SdrPathObj& rPathObj, const Any& rTarget, double fDuration /* = -1.0 */ )
1897 {
1898 CustomAnimationEffectPtr pEffect;
1899
1900 if( fDuration <= 0.0 )
1901 fDuration = 2.0;
1902
1903 try
1904 {
1905 Reference< XTimeContainer > xEffectContainer( createParallelTimeContainer() );
1906 const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.animations.AnimateMotion" ) );
1907 Reference< XAnimationNode > xAnimateMotion( ::comphelper::getProcessServiceFactory()->createInstance(aServiceName), UNO_QUERY_THROW );
1908
1909 xAnimateMotion->setDuration( Any( fDuration ) );
1910 xAnimateMotion->setFill( AnimationFill::HOLD );
1911 xEffectContainer->appendChild( xAnimateMotion );
1912
1913 sal_Int16 nSubItem = ShapeAnimationSubType::AS_WHOLE;
1914
1915 if( rTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
1916 nSubItem = ShapeAnimationSubType::ONLY_TEXT;
1917
1918 Reference< XAnimationNode > xEffectNode( xEffectContainer, UNO_QUERY_THROW );
1919 pEffect.reset( new CustomAnimationEffect( xEffectNode ) );
1920 pEffect->setEffectSequence( this );
1921 pEffect->setTarget( rTarget );
1922 pEffect->setTargetSubItem( nSubItem );
1923 pEffect->setNodeType( ::com::sun::star::presentation::EffectNodeType::ON_CLICK );
1924 pEffect->setPresetClass( ::com::sun::star::presentation::EffectPresetClass::MOTIONPATH );
1925 pEffect->setAcceleration( 0.5 );
1926 pEffect->setDecelerate( 0.5 );
1927 pEffect->setFill( AnimationFill::HOLD );
1928 pEffect->setBegin( 0.0 );
1929 pEffect->updatePathFromSdrPathObj( rPathObj );
1930 if( fDuration != -1.0 )
1931 pEffect->setDuration( fDuration );
1932
1933 maEffects.push_back(pEffect);
1934
1935 rebuild();
1936 }
1937 catch( Exception& )
1938 {
1939 DBG_ERROR( "sd::EffectSequenceHelper::append(), exception caught!" );
1940 }
1941
1942 return pEffect;
1943 }
1944
1945 // --------------------------------------------------------------------
1946
replace(const CustomAnimationEffectPtr & pEffect,const CustomAnimationPresetPtr & pPreset,const OUString & rPresetSubType,double fDuration)1947 void EffectSequenceHelper::replace( const CustomAnimationEffectPtr& pEffect, const CustomAnimationPresetPtr& pPreset, const OUString& rPresetSubType, double fDuration /* = -1.0 */ )
1948 {
1949 if( pEffect.get() && pPreset.get() ) try
1950 {
1951 Reference< XAnimationNode > xNewNode( pPreset->create( rPresetSubType ) );
1952 if( xNewNode.is() )
1953 {
1954 pEffect->replaceNode( xNewNode );
1955 if( fDuration != -1.0 )
1956 pEffect->setDuration( fDuration );
1957 }
1958
1959 rebuild();
1960 }
1961 catch( Exception& e )
1962 {
1963 (void)e;
1964 DBG_ERROR( "sd::EffectSequenceHelper::replace(), exception caught!" );
1965 }
1966 }
1967
1968 // --------------------------------------------------------------------
1969
replace(const CustomAnimationEffectPtr & pEffect,const CustomAnimationPresetPtr & pPreset,double fDuration)1970 void EffectSequenceHelper::replace( const CustomAnimationEffectPtr& pEffect, const CustomAnimationPresetPtr& pPreset, double fDuration /* = -1.0 */ )
1971 {
1972 OUString strEmpty;
1973 replace( pEffect, pPreset, strEmpty, fDuration );
1974 }
1975
1976 // --------------------------------------------------------------------
1977
remove(const CustomAnimationEffectPtr & pEffect)1978 void EffectSequenceHelper::remove( const CustomAnimationEffectPtr& pEffect )
1979 {
1980 if( pEffect.get() )
1981 {
1982 pEffect->setEffectSequence( 0 );
1983 maEffects.remove( pEffect );
1984 }
1985
1986 rebuild();
1987 }
1988
1989 // --------------------------------------------------------------------
1990
rebuild()1991 void EffectSequenceHelper::rebuild()
1992 {
1993 implRebuild();
1994 }
1995
1996 // --------------------------------------------------------------------
1997
implRebuild()1998 void EffectSequenceHelper::implRebuild()
1999 {
2000 try
2001 {
2002 // first we delete all time containers on the first two levels
2003 Reference< XEnumerationAccess > xEnumerationAccess( mxSequenceRoot, UNO_QUERY_THROW );
2004 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
2005 while( xEnumeration->hasMoreElements() )
2006 {
2007 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
2008 Reference< XTimeContainer > xChildContainer( xChildNode, UNO_QUERY_THROW );
2009
2010 Reference< XEnumerationAccess > xChildEnumerationAccess( xChildNode, UNO_QUERY_THROW );
2011 Reference< XEnumeration > xChildEnumeration( xChildEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
2012 while( xChildEnumeration->hasMoreElements() )
2013 {
2014 Reference< XAnimationNode > xNode( xChildEnumeration->nextElement(), UNO_QUERY_THROW );
2015 xChildContainer->removeChild( xNode );
2016 }
2017
2018 mxSequenceRoot->removeChild( xChildNode );
2019 }
2020
2021 // second, rebuild main sequence
2022 EffectSequence::iterator aIter( maEffects.begin() );
2023 EffectSequence::iterator aEnd( maEffects.end() );
2024 if( aIter != aEnd )
2025 {
2026 AfterEffectNodeList aAfterEffects;
2027
2028 CustomAnimationEffectPtr pEffect = (*aIter++);
2029
2030 bool bFirst = true;
2031 do
2032 {
2033 // create a par container for the next click node and all following with and after effects
2034 Reference< XTimeContainer > xOnClickContainer( createParallelTimeContainer() );
2035
2036 Event aEvent;
2037 if( mxEventSource.is() )
2038 {
2039 aEvent.Source <<= mxEventSource;
2040 aEvent.Trigger = EventTrigger::ON_CLICK;
2041 }
2042 else
2043 {
2044 aEvent.Trigger = EventTrigger::ON_NEXT;
2045 }
2046 aEvent.Repeat = 0;
2047
2048 Any aBegin( makeAny( aEvent ) );
2049 if( bFirst )
2050 {
2051 // if the first node is not a click action, this click container
2052 // must not have INDEFINITE begin but start at 0s
2053 bFirst = false;
2054 if( pEffect->getNodeType() != EffectNodeType::ON_CLICK )
2055 aBegin <<= (double)0.0;
2056 }
2057
2058 xOnClickContainer->setBegin( aBegin );
2059
2060 Reference< XAnimationNode > xOnClickContainerNode( xOnClickContainer, UNO_QUERY_THROW );
2061 mxSequenceRoot->appendChild( xOnClickContainerNode );
2062
2063 double fBegin = 0.0;
2064
2065 do
2066 {
2067 // create a par container for the current click or after effect node and all following with effects
2068 Reference< XTimeContainer > xWithContainer( createParallelTimeContainer() );
2069 Reference< XAnimationNode > xWithContainerNode( xWithContainer, UNO_QUERY_THROW );
2070 xWithContainer->setBegin( makeAny( fBegin ) );
2071 xOnClickContainer->appendChild( xWithContainerNode );
2072
2073 double fDuration = 0.0;
2074 do
2075 {
2076 Reference< XAnimationNode > xEffectNode( pEffect->getNode() );
2077 xWithContainer->appendChild( xEffectNode );
2078
2079 if( pEffect->hasAfterEffect() )
2080 {
2081 Reference< XAnimationNode > xAfterEffect( pEffect->createAfterEffectNode() );
2082 AfterEffectNode a( xAfterEffect, xEffectNode, pEffect->IsAfterEffectOnNext() );
2083 aAfterEffects.push_back( a );
2084 }
2085
2086 double fTemp = pEffect->getBegin() + pEffect->getAbsoluteDuration();
2087 if( fTemp > fDuration )
2088 fDuration = fTemp;
2089
2090 if( aIter != aEnd )
2091 pEffect = (*aIter++);
2092 else
2093 pEffect.reset();
2094 }
2095 while( pEffect.get() && (pEffect->getNodeType() == EffectNodeType::WITH_PREVIOUS) );
2096
2097 fBegin += fDuration;
2098 }
2099 while( pEffect.get() && (pEffect->getNodeType() != EffectNodeType::ON_CLICK) );
2100 }
2101 while( pEffect.get() );
2102
2103 // process after effect nodes
2104 std::for_each( aAfterEffects.begin(), aAfterEffects.end(), stl_process_after_effect_node_func );
2105
2106 updateTextGroups();
2107
2108 // reset duration, might have been altered (see below)
2109 mxSequenceRoot->setDuration( Any() );
2110 }
2111 else
2112 {
2113 // empty sequence, set duration to 0.0 explicitly
2114 // (otherwise, this sequence will never end)
2115 mxSequenceRoot->setDuration( makeAny((double)0.0) );
2116 }
2117 }
2118 catch( Exception& e )
2119 {
2120 (void)e;
2121 DBG_ERROR( "sd::EffectSequenceHelper::rebuild(), exception caught!" );
2122 }
2123 }
2124
2125 // --------------------------------------------------------------------
2126
createParallelTimeContainer() const2127 Reference< XTimeContainer > EffectSequenceHelper::createParallelTimeContainer() const
2128 {
2129 const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.animations.ParallelTimeContainer" ) );
2130 return Reference< XTimeContainer >( ::comphelper::getProcessServiceFactory()->createInstance(aServiceName), UNO_QUERY );
2131 }
2132
2133 // --------------------------------------------------------------------
2134
stl_CustomAnimationEffect_search_node_predict(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xSearchNode)2135 stl_CustomAnimationEffect_search_node_predict::stl_CustomAnimationEffect_search_node_predict( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xSearchNode )
2136 : mxSearchNode( xSearchNode )
2137 {
2138 }
2139
2140 // --------------------------------------------------------------------
2141
operator ()(CustomAnimationEffectPtr pEffect) const2142 bool stl_CustomAnimationEffect_search_node_predict::operator()( CustomAnimationEffectPtr pEffect ) const
2143 {
2144 return pEffect->getNode() == mxSearchNode;
2145 }
2146
2147 // --------------------------------------------------------------------
2148
implFindNextContainer(Reference<XTimeContainer> & xParent,Reference<XTimeContainer> & xCurrent,Reference<XTimeContainer> & xNext)2149 static bool implFindNextContainer( Reference< XTimeContainer >& xParent, Reference< XTimeContainer >& xCurrent, Reference< XTimeContainer >& xNext )
2150 throw(Exception)
2151 {
2152 Reference< XEnumerationAccess > xEnumerationAccess( xParent, UNO_QUERY_THROW );
2153 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration() );
2154 if( xEnumeration.is() )
2155 {
2156 Reference< XInterface > x;
2157 while( xEnumeration->hasMoreElements() && !xNext.is() )
2158 {
2159 if( (xEnumeration->nextElement() >>= x) && (x == xCurrent) )
2160 {
2161 if( xEnumeration->hasMoreElements() )
2162 xEnumeration->nextElement() >>= xNext;
2163 }
2164 }
2165 }
2166 return xNext.is();
2167 }
2168
2169 // --------------------------------------------------------------------
2170
stl_process_after_effect_node_func(AfterEffectNode & rNode)2171 void stl_process_after_effect_node_func(AfterEffectNode& rNode)
2172 {
2173 try
2174 {
2175 if( rNode.mxNode.is() && rNode.mxMaster.is() )
2176 {
2177 // set master node
2178 Reference< XAnimationNode > xMasterNode( rNode.mxMaster, UNO_QUERY_THROW );
2179 Sequence< NamedValue > aUserData( rNode.mxNode->getUserData() );
2180 sal_Int32 nSize = aUserData.getLength();
2181 aUserData.realloc(nSize+1);
2182 aUserData[nSize].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "master-element" ) );
2183 aUserData[nSize].Value <<= xMasterNode;
2184 rNode.mxNode->setUserData( aUserData );
2185
2186 // insert after effect node into timeline
2187 Reference< XTimeContainer > xContainer( rNode.mxMaster->getParent(), UNO_QUERY_THROW );
2188
2189 if( !rNode.mbOnNextEffect ) // sameClick
2190 {
2191 // insert the aftereffect after its effect is animated
2192 xContainer->insertAfter( rNode.mxNode, rNode.mxMaster );
2193 }
2194 else // nextClick
2195 {
2196 Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() );
2197 // insert the aftereffect in the next group
2198
2199 Reference< XTimeContainer > xClickContainer( xContainer->getParent(), UNO_QUERY_THROW );
2200 Reference< XTimeContainer > xSequenceContainer( xClickContainer->getParent(), UNO_QUERY_THROW );
2201
2202 Reference< XTimeContainer > xNextContainer;
2203
2204 // first try if we have an after effect container
2205 if( !implFindNextContainer( xClickContainer, xContainer, xNextContainer ) )
2206 {
2207 Reference< XTimeContainer > xNextClickContainer;
2208 // if not, try to find the next click effect container
2209 if( implFindNextContainer( xSequenceContainer, xClickContainer, xNextClickContainer ) )
2210 {
2211 Reference< XEnumerationAccess > xEnumerationAccess( xNextClickContainer, UNO_QUERY_THROW );
2212 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
2213 if( xEnumeration->hasMoreElements() )
2214 {
2215 // the next container is the first child container
2216 xEnumeration->nextElement() >>= xNextContainer;
2217 }
2218 else
2219 {
2220 // this does not yet have a child container, create one
2221 const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.ParallelTimeContainer") );
2222 xNextContainer = Reference< XTimeContainer >::query( xMsf->createInstance(aServiceName) );
2223
2224 if( xNextContainer.is() )
2225 {
2226 Reference< XAnimationNode > xNode( xNextContainer, UNO_QUERY_THROW );
2227 xNode->setBegin( makeAny( (double)0.0 ) );
2228 // xNode->setFill( AnimationFill::HOLD );
2229 xNextClickContainer->appendChild( xNode );
2230 }
2231 }
2232 DBG_ASSERT( xNextContainer.is(), "ppt::stl_process_after_effect_node_func::operator(), could not find/create container!" );
2233 }
2234 }
2235
2236 // if we don't have a next container, we add one to the sequence container
2237 if( !xNextContainer.is() )
2238 {
2239 const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.ParallelTimeContainer") );
2240 Reference< XTimeContainer > xNewClickContainer( xMsf->createInstance(aServiceName), UNO_QUERY_THROW );
2241
2242 Reference< XAnimationNode > xNewClickNode( xNewClickContainer, UNO_QUERY_THROW );
2243
2244 Event aEvent;
2245 aEvent.Trigger = EventTrigger::ON_NEXT;
2246 aEvent.Repeat = 0;
2247 xNewClickNode->setBegin( makeAny( aEvent ) );
2248
2249 Reference< XAnimationNode > xRefNode( xClickContainer, UNO_QUERY_THROW );
2250 xSequenceContainer->insertAfter( xNewClickNode, xRefNode );
2251
2252 xNextContainer = Reference< XTimeContainer >::query( xMsf->createInstance(aServiceName) );
2253
2254 DBG_ASSERT( xNextContainer.is(), "ppt::stl_process_after_effect_node_func::operator(), could not create container!" );
2255 if( xNextContainer.is() )
2256 {
2257 Reference< XAnimationNode > xNode( xNextContainer, UNO_QUERY_THROW );
2258 xNode->setBegin( makeAny( (double)0.0 ) );
2259 // xNode->setFill( AnimationFill::HOLD );
2260 xNewClickContainer->appendChild( xNode );
2261 }
2262 }
2263
2264 if( xNextContainer.is() )
2265 {
2266 // find begin time of first element
2267 Reference< XEnumerationAccess > xEnumerationAccess( xNextContainer, UNO_QUERY_THROW );
2268 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
2269 if( xEnumeration->hasMoreElements() )
2270 {
2271 Reference< XAnimationNode > xChild;
2272 // the next container is the first child container
2273 xEnumeration->nextElement() >>= xChild;
2274 if( xChild.is() )
2275 {
2276 Any aBegin( xChild->getBegin() );
2277 double fBegin = 0.0;
2278 if( (aBegin >>= fBegin) && (fBegin >= 0.0))
2279 rNode.mxNode->setBegin( aBegin );
2280 }
2281 }
2282
2283 xNextContainer->appendChild( rNode.mxNode );
2284 }
2285 }
2286 }
2287 }
2288 catch( Exception& e )
2289 {
2290 (void)e;
2291 DBG_ERROR( "ppt::stl_process_after_effect_node_func::operator(), exception caught!" );
2292 }
2293 }
2294
2295 // --------------------------------------------------------------------
2296
find(const CustomAnimationEffectPtr & pEffect)2297 EffectSequence::iterator EffectSequenceHelper::find( const CustomAnimationEffectPtr& pEffect )
2298 {
2299 return std::find( maEffects.begin(), maEffects.end(), pEffect );
2300 }
2301
2302 // --------------------------------------------------------------------
2303
findEffect(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode) const2304 CustomAnimationEffectPtr EffectSequenceHelper::findEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) const
2305 {
2306 CustomAnimationEffectPtr pEffect;
2307
2308 EffectSequence::const_iterator aIter( maEffects.begin() );
2309 for( ; aIter != maEffects.end(); aIter++ )
2310 {
2311 if( (*aIter)->getNode() == xNode )
2312 {
2313 pEffect = (*aIter);
2314 break;
2315 }
2316 }
2317
2318 return pEffect;
2319 }
2320
2321 // --------------------------------------------------------------------
2322
getOffsetFromEffect(const CustomAnimationEffectPtr & xEffect) const2323 sal_Int32 EffectSequenceHelper::getOffsetFromEffect( const CustomAnimationEffectPtr& xEffect ) const
2324 {
2325 sal_Int32 nOffset = 0;
2326
2327 EffectSequence::const_iterator aIter( maEffects.begin() );
2328 for( ; aIter != maEffects.end(); aIter++, nOffset++ )
2329 {
2330 if( (*aIter) == xEffect )
2331 return nOffset;
2332 }
2333
2334 return -1;
2335 }
2336
2337 // --------------------------------------------------------------------
2338
getEffectFromOffset(sal_Int32 nOffset) const2339 CustomAnimationEffectPtr EffectSequenceHelper::getEffectFromOffset( sal_Int32 nOffset ) const
2340 {
2341 EffectSequence::const_iterator aIter( maEffects.begin() );
2342 while( nOffset-- && aIter != maEffects.end() )
2343 aIter++;
2344
2345 CustomAnimationEffectPtr pEffect;
2346 if( aIter != maEffects.end() )
2347 pEffect = (*aIter);
2348
2349 return pEffect;
2350 }
2351
2352 // --------------------------------------------------------------------
2353
disposeShape(const Reference<XShape> & xShape)2354 bool EffectSequenceHelper::disposeShape( const Reference< XShape >& xShape )
2355 {
2356 bool bChanges = false;
2357
2358 EffectSequence::iterator aIter( maEffects.begin() );
2359 while( aIter != maEffects.end() )
2360 {
2361 if( (*aIter)->getTargetShape() == xShape )
2362 {
2363 (*aIter)->setEffectSequence( 0 );
2364 bChanges = true;
2365 aIter = maEffects.erase( aIter );
2366 }
2367 else
2368 {
2369 aIter++;
2370 }
2371 }
2372
2373 return bChanges;
2374 }
2375
2376 // --------------------------------------------------------------------
2377
hasEffect(const com::sun::star::uno::Reference<com::sun::star::drawing::XShape> & xShape)2378 bool EffectSequenceHelper::hasEffect( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape )
2379 {
2380 EffectSequence::iterator aIter( maEffects.begin() );
2381 while( aIter != maEffects.end() )
2382 {
2383 if( (*aIter)->getTargetShape() == xShape )
2384 return true;
2385 aIter++;
2386 }
2387
2388 return false;
2389 }
2390
2391 // --------------------------------------------------------------------
2392
insertTextRange(const com::sun::star::uno::Any & aTarget)2393 void EffectSequenceHelper::insertTextRange( const com::sun::star::uno::Any& aTarget )
2394 {
2395 bool bChanges = false;
2396
2397 ParagraphTarget aParaTarget;
2398 if( !(aTarget >>= aParaTarget ) )
2399 return;
2400
2401 EffectSequence::iterator aIter( maEffects.begin() );
2402 while( aIter != maEffects.end() )
2403 {
2404 if( (*aIter)->getTargetShape() == aParaTarget.Shape )
2405 bChanges |= (*aIter)->checkForText();
2406 aIter++;
2407 }
2408
2409 if( bChanges )
2410 rebuild();
2411 }
2412
2413 // --------------------------------------------------------------------
2414
disposeTextRange(const com::sun::star::uno::Any & aTarget)2415 void EffectSequenceHelper::disposeTextRange( const com::sun::star::uno::Any& aTarget )
2416 {
2417 ParagraphTarget aParaTarget;
2418 if( !(aTarget >>= aParaTarget ) )
2419 return;
2420
2421 bool bChanges = false;
2422 bool bErased = false;
2423
2424 EffectSequence::iterator aIter( maEffects.begin() );
2425 while( aIter != maEffects.end() )
2426 {
2427 Any aIterTarget( (*aIter)->getTarget() );
2428 if( aIterTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2429 {
2430 ParagraphTarget aIterParaTarget;
2431 if( (aIterTarget >>= aIterParaTarget) && (aIterParaTarget.Shape == aParaTarget.Shape) )
2432 {
2433 if( aIterParaTarget.Paragraph == aParaTarget.Paragraph )
2434 {
2435 // delete this effect if it targets the disposed paragraph directly
2436 (*aIter)->setEffectSequence( 0 );
2437 aIter = maEffects.erase( aIter );
2438 bChanges = true;
2439 bErased = true;
2440 }
2441 else
2442 {
2443 if( aIterParaTarget.Paragraph > aParaTarget.Paragraph )
2444 {
2445 // shift all paragraphs after disposed paragraph
2446 aIterParaTarget.Paragraph--;
2447 (*aIter)->setTarget( makeAny( aIterParaTarget ) );
2448 }
2449 }
2450 }
2451 }
2452 else if( (*aIter)->getTargetShape() == aParaTarget.Shape )
2453 {
2454 bChanges |= (*aIter)->checkForText();
2455 }
2456
2457 if( bErased )
2458 bErased = false;
2459 else
2460 aIter++;
2461 }
2462
2463 if( bChanges )
2464 rebuild();
2465 }
2466
2467 // --------------------------------------------------------------------
2468
CustomAnimationTextGroup(const Reference<XShape> & rTarget,sal_Int32 nGroupId)2469 CustomAnimationTextGroup::CustomAnimationTextGroup( const Reference< XShape >& rTarget, sal_Int32 nGroupId )
2470 : maTarget( rTarget ),
2471 mnGroupId( nGroupId )
2472 {
2473 reset();
2474 }
2475
2476 // --------------------------------------------------------------------
2477
reset()2478 void CustomAnimationTextGroup::reset()
2479 {
2480 mnTextGrouping = -1;
2481 mbAnimateForm = false;
2482 mbTextReverse = false;
2483 mfGroupingAuto = -1.0;
2484 mnLastPara = -1; // used to check for TextReverse
2485
2486 int i = 5;
2487 while( i-- ) mnDepthFlags[i] = 0;
2488
2489 maEffects.clear();
2490 }
2491
2492 // --------------------------------------------------------------------
2493
addEffect(CustomAnimationEffectPtr & pEffect)2494 void CustomAnimationTextGroup::addEffect( CustomAnimationEffectPtr& pEffect )
2495 {
2496 maEffects.push_back( pEffect );
2497
2498 Any aTarget( pEffect->getTarget() );
2499 if( aTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2500 {
2501 // now look at the paragraph
2502 ParagraphTarget aParaTarget;
2503 aTarget >>= aParaTarget;
2504
2505 if( mnLastPara != -1 )
2506 mbTextReverse = mnLastPara > aParaTarget.Paragraph;
2507
2508 mnLastPara = aParaTarget.Paragraph;
2509
2510 const sal_Int32 nParaDepth = pEffect->getParaDepth();
2511
2512 // only look at the first 5 levels
2513 if( nParaDepth < 5 )
2514 {
2515 // our first paragraph with this level?
2516 if( mnDepthFlags[nParaDepth] == 0 )
2517 {
2518 // so set it to the first found
2519 mnDepthFlags[nParaDepth] = (sal_Int8)pEffect->getNodeType();
2520 }
2521 else if( mnDepthFlags[nParaDepth] != pEffect->getNodeType() )
2522 {
2523 mnDepthFlags[nParaDepth] = -1;
2524 }
2525
2526 if( pEffect->getNodeType() == EffectNodeType::AFTER_PREVIOUS )
2527 mfGroupingAuto = pEffect->getBegin();
2528
2529 mnTextGrouping = 0;
2530 while( (mnTextGrouping < 5) && (mnDepthFlags[mnTextGrouping] > 0) )
2531 mnTextGrouping++;
2532 }
2533 }
2534 else
2535 {
2536 // if we have an effect with the shape as a target, we animate the background
2537 mbAnimateForm = pEffect->getTargetSubItem() != ShapeAnimationSubType::ONLY_TEXT;
2538 }
2539 }
2540
2541 // --------------------------------------------------------------------
2542
2543 class TextGroupMapImpl : public std::map< sal_Int32, CustomAnimationTextGroup* >
2544 {
2545 public:
2546 CustomAnimationTextGroup* findGroup( sal_Int32 nGroupId );
2547 };
2548
2549 // --------------------------------------------------------------------
2550
findGroup(sal_Int32 nGroupId)2551 CustomAnimationTextGroupPtr EffectSequenceHelper::findGroup( sal_Int32 nGroupId )
2552 {
2553 CustomAnimationTextGroupPtr aPtr;
2554
2555 CustomAnimationTextGroupMap::iterator aIter( maGroupMap.find( nGroupId ) );
2556 if( aIter != maGroupMap.end() )
2557 aPtr = (*aIter).second;
2558
2559 return aPtr;
2560 }
2561
2562 // --------------------------------------------------------------------
2563
updateTextGroups()2564 void EffectSequenceHelper::updateTextGroups()
2565 {
2566 maGroupMap.clear();
2567
2568 // first create all the groups
2569 EffectSequence::iterator aIter( maEffects.begin() );
2570 const EffectSequence::iterator aEnd( maEffects.end() );
2571 while( aIter != aEnd )
2572 {
2573 CustomAnimationEffectPtr pEffect( (*aIter++) );
2574
2575 const sal_Int32 nGroupId = pEffect->getGroupId();
2576
2577 if( nGroupId == -1 )
2578 continue; // trivial case, no group
2579
2580 CustomAnimationTextGroupPtr pGroup = findGroup( nGroupId );
2581 if( !pGroup.get() )
2582 {
2583 pGroup.reset( new CustomAnimationTextGroup( pEffect->getTargetShape(), nGroupId ) );
2584 maGroupMap[nGroupId] = pGroup;
2585 }
2586
2587 pGroup->addEffect( pEffect );
2588 }
2589 }
2590
2591 // --------------------------------------------------------------------
2592
createTextGroup(CustomAnimationEffectPtr pEffect,sal_Int32 nTextGrouping,double fTextGroupingAuto,sal_Bool bAnimateForm,sal_Bool bTextReverse)2593 CustomAnimationTextGroupPtr EffectSequenceHelper::createTextGroup( CustomAnimationEffectPtr pEffect, sal_Int32 nTextGrouping, double fTextGroupingAuto, sal_Bool bAnimateForm, sal_Bool bTextReverse )
2594 {
2595 // first finde a free group-id
2596 sal_Int32 nGroupId = 0;
2597
2598 CustomAnimationTextGroupMap::iterator aIter( maGroupMap.begin() );
2599 const CustomAnimationTextGroupMap::iterator aEnd( maGroupMap.end() );
2600 while( aIter != aEnd )
2601 {
2602 if( (*aIter).first == nGroupId )
2603 {
2604 nGroupId++;
2605 aIter = maGroupMap.begin();
2606 }
2607 else
2608 {
2609 aIter++;
2610 }
2611 }
2612
2613 Reference< XShape > xTarget( pEffect->getTargetShape() );
2614
2615 CustomAnimationTextGroupPtr pTextGroup( new CustomAnimationTextGroup( xTarget, nGroupId ) );
2616 maGroupMap[nGroupId] = pTextGroup;
2617
2618 bool bUsed = false;
2619
2620 // do we need to target the shape?
2621 if( (nTextGrouping == 0) || bAnimateForm )
2622 {
2623 sal_Int16 nSubItem;
2624 if( nTextGrouping == 0)
2625 nSubItem = bAnimateForm ? ShapeAnimationSubType::AS_WHOLE : ShapeAnimationSubType::ONLY_TEXT;
2626 else
2627 nSubItem = ShapeAnimationSubType::ONLY_BACKGROUND;
2628
2629 pEffect->setTarget( makeAny( xTarget ) );
2630 pEffect->setTargetSubItem( nSubItem );
2631 pEffect->setEffectSequence( this );
2632 pEffect->setGroupId( nGroupId );
2633
2634 pTextGroup->addEffect( pEffect );
2635 bUsed = true;
2636 }
2637
2638 pTextGroup->mnTextGrouping = nTextGrouping;
2639 pTextGroup->mfGroupingAuto = fTextGroupingAuto;
2640 pTextGroup->mbTextReverse = bTextReverse;
2641
2642 // now add an effect for each paragraph
2643 createTextGroupParagraphEffects( pTextGroup, pEffect, bUsed );
2644
2645 notify_listeners();
2646
2647 return pTextGroup;
2648 }
2649
2650 // --------------------------------------------------------------------
2651
createTextGroupParagraphEffects(CustomAnimationTextGroupPtr pTextGroup,CustomAnimationEffectPtr pEffect,bool bUsed)2652 void EffectSequenceHelper::createTextGroupParagraphEffects( CustomAnimationTextGroupPtr pTextGroup, CustomAnimationEffectPtr pEffect, bool bUsed )
2653 {
2654 Reference< XShape > xTarget( pTextGroup->maTarget );
2655
2656 sal_Int32 nTextGrouping = pTextGroup->mnTextGrouping;
2657 double fTextGroupingAuto = pTextGroup->mfGroupingAuto;
2658 sal_Bool bTextReverse = pTextGroup->mbTextReverse;
2659
2660 // now add an effect for each paragraph
2661 if( nTextGrouping >= 0 ) try
2662 {
2663 EffectSequence::iterator aInsertIter( find( pEffect ) );
2664
2665 const OUString strNumberingLevel( RTL_CONSTASCII_USTRINGPARAM("NumberingLevel") );
2666 Reference< XEnumerationAccess > xText( xTarget, UNO_QUERY_THROW );
2667 Reference< XEnumeration > xEnumeration( xText->createEnumeration(), UNO_QUERY_THROW );
2668
2669 std::list< sal_Int16 > aParaList;
2670 sal_Int16 nPara;
2671
2672 // fill the list with all valid paragraphs
2673 for( nPara = 0; xEnumeration->hasMoreElements(); nPara++ )
2674 {
2675 Reference< XTextRange > xRange( xEnumeration->nextElement(), UNO_QUERY );
2676 if( xRange.is() && xRange->getString().getLength() )
2677 {
2678 if( bTextReverse ) // sort them
2679 aParaList.push_front( nPara );
2680 else
2681 aParaList.push_back( nPara );
2682 }
2683 }
2684
2685 ParagraphTarget aTarget;
2686 aTarget.Shape = xTarget;
2687
2688 std::list< sal_Int16 >::iterator aIter( aParaList.begin() );
2689 std::list< sal_Int16 >::iterator aEnd( aParaList.end() );
2690 while( aIter != aEnd )
2691 {
2692 aTarget.Paragraph = (*aIter++);
2693
2694 CustomAnimationEffectPtr pNewEffect;
2695 if( bUsed )
2696 {
2697 // clone a new effect from first effect
2698 pNewEffect = pEffect->clone();
2699 ++aInsertIter;
2700 aInsertIter = maEffects.insert( aInsertIter, pNewEffect );
2701 }
2702 else
2703 {
2704 // reuse first effect if its not yet used
2705 pNewEffect = pEffect;
2706 bUsed = true;
2707 aInsertIter = find( pNewEffect );
2708 }
2709
2710 // set target and group-id
2711 pNewEffect->setTarget( makeAny( aTarget ) );
2712 pNewEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT );
2713 pNewEffect->setGroupId( pTextGroup->mnGroupId );
2714 pNewEffect->setEffectSequence( this );
2715
2716 // set correct node type
2717 if( pNewEffect->getParaDepth() < nTextGrouping )
2718 {
2719 if( fTextGroupingAuto == -1.0 )
2720 {
2721 pNewEffect->setNodeType( EffectNodeType::ON_CLICK );
2722 pNewEffect->setBegin( 0.0 );
2723 }
2724 else
2725 {
2726 pNewEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2727 pNewEffect->setBegin( fTextGroupingAuto );
2728 }
2729 }
2730 else
2731 {
2732 pNewEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2733 pNewEffect->setBegin( 0.0 );
2734 }
2735
2736 pTextGroup->addEffect( pNewEffect );
2737 }
2738 notify_listeners();
2739 }
2740 catch( Exception& e )
2741 {
2742 (void)e;
2743 DBG_ERROR("sd::EffectSequenceHelper::createTextGroup(), exception caught!" );
2744 }
2745 }
2746
2747 // --------------------------------------------------------------------
2748
setTextGrouping(CustomAnimationTextGroupPtr pTextGroup,sal_Int32 nTextGrouping)2749 void EffectSequenceHelper::setTextGrouping( CustomAnimationTextGroupPtr pTextGroup, sal_Int32 nTextGrouping )
2750 {
2751 if( pTextGroup->mnTextGrouping == nTextGrouping )
2752 {
2753 // first case, trivial case, do nothing
2754 }
2755 else if( (pTextGroup->mnTextGrouping == -1) && (nTextGrouping >= 0) )
2756 {
2757 // second case, we need to add new effects for each paragraph
2758
2759 CustomAnimationEffectPtr pEffect( pTextGroup->maEffects.front() );
2760
2761 pTextGroup->mnTextGrouping = nTextGrouping;
2762 createTextGroupParagraphEffects( pTextGroup, pEffect, true );
2763 notify_listeners();
2764 }
2765 else if( (pTextGroup->mnTextGrouping >= 0) && (nTextGrouping == -1 ) )
2766 {
2767 // third case, we need to remove effects for each paragraph
2768
2769 EffectSequence aEffects( pTextGroup->maEffects );
2770 pTextGroup->reset();
2771
2772 EffectSequence::iterator aIter( aEffects.begin() );
2773 const EffectSequence::iterator aEnd( aEffects.end() );
2774 while( aIter != aEnd )
2775 {
2776 CustomAnimationEffectPtr pEffect( (*aIter++) );
2777
2778 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2779 remove( pEffect );
2780 else
2781 pTextGroup->addEffect( pEffect );
2782 }
2783 notify_listeners();
2784 }
2785 else
2786 {
2787 // fourth case, we need to change the node types for the text nodes
2788 double fTextGroupingAuto = pTextGroup->mfGroupingAuto;
2789
2790 EffectSequence aEffects( pTextGroup->maEffects );
2791 pTextGroup->reset();
2792
2793 EffectSequence::iterator aIter( aEffects.begin() );
2794 const EffectSequence::iterator aEnd( aEffects.end() );
2795 while( aIter != aEnd )
2796 {
2797 CustomAnimationEffectPtr pEffect( (*aIter++) );
2798
2799 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2800 {
2801 // set correct node type
2802 if( pEffect->getParaDepth() < nTextGrouping )
2803 {
2804 if( fTextGroupingAuto == -1.0 )
2805 {
2806 pEffect->setNodeType( EffectNodeType::ON_CLICK );
2807 pEffect->setBegin( 0.0 );
2808 }
2809 else
2810 {
2811 pEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2812 pEffect->setBegin( fTextGroupingAuto );
2813 }
2814 }
2815 else
2816 {
2817 pEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2818 pEffect->setBegin( 0.0 );
2819 }
2820 }
2821
2822 pTextGroup->addEffect( pEffect );
2823
2824 }
2825 notify_listeners();
2826 }
2827 }
2828
2829 // --------------------------------------------------------------------
2830
setAnimateForm(CustomAnimationTextGroupPtr pTextGroup,sal_Bool bAnimateForm)2831 void EffectSequenceHelper::setAnimateForm( CustomAnimationTextGroupPtr pTextGroup, sal_Bool bAnimateForm )
2832 {
2833 if( pTextGroup->mbAnimateForm == bAnimateForm )
2834 {
2835 // trivial case, do nothing
2836 }
2837 else
2838 {
2839 EffectSequence aEffects( pTextGroup->maEffects );
2840 pTextGroup->reset();
2841
2842 EffectSequence::iterator aIter( aEffects.begin() );
2843 const EffectSequence::iterator aEnd( aEffects.end() );
2844
2845 // first insert if we have to
2846 if( bAnimateForm )
2847 {
2848 EffectSequence::iterator aInsertIter( find( (*aIter) ) );
2849
2850 CustomAnimationEffectPtr pEffect;
2851 if( (aEffects.size() == 1) && ((*aIter)->getTarget().getValueType() != ::getCppuType((const ParagraphTarget*)0) ) )
2852 {
2853 // special case, only one effect and that targets whole text,
2854 // convert this to target whole shape
2855 pEffect = (*aIter++);
2856 pEffect->setTargetSubItem( ShapeAnimationSubType::AS_WHOLE );
2857 }
2858 else
2859 {
2860 pEffect = (*aIter)->clone();
2861 pEffect->setTarget( makeAny( (*aIter)->getTargetShape() ) );
2862 pEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_BACKGROUND );
2863 maEffects.insert( aInsertIter, pEffect );
2864 }
2865
2866 pTextGroup->addEffect( pEffect );
2867 }
2868
2869 if( !bAnimateForm && (aEffects.size() == 1) )
2870 {
2871 CustomAnimationEffectPtr pEffect( (*aIter) );
2872 pEffect->setTarget( makeAny( (*aIter)->getTargetShape() ) );
2873 pEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT );
2874 pTextGroup->addEffect( pEffect );
2875 }
2876 else
2877 {
2878 // readd the rest to the group again
2879 while( aIter != aEnd )
2880 {
2881 CustomAnimationEffectPtr pEffect( (*aIter++) );
2882
2883 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2884 {
2885 pTextGroup->addEffect( pEffect );
2886 }
2887 else
2888 {
2889 DBG_ASSERT( !bAnimateForm, "sd::EffectSequenceHelper::setAnimateForm(), something is wrong here!" );
2890 remove( pEffect );
2891 }
2892 }
2893 }
2894 notify_listeners();
2895 }
2896 }
2897
2898 // --------------------------------------------------------------------
2899
setTextGroupingAuto(CustomAnimationTextGroupPtr pTextGroup,double fTextGroupingAuto)2900 void EffectSequenceHelper::setTextGroupingAuto( CustomAnimationTextGroupPtr pTextGroup, double fTextGroupingAuto )
2901 {
2902 sal_Int32 nTextGrouping = pTextGroup->mnTextGrouping;
2903
2904 EffectSequence aEffects( pTextGroup->maEffects );
2905 pTextGroup->reset();
2906
2907 EffectSequence::iterator aIter( aEffects.begin() );
2908 const EffectSequence::iterator aEnd( aEffects.end() );
2909 while( aIter != aEnd )
2910 {
2911 CustomAnimationEffectPtr pEffect( (*aIter++) );
2912
2913 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2914 {
2915 // set correct node type
2916 if( pEffect->getParaDepth() < nTextGrouping )
2917 {
2918 if( fTextGroupingAuto == -1.0 )
2919 {
2920 pEffect->setNodeType( EffectNodeType::ON_CLICK );
2921 pEffect->setBegin( 0.0 );
2922 }
2923 else
2924 {
2925 pEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2926 pEffect->setBegin( fTextGroupingAuto );
2927 }
2928 }
2929 else
2930 {
2931 pEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2932 pEffect->setBegin( 0.0 );
2933 }
2934 }
2935
2936 pTextGroup->addEffect( pEffect );
2937
2938 }
2939 notify_listeners();
2940 }
2941
2942 // --------------------------------------------------------------------
2943
2944 struct ImplStlTextGroupSortHelper
2945 {
ImplStlTextGroupSortHelpersd::ImplStlTextGroupSortHelper2946 ImplStlTextGroupSortHelper( bool bReverse ) : mbReverse( bReverse ) {};
2947 bool operator()( const CustomAnimationEffectPtr& p1, const CustomAnimationEffectPtr& p2 );
2948 bool mbReverse;
2949 sal_Int32 getTargetParagraph( const CustomAnimationEffectPtr& p1 );
2950 };
2951
2952 // --------------------------------------------------------------------
2953
getTargetParagraph(const CustomAnimationEffectPtr & p1)2954 sal_Int32 ImplStlTextGroupSortHelper::getTargetParagraph( const CustomAnimationEffectPtr& p1 )
2955 {
2956 const Any aTarget(p1->getTarget());
2957 if( aTarget.hasValue() && aTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2958 {
2959 ParagraphTarget aParaTarget;
2960 aTarget >>= aParaTarget;
2961 return aParaTarget.Paragraph;
2962 }
2963 else
2964 {
2965 return mbReverse ? 0x7fffffff : -1;
2966 }
2967 }
2968
2969 // --------------------------------------------------------------------
2970
operator ()(const CustomAnimationEffectPtr & p1,const CustomAnimationEffectPtr & p2)2971 bool ImplStlTextGroupSortHelper::operator()( const CustomAnimationEffectPtr& p1, const CustomAnimationEffectPtr& p2 )
2972 {
2973 if( mbReverse )
2974 {
2975 return getTargetParagraph( p2 ) < getTargetParagraph( p1 );
2976 }
2977 else
2978 {
2979 return getTargetParagraph( p1 ) < getTargetParagraph( p2 );
2980 }
2981 }
2982
2983 // --------------------------------------------------------------------
2984
setTextReverse(CustomAnimationTextGroupPtr pTextGroup,sal_Bool bTextReverse)2985 void EffectSequenceHelper::setTextReverse( CustomAnimationTextGroupPtr pTextGroup, sal_Bool bTextReverse )
2986 {
2987 if( pTextGroup->mbTextReverse == bTextReverse )
2988 {
2989 // do nothing
2990 }
2991 else
2992 {
2993 std::vector< CustomAnimationEffectPtr > aSortedVector(pTextGroup->maEffects.size());
2994 std::copy( pTextGroup->maEffects.begin(), pTextGroup->maEffects.end(), aSortedVector.begin() );
2995 ImplStlTextGroupSortHelper aSortHelper( bTextReverse );
2996 std::sort( aSortedVector.begin(), aSortedVector.end(), aSortHelper );
2997
2998 pTextGroup->reset();
2999
3000 std::vector< CustomAnimationEffectPtr >::iterator aIter( aSortedVector.begin() );
3001 const std::vector< CustomAnimationEffectPtr >::iterator aEnd( aSortedVector.end() );
3002
3003 if( aIter != aEnd )
3004 {
3005 pTextGroup->addEffect( (*aIter ) );
3006 EffectSequence::iterator aInsertIter( find( (*aIter++) ) );
3007 while( aIter != aEnd )
3008 {
3009 CustomAnimationEffectPtr pEffect( (*aIter++) );
3010 maEffects.erase( find( pEffect ) );
3011 aInsertIter = maEffects.insert( ++aInsertIter, pEffect );
3012 pTextGroup->addEffect( pEffect );
3013 }
3014 }
3015 notify_listeners();
3016 }
3017 }
3018
3019 // --------------------------------------------------------------------
3020
addListener(ISequenceListener * pListener)3021 void EffectSequenceHelper::addListener( ISequenceListener* pListener )
3022 {
3023 if( std::find( maListeners.begin(), maListeners.end(), pListener ) == maListeners.end() )
3024 maListeners.push_back( pListener );
3025 }
3026
3027 // --------------------------------------------------------------------
3028
removeListener(ISequenceListener * pListener)3029 void EffectSequenceHelper::removeListener( ISequenceListener* pListener )
3030 {
3031 maListeners.remove( pListener );
3032 }
3033
3034 // --------------------------------------------------------------------
3035
3036 struct stl_notify_listeners_func : public std::unary_function<ISequenceListener*, void>
3037 {
stl_notify_listeners_funcsd::stl_notify_listeners_func3038 stl_notify_listeners_func() {}
operator ()sd::stl_notify_listeners_func3039 void operator()(ISequenceListener* pListener) { pListener->notify_change(); }
3040 };
3041
3042 // --------------------------------------------------------------------
3043
notify_listeners()3044 void EffectSequenceHelper::notify_listeners()
3045 {
3046 stl_notify_listeners_func aFunc;
3047 std::for_each( maListeners.begin(), maListeners.end(), aFunc );
3048 }
3049
3050 // --------------------------------------------------------------------
3051
create(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode)3052 void EffectSequenceHelper::create( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
3053 {
3054 DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::create(), illegal argument" );
3055
3056 if( xNode.is() ) try
3057 {
3058 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
3059 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3060 while( xEnumeration->hasMoreElements() )
3061 {
3062 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3063 createEffectsequence( xChildNode );
3064 }
3065 }
3066 catch( Exception& )
3067 {
3068 DBG_ERROR( "sd::EffectSequenceHelper::create(), exception caught!" );
3069 }
3070 }
3071
3072 // --------------------------------------------------------------------
3073
createEffectsequence(const Reference<XAnimationNode> & xNode)3074 void EffectSequenceHelper::createEffectsequence( const Reference< XAnimationNode >& xNode )
3075 {
3076 DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::createEffectsequence(), illegal argument" );
3077
3078 if( xNode.is() ) try
3079 {
3080 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
3081 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3082 while( xEnumeration->hasMoreElements() )
3083 {
3084 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3085
3086 createEffects( xChildNode );
3087 }
3088 }
3089 catch( Exception& )
3090 {
3091 DBG_ERROR( "sd::EffectSequenceHelper::createEffectsequence(), exception caught!" );
3092 }
3093 }
3094
3095 // --------------------------------------------------------------------
3096
createEffects(const Reference<XAnimationNode> & xNode)3097 void EffectSequenceHelper::createEffects( const Reference< XAnimationNode >& xNode )
3098 {
3099 DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::createEffects(), illegal argument" );
3100
3101 if( xNode.is() ) try
3102 {
3103 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
3104 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3105 while( xEnumeration->hasMoreElements() )
3106 {
3107 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3108
3109 switch( xChildNode->getType() )
3110 {
3111 // found an effect
3112 case AnimationNodeType::PAR:
3113 case AnimationNodeType::ITERATE:
3114 {
3115 CustomAnimationEffectPtr pEffect( new CustomAnimationEffect( xChildNode ) );
3116
3117 if( pEffect->mnNodeType != -1 )
3118 {
3119 pEffect->setEffectSequence( this );
3120 maEffects.push_back(pEffect);
3121 }
3122 }
3123 break;
3124
3125 // found an after effect
3126 case AnimationNodeType::SET:
3127 case AnimationNodeType::ANIMATECOLOR:
3128 {
3129 processAfterEffect( xChildNode );
3130 }
3131 break;
3132 }
3133 }
3134 }
3135 catch( Exception& e )
3136 {
3137 (void)e;
3138 DBG_ERROR( "sd::EffectSequenceHelper::createEffects(), exception caught!" );
3139 }
3140 }
3141
3142 // --------------------------------------------------------------------
3143
processAfterEffect(const Reference<XAnimationNode> & xNode)3144 void EffectSequenceHelper::processAfterEffect( const Reference< XAnimationNode >& xNode )
3145 {
3146 try
3147 {
3148 Reference< XAnimationNode > xMaster;
3149
3150 Sequence< NamedValue > aUserData( xNode->getUserData() );
3151 sal_Int32 nLength = aUserData.getLength();
3152 const NamedValue* p = aUserData.getConstArray();
3153
3154 while( nLength-- )
3155 {
3156 if( p->Name.equalsAscii( "master-element" ) )
3157 {
3158 p->Value >>= xMaster;
3159 break;
3160 }
3161 p++;
3162 }
3163
3164 // only process if this is a valid after effect
3165 if( xMaster.is() )
3166 {
3167 CustomAnimationEffectPtr pMasterEffect;
3168
3169 // find the master effect
3170 stl_CustomAnimationEffect_search_node_predict aSearchPredict( xMaster );
3171 EffectSequence::iterator aIter( std::find_if( maEffects.begin(), maEffects.end(), aSearchPredict ) );
3172 if( aIter != maEffects.end() )
3173 pMasterEffect = (*aIter );
3174
3175 if( pMasterEffect.get() )
3176 {
3177 pMasterEffect->setHasAfterEffect( true );
3178
3179 // find out what kind of after effect this is
3180 if( xNode->getType() == AnimationNodeType::ANIMATECOLOR )
3181 {
3182 // its a dim
3183 Reference< XAnimate > xAnimate( xNode, UNO_QUERY_THROW );
3184 pMasterEffect->setDimColor( xAnimate->getTo() );
3185 pMasterEffect->setAfterEffectOnNext( true );
3186 }
3187 else
3188 {
3189 // its a hide
3190 Reference< XChild > xNodeChild( xNode, UNO_QUERY_THROW );
3191 Reference< XChild > xMasterChild( xMaster, UNO_QUERY_THROW );
3192 pMasterEffect->setAfterEffectOnNext( xNodeChild->getParent() != xMasterChild->getParent() );
3193 }
3194 }
3195 }
3196 }
3197 catch( Exception& e )
3198 {
3199 (void)e;
3200 DBG_ERROR( "sd::EffectSequenceHelper::processAfterEffect(), exception caught!" );
3201 }
3202 }
3203
3204 /*
3205 double EffectSequenceHelper::calculateIterateNodeDuration(
3206 {
3207 Reference< i18n::XBreakIterator > xBI( ImplGetBreakIterator() );
3208
3209 sal_Int32 nDone;
3210 sal_Int32 nNextCellBreak( xBI->nextCharacters(rTxt, nIdx, rLocale, i18n::CharacterIteratorMode::SKIPCELL, 0, nDone) );
3211 i18n::Boundary nNextWordBoundary( xBI->getWordBoundary(rTxt, nIdx, rLocale, i18n::WordType::ANY_WORD, sal_True) );
3212 sal_Int32 nNextSentenceBreak( xBI->endOfSentence(rTxt, nIdx, rLocale) );
3213
3214 const sal_Int32 nEndPos( nIdx + nLen );
3215 sal_Int32 i, currOffset(0);
3216 for( i=nIdx; i<nEndPos; ++i )
3217 {
3218 // TODO: Check whether position update is valid for CTL/BiDi
3219 rOutDev.DrawText( rPos + Point(currOffset,0), rTxt, i, 1 );
3220 currOffset = *pDXArray++;
3221
3222 // issue the comments at the respective break positions
3223 if( i == nNextCellBreak )
3224 {
3225 rMtf.AddAction( new MetaCommentAction( "XTEXT_EOC" ) );
3226 nNextCellBreak = xBI->nextCharacters(rTxt, i, rLocale, i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
3227 }
3228 if( i == nNextWordBoundary.endPos )
3229 {
3230 rMtf.AddAction( new MetaCommentAction( "XTEXT_EOW" ) );
3231 nNextWordBoundary = xBI->getWordBoundary(rTxt, i+1, rLocale, i18n::WordType::ANY_WORD, sal_True);
3232 }
3233 if( i == nNextSentenceBreak )
3234 {
3235 rMtf.AddAction( new MetaCommentAction( "XTEXT_EOS" ) );
3236 nNextSentenceBreak = xBI->endOfSentence(rTxt, i+1, rLocale);
3237 }
3238 }
3239 }
3240
3241 */
3242 // ====================================================================
3243
3244 class AnimationChangeListener : public cppu::WeakImplHelper1< XChangesListener >
3245 {
3246 public:
AnimationChangeListener(MainSequence * pMainSequence)3247 AnimationChangeListener( MainSequence* pMainSequence ) : mpMainSequence( pMainSequence ) {}
3248
3249 virtual void SAL_CALL changesOccurred( const ::com::sun::star::util::ChangesEvent& Event ) throw (RuntimeException);
3250 virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (RuntimeException);
3251 private:
3252 MainSequence* mpMainSequence;
3253 };
3254
changesOccurred(const::com::sun::star::util::ChangesEvent &)3255 void SAL_CALL AnimationChangeListener::changesOccurred( const ::com::sun::star::util::ChangesEvent& ) throw (RuntimeException)
3256 {
3257 if( mpMainSequence )
3258 mpMainSequence->startRecreateTimer();
3259 }
3260
disposing(const::com::sun::star::lang::EventObject &)3261 void SAL_CALL AnimationChangeListener::disposing( const ::com::sun::star::lang::EventObject& ) throw (RuntimeException)
3262 {
3263 }
3264
3265 // ====================================================================
3266
MainSequence()3267 MainSequence::MainSequence()
3268 : mxTimingRootNode( ::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.SequenceTimeContainer"))), UNO_QUERY )
3269 , mbRebuilding( false )
3270 , mnRebuildLockGuard( 0 )
3271 , mbPendingRebuildRequest( false )
3272 {
3273 if( mxTimingRootNode.is() )
3274 {
3275 Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
3276 aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
3277 aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::MAIN_SEQUENCE;
3278 mxTimingRootNode->setUserData( aUserData );
3279 }
3280 init();
3281 }
3282
3283 // --------------------------------------------------------------------
3284
MainSequence(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode)3285 MainSequence::MainSequence( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
3286 : mxTimingRootNode( xNode, UNO_QUERY )
3287 , mbRebuilding( false )
3288 , mnRebuildLockGuard( 0 )
3289 , mbPendingRebuildRequest( false )
3290 , mbIgnoreChanges( 0 )
3291 {
3292 init();
3293 }
3294
3295 // --------------------------------------------------------------------
3296
~MainSequence()3297 MainSequence::~MainSequence()
3298 {
3299 reset();
3300 }
3301
3302 // --------------------------------------------------------------------
3303
init()3304 void MainSequence::init()
3305 {
3306 mnSequenceType = EffectNodeType::MAIN_SEQUENCE;
3307
3308 maTimer.SetTimeoutHdl( LINK(this, MainSequence, onTimerHdl) );
3309 maTimer.SetTimeout(500);
3310
3311 mxChangesListener.set( new AnimationChangeListener( this ) );
3312
3313 createMainSequence();
3314 }
3315
3316 // --------------------------------------------------------------------
3317
reset(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xTimingRootNode)3318 void MainSequence::reset( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xTimingRootNode )
3319 {
3320 reset();
3321
3322 mxTimingRootNode.set( xTimingRootNode, UNO_QUERY );
3323
3324 createMainSequence();
3325 }
3326
3327 // --------------------------------------------------------------------
3328
getRootNode()3329 Reference< ::com::sun::star::animations::XAnimationNode > MainSequence::getRootNode()
3330 {
3331 DBG_ASSERT( mnRebuildLockGuard == 0, "MainSequence::getRootNode(), rebuild is locked, ist this really what you want?" );
3332
3333 if( maTimer.IsActive() && mbTimerMode )
3334 {
3335 // force a rebuild NOW if one is pending
3336 maTimer.Stop();
3337 implRebuild();
3338 }
3339
3340 return EffectSequenceHelper::getRootNode();
3341 }
3342
3343 // --------------------------------------------------------------------
3344
createMainSequence()3345 void MainSequence::createMainSequence()
3346 {
3347 if( mxTimingRootNode.is() ) try
3348 {
3349 Reference< XEnumerationAccess > xEnumerationAccess( mxTimingRootNode, UNO_QUERY_THROW );
3350 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3351 while( xEnumeration->hasMoreElements() )
3352 {
3353 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3354 sal_Int32 nNodeType = CustomAnimationEffect::get_node_type( xChildNode );
3355 if( nNodeType == EffectNodeType::MAIN_SEQUENCE )
3356 {
3357 mxSequenceRoot.set( xChildNode, UNO_QUERY );
3358 EffectSequenceHelper::create( xChildNode );
3359 }
3360 else if( nNodeType == EffectNodeType::INTERACTIVE_SEQUENCE )
3361 {
3362 Reference< XTimeContainer > xInteractiveRoot( xChildNode, UNO_QUERY_THROW );
3363 InteractiveSequencePtr pIS( new InteractiveSequence( xInteractiveRoot, this ) );
3364 pIS->addListener( this );
3365 maInteractiveSequenceList.push_back( pIS );
3366 }
3367 }
3368
3369 // see if we have a mainsequence at all. if not, create one...
3370 if( !mxSequenceRoot.is() )
3371 {
3372 mxSequenceRoot = Reference< XTimeContainer >::query(::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.SequenceTimeContainer"))));
3373 if( mxSequenceRoot.is() )
3374 {
3375 uno::Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
3376 aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
3377 aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::MAIN_SEQUENCE;
3378 mxSequenceRoot->setUserData( aUserData );
3379
3380 // empty sequence until now, set duration to 0.0
3381 // explicitly (otherwise, this sequence will never
3382 // end)
3383 mxSequenceRoot->setDuration( makeAny((double)0.0) );
3384
3385 Reference< XAnimationNode > xMainSequenceNode( mxSequenceRoot, UNO_QUERY_THROW );
3386 mxTimingRootNode->appendChild( xMainSequenceNode );
3387 }
3388 }
3389
3390 updateTextGroups();
3391
3392 notify_listeners();
3393
3394 Reference< XChangesNotifier > xNotifier( mxTimingRootNode, UNO_QUERY );
3395 if( xNotifier.is() )
3396 xNotifier->addChangesListener( mxChangesListener );
3397 }
3398 catch( Exception& e )
3399 {
3400 (void)e;
3401 DBG_ERROR( "sd::MainSequence::create(), exception caught!" );
3402 return;
3403 }
3404
3405 DBG_ASSERT( mxSequenceRoot.is(), "sd::MainSequence::create(), found no main sequence!" );
3406 }
3407
3408 // --------------------------------------------------------------------
3409
reset()3410 void MainSequence::reset()
3411 {
3412 EffectSequenceHelper::reset();
3413
3414 InteractiveSequenceList::iterator aIter;
3415 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3416 (*aIter)->reset();
3417 maInteractiveSequenceList.clear();
3418
3419 try
3420 {
3421 Reference< XChangesNotifier > xNotifier( mxTimingRootNode, UNO_QUERY );
3422 if( xNotifier.is() )
3423 xNotifier->removeChangesListener( mxChangesListener );
3424 }
3425 catch( Exception& )
3426 {
3427 // ...
3428 }
3429 }
3430
3431 // --------------------------------------------------------------------
3432
createInteractiveSequence(const::com::sun::star::uno::Reference<::com::sun::star::drawing::XShape> & xShape)3433 InteractiveSequencePtr MainSequence::createInteractiveSequence( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xShape )
3434 {
3435 InteractiveSequencePtr pIS;
3436
3437 // create a new interactive sequence container
3438 Reference< XTimeContainer > xISRoot( ::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.SequenceTimeContainer"))), UNO_QUERY );
3439 DBG_ASSERT( xISRoot.is(), "sd::MainSequence::createInteractiveSequence(), could not create \"com.sun.star.animations.SequenceTimeContainer\"!");
3440 if( xISRoot.is() )
3441 {
3442 uno::Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
3443 aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
3444 aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::INTERACTIVE_SEQUENCE ;
3445 xISRoot->setUserData( aUserData );
3446
3447 Reference< XChild > xChild( mxSequenceRoot, UNO_QUERY_THROW );
3448 Reference< XAnimationNode > xISNode( xISRoot, UNO_QUERY_THROW );
3449 Reference< XTimeContainer > xParent( xChild->getParent(), UNO_QUERY_THROW );
3450 xParent->appendChild( xISNode );
3451 }
3452 pIS.reset( new InteractiveSequence( xISRoot, this) );
3453 pIS->setTriggerShape( xShape );
3454 pIS->addListener( this );
3455 maInteractiveSequenceList.push_back( pIS );
3456 return pIS;
3457 }
3458
3459 // --------------------------------------------------------------------
3460
findEffect(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode) const3461 CustomAnimationEffectPtr MainSequence::findEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) const
3462 {
3463 CustomAnimationEffectPtr pEffect = EffectSequenceHelper::findEffect( xNode );
3464
3465 if( pEffect.get() == 0 )
3466 {
3467 InteractiveSequenceList::const_iterator aIter;
3468 for( aIter = maInteractiveSequenceList.begin(); (aIter != maInteractiveSequenceList.end()) && (pEffect.get() == 0); aIter++ )
3469 {
3470 pEffect = (*aIter)->findEffect( xNode );
3471 }
3472 }
3473 return pEffect;
3474 }
3475
3476 // --------------------------------------------------------------------
3477
getOffsetFromEffect(const CustomAnimationEffectPtr & pEffect) const3478 sal_Int32 MainSequence::getOffsetFromEffect( const CustomAnimationEffectPtr& pEffect ) const
3479 {
3480 sal_Int32 nOffset = EffectSequenceHelper::getOffsetFromEffect( pEffect );
3481
3482 if( nOffset != -1 )
3483 return nOffset;
3484
3485 nOffset = EffectSequenceHelper::getCount();
3486
3487 InteractiveSequenceList::const_iterator aIter;
3488 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3489 {
3490 sal_Int32 nTemp = (*aIter)->getOffsetFromEffect( pEffect );
3491 if( nTemp != -1 )
3492 return nOffset + nTemp;
3493
3494 nOffset += (*aIter)->getCount();
3495 }
3496
3497 return -1;
3498 }
3499
3500 // --------------------------------------------------------------------
3501
getEffectFromOffset(sal_Int32 nOffset) const3502 CustomAnimationEffectPtr MainSequence::getEffectFromOffset( sal_Int32 nOffset ) const
3503 {
3504 if( nOffset >= 0 )
3505 {
3506 if( nOffset < getCount() )
3507 return EffectSequenceHelper::getEffectFromOffset( nOffset );
3508
3509 nOffset -= getCount();
3510
3511 InteractiveSequenceList::const_iterator aIter( maInteractiveSequenceList.begin() );
3512
3513 while( (aIter != maInteractiveSequenceList.end()) && (nOffset > (*aIter)->getCount()) )
3514 nOffset -= (*aIter++)->getCount();
3515
3516 if( (aIter != maInteractiveSequenceList.end()) && (nOffset >= 0) )
3517 return (*aIter)->getEffectFromOffset( nOffset );
3518 }
3519
3520 CustomAnimationEffectPtr pEffect;
3521 return pEffect;
3522 }
3523
3524 // --------------------------------------------------------------------
3525
disposeShape(const Reference<XShape> & xShape)3526 bool MainSequence::disposeShape( const Reference< XShape >& xShape )
3527 {
3528 bool bChanges = EffectSequenceHelper::disposeShape( xShape );
3529
3530 InteractiveSequenceList::iterator aIter;
3531 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); )
3532 {
3533 bChanges |= (*aIter++)->disposeShape( xShape );
3534 }
3535
3536 if( bChanges )
3537 startRebuildTimer();
3538
3539 return bChanges;
3540 }
3541
3542 // --------------------------------------------------------------------
3543
hasEffect(const com::sun::star::uno::Reference<com::sun::star::drawing::XShape> & xShape)3544 bool MainSequence::hasEffect( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape )
3545 {
3546 if( EffectSequenceHelper::hasEffect( xShape ) )
3547 return true;
3548
3549 InteractiveSequenceList::iterator aIter;
3550 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); )
3551 {
3552 if( (*aIter)->getTriggerShape() == xShape )
3553 return true;
3554
3555 if( (*aIter++)->hasEffect( xShape ) )
3556 return true;
3557 }
3558
3559 return false;
3560 }
3561
3562 // --------------------------------------------------------------------
3563
insertTextRange(const com::sun::star::uno::Any & aTarget)3564 void MainSequence::insertTextRange( const com::sun::star::uno::Any& aTarget )
3565 {
3566 EffectSequenceHelper::insertTextRange( aTarget );
3567
3568 InteractiveSequenceList::iterator aIter;
3569 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3570 {
3571 (*aIter)->insertTextRange( aTarget );
3572 }
3573 }
3574 // --------------------------------------------------------------------
3575
disposeTextRange(const com::sun::star::uno::Any & aTarget)3576 void MainSequence::disposeTextRange( const com::sun::star::uno::Any& aTarget )
3577 {
3578 EffectSequenceHelper::disposeTextRange( aTarget );
3579
3580 InteractiveSequenceList::iterator aIter;
3581 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3582 {
3583 (*aIter)->disposeTextRange( aTarget );
3584 }
3585 }
3586
3587 // --------------------------------------------------------------------
3588
3589 /** callback from the sd::View when an object just left text edit mode */
onTextChanged(const Reference<XShape> & xShape)3590 void MainSequence::onTextChanged( const Reference< XShape >& xShape )
3591 {
3592 EffectSequenceHelper::onTextChanged( xShape );
3593
3594 InteractiveSequenceList::iterator aIter;
3595 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3596 {
3597 (*aIter)->onTextChanged( xShape );
3598 }
3599 }
3600
3601 // --------------------------------------------------------------------
3602
onTextChanged(const Reference<XShape> & xShape)3603 void EffectSequenceHelper::onTextChanged( const Reference< XShape >& xShape )
3604 {
3605 bool bChanges = false;
3606
3607 EffectSequence::iterator aIter;
3608 for( aIter = maEffects.begin(); aIter != maEffects.end(); aIter++ )
3609 {
3610 if( (*aIter)->getTargetShape() == xShape )
3611 bChanges |= (*aIter)->checkForText();
3612 }
3613
3614 if( bChanges )
3615 EffectSequenceHelper::implRebuild();
3616 }
3617
3618 // --------------------------------------------------------------------
3619
rebuild()3620 void MainSequence::rebuild()
3621 {
3622 startRebuildTimer();
3623 }
3624
3625 // --------------------------------------------------------------------
3626
lockRebuilds()3627 void MainSequence::lockRebuilds()
3628 {
3629 mnRebuildLockGuard++;
3630 }
3631
3632 // --------------------------------------------------------------------
3633
unlockRebuilds()3634 void MainSequence::unlockRebuilds()
3635 {
3636 DBG_ASSERT( mnRebuildLockGuard, "sd::MainSequence::unlockRebuilds(), no corresponding lockRebuilds() call!" );
3637 if( mnRebuildLockGuard )
3638 mnRebuildLockGuard--;
3639
3640 if( (mnRebuildLockGuard == 0) && mbPendingRebuildRequest )
3641 {
3642 mbPendingRebuildRequest = false;
3643 startRebuildTimer();
3644 }
3645 }
3646
3647 // --------------------------------------------------------------------
3648
implRebuild()3649 void MainSequence::implRebuild()
3650 {
3651 if( mnRebuildLockGuard )
3652 {
3653 mbPendingRebuildRequest = true;
3654 return;
3655 }
3656
3657 mbRebuilding = true;
3658
3659 EffectSequenceHelper::implRebuild();
3660
3661 InteractiveSequenceList::iterator aIter( maInteractiveSequenceList.begin() );
3662 const InteractiveSequenceList::iterator aEnd( maInteractiveSequenceList.end() );
3663 while( aIter != aEnd )
3664 {
3665 InteractiveSequencePtr pIS( (*aIter) );
3666 if( pIS->maEffects.empty() )
3667 {
3668 // remove empty interactive sequences
3669 aIter = maInteractiveSequenceList.erase( aIter );
3670
3671 Reference< XChild > xChild( mxSequenceRoot, UNO_QUERY_THROW );
3672 Reference< XTimeContainer > xParent( xChild->getParent(), UNO_QUERY_THROW );
3673 Reference< XAnimationNode > xISNode( pIS->mxSequenceRoot, UNO_QUERY_THROW );
3674 xParent->removeChild( xISNode );
3675 }
3676 else
3677 {
3678 pIS->implRebuild();
3679 aIter++;
3680 }
3681 }
3682
3683 notify_listeners();
3684 mbRebuilding = false;
3685 }
3686
3687 // --------------------------------------------------------------------
3688
notify_change()3689 void MainSequence::notify_change()
3690 {
3691 notify_listeners();
3692 }
3693
3694 // --------------------------------------------------------------------
3695
setTrigger(const CustomAnimationEffectPtr & pEffect,const::com::sun::star::uno::Reference<::com::sun::star::drawing::XShape> & xTriggerShape)3696 bool MainSequence::setTrigger( const CustomAnimationEffectPtr& pEffect, const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xTriggerShape )
3697 {
3698 EffectSequenceHelper* pOldSequence = pEffect->getEffectSequence();
3699
3700 EffectSequenceHelper* pNewSequence = 0;
3701 if( xTriggerShape.is() )
3702 {
3703 InteractiveSequenceList::iterator aIter( maInteractiveSequenceList.begin() );
3704 const InteractiveSequenceList::iterator aEnd( maInteractiveSequenceList.end() );
3705 while( aIter != aEnd )
3706 {
3707 InteractiveSequencePtr pIS( (*aIter++) );
3708 if( pIS->getTriggerShape() == xTriggerShape )
3709 {
3710 pNewSequence = pIS.get();
3711 break;
3712 }
3713 }
3714
3715 if( !pNewSequence )
3716 pNewSequence = createInteractiveSequence( xTriggerShape ).get();
3717 }
3718 else
3719 {
3720 pNewSequence = this;
3721 }
3722
3723 if( pOldSequence != pNewSequence )
3724 {
3725 if( pOldSequence )
3726 pOldSequence->maEffects.remove( pEffect );
3727 if( pNewSequence )
3728 pNewSequence->maEffects.push_back( pEffect );
3729 pEffect->setEffectSequence( pNewSequence );
3730 return true;
3731 }
3732 else
3733 {
3734 return false;
3735 }
3736
3737 }
3738
3739 // --------------------------------------------------------------------
3740
IMPL_LINK(MainSequence,onTimerHdl,Timer *,EMPTYARG)3741 IMPL_LINK( MainSequence, onTimerHdl, Timer *, EMPTYARG )
3742 {
3743 if( mbTimerMode )
3744 {
3745 implRebuild();
3746 }
3747 else
3748 {
3749 reset();
3750 createMainSequence();
3751 }
3752
3753 return 0;
3754 }
3755
3756 // --------------------------------------------------------------------
3757
3758 /** starts a timer that recreates the internal structure from the API core after 1 second */
startRecreateTimer()3759 void MainSequence::startRecreateTimer()
3760 {
3761 if( !mbRebuilding && (mbIgnoreChanges == 0) )
3762 {
3763 mbTimerMode = false;
3764 maTimer.Start();
3765 }
3766 }
3767
3768 // --------------------------------------------------------------------
3769
3770 /** starts a timer that rebuilds the API core from the internal structure after 1 second */
startRebuildTimer()3771 void MainSequence::startRebuildTimer()
3772 {
3773 mbTimerMode = true;
3774 maTimer.Start();
3775 }
3776
3777 // ====================================================================
3778
InteractiveSequence(const Reference<XTimeContainer> & xSequenceRoot,MainSequence * pMainSequence)3779 InteractiveSequence::InteractiveSequence( const Reference< XTimeContainer >& xSequenceRoot, MainSequence* pMainSequence )
3780 : EffectSequenceHelper( xSequenceRoot ), mpMainSequence( pMainSequence )
3781 {
3782 mnSequenceType = EffectNodeType::INTERACTIVE_SEQUENCE;
3783
3784 try
3785 {
3786 if( mxSequenceRoot.is() )
3787 {
3788 Reference< XEnumerationAccess > xEnumerationAccess( mxSequenceRoot, UNO_QUERY_THROW );
3789 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3790 while( !mxEventSource.is() && xEnumeration->hasMoreElements() )
3791 {
3792 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3793
3794 Event aEvent;
3795 if( (xChildNode->getBegin() >>= aEvent) && (aEvent.Trigger == EventTrigger::ON_CLICK) )
3796 aEvent.Source >>= mxEventSource;
3797 }
3798 }
3799 }
3800 catch( Exception& e )
3801 {
3802 (void)e;
3803 DBG_ERROR( "sd::InteractiveSequence::InteractiveSequence(), exception caught!" );
3804 return;
3805 }
3806 }
3807
3808 // --------------------------------------------------------------------
3809
rebuild()3810 void InteractiveSequence::rebuild()
3811 {
3812 mpMainSequence->rebuild();
3813 }
3814
implRebuild()3815 void InteractiveSequence::implRebuild()
3816 {
3817 EffectSequenceHelper::implRebuild();
3818 }
3819
3820 // --------------------------------------------------------------------
3821
MainSequenceRebuildGuard(const MainSequencePtr & pMainSequence)3822 MainSequenceRebuildGuard::MainSequenceRebuildGuard( const MainSequencePtr& pMainSequence )
3823 : mpMainSequence( pMainSequence )
3824 {
3825 if( mpMainSequence.get() )
3826 mpMainSequence->lockRebuilds();
3827 }
3828
~MainSequenceRebuildGuard()3829 MainSequenceRebuildGuard::~MainSequenceRebuildGuard()
3830 {
3831 if( mpMainSequence.get() )
3832 mpMainSequence->unlockRebuilds();
3833 }
3834
3835
3836 }
3837