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