bump product version to 5.0.4.1
[LibreOffice.git] / sd / source / filter / ppt / ppt97animations.cxx
blob1278444df3ec0037a819f3dc6a3b57899c89b7b1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "ppt97animations.hxx"
22 #include <svx/svdobj.hxx>
23 #include "sdpage.hxx"
24 #include <tools/debug.hxx>
25 #include <svx/unoapi.hxx>
26 #include "EffectMigration.hxx"
27 #include <CustomAnimationPreset.hxx>
28 #include <com/sun/star/drawing/XShape.hpp>
29 #include <com/sun/star/presentation/TextAnimationType.hpp>
30 #include <com/sun/star/presentation/EffectNodeType.hpp>
31 #include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
33 using namespace ::com::sun::star;
35 void Ppt97AnimationInfoAtom::ReadStream( SvStream& rIn )
37 rIn.ReadUInt32( nDimColor );
38 rIn.ReadUInt32( nFlags );
39 rIn.ReadUInt32( nSoundRef );
40 rIn.ReadInt32( nDelayTime );
41 rIn.ReadUInt16( nOrderID );
42 rIn.ReadUInt16( nSlideCount );
43 rIn.ReadUChar( nBuildType );
44 rIn.ReadUChar( nFlyMethod );
45 rIn.ReadUChar( nFlyDirection );
46 rIn.ReadUChar( nAfterEffect );
47 rIn.ReadUChar( nSubEffect );
48 rIn.ReadUChar( nOLEVerb );
49 rIn.ReadUChar( nUnknown1 );
50 rIn.ReadUChar( nUnknown2 );
53 #define MEMBER_CONSTRUCTOR_LIST() \
54 m_aAtom() \
55 , m_aSoundFileUrl() \
56 , m_bDirtyCache(true) \
57 , m_aPresetId() \
58 , m_aSubType() \
59 , m_bHasSpecialDuration(false) \
60 , m_fDurationInSeconds(0.001)
62 Ppt97Animation::Ppt97Animation( SvStream& rInputStream )
63 : MEMBER_CONSTRUCTOR_LIST()
65 m_aAtom.ReadStream( rInputStream );
68 Ppt97Animation::Ppt97Animation( const Ppt97Animation& rAnimation )
69 : MEMBER_CONSTRUCTOR_LIST()
71 *this = rAnimation;
74 Ppt97Animation& Ppt97Animation::operator= ( const Ppt97Animation& rAnimation )
76 m_aAtom = rAnimation.m_aAtom;
77 m_aSoundFileUrl = rAnimation.m_aSoundFileUrl;
78 m_bDirtyCache = rAnimation.m_bDirtyCache;
79 m_aPresetId = rAnimation.m_aPresetId;
80 m_aSubType = rAnimation.m_aSubType;
81 m_bHasSpecialDuration = rAnimation.m_bHasSpecialDuration;
82 m_fDurationInSeconds = rAnimation.m_fDurationInSeconds;
84 return *this;
87 Ppt97Animation::~Ppt97Animation()
91 bool Ppt97Animation::operator < ( const Ppt97Animation& rAnimation ) const
93 return m_aAtom.nOrderID < rAnimation.m_aAtom.nOrderID;
95 bool Ppt97Animation::operator > ( const Ppt97Animation& rAnimation ) const
97 return m_aAtom.nOrderID > rAnimation.m_aAtom.nOrderID;
99 bool Ppt97Animation::HasEffect() const
101 return m_aAtom.nBuildType != 0;
103 bool Ppt97Animation::HasParagraphEffect() const
105 return m_aAtom.nBuildType > 1;
107 sal_Int32 Ppt97Animation::GetParagraphLevel() const
109 sal_Int32 nParagraphLevel = 0;
110 if(m_aAtom.nBuildType>1)
111 nParagraphLevel = m_aAtom.nBuildType-1;
112 return nParagraphLevel;
114 bool Ppt97Animation::HasSoundEffect() const
116 return m_aAtom.nSoundRef && m_aAtom.nFlags & 0x0010;
118 bool Ppt97Animation::HasStopPreviousSound() const
120 return m_aAtom.nFlags & 0x0040;
122 bool Ppt97Animation::HasReverseOrder() const
124 return m_aAtom.nFlags & 0x001;
126 bool Ppt97Animation::HasAnimateAssociatedShape() const
128 return m_aAtom.nFlags & 0x004000;
130 bool Ppt97Animation::HasAfterEffect() const
132 return m_aAtom.nAfterEffect != 0;
134 bool Ppt97Animation::HasAfterEffect_ChangeColor() const
136 return m_aAtom.nAfterEffect == 1;
138 bool Ppt97Animation::HasAfterEffect_DimAtNextEffect() const
140 return m_aAtom.nAfterEffect == 2;
142 #ifdef FUTURE
143 bool Ppt97Animation::HasAfterEffect_DimAfterEffect() const
145 return m_aAtom.nAfterEffect == 3;
147 #endif
148 void Ppt97Animation::SetSoundFileUrl( const OUString& rSoundFileUrl )
150 m_aSoundFileUrl = rSoundFileUrl;
153 double Ppt97Animation::GetDelayTimeInSeconds() const
155 return m_aAtom.nDelayTime != 0X7FFFFFFF ? m_aAtom.nDelayTime/1000.0 : 0.0;
158 bool Ppt97Animation::GetSpecialDuration( double& rfDurationInSeconds ) const
160 UpdateCacheData();
161 if( m_bHasSpecialDuration )
162 rfDurationInSeconds = m_fDurationInSeconds;
163 return m_bHasSpecialDuration;
166 bool Ppt97Animation::GetSpecialTextIterationDelay( double& rfTextIterationDelay ) const
168 bool bRet = false;
169 switch(this->GetTextAnimationType())
171 case presentation::TextAnimationType::BY_LETTER:
172 rfTextIterationDelay = 0.075;
173 bRet = true;
174 break;
175 case presentation::TextAnimationType::BY_WORD:
176 rfTextIterationDelay = 0.3;
177 bRet = true;
178 break;
179 default:
180 break;
182 return bRet;
185 void Ppt97Animation::SetDimColor( sal_Int32 nDimColor )
187 m_aAtom.nDimColor = nDimColor;
189 void Ppt97Animation::SetAnimateAssociatedShape( bool bAnimate )
191 if( !bAnimate )
193 //the appear effect cannot be animated without text
194 if( this->GetPresetId() == "ooo-entrance-appear" )
195 return;
196 //the random effect may be the appear effect and than has the same problem
197 if( this->GetPresetId() == "ooo-entrance-random" )
199 //this case is not 100% correct -> feel free to complete
200 //i consider this case as seldom and not that problematic and a simple correct fix is not in sight
201 DBG_WARNING("you tried to deselect the animation of the form for random animation-> this has been refused");
202 return;
207 if(bAnimate)
208 m_aAtom.nFlags = m_aAtom.nFlags | 0x004000;
209 else if( HasAnimateAssociatedShape() )
211 m_aAtom.nFlags = m_aAtom.nFlags ^ 0x004000;
215 sal_Int16 Ppt97Animation::GetEffectNodeType() const //see com::sun::star::presentation::EffectNodeType
217 sal_Int16 nRet = presentation::EffectNodeType::ON_CLICK;
218 if( m_aAtom.nFlags & 0x04 )
220 nRet = presentation::EffectNodeType::AFTER_PREVIOUS;
222 return nRet;
225 sal_Int16 Ppt97Animation::GetTextAnimationType() const
227 sal_Int16 nRet = presentation::TextAnimationType::BY_PARAGRAPH;
228 switch( m_aAtom.nSubEffect )
230 case 0:
231 break;
232 case 2:
233 nRet = presentation::TextAnimationType::BY_LETTER;
234 break;
235 default:
236 nRet = presentation::TextAnimationType::BY_WORD;
237 break;
239 return nRet;
241 OUString Ppt97Animation::GetPresetId() const
243 UpdateCacheData();
244 return m_aPresetId;
246 OUString Ppt97Animation::GetPresetSubType() const
248 UpdateCacheData();
249 return m_aSubType;
252 void Ppt97Animation::ClearCacheData() const
254 m_aPresetId.clear();
255 m_aSubType.clear();
256 m_bHasSpecialDuration = false;
257 m_fDurationInSeconds = 0.001;
259 void Ppt97Animation::UpdateCacheData() const
261 if( !m_bDirtyCache )
262 return;
264 ClearCacheData();
266 if( !HasEffect() )
268 m_bDirtyCache = false;
269 return;
272 switch( m_aAtom.nFlyMethod )
274 case 0x0:
275 m_aPresetId = "ooo-entrance-appear"; // --- appear ---
276 break;
277 case 0x01:
278 m_aPresetId = "ooo-entrance-random"; // --- random ---
279 break;
280 case 0x02: // --- blinds effect ---
282 switch ( m_aAtom.nFlyDirection )
284 case 0x0:
285 m_aPresetId = "ooo-entrance-venetian-blinds";
286 m_aSubType = "horizontal"; // horizontal
287 break;
288 case 0x1:
289 m_aPresetId = "ooo-entrance-venetian-blinds";
290 m_aSubType = "vertical"; // vertical
291 break;
294 break;
295 case 0x03: // --- (hor/ver) shifted appear ---
297 switch ( m_aAtom.nFlyDirection )
299 case 0x0:
300 m_aPresetId = "ooo-entrance-checkerboard";
301 m_aSubType = "across"; // vertical ???
302 break;
303 case 0x1:
304 m_aPresetId = "ooo-entrance-checkerboard";
305 m_aSubType = "downward"; // horizontal ???
306 break;
309 break;
310 case 0x05:
311 m_aPresetId = "ooo-entrance-dissolve-in";
312 break;
313 case 0x08: // --- (hor/ver) lines ---
315 switch ( m_aAtom.nFlyDirection )
317 case 0x0:
318 m_aPresetId = "ooo-entrance-random-bars";
319 m_aSubType = "vertical"; // horizontal ???
320 break;
321 case 0x1:
322 m_aPresetId = "ooo-entrance-random-bars";
323 m_aSubType = "horizontal"; // vertical ???
324 break;
327 break;
328 case 0x09: // --- diagonal ---
330 switch ( m_aAtom.nFlyDirection )
332 case 0x4:
333 m_aPresetId = "ooo-entrance-diagonal-squares";
334 m_aSubType = "left-to-top"; // to left top
335 break;
336 case 0x5:
337 m_aPresetId = "ooo-entrance-diagonal-squares";
338 m_aSubType = "right-to-top"; // to right top
339 break;
340 case 0x6:
341 m_aPresetId = "ooo-entrance-diagonal-squares";
342 m_aSubType = "left-to-bottom"; // to left bottom
343 break;
344 case 0x7:
345 m_aPresetId = "ooo-entrance-diagonal-squares";
346 m_aSubType = "right-to-bottom"; // to right bottom
347 break;
350 break;
351 case 0x0a: // --- roll/wipe ---
353 switch ( m_aAtom.nFlyDirection )
355 case 0x0:
356 m_aPresetId = "ooo-entrance-wipe";
357 m_aSubType = "from-right"; // from right
358 break;
359 case 0x1:
360 m_aPresetId = "ooo-entrance-wipe";
361 m_aSubType = "from-bottom"; // from bottom
362 break;
363 case 0x2:
364 m_aPresetId = "ooo-entrance-wipe";
365 m_aSubType = "from-left"; // from left
366 break;
367 case 0x3:
368 m_aPresetId = "ooo-entrance-wipe";
369 m_aSubType = "from-top"; // from top
370 break;
373 break;
374 case 0x0b: //--- fade in ---
376 switch ( m_aAtom.nFlyDirection )
378 case 0x0:
379 m_aPresetId = "ooo-entrance-box";
380 m_aSubType = "out"; // from center
381 break;
382 case 0x1:
383 m_aPresetId = "ooo-entrance-box";
384 m_aSubType = "in"; // to center
385 break;
388 break;
389 case 0x0c: // --- text effects ---
391 switch ( m_aAtom.nFlyDirection )
393 case 0x0:
394 m_aPresetId = "ooo-entrance-fly-in";
395 m_aSubType = "from-left";
397 break;
398 case 0x1:
399 m_aPresetId = "ooo-entrance-fly-in";
400 m_aSubType = "from-top";
401 break;
402 case 0x2:
403 m_aPresetId = "ooo-entrance-fly-in";
404 m_aSubType = "from-right";
405 break;
406 case 0x3:
407 m_aPresetId = "ooo-entrance-fly-in";
408 m_aSubType = "from-bottom";
409 break;
410 case 0x4:
411 m_aPresetId = "ooo-entrance-fly-in";
412 m_aSubType = "from-top-left";
413 break;
414 case 0x5:
415 m_aPresetId = "ooo-entrance-fly-in";
416 m_aSubType = "from-top-right";
417 break;
418 case 0x6:
419 m_aPresetId = "ooo-entrance-fly-in";
420 m_aSubType = "from-bottom-left";
421 break;
422 case 0x7:
423 m_aPresetId = "ooo-entrance-fly-in";
424 m_aSubType = "from-bottom-right";
425 break;
426 case 0x8: // -- short text effects --
427 m_aPresetId = "ooo-entrance-peek-in";
428 m_aSubType = "from-left";
429 break;
430 case 0x9:
431 m_aPresetId = "ooo-entrance-peek-in";
432 m_aSubType = "from-bottom";
433 break;
434 case 0xa:
435 m_aPresetId = "ooo-entrance-peek-in";
436 m_aSubType = "from-right";
437 break;
438 case 0xb:
439 m_aPresetId = "ooo-entrance-peek-in";
440 m_aSubType = "from-top";
441 break;
442 case 0xc: // -- slow text effects --
444 m_aPresetId = "ooo-entrance-fly-in-slow";
445 m_aSubType = "from-left";
447 break;
448 case 0xd:
450 m_aPresetId = "ooo-entrance-fly-in-slow";
451 m_aSubType = "from-top";
453 break;
454 case 0xe:
456 m_aPresetId = "ooo-entrance-fly-in-slow";
457 m_aSubType = "from-right";
459 break;
460 case 0xf:
462 m_aPresetId = "ooo-entrance-fly-in-slow";
463 m_aSubType = "from-bottom";
465 break;
466 case 0x10: // --- zoom ---
467 m_aPresetId = "ooo-entrance-zoom";
468 m_aSubType = "in";
469 break;
470 case 0x11:
471 m_aPresetId = "ooo-entrance-zoom";
472 m_aSubType = "in-slightly";
473 break;
474 case 0x12:
475 m_aPresetId = "ooo-entrance-zoom";
476 m_aSubType = "out";
477 break;
478 case 0x13:
479 m_aPresetId = "ooo-entrance-zoom";
480 m_aSubType = "out-slightly";
481 break;
482 case 0x14:
483 m_aPresetId = "ooo-entrance-zoom";
484 m_aSubType = "in-from-screen-center";
485 break;
486 case 0x15:
487 m_aPresetId = "ooo-entrance-zoom";
488 m_aSubType = "out-from-screen-center";
489 break;
490 case 0x16: // --- stretch ---
491 m_aPresetId = "ooo-entrance-stretchy";
492 m_aSubType = "across";
493 break;
494 case 0x17:
495 m_aPresetId = "ooo-entrance-stretchy";
496 m_aSubType = "from-left";
497 break;
498 case 0x18:
499 m_aPresetId = "ooo-entrance-stretchy";
500 m_aSubType = "from-top";
501 break;
502 case 0x19:
503 m_aPresetId = "ooo-entrance-stretchy";
504 m_aSubType = "from-right";
505 break;
506 case 0x1a:
507 m_aPresetId = "ooo-entrance-stretchy";
508 m_aSubType = "from-bottom";
509 break;
510 case 0x1b: // --- rotate ---
511 m_aPresetId = "ooo-entrance-swivel";
512 m_aSubType = "vertical";
513 break;
514 case 0x1c: // --- spirale ---
515 m_aPresetId = "ooo-entrance-spiral-in";
516 break;
519 break;
520 case 0x0d: // --- open/close ---
522 switch ( m_aAtom.nFlyDirection )
524 case 0x0:
525 m_aPresetId = "ooo-entrance-split";
526 m_aSubType = "horizontal-out"; //horizontal open
527 break;
528 case 0x1:
529 m_aPresetId = "ooo-entrance-split";
530 m_aSubType = "horizontal-in"; //horizontal close
531 break;
532 case 0x2:
533 m_aPresetId = "ooo-entrance-split";
534 m_aSubType = "vertical-out"; // vertical open
535 break;
536 case 0x3:
537 m_aPresetId = "ooo-entrance-split";
538 m_aSubType = "vertical-in"; // vertical close
539 break;
542 break;
543 case 0x0e: // --- blink ---
545 m_aPresetId = "ooo-entrance-flash-once";
546 switch ( m_aAtom.nFlyDirection )
548 case 0x0: //fast
549 m_fDurationInSeconds = 0.075;
550 m_bHasSpecialDuration = true;
551 break;
552 case 0x1: //medium
553 m_fDurationInSeconds = 0.5;
554 m_bHasSpecialDuration = true;
555 break;
556 case 0x2: //slow
557 m_fDurationInSeconds = 1.0;
558 m_bHasSpecialDuration = true;
559 break;
562 break;
563 default:
565 m_aPresetId = "ooo-entrance-appear";
566 OSL_FAIL("no effect mapped");
568 break;
570 m_bDirtyCache = false;
573 void Ppt97Animation::createAndSetCustomAnimationEffect( SdrObject* pObj )
576 if( !this->HasEffect() )
577 return;
578 if( !pObj || !pObj->GetPage() )
580 OSL_FAIL("no valid SdrObject or page found for ppt import");
581 return;
584 uno::Reference< drawing::XShape > xShape = GetXShapeForSdrObject( pObj );
585 if( !xShape.is() )
587 OSL_FAIL("no XShape interface found for ppt import");
588 return;
590 ::sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->GetPage())->getMainSequence();
591 if( !pMainSequence.get() )
593 OSL_FAIL("no MainSequence found for ppt import");
594 return;
597 const ::sd::CustomAnimationPresets& rPresets( ::sd::CustomAnimationPresets::getCustomAnimationPresets() );
598 ::sd::CustomAnimationPresetPtr pPreset( rPresets.getEffectDescriptor( this->GetPresetId() ) );
599 if( !pPreset.get() )
601 OSL_FAIL("no suitable preset found for ppt import");
602 return;
605 //--------------start doing something
607 //1. ------ create an effect from the presets ------
608 ::sd::CustomAnimationEffectPtr pEffect( new ::sd::CustomAnimationEffect( pPreset->create( this->GetPresetSubType() ) ) );
609 if( !pEffect.get() )
611 DBG_ASSERT(pEffect.get(),"no suitable effect found");
612 return;
615 //2. ------ adapt the created effect ------
617 // set the shape targeted by this effect
618 pEffect->setTarget( makeAny( xShape ) );
620 pEffect->setBegin( this->GetDelayTimeInSeconds() );
622 // some effects need a different duration than that of the mapped preset effect
623 double fDurationInSeconds = 1.0; //in seconds
624 if( this->GetSpecialDuration( fDurationInSeconds ) )
625 pEffect->setDuration( fDurationInSeconds );
627 // set after effect
628 if( this->HasAfterEffect() )
630 pEffect->setHasAfterEffect( true );
631 if( this->HasAfterEffect_ChangeColor() )
632 pEffect->setDimColor( uno::makeAny( this->GetDimColor() ) );
633 else
634 pEffect->setAfterEffectOnNext( this->HasAfterEffect_DimAtNextEffect() );
637 // set sound effect
638 if( this->HasSoundEffect() )
639 pEffect->createAudio( uno::makeAny( m_aSoundFileUrl ) );
641 // text iteration
642 pEffect->setIterateType( this->GetTextAnimationType() );
644 // some effects need a different delay between text iteration than that of the mapped preset effect
645 double fTextIterationDelay = 1.0;
646 if( this->GetSpecialTextIterationDelay( fTextIterationDelay ) )
647 pEffect->setIterateInterval( fTextIterationDelay );
649 // is the effect started on click or after the last effect (Another possible value is EffectNodeType::WITH_PREVIOUS )
650 pEffect->setNodeType( this->GetEffectNodeType() );
652 //set stop sound effect
653 if( this->HasStopPreviousSound() )
654 pEffect->setStopAudio();
656 // append the effect to the main sequence
657 if( !this->HasParagraphEffect() )
659 // TODO: !this->HasAnimateAssociatedShape() can possibly have this set to ONLY_TEXT - see i#42737
660 pEffect->setTargetSubItem( presentation::ShapeAnimationSubType::AS_WHOLE );
663 //3. ------ put the created effect to the model and do some last changes fro paragraph effects ------
664 pMainSequence->append( pEffect );
665 if( this->HasParagraphEffect() )
667 sal_Int32 nParagraphLevel = this->GetParagraphLevel();
668 double fDelaySeconds = this->GetDelayTimeInSeconds();
669 bool bAnimateAssociatedShape = this->HasAnimateAssociatedShape();//or only text
670 bool bTextReverse = this->HasReverseOrder();
672 // now create effects for each paragraph
673 ::sd::CustomAnimationTextGroupPtr pGroup = pMainSequence->
674 createTextGroup( pEffect, nParagraphLevel, fDelaySeconds, bAnimateAssociatedShape, bTextReverse );
676 if( pGroup )
678 const ::sd::EffectSequence& rEffects = pGroup->getEffects();
679 ::sd::EffectSequence::const_iterator aIter = rEffects.begin();
681 ::sd::CustomAnimationEffectPtr pLastEffect;
682 sal_Int32 nIndex = 0;
683 for( ; aIter != rEffects.end(); ++aIter )
685 ::sd::CustomAnimationEffectPtr pGroupEffect(*aIter);
687 ////todo? if( nIndex > 1 && pLastEffect && this->HasSoundEffect() )
688 //// pLastEffect->setStopAudio();
689 if( nIndex < 2 )
691 pGroupEffect->setNodeType( this->GetEffectNodeType() );
693 else if( nIndex > 0 )
695 bool bAtParagraphBegin = false;
696 if(!bTextReverse)
697 bAtParagraphBegin = pGroupEffect->getParaDepth() < nParagraphLevel;
698 else
699 bAtParagraphBegin = !pLastEffect || pLastEffect->getParaDepth() < nParagraphLevel;
700 if( bAtParagraphBegin )
701 pGroupEffect->setNodeType( this->GetEffectNodeType() );
702 else if( this->GetTextAnimationType() == presentation::TextAnimationType::BY_PARAGRAPH )
703 pGroupEffect->setNodeType( presentation::EffectNodeType::WITH_PREVIOUS );
704 else
705 pGroupEffect->setNodeType( presentation::EffectNodeType::AFTER_PREVIOUS );
707 pLastEffect = pGroupEffect;
708 nIndex++;
712 pMainSequence->rebuild();
715 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */