tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / slideshow / source / engine / animationnodes / animationnodefactory.cxx
blob4df097cb08c077fe5004ea6531d9af030f831fc2
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 .
21 #include <com/sun/star/drawing/XShape.hpp>
22 #include <com/sun/star/animations/AnimationNodeType.hpp>
23 #include <com/sun/star/presentation/TextAnimationType.hpp>
24 #include <com/sun/star/animations/XIterateContainer.hpp>
25 #include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
26 #include <com/sun/star/presentation/ParagraphTarget.hpp>
27 #include <basegfx/numeric/ftools.hxx>
28 #include <sal/log.hxx>
30 #include <animationnodefactory.hxx>
31 #include "paralleltimecontainer.hxx"
32 #include "sequentialtimecontainer.hxx"
33 #include "propertyanimationnode.hxx"
34 #include "animationsetnode.hxx"
35 #include "animationpathmotionnode.hxx"
36 #include "animationphysicsnode.hxx"
37 #include "animationcolornode.hxx"
38 #include "animationtransformnode.hxx"
39 #include "animationtransitionfilternode.hxx"
40 #include "animationaudionode.hxx"
41 #include "animationcommandnode.hxx"
42 #include "nodetools.hxx"
43 #include <tools.hxx>
45 #include <memory>
47 using namespace ::com::sun::star;
49 namespace slideshow::internal {
51 namespace {
53 // forward declaration needed by NodeCreator
54 BaseNodeSharedPtr implCreateAnimationNode(
55 const uno::Reference< animations::XAnimationNode >& xNode,
56 const BaseContainerNodeSharedPtr& rParent,
57 const NodeContext& rContext );
59 class NodeCreator
61 public:
62 NodeCreator( BaseContainerNodeSharedPtr& rParent,
63 const NodeContext& rContext )
64 : mrParent( rParent ), mrContext( rContext ) {}
66 void operator()(
67 const uno::Reference< animations::XAnimationNode >& xChildNode ) const
69 createChild( xChildNode, mrContext );
72 protected:
73 void createChild(
74 const uno::Reference< animations::XAnimationNode >& xChildNode,
75 const NodeContext& rContext ) const
77 BaseNodeSharedPtr pChild( implCreateAnimationNode( xChildNode,
78 mrParent,
79 rContext ) );
81 OSL_ENSURE( pChild,
82 "NodeCreator::operator(): child creation failed" );
84 // TODO(Q1): This yields circular references, which, it seems, is
85 // unavoidable here
86 if( pChild )
87 mrParent->appendChildNode( pChild );
90 BaseContainerNodeSharedPtr& mrParent;
91 const NodeContext& mrContext;
94 /** Same as NodeCreator, only that NodeContext's
95 SubsetShape is cloned for every child node.
97 This is used for iterated animation node generation
99 class CloningNodeCreator : private NodeCreator
101 public:
102 CloningNodeCreator( BaseContainerNodeSharedPtr& rParent,
103 const NodeContext& rContext )
104 : NodeCreator( rParent, rContext ) {}
106 void operator()(
107 const uno::Reference< animations::XAnimationNode >& xChildNode ) const
109 NodeContext aContext( mrContext );
111 // TODO(Q1): There's a catch here. If you clone a
112 // subset whose actual subsetting has already been
113 // realized (i.e. if enableSubsetShape() has been
114 // called already), and the original of your clone
115 // goes out of scope, then your subset will be
116 // gone (SubsettableShapeManager::revokeSubset() be
117 // called). As of now, this behaviour is not
118 // triggered here (we either clone, XOR we enable
119 // subset initially), but one might consider
120 // reworking DrawShape/ShapeSubset to avoid this.
122 // clone ShapeSubset, since each node needs their
123 // own version of the ShapeSubset (otherwise,
124 // e.g. activity counting does not work - subset
125 // would be removed after first animation node
126 // disables it).
128 // NOTE: this is only a problem for animation
129 // nodes that explicitly call
130 // disableSubsetShape(). Independent shape subsets
131 // (like those created for ParagraphTargets)
132 // solely rely on the ShapeSubset destructor to
133 // normalize things, which does the right thing
134 // here: the subset is only removed after _the
135 // last_ animation node releases the shared ptr.
136 aContext.mpMasterShapeSubset =
137 std::make_shared<ShapeSubset>( *aContext.mpMasterShapeSubset );
139 createChild( xChildNode, aContext );
143 /** Create animation nodes for text iterations
145 This method clones the animation nodes below xIterNode
146 for every iterated shape entity.
148 bool implCreateIteratedNodes(
149 const uno::Reference< animations::XIterateContainer >& xIterNode,
150 BaseContainerNodeSharedPtr& rParent,
151 const NodeContext& rContext )
153 ENSURE_OR_THROW( xIterNode.is(),
154 "implCreateIteratedNodes(): Invalid node" );
156 const double nIntervalTimeout( xIterNode->getIterateInterval() );
158 // valid iterate interval? We're ruling out monstrous
159 // values here, to avoid pseudo 'hangs' in the
160 // presentation
161 if( nIntervalTimeout < 0.0 ||
162 nIntervalTimeout > 1000.0 )
164 return false; // not an active iteration
167 if( ::basegfx::fTools::equalZero( nIntervalTimeout ) )
168 SAL_INFO("slideshow", "implCreateIteratedNodes(): "
169 "iterate interval close to zero, there's "
170 "no point in defining such an effect "
171 "(visually equivalent to whole-shape effect)" );
173 // Determine target shape (or subset)
174 // ==================================
176 // TODO(E1): I'm not too sure what to expect here...
177 ENSURE_OR_RETURN_FALSE(
178 xIterNode->getTarget().hasValue(),
179 "implCreateIteratedNodes(): no target on ITERATE node" );
181 uno::Reference< drawing::XShape > xTargetShape( xIterNode->getTarget(),
182 uno::UNO_QUERY );
184 presentation::ParagraphTarget aTarget;
185 sal_Int16 nSubItem( xIterNode->getSubItem() );
186 bool bParagraphTarget( false );
188 if( !xTargetShape.is() )
190 // no shape provided. Maybe a ParagraphTarget?
191 if( !(xIterNode->getTarget() >>= aTarget) )
192 ENSURE_OR_RETURN_FALSE(
193 false,
194 "implCreateIteratedNodes(): could not extract any "
195 "target information" );
197 xTargetShape = aTarget.Shape;
199 ENSURE_OR_RETURN_FALSE(
200 xTargetShape.is(),
201 "implCreateIteratedNodes(): invalid shape in ParagraphTarget" );
203 // we've a paragraph target to iterate over, thus,
204 // the whole animation container refers only to
205 // the text
206 nSubItem = presentation::ShapeAnimationSubType::ONLY_TEXT;
208 bParagraphTarget = true;
211 // Lookup shape, and fill NodeContext
212 // ==================================
214 AttributableShapeSharedPtr pTargetShape(
215 lookupAttributableShape( rContext.maContext.mpSubsettableShapeManager,
216 xTargetShape ) );
218 const DocTreeNodeSupplier& rTreeNodeSupplier(
219 pTargetShape->getTreeNodeSupplier() );
221 ShapeSubsetSharedPtr pTargetSubset;
223 NodeContext aContext( rContext );
225 // paragraph targets already need a subset as the
226 // master shape (they're representing only a single
227 // paragraph)
228 if( bParagraphTarget )
230 ENSURE_OR_RETURN_FALSE(
231 aTarget.Paragraph >= 0 &&
232 rTreeNodeSupplier.getNumberOfTreeNodes(
233 DocTreeNode::NodeType::LogicalParagraph ) > aTarget.Paragraph,
234 "implCreateIteratedNodes(): paragraph index out of range" );
236 pTargetSubset =
237 std::make_shared<ShapeSubset>(
238 pTargetShape,
239 // retrieve index aTarget.Paragraph of
240 // type PARAGRAPH from this shape
241 rTreeNodeSupplier.getTreeNode(
242 aTarget.Paragraph,
243 DocTreeNode::NodeType::LogicalParagraph ),
244 rContext.maContext.mpSubsettableShapeManager );
246 // iterate target is not the whole shape, but only
247 // the selected paragraph - subset _must_ be
248 // independent, to be able to affect visibility
249 // independent of master shape
250 aContext.mbIsIndependentSubset = true;
252 // already enable parent subset right here, to
253 // make potentially generated subsets subtract
254 // their content from the parent subset (and not
255 // the original shape). Otherwise, already
256 // subsetted parents (e.g. paragraphs) would not
257 // have their characters removed, when the child
258 // iterations start.
259 // Furthermore, the setup of initial shape
260 // attributes of course needs the subset shape
261 // generated, to apply e.g. visibility changes.
262 pTargetSubset->enableSubsetShape();
264 else
266 pTargetSubset =
267 std::make_shared<ShapeSubset>( pTargetShape,
268 rContext.maContext.mpSubsettableShapeManager );
271 aContext.mpMasterShapeSubset = pTargetSubset;
272 uno::Reference< animations::XAnimationNode > xNode( xIterNode,
273 uno::UNO_QUERY_THROW );
275 // Generate subsets
276 // ================
278 if( bParagraphTarget ||
279 nSubItem != presentation::ShapeAnimationSubType::ONLY_TEXT )
281 // prepend with animations for
282 // full Shape (will be subtracted
283 // from the subset parts within
284 // the Shape::createSubset()
285 // method). For ONLY_TEXT effects,
286 // we skip this part, to animate
287 // only the text.
289 // OR
291 // prepend with subset animation for full
292 // _paragraph_, from which the individual
293 // paragraph subsets are subtracted. Note that the
294 // subitem is superfluous here, we always assume
295 // ONLY_TEXT, if a paragraph is referenced as the
296 // master of an iteration effect.
297 NodeCreator aCreator( rParent, aContext );
298 if( !for_each_childNode( xNode, aCreator ) )
300 ENSURE_OR_RETURN_FALSE(
301 false,
302 "implCreateIteratedNodes(): iterated child node creation failed" );
306 // TODO(F2): This does not do the correct
307 // thing. Having nSubItem be set to ONLY_BACKGROUND
308 // should result in the text staying unanimated in the
309 // foreground, while the shape moves in the background
310 // (this behaviour is perfectly possible with the
311 // slideshow engine, only that the text won't be
312 // currently visible, because animations are always in
313 // the foreground)
314 if( nSubItem != presentation::ShapeAnimationSubType::ONLY_BACKGROUND )
316 // determine type of subitem iteration (logical
317 // text unit to animate)
318 DocTreeNode::NodeType eIterateNodeType(
319 DocTreeNode::NodeType::LogicalCharacterCell );
321 switch( xIterNode->getIterateType() )
323 case presentation::TextAnimationType::BY_PARAGRAPH:
324 eIterateNodeType = DocTreeNode::NodeType::LogicalParagraph;
325 break;
327 case presentation::TextAnimationType::BY_WORD:
328 eIterateNodeType = DocTreeNode::NodeType::LogicalWord;
329 break;
331 case presentation::TextAnimationType::BY_LETTER:
332 eIterateNodeType = DocTreeNode::NodeType::LogicalCharacterCell;
333 break;
335 default:
336 ENSURE_OR_THROW(
337 false, "implCreateIteratedNodes(): "
338 "Unexpected IterateType on XIterateContainer");
339 break;
342 if( bParagraphTarget &&
343 eIterateNodeType != DocTreeNode::NodeType::LogicalWord &&
344 eIterateNodeType != DocTreeNode::NodeType::LogicalCharacterCell )
346 // will not animate the whole paragraph, when
347 // only the paragraph is animated at all.
348 OSL_FAIL( "implCreateIteratedNodes(): Ignoring paragraph iteration for paragraph master" );
350 else
352 // setup iteration parameters
355 // iterate target is the whole shape (or the
356 // whole parent subshape), thus, can save
357 // loads of subset shapes by generating them
358 // only when the effects become active -
359 // before and after the effect active
360 // duration, all attributes are shared by
361 // master shape and subset (since the iterated
362 // effects are all the same).
363 aContext.mbIsIndependentSubset = false;
365 // determine number of nodes for given subitem
366 // type
367 sal_Int32 nTreeNodes( 0 );
368 if( bParagraphTarget )
370 // create the iterated subset _relative_ to
371 // the given paragraph index (i.e. animate the
372 // given subset type, but only when it's part
373 // of the given paragraph)
374 nTreeNodes = rTreeNodeSupplier.getNumberOfSubsetTreeNodes(
375 pTargetSubset->getSubset(),
376 eIterateNodeType );
378 else
380 // generate normal subset
381 nTreeNodes = rTreeNodeSupplier.getNumberOfTreeNodes(
382 eIterateNodeType );
386 // iterate node, generate copies of the children for each subset
389 // NodeContext::mnStartDelay contains additional node delay.
390 // This will make the duplicated nodes for each iteration start
391 // increasingly later.
392 aContext.mnStartDelay = nIntervalTimeout;
394 for( sal_Int32 i=0; i<nTreeNodes; ++i )
396 // create subset with the corresponding tree nodes
397 if( bParagraphTarget )
399 // create subsets relative to paragraph subset
400 aContext.mpMasterShapeSubset =
401 std::make_shared<ShapeSubset>(
402 pTargetSubset,
403 rTreeNodeSupplier.getSubsetTreeNode(
404 pTargetSubset->getSubset(),
406 eIterateNodeType ) );
408 else
410 // create subsets from main shape
411 aContext.mpMasterShapeSubset =
412 std::make_shared<ShapeSubset>( pTargetSubset,
413 rTreeNodeSupplier.getTreeNode(
415 eIterateNodeType ) );
418 CloningNodeCreator aCreator( rParent, aContext );
419 if( !for_each_childNode( xNode, aCreator ) )
421 ENSURE_OR_RETURN_FALSE(
422 false, "implCreateIteratedNodes(): "
423 "iterated child node creation failed" );
426 aContext.mnStartDelay += nIntervalTimeout;
431 // done with iterate child generation
432 return true;
435 BaseNodeSharedPtr implCreateAnimationNode(
436 const uno::Reference< animations::XAnimationNode >& xNode,
437 const BaseContainerNodeSharedPtr& rParent,
438 const NodeContext& rContext )
440 ENSURE_OR_THROW( xNode.is(),
441 "implCreateAnimationNode(): invalid XAnimationNode" );
443 BaseNodeSharedPtr pCreatedNode;
444 BaseContainerNodeSharedPtr pCreatedContainer;
446 // create the internal node, corresponding to xNode
447 switch( xNode->getType() )
449 case animations::AnimationNodeType::CUSTOM:
450 OSL_FAIL( "implCreateAnimationNode(): "
451 "CUSTOM not yet implemented" );
452 return pCreatedNode;
454 case animations::AnimationNodeType::PAR:
455 pCreatedNode = pCreatedContainer =
456 std::make_shared<ParallelTimeContainer>( xNode, rParent, rContext );
457 break;
459 case animations::AnimationNodeType::ITERATE:
460 // map iterate container to ParallelTimeContainer.
461 // the iterating functionality is to be found
462 // below, (see method implCreateIteratedNodes)
463 pCreatedNode = pCreatedContainer =
464 std::make_shared<ParallelTimeContainer>( xNode, rParent, rContext );
465 break;
467 case animations::AnimationNodeType::SEQ:
468 pCreatedNode = pCreatedContainer =
469 std::make_shared<SequentialTimeContainer>( xNode, rParent, rContext );
470 break;
472 case animations::AnimationNodeType::ANIMATE:
473 pCreatedNode = std::make_shared<PropertyAnimationNode>(
474 xNode, rParent, rContext );
475 break;
477 case animations::AnimationNodeType::SET:
478 pCreatedNode = std::make_shared<AnimationSetNode>(
479 xNode, rParent, rContext );
480 break;
482 case animations::AnimationNodeType::ANIMATEMOTION:
483 pCreatedNode = std::make_shared<AnimationPathMotionNode>(
484 xNode, rParent, rContext );
485 break;
487 case animations::AnimationNodeType::ANIMATECOLOR:
488 pCreatedNode = std::make_shared<AnimationColorNode>(
489 xNode, rParent, rContext );
490 break;
492 case animations::AnimationNodeType::ANIMATETRANSFORM:
493 pCreatedNode = std::make_shared<AnimationTransformNode>(
494 xNode, rParent, rContext );
495 break;
497 case animations::AnimationNodeType::ANIMATEPHYSICS:
498 pCreatedNode = std::make_shared<AnimationPhysicsNode>(
499 xNode, rParent, rContext );
500 break;
502 case animations::AnimationNodeType::TRANSITIONFILTER:
503 pCreatedNode = std::make_shared<AnimationTransitionFilterNode>(
504 xNode, rParent, rContext );
505 break;
507 case animations::AnimationNodeType::AUDIO:
508 pCreatedNode = std::make_shared<AnimationAudioNode>(
509 xNode, rParent, rContext );
510 break;
512 case animations::AnimationNodeType::COMMAND:
513 pCreatedNode = std::make_shared<AnimationCommandNode>(
514 xNode, rParent, rContext );
515 break;
517 default:
518 OSL_FAIL( "implCreateAnimationNode(): "
519 "invalid AnimationNodeType" );
520 return pCreatedNode;
523 // TODO(Q1): This yields circular references, which, it seems, is
524 // unavoidable here
526 // HACK: node objects need shared_ptr to themselves,
527 // which we pass them here.
528 pCreatedNode->setSelf( pCreatedNode );
530 // if we've got a container node object, recursively add
531 // its children
532 if( pCreatedContainer )
534 uno::Reference< animations::XIterateContainer > xIterNode(
535 xNode, uno::UNO_QUERY );
537 // when this node is an XIterateContainer with
538 // active iterations, this method will generate
539 // the appropriate children
540 if( xIterNode.is() )
542 // note that implCreateIteratedNodes() might
543 // choose not to generate any child nodes
544 // (e.g. when the iterate timeout is outside
545 // sensible limits). Then, no child nodes are
546 // generated at all, since typically, child
547 // node attribute are incomplete for iteration
548 // children.
549 implCreateIteratedNodes( xIterNode,
550 pCreatedContainer,
551 rContext );
553 else
555 // no iterate subset node, just plain child generation now
556 NodeCreator aCreator( pCreatedContainer, rContext );
557 if( !for_each_childNode( xNode, aCreator ) )
559 OSL_FAIL( "implCreateAnimationNode(): "
560 "child node creation failed" );
561 return BaseNodeSharedPtr();
566 return pCreatedNode;
569 } // anon namespace
571 AnimationNodeSharedPtr AnimationNodeFactory::createAnimationNode(
572 const uno::Reference< animations::XAnimationNode >& xNode,
573 const ::basegfx::B2DVector& rSlideSize,
574 const SlideShowContext& rContext )
576 ENSURE_OR_THROW(
577 xNode.is(),
578 "AnimationNodeFactory::createAnimationNode(): invalid XAnimationNode" );
580 return implCreateAnimationNode(
581 xNode,
582 BaseContainerNodeSharedPtr(), // no parent
583 NodeContext( rContext,
584 rSlideSize ));
587 #if defined(DBG_UTIL)
588 void AnimationNodeFactory::showTree( AnimationNodeSharedPtr const & pRootNode )
590 if( pRootNode )
591 DEBUG_NODES_SHOWTREE( std::dynamic_pointer_cast<BaseContainerNode>(
592 pRootNode).get() );
594 #endif
596 } // namespace slideshow
598 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */