LibreOffice Module sd (master) 1
pptx-animations-nodectx.cxx
Go to the documentation of this file.
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
11#include <com/sun/star/animations/AnimationNodeType.hpp>
12#include <com/sun/star/animations/XAnimate.hpp>
13#include <com/sun/star/animations/XAnimationNode.hpp>
14#include <com/sun/star/animations/XCommand.hpp>
15#include <com/sun/star/animations/XAudio.hpp>
16#include <com/sun/star/animations/XIterateContainer.hpp>
17#include <com/sun/star/drawing/XShape.hpp>
18#include <com/sun/star/container/XEnumerationAccess.hpp>
19#include <com/sun/star/container/XEnumeration.hpp>
20#include <com/sun/star/presentation/EffectNodeType.hpp>
21#include <com/sun/star/presentation/EffectPresetClass.hpp>
22#include <com/sun/star/presentation/ParagraphTarget.hpp>
23#include <com/sun/star/beans/XPropertySet.hpp>
24
25#include <o3tl/any.hxx>
26#include <o3tl/string_view.hxx>
27
28using ::com::sun::star::beans::NamedValue;
29using ::com::sun::star::beans::XPropertySet;
30using ::com::sun::star::drawing::XShape;
31
32using namespace ::com::sun::star::animations;
33using namespace ::com::sun::star::drawing;
34using namespace ::com::sun::star::container;
35using namespace ::com::sun::star::presentation;
36using namespace ::com::sun::star::uno;
37
38namespace oox::core
39{
40namespace
41{
42bool isValidTarget(const Any& rTarget)
43{
44 Reference<XShape> xShape;
45
46 if ((rTarget >>= xShape) && xShape.is())
47 return true;
48
49 ParagraphTarget aParagraphTarget;
50
51 return (rTarget >>= aParagraphTarget) && aParagraphTarget.Shape.is();
52}
53
54bool IsAudioURL(std::u16string_view rURL)
55{
56 return o3tl::endsWithIgnoreAsciiCase(rURL, ".wav")
57 || o3tl::endsWithIgnoreAsciiCase(rURL, ".m4a");
58}
59
61bool IsVideoURL(std::u16string_view rURL) { return o3tl::endsWithIgnoreAsciiCase(rURL, ".mp4"); }
62
63bool initCondList(const Any& rAny, std::vector<Cond>& rList, bool bIsMainSeqChild)
64{
65 bool bEventTrigger = false;
66 if (!rAny.hasValue())
67 return false;
68
69 Sequence<Any> aCondSeq;
70 if (rAny >>= aCondSeq)
71 {
72 for (const auto& rCond : std::as_const(aCondSeq))
73 {
74 Cond aCond(rCond, bIsMainSeqChild);
75 if (aCond.isValid())
76 {
77 rList.push_back(aCond);
78 if (aCond.mpEvent)
79 bEventTrigger = true;
80 }
81 }
82 }
83 else
84 {
85 Cond aCond(rAny, bIsMainSeqChild);
86 if (aCond.isValid())
87 {
88 rList.push_back(aCond);
89 if (aCond.mpEvent)
90 bEventTrigger = true;
91 }
92 }
93 return bEventTrigger;
94}
95}
96
97NodeContext::NodeContext(const Reference<XAnimationNode>& xNode, bool bMainSeqChild,
98 bool bIsIterateChild)
99 : mxNode(xNode)
100 , mbValid(true)
101 , mbOnSubTnLst(false)
102 , mnEffectNodeType(-1)
103 , mnEffectPresetClass(css::presentation::EffectPresetClass::CUSTOM)
104{
105 assert(xNode.is());
106
107 initUserData();
108
109 initValid(initChildNodes(), bIsIterateChild);
110
111 // Put event triggered Audio time nodes to SubTnLst.
112 // Add other types of nodes once we find more test cases.
113 mbOnSubTnLst = initCondList(getNodeForCondition()->getBegin(), maBeginCondList, bMainSeqChild)
114 && mxNode->getType() == AnimationNodeType::AUDIO;
115
116 initCondList(getNodeForCondition()->getEnd(), maEndCondList, bMainSeqChild);
117}
118
119void NodeContext::initUserData()
120{
121 assert(mxNode.is());
122
123 Sequence<NamedValue> aUserData = mxNode->getUserData();
124 for (const NamedValue& rProp : aUserData)
125 {
126 if (rProp.Name == "node-type")
127 {
128 rProp.Value >>= mnEffectNodeType;
129 }
130 else if (rProp.Name == "preset-class")
131 {
132 rProp.Value >>= mnEffectPresetClass;
133 }
134 else if (rProp.Name == "preset-id")
135 {
136 rProp.Value >>= msEffectPresetId;
137 }
138 else if (rProp.Name == "preset-sub-type")
139 {
140 rProp.Value >>= msEffectPresetSubType;
141 }
142 }
143}
144
145void NodeContext::initValid(bool bHasValidChild, bool bIsIterateChild)
146{
147 sal_Int16 nType = mxNode->getType();
148
149 if (nType == AnimationNodeType::ITERATE)
150 {
151 Reference<XIterateContainer> xIterate(mxNode, UNO_QUERY);
152 mbValid = xIterate.is() && (bIsIterateChild || isValidTarget(xIterate->getTarget()))
153 && !maChildNodes.empty();
154 }
155 else if (nType == AnimationNodeType::COMMAND)
156 {
157 Reference<XCommand> xCommand(mxNode, UNO_QUERY);
158 mbValid = xCommand.is() && (bIsIterateChild || isValidTarget(xCommand->getTarget()));
159 }
160 else if (nType == AnimationNodeType::PAR || nType == AnimationNodeType::SEQ)
161 {
162 mbValid = bHasValidChild;
163 }
164 else if (nType == AnimationNodeType::AUDIO)
165 {
166 Reference<XAudio> xAudio(mxNode, UNO_QUERY);
167 OUString sURL;
168 Reference<XShape> xShape;
169 mbValid = false;
170 if (xAudio.is())
171 {
172 if (xAudio->getSource() >>= sURL)
173 {
174 mbValid = IsAudioURL(sURL);
175 }
176 else if (xAudio->getSource() >>= xShape)
177 {
178 Reference<XPropertySet> xShapeProps(xShape, UNO_QUERY);
179 bool bHasMediaURL
180 = xShapeProps->getPropertySetInfo()->hasPropertyByName("MediaURL");
181 if (bHasMediaURL && (xShapeProps->getPropertyValue("MediaURL") >>= sURL))
182 {
183 mbValid = IsAudioURL(sURL) || IsVideoURL(sURL);
184 }
185 }
186 }
187 }
188 else
189 {
190 Reference<XAnimate> xAnimate(mxNode, UNO_QUERY);
191 mbValid = xAnimate.is() && (bIsIterateChild || isValidTarget(xAnimate->getTarget()));
192 }
193}
194
195bool NodeContext::initChildNodes()
196{
197 bool bValid = false;
198 Reference<XEnumerationAccess> xEnumerationAccess(mxNode, UNO_QUERY);
199 if (xEnumerationAccess.is())
200 {
201 Reference<XEnumeration> xEnumeration = xEnumerationAccess->createEnumeration();
202 bool bIsMainSeq = mnEffectNodeType == EffectNodeType::MAIN_SEQUENCE;
203 bool bIsIterateChild = mxNode->getType() == AnimationNodeType::ITERATE;
204 if (xEnumeration.is())
205 {
206 while (xEnumeration->hasMoreElements())
207 {
208 Reference<XAnimationNode> xChildNode(xEnumeration->nextElement(), UNO_QUERY);
209 if (xChildNode.is())
210 {
211 auto pChildContext
212 = std::make_unique<NodeContext>(xChildNode, bIsMainSeq, bIsIterateChild);
213 if (pChildContext->isValid())
214 bValid = true;
215 maChildNodes.push_back(std::move(pChildContext));
216 }
217 }
218 }
219 }
220 return bValid;
221}
222
223const Reference<XAnimationNode>& NodeContext::getNodeForCondition() const
224{
225 const bool bParent
226 = (mnEffectNodeType != EffectNodeType::INTERACTIVE_SEQUENCE || maChildNodes.empty());
227 const Reference<XAnimationNode>& rNode = bParent ? mxNode : maChildNodes[0]->getNode();
228 return rNode;
229}
230}
231/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
NodeContext(const css::uno::Reference< css::animations::XAnimationNode > &xNode, bool bMainSeqChild, bool bIsIterateChild)
bool endsWithIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2, std::u16string_view *rest=nullptr)
QPRO_FUNC_TYPE nType
bool mbValid