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
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 {
2151 Reference< XEnumerationAccess > xEnumerationAccess( xParent, UNO_QUERY_THROW );
2152 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration() );
2153 if( xEnumeration.is() )
2154 {
2155 Reference< XInterface > x;
2156 while( xEnumeration->hasMoreElements() && !xNext.is() )
2157 {
2158 if( (xEnumeration->nextElement() >>= x) && (x == xCurrent) )
2159 {
2160 if( xEnumeration->hasMoreElements() )
2161 xEnumeration->nextElement() >>= xNext;
2162 }
2163 }
2164 }
2165 return xNext.is();
2166 }
2167
2168 // --------------------------------------------------------------------
2169
stl_process_after_effect_node_func(AfterEffectNode & rNode)2170 void stl_process_after_effect_node_func(AfterEffectNode& rNode)
2171 {
2172 try
2173 {
2174 if( rNode.mxNode.is() && rNode.mxMaster.is() )
2175 {
2176 // set master node
2177 Reference< XAnimationNode > xMasterNode( rNode.mxMaster, UNO_QUERY_THROW );
2178 Sequence< NamedValue > aUserData( rNode.mxNode->getUserData() );
2179 sal_Int32 nSize = aUserData.getLength();
2180 aUserData.realloc(nSize+1);
2181 aUserData[nSize].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "master-element" ) );
2182 aUserData[nSize].Value <<= xMasterNode;
2183 rNode.mxNode->setUserData( aUserData );
2184
2185 // insert after effect node into timeline
2186 Reference< XTimeContainer > xContainer( rNode.mxMaster->getParent(), UNO_QUERY_THROW );
2187
2188 if( !rNode.mbOnNextEffect ) // sameClick
2189 {
2190 // insert the aftereffect after its effect is animated
2191 xContainer->insertAfter( rNode.mxNode, rNode.mxMaster );
2192 }
2193 else // nextClick
2194 {
2195 Reference< XMultiServiceFactory > xMsf( ::comphelper::getProcessServiceFactory() );
2196 // insert the aftereffect in the next group
2197
2198 Reference< XTimeContainer > xClickContainer( xContainer->getParent(), UNO_QUERY_THROW );
2199 Reference< XTimeContainer > xSequenceContainer( xClickContainer->getParent(), UNO_QUERY_THROW );
2200
2201 Reference< XTimeContainer > xNextContainer;
2202
2203 // first try if we have an after effect container
2204 if( !implFindNextContainer( xClickContainer, xContainer, xNextContainer ) )
2205 {
2206 Reference< XTimeContainer > xNextClickContainer;
2207 // if not, try to find the next click effect container
2208 if( implFindNextContainer( xSequenceContainer, xClickContainer, xNextClickContainer ) )
2209 {
2210 Reference< XEnumerationAccess > xEnumerationAccess( xNextClickContainer, UNO_QUERY_THROW );
2211 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
2212 if( xEnumeration->hasMoreElements() )
2213 {
2214 // the next container is the first child container
2215 xEnumeration->nextElement() >>= xNextContainer;
2216 }
2217 else
2218 {
2219 // this does not yet have a child container, create one
2220 const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.ParallelTimeContainer") );
2221 xNextContainer = Reference< XTimeContainer >::query( xMsf->createInstance(aServiceName) );
2222
2223 if( xNextContainer.is() )
2224 {
2225 Reference< XAnimationNode > xNode( xNextContainer, UNO_QUERY_THROW );
2226 xNode->setBegin( makeAny( (double)0.0 ) );
2227 // xNode->setFill( AnimationFill::HOLD );
2228 xNextClickContainer->appendChild( xNode );
2229 }
2230 }
2231 DBG_ASSERT( xNextContainer.is(), "ppt::stl_process_after_effect_node_func::operator(), could not find/create container!" );
2232 }
2233 }
2234
2235 // if we don't have a next container, we add one to the sequence container
2236 if( !xNextContainer.is() )
2237 {
2238 const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.ParallelTimeContainer") );
2239 Reference< XTimeContainer > xNewClickContainer( xMsf->createInstance(aServiceName), UNO_QUERY_THROW );
2240
2241 Reference< XAnimationNode > xNewClickNode( xNewClickContainer, UNO_QUERY_THROW );
2242
2243 Event aEvent;
2244 aEvent.Trigger = EventTrigger::ON_NEXT;
2245 aEvent.Repeat = 0;
2246 xNewClickNode->setBegin( makeAny( aEvent ) );
2247
2248 Reference< XAnimationNode > xRefNode( xClickContainer, UNO_QUERY_THROW );
2249 xSequenceContainer->insertAfter( xNewClickNode, xRefNode );
2250
2251 xNextContainer = Reference< XTimeContainer >::query( xMsf->createInstance(aServiceName) );
2252
2253 DBG_ASSERT( xNextContainer.is(), "ppt::stl_process_after_effect_node_func::operator(), could not create container!" );
2254 if( xNextContainer.is() )
2255 {
2256 Reference< XAnimationNode > xNode( xNextContainer, UNO_QUERY_THROW );
2257 xNode->setBegin( makeAny( (double)0.0 ) );
2258 // xNode->setFill( AnimationFill::HOLD );
2259 xNewClickContainer->appendChild( xNode );
2260 }
2261 }
2262
2263 if( xNextContainer.is() )
2264 {
2265 // find begin time of first element
2266 Reference< XEnumerationAccess > xEnumerationAccess( xNextContainer, UNO_QUERY_THROW );
2267 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
2268 if( xEnumeration->hasMoreElements() )
2269 {
2270 Reference< XAnimationNode > xChild;
2271 // the next container is the first child container
2272 xEnumeration->nextElement() >>= xChild;
2273 if( xChild.is() )
2274 {
2275 Any aBegin( xChild->getBegin() );
2276 double fBegin = 0.0;
2277 if( (aBegin >>= fBegin) && (fBegin >= 0.0))
2278 rNode.mxNode->setBegin( aBegin );
2279 }
2280 }
2281
2282 xNextContainer->appendChild( rNode.mxNode );
2283 }
2284 }
2285 }
2286 }
2287 catch( Exception& e )
2288 {
2289 (void)e;
2290 DBG_ERROR( "ppt::stl_process_after_effect_node_func::operator(), exception caught!" );
2291 }
2292 }
2293
2294 // --------------------------------------------------------------------
2295
find(const CustomAnimationEffectPtr & pEffect)2296 EffectSequence::iterator EffectSequenceHelper::find( const CustomAnimationEffectPtr& pEffect )
2297 {
2298 return std::find( maEffects.begin(), maEffects.end(), pEffect );
2299 }
2300
2301 // --------------------------------------------------------------------
2302
findEffect(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode) const2303 CustomAnimationEffectPtr EffectSequenceHelper::findEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) const
2304 {
2305 CustomAnimationEffectPtr pEffect;
2306
2307 EffectSequence::const_iterator aIter( maEffects.begin() );
2308 for( ; aIter != maEffects.end(); aIter++ )
2309 {
2310 if( (*aIter)->getNode() == xNode )
2311 {
2312 pEffect = (*aIter);
2313 break;
2314 }
2315 }
2316
2317 return pEffect;
2318 }
2319
2320 // --------------------------------------------------------------------
2321
getOffsetFromEffect(const CustomAnimationEffectPtr & xEffect) const2322 sal_Int32 EffectSequenceHelper::getOffsetFromEffect( const CustomAnimationEffectPtr& xEffect ) const
2323 {
2324 sal_Int32 nOffset = 0;
2325
2326 EffectSequence::const_iterator aIter( maEffects.begin() );
2327 for( ; aIter != maEffects.end(); aIter++, nOffset++ )
2328 {
2329 if( (*aIter) == xEffect )
2330 return nOffset;
2331 }
2332
2333 return -1;
2334 }
2335
2336 // --------------------------------------------------------------------
2337
getEffectFromOffset(sal_Int32 nOffset) const2338 CustomAnimationEffectPtr EffectSequenceHelper::getEffectFromOffset( sal_Int32 nOffset ) const
2339 {
2340 EffectSequence::const_iterator aIter( maEffects.begin() );
2341 while( nOffset-- && aIter != maEffects.end() )
2342 aIter++;
2343
2344 CustomAnimationEffectPtr pEffect;
2345 if( aIter != maEffects.end() )
2346 pEffect = (*aIter);
2347
2348 return pEffect;
2349 }
2350
2351 // --------------------------------------------------------------------
2352
disposeShape(const Reference<XShape> & xShape)2353 bool EffectSequenceHelper::disposeShape( const Reference< XShape >& xShape )
2354 {
2355 bool bChanges = false;
2356
2357 EffectSequence::iterator aIter( maEffects.begin() );
2358 while( aIter != maEffects.end() )
2359 {
2360 if( (*aIter)->getTargetShape() == xShape )
2361 {
2362 (*aIter)->setEffectSequence( 0 );
2363 bChanges = true;
2364 aIter = maEffects.erase( aIter );
2365 }
2366 else
2367 {
2368 aIter++;
2369 }
2370 }
2371
2372 return bChanges;
2373 }
2374
2375 // --------------------------------------------------------------------
2376
hasEffect(const com::sun::star::uno::Reference<com::sun::star::drawing::XShape> & xShape)2377 bool EffectSequenceHelper::hasEffect( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape )
2378 {
2379 EffectSequence::iterator aIter( maEffects.begin() );
2380 while( aIter != maEffects.end() )
2381 {
2382 if( (*aIter)->getTargetShape() == xShape )
2383 return true;
2384 aIter++;
2385 }
2386
2387 return false;
2388 }
2389
2390 // --------------------------------------------------------------------
2391
insertTextRange(const com::sun::star::uno::Any & aTarget)2392 void EffectSequenceHelper::insertTextRange( const com::sun::star::uno::Any& aTarget )
2393 {
2394 bool bChanges = false;
2395
2396 ParagraphTarget aParaTarget;
2397 if( !(aTarget >>= aParaTarget ) )
2398 return;
2399
2400 EffectSequence::iterator aIter( maEffects.begin() );
2401 while( aIter != maEffects.end() )
2402 {
2403 if( (*aIter)->getTargetShape() == aParaTarget.Shape )
2404 bChanges |= (*aIter)->checkForText();
2405 aIter++;
2406 }
2407
2408 if( bChanges )
2409 rebuild();
2410 }
2411
2412 // --------------------------------------------------------------------
2413
disposeTextRange(const com::sun::star::uno::Any & aTarget)2414 void EffectSequenceHelper::disposeTextRange( const com::sun::star::uno::Any& aTarget )
2415 {
2416 ParagraphTarget aParaTarget;
2417 if( !(aTarget >>= aParaTarget ) )
2418 return;
2419
2420 bool bChanges = false;
2421 bool bErased = false;
2422
2423 EffectSequence::iterator aIter( maEffects.begin() );
2424 while( aIter != maEffects.end() )
2425 {
2426 Any aIterTarget( (*aIter)->getTarget() );
2427 if( aIterTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2428 {
2429 ParagraphTarget aIterParaTarget;
2430 if( (aIterTarget >>= aIterParaTarget) && (aIterParaTarget.Shape == aParaTarget.Shape) )
2431 {
2432 if( aIterParaTarget.Paragraph == aParaTarget.Paragraph )
2433 {
2434 // delete this effect if it targets the disposed paragraph directly
2435 (*aIter)->setEffectSequence( 0 );
2436 aIter = maEffects.erase( aIter );
2437 bChanges = true;
2438 bErased = true;
2439 }
2440 else
2441 {
2442 if( aIterParaTarget.Paragraph > aParaTarget.Paragraph )
2443 {
2444 // shift all paragraphs after disposed paragraph
2445 aIterParaTarget.Paragraph--;
2446 (*aIter)->setTarget( makeAny( aIterParaTarget ) );
2447 }
2448 }
2449 }
2450 }
2451 else if( (*aIter)->getTargetShape() == aParaTarget.Shape )
2452 {
2453 bChanges |= (*aIter)->checkForText();
2454 }
2455
2456 if( bErased )
2457 bErased = false;
2458 else
2459 aIter++;
2460 }
2461
2462 if( bChanges )
2463 rebuild();
2464 }
2465
2466 // --------------------------------------------------------------------
2467
CustomAnimationTextGroup(const Reference<XShape> & rTarget,sal_Int32 nGroupId)2468 CustomAnimationTextGroup::CustomAnimationTextGroup( const Reference< XShape >& rTarget, sal_Int32 nGroupId )
2469 : maTarget( rTarget ),
2470 mnGroupId( nGroupId )
2471 {
2472 reset();
2473 }
2474
2475 // --------------------------------------------------------------------
2476
reset()2477 void CustomAnimationTextGroup::reset()
2478 {
2479 mnTextGrouping = -1;
2480 mbAnimateForm = false;
2481 mbTextReverse = false;
2482 mfGroupingAuto = -1.0;
2483 mnLastPara = -1; // used to check for TextReverse
2484
2485 int i = 5;
2486 while( i-- ) mnDepthFlags[i] = 0;
2487
2488 maEffects.clear();
2489 }
2490
2491 // --------------------------------------------------------------------
2492
addEffect(CustomAnimationEffectPtr & pEffect)2493 void CustomAnimationTextGroup::addEffect( CustomAnimationEffectPtr& pEffect )
2494 {
2495 maEffects.push_back( pEffect );
2496
2497 Any aTarget( pEffect->getTarget() );
2498 if( aTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2499 {
2500 // now look at the paragraph
2501 ParagraphTarget aParaTarget;
2502 aTarget >>= aParaTarget;
2503
2504 if( mnLastPara != -1 )
2505 mbTextReverse = mnLastPara > aParaTarget.Paragraph;
2506
2507 mnLastPara = aParaTarget.Paragraph;
2508
2509 const sal_Int32 nParaDepth = pEffect->getParaDepth();
2510
2511 // only look at the first 5 levels
2512 if( nParaDepth < 5 )
2513 {
2514 // our first paragraph with this level?
2515 if( mnDepthFlags[nParaDepth] == 0 )
2516 {
2517 // so set it to the first found
2518 mnDepthFlags[nParaDepth] = (sal_Int8)pEffect->getNodeType();
2519 }
2520 else if( mnDepthFlags[nParaDepth] != pEffect->getNodeType() )
2521 {
2522 mnDepthFlags[nParaDepth] = -1;
2523 }
2524
2525 if( pEffect->getNodeType() == EffectNodeType::AFTER_PREVIOUS )
2526 mfGroupingAuto = pEffect->getBegin();
2527
2528 mnTextGrouping = 0;
2529 while( (mnTextGrouping < 5) && (mnDepthFlags[mnTextGrouping] > 0) )
2530 mnTextGrouping++;
2531 }
2532 }
2533 else
2534 {
2535 // if we have an effect with the shape as a target, we animate the background
2536 mbAnimateForm = pEffect->getTargetSubItem() != ShapeAnimationSubType::ONLY_TEXT;
2537 }
2538 }
2539
2540 // --------------------------------------------------------------------
2541
2542 class TextGroupMapImpl : public std::map< sal_Int32, CustomAnimationTextGroup* >
2543 {
2544 public:
2545 CustomAnimationTextGroup* findGroup( sal_Int32 nGroupId );
2546 };
2547
2548 // --------------------------------------------------------------------
2549
findGroup(sal_Int32 nGroupId)2550 CustomAnimationTextGroupPtr EffectSequenceHelper::findGroup( sal_Int32 nGroupId )
2551 {
2552 CustomAnimationTextGroupPtr aPtr;
2553
2554 CustomAnimationTextGroupMap::iterator aIter( maGroupMap.find( nGroupId ) );
2555 if( aIter != maGroupMap.end() )
2556 aPtr = (*aIter).second;
2557
2558 return aPtr;
2559 }
2560
2561 // --------------------------------------------------------------------
2562
updateTextGroups()2563 void EffectSequenceHelper::updateTextGroups()
2564 {
2565 maGroupMap.clear();
2566
2567 // first create all the groups
2568 EffectSequence::iterator aIter( maEffects.begin() );
2569 const EffectSequence::iterator aEnd( maEffects.end() );
2570 while( aIter != aEnd )
2571 {
2572 CustomAnimationEffectPtr pEffect( (*aIter++) );
2573
2574 const sal_Int32 nGroupId = pEffect->getGroupId();
2575
2576 if( nGroupId == -1 )
2577 continue; // trivial case, no group
2578
2579 CustomAnimationTextGroupPtr pGroup = findGroup( nGroupId );
2580 if( !pGroup.get() )
2581 {
2582 pGroup.reset( new CustomAnimationTextGroup( pEffect->getTargetShape(), nGroupId ) );
2583 maGroupMap[nGroupId] = pGroup;
2584 }
2585
2586 pGroup->addEffect( pEffect );
2587 }
2588 }
2589
2590 // --------------------------------------------------------------------
2591
createTextGroup(CustomAnimationEffectPtr pEffect,sal_Int32 nTextGrouping,double fTextGroupingAuto,sal_Bool bAnimateForm,sal_Bool bTextReverse)2592 CustomAnimationTextGroupPtr EffectSequenceHelper::createTextGroup( CustomAnimationEffectPtr pEffect, sal_Int32 nTextGrouping, double fTextGroupingAuto, sal_Bool bAnimateForm, sal_Bool bTextReverse )
2593 {
2594 // first finde a free group-id
2595 sal_Int32 nGroupId = 0;
2596
2597 CustomAnimationTextGroupMap::iterator aIter( maGroupMap.begin() );
2598 const CustomAnimationTextGroupMap::iterator aEnd( maGroupMap.end() );
2599 while( aIter != aEnd )
2600 {
2601 if( (*aIter).first == nGroupId )
2602 {
2603 nGroupId++;
2604 aIter = maGroupMap.begin();
2605 }
2606 else
2607 {
2608 aIter++;
2609 }
2610 }
2611
2612 Reference< XShape > xTarget( pEffect->getTargetShape() );
2613
2614 CustomAnimationTextGroupPtr pTextGroup( new CustomAnimationTextGroup( xTarget, nGroupId ) );
2615 maGroupMap[nGroupId] = pTextGroup;
2616
2617 bool bUsed = false;
2618
2619 // do we need to target the shape?
2620 if( (nTextGrouping == 0) || bAnimateForm )
2621 {
2622 sal_Int16 nSubItem;
2623 if( nTextGrouping == 0)
2624 nSubItem = bAnimateForm ? ShapeAnimationSubType::AS_WHOLE : ShapeAnimationSubType::ONLY_TEXT;
2625 else
2626 nSubItem = ShapeAnimationSubType::ONLY_BACKGROUND;
2627
2628 pEffect->setTarget( makeAny( xTarget ) );
2629 pEffect->setTargetSubItem( nSubItem );
2630 pEffect->setEffectSequence( this );
2631 pEffect->setGroupId( nGroupId );
2632
2633 pTextGroup->addEffect( pEffect );
2634 bUsed = true;
2635 }
2636
2637 pTextGroup->mnTextGrouping = nTextGrouping;
2638 pTextGroup->mfGroupingAuto = fTextGroupingAuto;
2639 pTextGroup->mbTextReverse = bTextReverse;
2640
2641 // now add an effect for each paragraph
2642 createTextGroupParagraphEffects( pTextGroup, pEffect, bUsed );
2643
2644 notify_listeners();
2645
2646 return pTextGroup;
2647 }
2648
2649 // --------------------------------------------------------------------
2650
createTextGroupParagraphEffects(CustomAnimationTextGroupPtr pTextGroup,CustomAnimationEffectPtr pEffect,bool bUsed)2651 void EffectSequenceHelper::createTextGroupParagraphEffects( CustomAnimationTextGroupPtr pTextGroup, CustomAnimationEffectPtr pEffect, bool bUsed )
2652 {
2653 Reference< XShape > xTarget( pTextGroup->maTarget );
2654
2655 sal_Int32 nTextGrouping = pTextGroup->mnTextGrouping;
2656 double fTextGroupingAuto = pTextGroup->mfGroupingAuto;
2657 sal_Bool bTextReverse = pTextGroup->mbTextReverse;
2658
2659 // now add an effect for each paragraph
2660 if( nTextGrouping >= 0 ) try
2661 {
2662 EffectSequence::iterator aInsertIter( find( pEffect ) );
2663
2664 const OUString strNumberingLevel( RTL_CONSTASCII_USTRINGPARAM("NumberingLevel") );
2665 Reference< XEnumerationAccess > xText( xTarget, UNO_QUERY_THROW );
2666 Reference< XEnumeration > xEnumeration( xText->createEnumeration(), UNO_QUERY_THROW );
2667
2668 std::list< sal_Int16 > aParaList;
2669 sal_Int16 nPara;
2670
2671 // fill the list with all valid paragraphs
2672 for( nPara = 0; xEnumeration->hasMoreElements(); nPara++ )
2673 {
2674 Reference< XTextRange > xRange( xEnumeration->nextElement(), UNO_QUERY );
2675 if( xRange.is() && xRange->getString().getLength() )
2676 {
2677 if( bTextReverse ) // sort them
2678 aParaList.push_front( nPara );
2679 else
2680 aParaList.push_back( nPara );
2681 }
2682 }
2683
2684 ParagraphTarget aTarget;
2685 aTarget.Shape = xTarget;
2686
2687 std::list< sal_Int16 >::iterator aIter( aParaList.begin() );
2688 std::list< sal_Int16 >::iterator aEnd( aParaList.end() );
2689 while( aIter != aEnd )
2690 {
2691 aTarget.Paragraph = (*aIter++);
2692
2693 CustomAnimationEffectPtr pNewEffect;
2694 if( bUsed )
2695 {
2696 // clone a new effect from first effect
2697 pNewEffect = pEffect->clone();
2698 ++aInsertIter;
2699 aInsertIter = maEffects.insert( aInsertIter, pNewEffect );
2700 }
2701 else
2702 {
2703 // reuse first effect if its not yet used
2704 pNewEffect = pEffect;
2705 bUsed = true;
2706 aInsertIter = find( pNewEffect );
2707 }
2708
2709 // set target and group-id
2710 pNewEffect->setTarget( makeAny( aTarget ) );
2711 pNewEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT );
2712 pNewEffect->setGroupId( pTextGroup->mnGroupId );
2713 pNewEffect->setEffectSequence( this );
2714
2715 // set correct node type
2716 if( pNewEffect->getParaDepth() < nTextGrouping )
2717 {
2718 if( fTextGroupingAuto == -1.0 )
2719 {
2720 pNewEffect->setNodeType( EffectNodeType::ON_CLICK );
2721 pNewEffect->setBegin( 0.0 );
2722 }
2723 else
2724 {
2725 pNewEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2726 pNewEffect->setBegin( fTextGroupingAuto );
2727 }
2728 }
2729 else
2730 {
2731 pNewEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2732 pNewEffect->setBegin( 0.0 );
2733 }
2734
2735 pTextGroup->addEffect( pNewEffect );
2736 }
2737 notify_listeners();
2738 }
2739 catch( Exception& e )
2740 {
2741 (void)e;
2742 DBG_ERROR("sd::EffectSequenceHelper::createTextGroup(), exception caught!" );
2743 }
2744 }
2745
2746 // --------------------------------------------------------------------
2747
setTextGrouping(CustomAnimationTextGroupPtr pTextGroup,sal_Int32 nTextGrouping)2748 void EffectSequenceHelper::setTextGrouping( CustomAnimationTextGroupPtr pTextGroup, sal_Int32 nTextGrouping )
2749 {
2750 if( pTextGroup->mnTextGrouping == nTextGrouping )
2751 {
2752 // first case, trivial case, do nothing
2753 }
2754 else if( (pTextGroup->mnTextGrouping == -1) && (nTextGrouping >= 0) )
2755 {
2756 // second case, we need to add new effects for each paragraph
2757
2758 CustomAnimationEffectPtr pEffect( pTextGroup->maEffects.front() );
2759
2760 pTextGroup->mnTextGrouping = nTextGrouping;
2761 createTextGroupParagraphEffects( pTextGroup, pEffect, true );
2762 notify_listeners();
2763 }
2764 else if( (pTextGroup->mnTextGrouping >= 0) && (nTextGrouping == -1 ) )
2765 {
2766 // third case, we need to remove effects for each paragraph
2767
2768 EffectSequence aEffects( pTextGroup->maEffects );
2769 pTextGroup->reset();
2770
2771 EffectSequence::iterator aIter( aEffects.begin() );
2772 const EffectSequence::iterator aEnd( aEffects.end() );
2773 while( aIter != aEnd )
2774 {
2775 CustomAnimationEffectPtr pEffect( (*aIter++) );
2776
2777 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2778 remove( pEffect );
2779 else
2780 pTextGroup->addEffect( pEffect );
2781 }
2782 notify_listeners();
2783 }
2784 else
2785 {
2786 // fourth case, we need to change the node types for the text nodes
2787 double fTextGroupingAuto = pTextGroup->mfGroupingAuto;
2788
2789 EffectSequence aEffects( pTextGroup->maEffects );
2790 pTextGroup->reset();
2791
2792 EffectSequence::iterator aIter( aEffects.begin() );
2793 const EffectSequence::iterator aEnd( aEffects.end() );
2794 while( aIter != aEnd )
2795 {
2796 CustomAnimationEffectPtr pEffect( (*aIter++) );
2797
2798 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2799 {
2800 // set correct node type
2801 if( pEffect->getParaDepth() < nTextGrouping )
2802 {
2803 if( fTextGroupingAuto == -1.0 )
2804 {
2805 pEffect->setNodeType( EffectNodeType::ON_CLICK );
2806 pEffect->setBegin( 0.0 );
2807 }
2808 else
2809 {
2810 pEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2811 pEffect->setBegin( fTextGroupingAuto );
2812 }
2813 }
2814 else
2815 {
2816 pEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2817 pEffect->setBegin( 0.0 );
2818 }
2819 }
2820
2821 pTextGroup->addEffect( pEffect );
2822
2823 }
2824 notify_listeners();
2825 }
2826 }
2827
2828 // --------------------------------------------------------------------
2829
setAnimateForm(CustomAnimationTextGroupPtr pTextGroup,sal_Bool bAnimateForm)2830 void EffectSequenceHelper::setAnimateForm( CustomAnimationTextGroupPtr pTextGroup, sal_Bool bAnimateForm )
2831 {
2832 if( pTextGroup->mbAnimateForm == bAnimateForm )
2833 {
2834 // trivial case, do nothing
2835 }
2836 else
2837 {
2838 EffectSequence aEffects( pTextGroup->maEffects );
2839 pTextGroup->reset();
2840
2841 EffectSequence::iterator aIter( aEffects.begin() );
2842 const EffectSequence::iterator aEnd( aEffects.end() );
2843
2844 // first insert if we have to
2845 if( bAnimateForm )
2846 {
2847 EffectSequence::iterator aInsertIter( find( (*aIter) ) );
2848
2849 CustomAnimationEffectPtr pEffect;
2850 if( (aEffects.size() == 1) && ((*aIter)->getTarget().getValueType() != ::getCppuType((const ParagraphTarget*)0) ) )
2851 {
2852 // special case, only one effect and that targets whole text,
2853 // convert this to target whole shape
2854 pEffect = (*aIter++);
2855 pEffect->setTargetSubItem( ShapeAnimationSubType::AS_WHOLE );
2856 }
2857 else
2858 {
2859 pEffect = (*aIter)->clone();
2860 pEffect->setTarget( makeAny( (*aIter)->getTargetShape() ) );
2861 pEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_BACKGROUND );
2862 maEffects.insert( aInsertIter, pEffect );
2863 }
2864
2865 pTextGroup->addEffect( pEffect );
2866 }
2867
2868 if( !bAnimateForm && (aEffects.size() == 1) )
2869 {
2870 CustomAnimationEffectPtr pEffect( (*aIter) );
2871 pEffect->setTarget( makeAny( (*aIter)->getTargetShape() ) );
2872 pEffect->setTargetSubItem( ShapeAnimationSubType::ONLY_TEXT );
2873 pTextGroup->addEffect( pEffect );
2874 }
2875 else
2876 {
2877 // readd the rest to the group again
2878 while( aIter != aEnd )
2879 {
2880 CustomAnimationEffectPtr pEffect( (*aIter++) );
2881
2882 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2883 {
2884 pTextGroup->addEffect( pEffect );
2885 }
2886 else
2887 {
2888 DBG_ASSERT( !bAnimateForm, "sd::EffectSequenceHelper::setAnimateForm(), something is wrong here!" );
2889 remove( pEffect );
2890 }
2891 }
2892 }
2893 notify_listeners();
2894 }
2895 }
2896
2897 // --------------------------------------------------------------------
2898
setTextGroupingAuto(CustomAnimationTextGroupPtr pTextGroup,double fTextGroupingAuto)2899 void EffectSequenceHelper::setTextGroupingAuto( CustomAnimationTextGroupPtr pTextGroup, double fTextGroupingAuto )
2900 {
2901 sal_Int32 nTextGrouping = pTextGroup->mnTextGrouping;
2902
2903 EffectSequence aEffects( pTextGroup->maEffects );
2904 pTextGroup->reset();
2905
2906 EffectSequence::iterator aIter( aEffects.begin() );
2907 const EffectSequence::iterator aEnd( aEffects.end() );
2908 while( aIter != aEnd )
2909 {
2910 CustomAnimationEffectPtr pEffect( (*aIter++) );
2911
2912 if( pEffect->getTarget().getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2913 {
2914 // set correct node type
2915 if( pEffect->getParaDepth() < nTextGrouping )
2916 {
2917 if( fTextGroupingAuto == -1.0 )
2918 {
2919 pEffect->setNodeType( EffectNodeType::ON_CLICK );
2920 pEffect->setBegin( 0.0 );
2921 }
2922 else
2923 {
2924 pEffect->setNodeType( EffectNodeType::AFTER_PREVIOUS );
2925 pEffect->setBegin( fTextGroupingAuto );
2926 }
2927 }
2928 else
2929 {
2930 pEffect->setNodeType( EffectNodeType::WITH_PREVIOUS );
2931 pEffect->setBegin( 0.0 );
2932 }
2933 }
2934
2935 pTextGroup->addEffect( pEffect );
2936
2937 }
2938 notify_listeners();
2939 }
2940
2941 // --------------------------------------------------------------------
2942
2943 struct ImplStlTextGroupSortHelper
2944 {
ImplStlTextGroupSortHelpersd::ImplStlTextGroupSortHelper2945 ImplStlTextGroupSortHelper( bool bReverse ) : mbReverse( bReverse ) {};
2946 bool operator()( const CustomAnimationEffectPtr& p1, const CustomAnimationEffectPtr& p2 );
2947 bool mbReverse;
2948 sal_Int32 getTargetParagraph( const CustomAnimationEffectPtr& p1 );
2949 };
2950
2951 // --------------------------------------------------------------------
2952
getTargetParagraph(const CustomAnimationEffectPtr & p1)2953 sal_Int32 ImplStlTextGroupSortHelper::getTargetParagraph( const CustomAnimationEffectPtr& p1 )
2954 {
2955 const Any aTarget(p1->getTarget());
2956 if( aTarget.hasValue() && aTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
2957 {
2958 ParagraphTarget aParaTarget;
2959 aTarget >>= aParaTarget;
2960 return aParaTarget.Paragraph;
2961 }
2962 else
2963 {
2964 return mbReverse ? 0x7fffffff : -1;
2965 }
2966 }
2967
2968 // --------------------------------------------------------------------
2969
operator ()(const CustomAnimationEffectPtr & p1,const CustomAnimationEffectPtr & p2)2970 bool ImplStlTextGroupSortHelper::operator()( const CustomAnimationEffectPtr& p1, const CustomAnimationEffectPtr& p2 )
2971 {
2972 if( mbReverse )
2973 {
2974 return getTargetParagraph( p2 ) < getTargetParagraph( p1 );
2975 }
2976 else
2977 {
2978 return getTargetParagraph( p1 ) < getTargetParagraph( p2 );
2979 }
2980 }
2981
2982 // --------------------------------------------------------------------
2983
setTextReverse(CustomAnimationTextGroupPtr pTextGroup,sal_Bool bTextReverse)2984 void EffectSequenceHelper::setTextReverse( CustomAnimationTextGroupPtr pTextGroup, sal_Bool bTextReverse )
2985 {
2986 if( pTextGroup->mbTextReverse == bTextReverse )
2987 {
2988 // do nothing
2989 }
2990 else
2991 {
2992 std::vector< CustomAnimationEffectPtr > aSortedVector(pTextGroup->maEffects.size());
2993 std::copy( pTextGroup->maEffects.begin(), pTextGroup->maEffects.end(), aSortedVector.begin() );
2994 ImplStlTextGroupSortHelper aSortHelper( bTextReverse );
2995 std::sort( aSortedVector.begin(), aSortedVector.end(), aSortHelper );
2996
2997 pTextGroup->reset();
2998
2999 std::vector< CustomAnimationEffectPtr >::iterator aIter( aSortedVector.begin() );
3000 const std::vector< CustomAnimationEffectPtr >::iterator aEnd( aSortedVector.end() );
3001
3002 if( aIter != aEnd )
3003 {
3004 pTextGroup->addEffect( (*aIter ) );
3005 EffectSequence::iterator aInsertIter( find( (*aIter++) ) );
3006 while( aIter != aEnd )
3007 {
3008 CustomAnimationEffectPtr pEffect( (*aIter++) );
3009 maEffects.erase( find( pEffect ) );
3010 aInsertIter = maEffects.insert( ++aInsertIter, pEffect );
3011 pTextGroup->addEffect( pEffect );
3012 }
3013 }
3014 notify_listeners();
3015 }
3016 }
3017
3018 // --------------------------------------------------------------------
3019
addListener(ISequenceListener * pListener)3020 void EffectSequenceHelper::addListener( ISequenceListener* pListener )
3021 {
3022 if( std::find( maListeners.begin(), maListeners.end(), pListener ) == maListeners.end() )
3023 maListeners.push_back( pListener );
3024 }
3025
3026 // --------------------------------------------------------------------
3027
removeListener(ISequenceListener * pListener)3028 void EffectSequenceHelper::removeListener( ISequenceListener* pListener )
3029 {
3030 maListeners.remove( pListener );
3031 }
3032
3033 // --------------------------------------------------------------------
3034
3035 struct stl_notify_listeners_func : public std::unary_function<ISequenceListener*, void>
3036 {
stl_notify_listeners_funcsd::stl_notify_listeners_func3037 stl_notify_listeners_func() {}
operator ()sd::stl_notify_listeners_func3038 void operator()(ISequenceListener* pListener) { pListener->notify_change(); }
3039 };
3040
3041 // --------------------------------------------------------------------
3042
notify_listeners()3043 void EffectSequenceHelper::notify_listeners()
3044 {
3045 stl_notify_listeners_func aFunc;
3046 std::for_each( maListeners.begin(), maListeners.end(), aFunc );
3047 }
3048
3049 // --------------------------------------------------------------------
3050
create(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode)3051 void EffectSequenceHelper::create( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
3052 {
3053 DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::create(), illegal argument" );
3054
3055 if( xNode.is() ) try
3056 {
3057 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
3058 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3059 while( xEnumeration->hasMoreElements() )
3060 {
3061 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3062 createEffectsequence( xChildNode );
3063 }
3064 }
3065 catch( Exception& )
3066 {
3067 DBG_ERROR( "sd::EffectSequenceHelper::create(), exception caught!" );
3068 }
3069 }
3070
3071 // --------------------------------------------------------------------
3072
createEffectsequence(const Reference<XAnimationNode> & xNode)3073 void EffectSequenceHelper::createEffectsequence( const Reference< XAnimationNode >& xNode )
3074 {
3075 DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::createEffectsequence(), illegal argument" );
3076
3077 if( xNode.is() ) try
3078 {
3079 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
3080 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3081 while( xEnumeration->hasMoreElements() )
3082 {
3083 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3084
3085 createEffects( xChildNode );
3086 }
3087 }
3088 catch( Exception& )
3089 {
3090 DBG_ERROR( "sd::EffectSequenceHelper::createEffectsequence(), exception caught!" );
3091 }
3092 }
3093
3094 // --------------------------------------------------------------------
3095
createEffects(const Reference<XAnimationNode> & xNode)3096 void EffectSequenceHelper::createEffects( const Reference< XAnimationNode >& xNode )
3097 {
3098 DBG_ASSERT( xNode.is(), "sd::EffectSequenceHelper::createEffects(), illegal argument" );
3099
3100 if( xNode.is() ) try
3101 {
3102 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW );
3103 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3104 while( xEnumeration->hasMoreElements() )
3105 {
3106 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3107
3108 switch( xChildNode->getType() )
3109 {
3110 // found an effect
3111 case AnimationNodeType::PAR:
3112 case AnimationNodeType::ITERATE:
3113 {
3114 CustomAnimationEffectPtr pEffect( new CustomAnimationEffect( xChildNode ) );
3115
3116 if( pEffect->mnNodeType != -1 )
3117 {
3118 pEffect->setEffectSequence( this );
3119 maEffects.push_back(pEffect);
3120 }
3121 }
3122 break;
3123
3124 // found an after effect
3125 case AnimationNodeType::SET:
3126 case AnimationNodeType::ANIMATECOLOR:
3127 {
3128 processAfterEffect( xChildNode );
3129 }
3130 break;
3131 }
3132 }
3133 }
3134 catch( Exception& e )
3135 {
3136 (void)e;
3137 DBG_ERROR( "sd::EffectSequenceHelper::createEffects(), exception caught!" );
3138 }
3139 }
3140
3141 // --------------------------------------------------------------------
3142
processAfterEffect(const Reference<XAnimationNode> & xNode)3143 void EffectSequenceHelper::processAfterEffect( const Reference< XAnimationNode >& xNode )
3144 {
3145 try
3146 {
3147 Reference< XAnimationNode > xMaster;
3148
3149 Sequence< NamedValue > aUserData( xNode->getUserData() );
3150 sal_Int32 nLength = aUserData.getLength();
3151 const NamedValue* p = aUserData.getConstArray();
3152
3153 while( nLength-- )
3154 {
3155 if( p->Name.equalsAscii( "master-element" ) )
3156 {
3157 p->Value >>= xMaster;
3158 break;
3159 }
3160 p++;
3161 }
3162
3163 // only process if this is a valid after effect
3164 if( xMaster.is() )
3165 {
3166 CustomAnimationEffectPtr pMasterEffect;
3167
3168 // find the master effect
3169 stl_CustomAnimationEffect_search_node_predict aSearchPredict( xMaster );
3170 EffectSequence::iterator aIter( std::find_if( maEffects.begin(), maEffects.end(), aSearchPredict ) );
3171 if( aIter != maEffects.end() )
3172 pMasterEffect = (*aIter );
3173
3174 if( pMasterEffect.get() )
3175 {
3176 pMasterEffect->setHasAfterEffect( true );
3177
3178 // find out what kind of after effect this is
3179 if( xNode->getType() == AnimationNodeType::ANIMATECOLOR )
3180 {
3181 // its a dim
3182 Reference< XAnimate > xAnimate( xNode, UNO_QUERY_THROW );
3183 pMasterEffect->setDimColor( xAnimate->getTo() );
3184 pMasterEffect->setAfterEffectOnNext( true );
3185 }
3186 else
3187 {
3188 // its a hide
3189 Reference< XChild > xNodeChild( xNode, UNO_QUERY_THROW );
3190 Reference< XChild > xMasterChild( xMaster, UNO_QUERY_THROW );
3191 pMasterEffect->setAfterEffectOnNext( xNodeChild->getParent() != xMasterChild->getParent() );
3192 }
3193 }
3194 }
3195 }
3196 catch( Exception& e )
3197 {
3198 (void)e;
3199 DBG_ERROR( "sd::EffectSequenceHelper::processAfterEffect(), exception caught!" );
3200 }
3201 }
3202
3203 /*
3204 double EffectSequenceHelper::calculateIterateNodeDuration(
3205 {
3206 Reference< i18n::XBreakIterator > xBI( ImplGetBreakIterator() );
3207
3208 sal_Int32 nDone;
3209 sal_Int32 nNextCellBreak( xBI->nextCharacters(rTxt, nIdx, rLocale, i18n::CharacterIteratorMode::SKIPCELL, 0, nDone) );
3210 i18n::Boundary nNextWordBoundary( xBI->getWordBoundary(rTxt, nIdx, rLocale, i18n::WordType::ANY_WORD, sal_True) );
3211 sal_Int32 nNextSentenceBreak( xBI->endOfSentence(rTxt, nIdx, rLocale) );
3212
3213 const sal_Int32 nEndPos( nIdx + nLen );
3214 sal_Int32 i, currOffset(0);
3215 for( i=nIdx; i<nEndPos; ++i )
3216 {
3217 // TODO: Check whether position update is valid for CTL/BiDi
3218 rOutDev.DrawText( rPos + Point(currOffset,0), rTxt, i, 1 );
3219 currOffset = *pDXArray++;
3220
3221 // issue the comments at the respective break positions
3222 if( i == nNextCellBreak )
3223 {
3224 rMtf.AddAction( new MetaCommentAction( "XTEXT_EOC" ) );
3225 nNextCellBreak = xBI->nextCharacters(rTxt, i, rLocale, i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
3226 }
3227 if( i == nNextWordBoundary.endPos )
3228 {
3229 rMtf.AddAction( new MetaCommentAction( "XTEXT_EOW" ) );
3230 nNextWordBoundary = xBI->getWordBoundary(rTxt, i+1, rLocale, i18n::WordType::ANY_WORD, sal_True);
3231 }
3232 if( i == nNextSentenceBreak )
3233 {
3234 rMtf.AddAction( new MetaCommentAction( "XTEXT_EOS" ) );
3235 nNextSentenceBreak = xBI->endOfSentence(rTxt, i+1, rLocale);
3236 }
3237 }
3238 }
3239
3240 */
3241 // ====================================================================
3242
3243 class AnimationChangeListener : public cppu::WeakImplHelper1< XChangesListener >
3244 {
3245 public:
AnimationChangeListener(MainSequence * pMainSequence)3246 AnimationChangeListener( MainSequence* pMainSequence ) : mpMainSequence( pMainSequence ) {}
3247
3248 virtual void SAL_CALL changesOccurred( const ::com::sun::star::util::ChangesEvent& Event );
3249 virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source );
3250 private:
3251 MainSequence* mpMainSequence;
3252 };
3253
changesOccurred(const::com::sun::star::util::ChangesEvent &)3254 void SAL_CALL AnimationChangeListener::changesOccurred( const ::com::sun::star::util::ChangesEvent& )
3255 {
3256 if( mpMainSequence )
3257 mpMainSequence->startRecreateTimer();
3258 }
3259
disposing(const::com::sun::star::lang::EventObject &)3260 void SAL_CALL AnimationChangeListener::disposing( const ::com::sun::star::lang::EventObject& )
3261 {
3262 }
3263
3264 // ====================================================================
3265
MainSequence()3266 MainSequence::MainSequence()
3267 : mxTimingRootNode( ::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.SequenceTimeContainer"))), UNO_QUERY )
3268 , mbRebuilding( false )
3269 , mnRebuildLockGuard( 0 )
3270 , mbPendingRebuildRequest( false )
3271 {
3272 if( mxTimingRootNode.is() )
3273 {
3274 Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
3275 aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
3276 aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::MAIN_SEQUENCE;
3277 mxTimingRootNode->setUserData( aUserData );
3278 }
3279 init();
3280 }
3281
3282 // --------------------------------------------------------------------
3283
MainSequence(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode)3284 MainSequence::MainSequence( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode )
3285 : mxTimingRootNode( xNode, UNO_QUERY )
3286 , mbRebuilding( false )
3287 , mnRebuildLockGuard( 0 )
3288 , mbPendingRebuildRequest( false )
3289 , mbIgnoreChanges( 0 )
3290 {
3291 init();
3292 }
3293
3294 // --------------------------------------------------------------------
3295
~MainSequence()3296 MainSequence::~MainSequence()
3297 {
3298 reset();
3299 }
3300
3301 // --------------------------------------------------------------------
3302
init()3303 void MainSequence::init()
3304 {
3305 mnSequenceType = EffectNodeType::MAIN_SEQUENCE;
3306
3307 maTimer.SetTimeoutHdl( LINK(this, MainSequence, onTimerHdl) );
3308 maTimer.SetTimeout(500);
3309
3310 mxChangesListener.set( new AnimationChangeListener( this ) );
3311
3312 createMainSequence();
3313 }
3314
3315 // --------------------------------------------------------------------
3316
reset(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xTimingRootNode)3317 void MainSequence::reset( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xTimingRootNode )
3318 {
3319 reset();
3320
3321 mxTimingRootNode.set( xTimingRootNode, UNO_QUERY );
3322
3323 createMainSequence();
3324 }
3325
3326 // --------------------------------------------------------------------
3327
getRootNode()3328 Reference< ::com::sun::star::animations::XAnimationNode > MainSequence::getRootNode()
3329 {
3330 DBG_ASSERT( mnRebuildLockGuard == 0, "MainSequence::getRootNode(), rebuild is locked, ist this really what you want?" );
3331
3332 if( maTimer.IsActive() && mbTimerMode )
3333 {
3334 // force a rebuild NOW if one is pending
3335 maTimer.Stop();
3336 implRebuild();
3337 }
3338
3339 return EffectSequenceHelper::getRootNode();
3340 }
3341
3342 // --------------------------------------------------------------------
3343
createMainSequence()3344 void MainSequence::createMainSequence()
3345 {
3346 if( mxTimingRootNode.is() ) try
3347 {
3348 Reference< XEnumerationAccess > xEnumerationAccess( mxTimingRootNode, UNO_QUERY_THROW );
3349 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3350 while( xEnumeration->hasMoreElements() )
3351 {
3352 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3353 sal_Int32 nNodeType = CustomAnimationEffect::get_node_type( xChildNode );
3354 if( nNodeType == EffectNodeType::MAIN_SEQUENCE )
3355 {
3356 mxSequenceRoot.set( xChildNode, UNO_QUERY );
3357 EffectSequenceHelper::create( xChildNode );
3358 }
3359 else if( nNodeType == EffectNodeType::INTERACTIVE_SEQUENCE )
3360 {
3361 Reference< XTimeContainer > xInteractiveRoot( xChildNode, UNO_QUERY_THROW );
3362 InteractiveSequencePtr pIS( new InteractiveSequence( xInteractiveRoot, this ) );
3363 pIS->addListener( this );
3364 maInteractiveSequenceList.push_back( pIS );
3365 }
3366 }
3367
3368 // see if we have a mainsequence at all. if not, create one...
3369 if( !mxSequenceRoot.is() )
3370 {
3371 mxSequenceRoot = Reference< XTimeContainer >::query(::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.SequenceTimeContainer"))));
3372 if( mxSequenceRoot.is() )
3373 {
3374 uno::Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
3375 aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
3376 aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::MAIN_SEQUENCE;
3377 mxSequenceRoot->setUserData( aUserData );
3378
3379 // empty sequence until now, set duration to 0.0
3380 // explicitly (otherwise, this sequence will never
3381 // end)
3382 mxSequenceRoot->setDuration( makeAny((double)0.0) );
3383
3384 Reference< XAnimationNode > xMainSequenceNode( mxSequenceRoot, UNO_QUERY_THROW );
3385 mxTimingRootNode->appendChild( xMainSequenceNode );
3386 }
3387 }
3388
3389 updateTextGroups();
3390
3391 notify_listeners();
3392
3393 Reference< XChangesNotifier > xNotifier( mxTimingRootNode, UNO_QUERY );
3394 if( xNotifier.is() )
3395 xNotifier->addChangesListener( mxChangesListener );
3396 }
3397 catch( Exception& e )
3398 {
3399 (void)e;
3400 DBG_ERROR( "sd::MainSequence::create(), exception caught!" );
3401 return;
3402 }
3403
3404 DBG_ASSERT( mxSequenceRoot.is(), "sd::MainSequence::create(), found no main sequence!" );
3405 }
3406
3407 // --------------------------------------------------------------------
3408
reset()3409 void MainSequence::reset()
3410 {
3411 EffectSequenceHelper::reset();
3412
3413 InteractiveSequenceList::iterator aIter;
3414 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3415 (*aIter)->reset();
3416 maInteractiveSequenceList.clear();
3417
3418 try
3419 {
3420 Reference< XChangesNotifier > xNotifier( mxTimingRootNode, UNO_QUERY );
3421 if( xNotifier.is() )
3422 xNotifier->removeChangesListener( mxChangesListener );
3423 }
3424 catch( Exception& )
3425 {
3426 // ...
3427 }
3428 }
3429
3430 // --------------------------------------------------------------------
3431
createInteractiveSequence(const::com::sun::star::uno::Reference<::com::sun::star::drawing::XShape> & xShape)3432 InteractiveSequencePtr MainSequence::createInteractiveSequence( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xShape )
3433 {
3434 InteractiveSequencePtr pIS;
3435
3436 // create a new interactive sequence container
3437 Reference< XTimeContainer > xISRoot( ::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.SequenceTimeContainer"))), UNO_QUERY );
3438 DBG_ASSERT( xISRoot.is(), "sd::MainSequence::createInteractiveSequence(), could not create \"com.sun.star.animations.SequenceTimeContainer\"!");
3439 if( xISRoot.is() )
3440 {
3441 uno::Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
3442 aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
3443 aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::INTERACTIVE_SEQUENCE ;
3444 xISRoot->setUserData( aUserData );
3445
3446 Reference< XChild > xChild( mxSequenceRoot, UNO_QUERY_THROW );
3447 Reference< XAnimationNode > xISNode( xISRoot, UNO_QUERY_THROW );
3448 Reference< XTimeContainer > xParent( xChild->getParent(), UNO_QUERY_THROW );
3449 xParent->appendChild( xISNode );
3450 }
3451 pIS.reset( new InteractiveSequence( xISRoot, this) );
3452 pIS->setTriggerShape( xShape );
3453 pIS->addListener( this );
3454 maInteractiveSequenceList.push_back( pIS );
3455 return pIS;
3456 }
3457
3458 // --------------------------------------------------------------------
3459
findEffect(const::com::sun::star::uno::Reference<::com::sun::star::animations::XAnimationNode> & xNode) const3460 CustomAnimationEffectPtr MainSequence::findEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) const
3461 {
3462 CustomAnimationEffectPtr pEffect = EffectSequenceHelper::findEffect( xNode );
3463
3464 if( pEffect.get() == 0 )
3465 {
3466 InteractiveSequenceList::const_iterator aIter;
3467 for( aIter = maInteractiveSequenceList.begin(); (aIter != maInteractiveSequenceList.end()) && (pEffect.get() == 0); aIter++ )
3468 {
3469 pEffect = (*aIter)->findEffect( xNode );
3470 }
3471 }
3472 return pEffect;
3473 }
3474
3475 // --------------------------------------------------------------------
3476
getOffsetFromEffect(const CustomAnimationEffectPtr & pEffect) const3477 sal_Int32 MainSequence::getOffsetFromEffect( const CustomAnimationEffectPtr& pEffect ) const
3478 {
3479 sal_Int32 nOffset = EffectSequenceHelper::getOffsetFromEffect( pEffect );
3480
3481 if( nOffset != -1 )
3482 return nOffset;
3483
3484 nOffset = EffectSequenceHelper::getCount();
3485
3486 InteractiveSequenceList::const_iterator aIter;
3487 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3488 {
3489 sal_Int32 nTemp = (*aIter)->getOffsetFromEffect( pEffect );
3490 if( nTemp != -1 )
3491 return nOffset + nTemp;
3492
3493 nOffset += (*aIter)->getCount();
3494 }
3495
3496 return -1;
3497 }
3498
3499 // --------------------------------------------------------------------
3500
getEffectFromOffset(sal_Int32 nOffset) const3501 CustomAnimationEffectPtr MainSequence::getEffectFromOffset( sal_Int32 nOffset ) const
3502 {
3503 if( nOffset >= 0 )
3504 {
3505 if( nOffset < getCount() )
3506 return EffectSequenceHelper::getEffectFromOffset( nOffset );
3507
3508 nOffset -= getCount();
3509
3510 InteractiveSequenceList::const_iterator aIter( maInteractiveSequenceList.begin() );
3511
3512 while( (aIter != maInteractiveSequenceList.end()) && (nOffset > (*aIter)->getCount()) )
3513 nOffset -= (*aIter++)->getCount();
3514
3515 if( (aIter != maInteractiveSequenceList.end()) && (nOffset >= 0) )
3516 return (*aIter)->getEffectFromOffset( nOffset );
3517 }
3518
3519 CustomAnimationEffectPtr pEffect;
3520 return pEffect;
3521 }
3522
3523 // --------------------------------------------------------------------
3524
disposeShape(const Reference<XShape> & xShape)3525 bool MainSequence::disposeShape( const Reference< XShape >& xShape )
3526 {
3527 bool bChanges = EffectSequenceHelper::disposeShape( xShape );
3528
3529 InteractiveSequenceList::iterator aIter;
3530 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); )
3531 {
3532 bChanges |= (*aIter++)->disposeShape( xShape );
3533 }
3534
3535 if( bChanges )
3536 startRebuildTimer();
3537
3538 return bChanges;
3539 }
3540
3541 // --------------------------------------------------------------------
3542
hasEffect(const com::sun::star::uno::Reference<com::sun::star::drawing::XShape> & xShape)3543 bool MainSequence::hasEffect( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape )
3544 {
3545 if( EffectSequenceHelper::hasEffect( xShape ) )
3546 return true;
3547
3548 InteractiveSequenceList::iterator aIter;
3549 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); )
3550 {
3551 if( (*aIter)->getTriggerShape() == xShape )
3552 return true;
3553
3554 if( (*aIter++)->hasEffect( xShape ) )
3555 return true;
3556 }
3557
3558 return false;
3559 }
3560
3561 // --------------------------------------------------------------------
3562
insertTextRange(const com::sun::star::uno::Any & aTarget)3563 void MainSequence::insertTextRange( const com::sun::star::uno::Any& aTarget )
3564 {
3565 EffectSequenceHelper::insertTextRange( aTarget );
3566
3567 InteractiveSequenceList::iterator aIter;
3568 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3569 {
3570 (*aIter)->insertTextRange( aTarget );
3571 }
3572 }
3573 // --------------------------------------------------------------------
3574
disposeTextRange(const com::sun::star::uno::Any & aTarget)3575 void MainSequence::disposeTextRange( const com::sun::star::uno::Any& aTarget )
3576 {
3577 EffectSequenceHelper::disposeTextRange( aTarget );
3578
3579 InteractiveSequenceList::iterator aIter;
3580 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3581 {
3582 (*aIter)->disposeTextRange( aTarget );
3583 }
3584 }
3585
3586 // --------------------------------------------------------------------
3587
3588 /** callback from the sd::View when an object just left text edit mode */
onTextChanged(const Reference<XShape> & xShape)3589 void MainSequence::onTextChanged( const Reference< XShape >& xShape )
3590 {
3591 EffectSequenceHelper::onTextChanged( xShape );
3592
3593 InteractiveSequenceList::iterator aIter;
3594 for( aIter = maInteractiveSequenceList.begin(); aIter != maInteractiveSequenceList.end(); aIter++ )
3595 {
3596 (*aIter)->onTextChanged( xShape );
3597 }
3598 }
3599
3600 // --------------------------------------------------------------------
3601
onTextChanged(const Reference<XShape> & xShape)3602 void EffectSequenceHelper::onTextChanged( const Reference< XShape >& xShape )
3603 {
3604 bool bChanges = false;
3605
3606 EffectSequence::iterator aIter;
3607 for( aIter = maEffects.begin(); aIter != maEffects.end(); aIter++ )
3608 {
3609 if( (*aIter)->getTargetShape() == xShape )
3610 bChanges |= (*aIter)->checkForText();
3611 }
3612
3613 if( bChanges )
3614 EffectSequenceHelper::implRebuild();
3615 }
3616
3617 // --------------------------------------------------------------------
3618
rebuild()3619 void MainSequence::rebuild()
3620 {
3621 startRebuildTimer();
3622 }
3623
3624 // --------------------------------------------------------------------
3625
lockRebuilds()3626 void MainSequence::lockRebuilds()
3627 {
3628 mnRebuildLockGuard++;
3629 }
3630
3631 // --------------------------------------------------------------------
3632
unlockRebuilds()3633 void MainSequence::unlockRebuilds()
3634 {
3635 DBG_ASSERT( mnRebuildLockGuard, "sd::MainSequence::unlockRebuilds(), no corresponding lockRebuilds() call!" );
3636 if( mnRebuildLockGuard )
3637 mnRebuildLockGuard--;
3638
3639 if( (mnRebuildLockGuard == 0) && mbPendingRebuildRequest )
3640 {
3641 mbPendingRebuildRequest = false;
3642 startRebuildTimer();
3643 }
3644 }
3645
3646 // --------------------------------------------------------------------
3647
implRebuild()3648 void MainSequence::implRebuild()
3649 {
3650 if( mnRebuildLockGuard )
3651 {
3652 mbPendingRebuildRequest = true;
3653 return;
3654 }
3655
3656 mbRebuilding = true;
3657
3658 EffectSequenceHelper::implRebuild();
3659
3660 InteractiveSequenceList::iterator aIter( maInteractiveSequenceList.begin() );
3661 const InteractiveSequenceList::iterator aEnd( maInteractiveSequenceList.end() );
3662 while( aIter != aEnd )
3663 {
3664 InteractiveSequencePtr pIS( (*aIter) );
3665 if( pIS->maEffects.empty() )
3666 {
3667 // remove empty interactive sequences
3668 aIter = maInteractiveSequenceList.erase( aIter );
3669
3670 Reference< XChild > xChild( mxSequenceRoot, UNO_QUERY_THROW );
3671 Reference< XTimeContainer > xParent( xChild->getParent(), UNO_QUERY_THROW );
3672 Reference< XAnimationNode > xISNode( pIS->mxSequenceRoot, UNO_QUERY_THROW );
3673 xParent->removeChild( xISNode );
3674 }
3675 else
3676 {
3677 pIS->implRebuild();
3678 aIter++;
3679 }
3680 }
3681
3682 notify_listeners();
3683 mbRebuilding = false;
3684 }
3685
3686 // --------------------------------------------------------------------
3687
notify_change()3688 void MainSequence::notify_change()
3689 {
3690 notify_listeners();
3691 }
3692
3693 // --------------------------------------------------------------------
3694
setTrigger(const CustomAnimationEffectPtr & pEffect,const::com::sun::star::uno::Reference<::com::sun::star::drawing::XShape> & xTriggerShape)3695 bool MainSequence::setTrigger( const CustomAnimationEffectPtr& pEffect, const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xTriggerShape )
3696 {
3697 EffectSequenceHelper* pOldSequence = pEffect->getEffectSequence();
3698
3699 EffectSequenceHelper* pNewSequence = 0;
3700 if( xTriggerShape.is() )
3701 {
3702 InteractiveSequenceList::iterator aIter( maInteractiveSequenceList.begin() );
3703 const InteractiveSequenceList::iterator aEnd( maInteractiveSequenceList.end() );
3704 while( aIter != aEnd )
3705 {
3706 InteractiveSequencePtr pIS( (*aIter++) );
3707 if( pIS->getTriggerShape() == xTriggerShape )
3708 {
3709 pNewSequence = pIS.get();
3710 break;
3711 }
3712 }
3713
3714 if( !pNewSequence )
3715 pNewSequence = createInteractiveSequence( xTriggerShape ).get();
3716 }
3717 else
3718 {
3719 pNewSequence = this;
3720 }
3721
3722 if( pOldSequence != pNewSequence )
3723 {
3724 if( pOldSequence )
3725 pOldSequence->maEffects.remove( pEffect );
3726 if( pNewSequence )
3727 pNewSequence->maEffects.push_back( pEffect );
3728 pEffect->setEffectSequence( pNewSequence );
3729 return true;
3730 }
3731 else
3732 {
3733 return false;
3734 }
3735
3736 }
3737
3738 // --------------------------------------------------------------------
3739
IMPL_LINK(MainSequence,onTimerHdl,Timer *,EMPTYARG)3740 IMPL_LINK( MainSequence, onTimerHdl, Timer *, EMPTYARG )
3741 {
3742 if( mbTimerMode )
3743 {
3744 implRebuild();
3745 }
3746 else
3747 {
3748 reset();
3749 createMainSequence();
3750 }
3751
3752 return 0;
3753 }
3754
3755 // --------------------------------------------------------------------
3756
3757 /** starts a timer that recreates the internal structure from the API core after 1 second */
startRecreateTimer()3758 void MainSequence::startRecreateTimer()
3759 {
3760 if( !mbRebuilding && (mbIgnoreChanges == 0) )
3761 {
3762 mbTimerMode = false;
3763 maTimer.Start();
3764 }
3765 }
3766
3767 // --------------------------------------------------------------------
3768
3769 /** starts a timer that rebuilds the API core from the internal structure after 1 second */
startRebuildTimer()3770 void MainSequence::startRebuildTimer()
3771 {
3772 mbTimerMode = true;
3773 maTimer.Start();
3774 }
3775
3776 // ====================================================================
3777
InteractiveSequence(const Reference<XTimeContainer> & xSequenceRoot,MainSequence * pMainSequence)3778 InteractiveSequence::InteractiveSequence( const Reference< XTimeContainer >& xSequenceRoot, MainSequence* pMainSequence )
3779 : EffectSequenceHelper( xSequenceRoot ), mpMainSequence( pMainSequence )
3780 {
3781 mnSequenceType = EffectNodeType::INTERACTIVE_SEQUENCE;
3782
3783 try
3784 {
3785 if( mxSequenceRoot.is() )
3786 {
3787 Reference< XEnumerationAccess > xEnumerationAccess( mxSequenceRoot, UNO_QUERY_THROW );
3788 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW );
3789 while( !mxEventSource.is() && xEnumeration->hasMoreElements() )
3790 {
3791 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
3792
3793 Event aEvent;
3794 if( (xChildNode->getBegin() >>= aEvent) && (aEvent.Trigger == EventTrigger::ON_CLICK) )
3795 aEvent.Source >>= mxEventSource;
3796 }
3797 }
3798 }
3799 catch( Exception& e )
3800 {
3801 (void)e;
3802 DBG_ERROR( "sd::InteractiveSequence::InteractiveSequence(), exception caught!" );
3803 return;
3804 }
3805 }
3806
3807 // --------------------------------------------------------------------
3808
rebuild()3809 void InteractiveSequence::rebuild()
3810 {
3811 mpMainSequence->rebuild();
3812 }
3813
implRebuild()3814 void InteractiveSequence::implRebuild()
3815 {
3816 EffectSequenceHelper::implRebuild();
3817 }
3818
3819 // --------------------------------------------------------------------
3820
MainSequenceRebuildGuard(const MainSequencePtr & pMainSequence)3821 MainSequenceRebuildGuard::MainSequenceRebuildGuard( const MainSequencePtr& pMainSequence )
3822 : mpMainSequence( pMainSequence )
3823 {
3824 if( mpMainSequence.get() )
3825 mpMainSequence->lockRebuilds();
3826 }
3827
~MainSequenceRebuildGuard()3828 MainSequenceRebuildGuard::~MainSequenceRebuildGuard()
3829 {
3830 if( mpMainSequence.get() )
3831 mpMainSequence->unlockRebuilds();
3832 }
3833
3834
3835 }
3836