LibreOffice Module sd (master) 1
CustomAnimationPreset.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 * 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 <sal/config.h>
21
22#include <com/sun/star/util/XCloneable.hpp>
23#include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
24#include <com/sun/star/container/XNameAccess.hpp>
25#include <com/sun/star/configuration/theDefaultProvider.hpp>
26#include <com/sun/star/xml/sax/InputSource.hpp>
27#include <com/sun/star/xml/sax/XFastParser.hpp>
28#include <com/sun/star/presentation/EffectPresetClass.hpp>
29#include <com/sun/star/beans/NamedValue.hpp>
34#include <comphelper/random.hxx>
35#include <comphelper/lok.hxx>
37#include <tools/stream.hxx>
39#include <o3tl/string_view.hxx>
40
41#include <vcl/svapp.hxx>
44
45#include <algorithm>
46#include <vector>
47
48using namespace ::com::sun::star;
49using namespace ::com::sun::star::uno;
50using namespace ::com::sun::star::animations;
51using namespace ::com::sun::star::presentation;
52
53using ::com::sun::star::io::XInputStream;
54using ::com::sun::star::lang::XMultiServiceFactory;
55using ::com::sun::star::container::XNameAccess;
56using ::com::sun::star::util::XCloneable;
57using ::com::sun::star::beans::NamedValue;
58
59namespace sd {
60
61static Reference< XNameAccess > getNodeAccess( const Reference< XMultiServiceFactory >& xConfigProvider, const OUString& rNodePath )
62{
63 Reference< XNameAccess > xConfigAccess;
64
65 try
66 {
67 Sequence<Any> aArgs(comphelper::InitAnyPropertySequence(
68 {
69 {"nodepath", uno::Any(rNodePath)}
70 }));
71
72 xConfigAccess.set(
73 xConfigProvider->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", aArgs ),
74 UNO_QUERY);
75 }
76 catch (const Exception&)
77 {
78 TOOLS_WARN_EXCEPTION( "sd", "sd::getNodeAccess()" );
79 }
80
81 return xConfigAccess;
82}
83
84void implImportLabels( const Reference< XMultiServiceFactory >& xConfigProvider, const OUString& rNodePath, UStringMap& rStringMap )
85{
86 try
87 {
88 Reference< XNameAccess > xConfigAccess( getNodeAccess( xConfigProvider, rNodePath ) );
89 if( xConfigAccess.is() )
90 {
91 Reference< XNameAccess > xNameAccess;
92 const Sequence< OUString > aNames( xConfigAccess->getElementNames() );
93 for(const OUString& rName : aNames)
94 {
95 xConfigAccess->getByName( rName ) >>= xNameAccess;
96 if( xNameAccess.is() )
97 {
98 OUString aUIName;
99 xNameAccess->getByName( "Label" ) >>= aUIName;
100 if( !aUIName.isEmpty() )
101 {
102 rStringMap[ rName ] = aUIName;
103 }
104 }
105 }
106 }
107 }
108 catch (const Exception&)
109 {
110 TOOLS_WARN_EXCEPTION( "sd", "sd::implImportLabels()" );
111 }
112}
113
115{
116 maPresetId = pEffect->getPresetId();
117 maProperty = pEffect->getProperty();
118
119 add( pEffect );
120
121 mfDuration = pEffect->getDuration();
122 maDefaultSubTyp = pEffect->getPresetSubType();
123
124 const Sequence< NamedValue > aUserData( pEffect->getNode()->getUserData() );
125
126 mbIsTextOnly = std::any_of(aUserData.begin(), aUserData.end(),
127 [](const NamedValue& rProp) { return rProp.Name == "text-only"; });
128}
129
131{
132 maSubTypes[ pEffect->getPresetSubType() ] = pEffect;
133}
134
136{
137 std::vector<OUString> aSubTypes;
138
139 if( maSubTypes.size() > 1 )
140 {
141 std::transform(maSubTypes.begin(), maSubTypes.end(), std::back_inserter(aSubTypes),
142 [](EffectsSubTypeMap::value_type& rEntry) -> OUString { return rEntry.first; });
143 }
144
145 return aSubTypes;
146}
147
148Reference< XAnimationNode > CustomAnimationPreset::create( const OUString& rstrSubType )
149{
150 try
151 {
152 OUString strSubType( rstrSubType );
153 if( strSubType.isEmpty() )
154 strSubType = maDefaultSubTyp;
155
156 CustomAnimationEffectPtr pEffect = maSubTypes[strSubType];
157 if( pEffect )
158 {
159 Reference< XCloneable > xCloneable( pEffect->getNode(), UNO_QUERY_THROW );
160 Reference< XAnimationNode > xNode( xCloneable->createClone(), UNO_QUERY_THROW );
161 return xNode;
162 }
163 }
164 catch (const Exception&)
165 {
166 TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPresets::create()" );
167 }
168
169 Reference< XAnimationNode > xNode;
170 return xNode;
171}
172
173std::vector<OUString> CustomAnimationPreset::getProperties() const
174{
175 std::vector<OUString> aPropertyList;
176 if (!maProperty.isEmpty())
177 {
178 sal_Int32 nPos = 0;
179 do
180 {
181 aPropertyList.push_back(maProperty.getToken(0, ';', nPos));
182 }
183 while (nPos >= 0);
184 }
185 return aPropertyList;
186}
187
188bool CustomAnimationPreset::hasProperty( std::u16string_view rProperty )const
189{
190 if (maProperty.isEmpty())
191 return false;
192
193 sal_Int32 nPos = 0;
194 do
195 {
196 if (o3tl::getToken(maProperty, 0, ';', nPos) == rProperty)
197 return true;
198 }
199 while (nPos >= 0);
200
201 return false;
202}
203
205{
206}
207
209{
210}
211
212Reference< XAnimationNode > implImportEffects( const Reference< XMultiServiceFactory >& xServiceFactory, const OUString& rPath )
213{
214 Reference< XAnimationNode > xRootNode;
215
216 try
217 {
218 // create stream
219 std::unique_ptr<SvStream> pIStm = ::utl::UcbStreamHelper::CreateStream( rPath, StreamMode::READ );
220 Reference<XInputStream> xInputStream( new utl::OInputStreamWrapper( std::move(pIStm) ) );
221
222 // prepare ParserInputSource
223 xml::sax::InputSource aParserInput;
224 aParserInput.sSystemId = rPath;
225 aParserInput.aInputStream = xInputStream;
226
227 // get filter
228 Reference< xml::sax::XFastParser > xFilter( xServiceFactory->createInstance("com.sun.star.comp.Xmloff.AnimationsImport" ), UNO_QUERY_THROW );
229
230 xFilter->parseStream( aParserInput );
231
232 Reference< XAnimationNodeSupplier > xAnimationNodeSupplier( xFilter, UNO_QUERY_THROW );
233 xRootNode = xAnimationNodeSupplier->getAnimationNode();
234 }
235 catch (const Exception&)
236 {
237 TOOLS_WARN_EXCEPTION("sd", "");
238 }
239
240 return xRootNode;
241}
242
244{
245 try
246 {
247 uno::Reference< uno::XComponentContext > xContext(
249 Reference< XMultiServiceFactory > xServiceFactory(
250 xContext->getServiceManager(), UNO_QUERY_THROW );
251
252 Reference< XMultiServiceFactory > xConfigProvider =
253 configuration::theDefaultProvider::get( xContext );
254
255 // read path to transition effects files from config
256 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
257 {
258 {"nodepath", uno::Any(OUString("/org.openoffice.Office.Impress/Misc"))}
259 }));
260 Reference<container::XNameAccess> xNameAccess(
261 xConfigProvider->createInstanceWithArguments(
262 "com.sun.star.configuration.ConfigurationAccess",
263 aArgs ), UNO_QUERY_THROW );
264 uno::Sequence< OUString > aFiles;
265 xNameAccess->getByName( "EffectFiles" ) >>= aFiles;
266
267 for( const auto& rFile : std::as_const(aFiles) )
268 {
269 OUString aURL = comphelper::getExpandedUri(xContext, rFile);
270
271 mxRootNode = implImportEffects( xServiceFactory, aURL );
272
273 if( mxRootNode.is() )
274 {
275 Reference< XTimeContainer > xRootContainer( mxRootNode, UNO_QUERY_THROW );
276 EffectSequenceHelper aSequence( xRootContainer );
277
278 EffectSequence::iterator aIter( aSequence.getBegin() );
279 const EffectSequence::iterator aEnd( aSequence.getEnd() );
280
281 while( aIter != aEnd )
282 {
283 CustomAnimationEffectPtr pEffect = *aIter;
284
285 const OUString aPresetId( pEffect->getPresetId() );
286 CustomAnimationPresetPtr pDescriptor = getEffectDescriptor( aPresetId );
287 if( pDescriptor )
288 pDescriptor->add( pEffect );
289 else
290 {
291 pDescriptor = std::make_shared<CustomAnimationPreset>( pEffect );
292 pDescriptor->maLabel = getUINameForPresetId( pEffect->getPresetId() );
293 maEffectDescriptorMap[aPresetId] = pDescriptor;
294 }
295
296 ++aIter;
297 }
298 }
299 }
300 }
301 catch (const Exception&)
302 {
303 TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPresets::importEffects()" );
304 }
305}
306
308{
309 try
310 {
311 // Get service factory
312 Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
313
314 Reference< XMultiServiceFactory > xConfigProvider =
315 configuration::theDefaultProvider::get( xContext );
316
317 implImportLabels( xConfigProvider, "/org.openoffice.Office.UI.Effects/UserInterface/Properties", maPropertyNameMap );
318
319 implImportLabels( xConfigProvider, "/org.openoffice.Office.UI.Effects/UserInterface/Effects", maEffectNameMap );
320
322
323 importPresets( xConfigProvider, "/org.openoffice.Office.UI.Effects/Presets/Entrance", maEntrancePresets );
324
325 importPresets( xConfigProvider, "/org.openoffice.Office.UI.Effects/Presets/Emphasis", maEmphasisPresets );
326
327 importPresets( xConfigProvider, "/org.openoffice.Office.UI.Effects/Presets/Exit", maExitPresets );
328
329 importPresets( xConfigProvider, "/org.openoffice.Office.UI.Effects/Presets/MotionPaths", maMotionPathsPresets );
330
331 importPresets( xConfigProvider, "/org.openoffice.Office.UI.Effects/Presets/Misc", maMiscPresets );
332 }
333 catch (const Exception&)
334 {
335 TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPresets::importResources()" );
336 }
337}
338
339void CustomAnimationPresets::importPresets( const Reference< XMultiServiceFactory >& xConfigProvider, const OUString& rNodePath, PresetCategoryList& rPresetMap )
340{
341#ifdef DEBUG
342 OUString aMissedPresetIds;
343#endif
344
345 try
346 {
347 Reference< XNameAccess > xTypeAccess( getNodeAccess( xConfigProvider, rNodePath ) );
348 if( xTypeAccess.is() )
349 {
350 Reference< XNameAccess > xCategoryAccess;
351
352 const Sequence< OUString > aNames( xTypeAccess->getElementNames() );
353 for(const OUString& rName : aNames)
354 {
355 xTypeAccess->getByName( rName ) >>= xCategoryAccess;
356
357 if( xCategoryAccess.is() && xCategoryAccess->hasByName( "Label" ) && xCategoryAccess->hasByName( "Effects" ) )
358 {
359 OUString aLabel;
360 xCategoryAccess->getByName( "Label" ) >>= aLabel;
361
362 Sequence< OUString > aEffects;
363 xCategoryAccess->getByName( "Effects" ) >>= aEffects;
364
365 EffectDescriptorList aEffectsList;
366
367 for( const OUString& rEffectName : std::as_const(aEffects) )
368 {
369 CustomAnimationPresetPtr pEffect = getEffectDescriptor( rEffectName );
370 if( pEffect )
371 {
372 aEffectsList.push_back( pEffect );
373 }
374#ifdef DEBUG
375 else
376 {
377 aMissedPresetIds += OUString(rEffectName);
378 aMissedPresetIds += "\n";
379 }
380#endif
381 }
382 rPresetMap.push_back( std::make_shared<PresetCategory>( aLabel, std::move(aEffectsList) ) );
383 }
384 }
385 }
386 }
387 catch (const Exception&)
388 {
389 TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPresets::importPresets()" );
390 }
391
392#ifdef DEBUG
393 SAL_WARN_IF(!aMissedPresetIds.isEmpty(), "sd", "sd::CustomAnimationPresets::importPresets(), invalid preset id: "
394 << aMissedPresetIds);
395#endif
396}
397
399{
400 EffectDescriptorMap::const_iterator aIter( maEffectDescriptorMap.find( rPresetId ) );
401
402 if( aIter != maEffectDescriptorMap.end() )
403 {
404 return (*aIter).second;
405 }
406 else
407 {
408 return CustomAnimationPresetPtr(nullptr);
409 }
410}
411
412const OUString& CustomAnimationPresets::getUINameForPresetId( const OUString& rPresetId ) const
413{
414 return translateName( rPresetId, maEffectNameMap );
415}
416
417const OUString& CustomAnimationPresets::getUINameForProperty( const OUString& rPresetId ) const
418{
419 return translateName( rPresetId, maPropertyNameMap );
420}
421
422const OUString& CustomAnimationPresets::translateName( const OUString& rId, const UStringMap& rNameMap )
423{
424 UStringMap::const_iterator aIter( rNameMap.find( rId ) );
425
426 if( aIter != rNameMap.end() )
427 {
428 return (*aIter).second;
429 }
430 else
431 {
432 return rId;
433 }
434}
435void CustomAnimationPresets::changePresetSubType( const CustomAnimationEffectPtr& pEffect, const OUString& rPresetSubType ) const
436{
437 if( pEffect && pEffect->getPresetSubType() != rPresetSubType )
438 {
439 CustomAnimationPresetPtr pDescriptor( getEffectDescriptor( pEffect->getPresetId() ) );
440
441 if( pDescriptor )
442 {
443 Reference< XAnimationNode > xNewNode( pDescriptor->create( rPresetSubType ) );
444 if( xNewNode.is() )
445 pEffect->replaceNode( xNewNode );
446 }
447 }
448}
449
450std::map<OUString, CustomAnimationPresets> CustomAnimationPresets::mPresetsMap;
451
453{
454 // Support localization per-view. Currently not useful for Desktop
455 // but very much critical for LOK. The cache now is per-language.
456 const OUString aLang = comphelper::LibreOfficeKit::isActive()
459
460 SolarMutexGuard aGuard;
461 const auto it = mPresetsMap.find(aLang);
462 if (it != mPresetsMap.end())
463 return it->second;
464
465 CustomAnimationPresets& rPresets = mPresetsMap[aLang];
466 rPresets.importResources();
467 return rPresets;
468}
469
470Reference< XAnimationNode > CustomAnimationPresets::getRandomPreset( sal_Int16 nPresetClass ) const
471{
472 Reference< XAnimationNode > xNode;
473
474 const PresetCategoryList* pCategoryList = nullptr;
475 switch( nPresetClass )
476 {
477 case EffectPresetClass::ENTRANCE: pCategoryList = &maEntrancePresets; break;
478 case EffectPresetClass::EXIT: pCategoryList = &maExitPresets; break;
479 case EffectPresetClass::EMPHASIS: pCategoryList = &maEmphasisPresets; break;
480 case EffectPresetClass::MOTIONPATH: pCategoryList = &maMotionPathsPresets; break;
481 default:
482 pCategoryList = nullptr;
483 }
484
485 if( pCategoryList && !pCategoryList->empty() )
486 {
487 sal_Int32 nCategory = comphelper::rng::uniform_size_distribution(0, pCategoryList->size()-1);
488
489 PresetCategoryPtr pCategory = (*pCategoryList)[nCategory];
490 if( pCategory && !pCategory->maEffects.empty() )
491 {
492 sal_Int32 nDescriptor = comphelper::rng::uniform_size_distribution(0, pCategory->maEffects.size()-1);
493 CustomAnimationPresetPtr pPreset = pCategory->maEffects[nDescriptor];
494 if( pPreset )
495 {
496 std::vector<OUString> aSubTypes = pPreset->getSubTypes();
497
498 OUString aSubType;
499 if( !aSubTypes.empty() )
500 {
501 size_t nSubType = comphelper::rng::uniform_size_distribution(0, aSubTypes.size()-1);
502 aSubType = aSubTypes[nSubType];
503 }
504 xNode = pPreset->create( aSubType );
505 }
506 }
507 }
508
509 return xNode;
510}
511
512}
513
514/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const OUString & getBcp47(bool bResolveSystem=true) const
LanguageTag GetLanguageTag() const
std::vector< OUString > getSubTypes()
CustomAnimationPreset(const CustomAnimationEffectPtr &pEffect)
std::vector< OUString > getProperties() const
SD_DLLPUBLIC css::uno::Reference< css::animations::XAnimationNode > create(const OUString &rstrSubType)
bool hasProperty(std::u16string_view rProperty) const
void add(const CustomAnimationEffectPtr &pEffect)
SAL_DLLPRIVATE void importEffects()
static SAL_DLLPRIVATE std::map< OUString, CustomAnimationPresets > mPresetsMap
Maps per-language the animation presets.
SAL_DLLPRIVATE void changePresetSubType(const CustomAnimationEffectPtr &pEffect, const OUString &rPresetSubType) const
SAL_DLLPRIVATE void importResources()
static SAL_DLLPRIVATE const OUString & translateName(const OUString &rId, const UStringMap &rNameMap)
css::uno::Reference< css::animations::XAnimationNode > mxRootNode
CustomAnimationPresetPtr getEffectDescriptor(const OUString &rPresetId) const
SAL_DLLPRIVATE const OUString & getUINameForPresetId(const OUString &rPresetId) const
EffectDescriptorMap maEffectDescriptorMap
SAL_DLLPRIVATE void importPresets(const css::uno::Reference< css::lang::XMultiServiceFactory > &xConfigProvider, const OUString &rNodePath, PresetCategoryList &rPresetMap)
static const CustomAnimationPresets & getCustomAnimationPresets()
This method gets presets instance, which is localized for the current user's locale.
SAL_DLLPRIVATE const OUString & getUINameForProperty(const OUString &rProperty) const
SAL_DLLPRIVATE css::uno::Reference< css::animations::XAnimationNode > getRandomPreset(sal_Int16 nPresetClass) const
SAL_DLLPRIVATE EffectSequence::iterator getEnd()
SAL_DLLPRIVATE EffectSequence::iterator getBegin()
static std::unique_ptr< SvStream > CreateStream(const OUString &rFileName, StreamMode eOpenMode, css::uno::Reference< css::awt::XWindow > xParentWin=nullptr)
#define TOOLS_WARN_EXCEPTION(area, stream)
URL aURL
OUString aUIName
sal_uInt16 nPos
#define SAL_WARN_IF(condition, area, stream)
@ Exception
const LanguageTag & getLanguageTag()
size_t uniform_size_distribution(size_t a, size_t b)
COMPHELPER_DLLPUBLIC OUString getExpandedUri(css::uno::Reference< css::uno::XComponentContext > const &context, OUString const &uri)
css::uno::Sequence< css::uno::Any > InitAnyPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
Reference< XComponentContext > getProcessComponentContext()
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
void implImportLabels(const Reference< XMultiServiceFactory > &xConfigProvider, const OUString &rNodePath, UStringMap &rStringMap)
std::vector< PresetCategoryPtr > PresetCategoryList
std::shared_ptr< CustomAnimationPreset > CustomAnimationPresetPtr
Reference< XAnimationNode > implImportEffects(const Reference< XMultiServiceFactory > &xServiceFactory, const OUString &rPath)
std::unordered_map< OUString, OUString > UStringMap
std::shared_ptr< CustomAnimationEffect > CustomAnimationEffectPtr
std::shared_ptr< PresetCategory > PresetCategoryPtr
static Reference< XNameAccess > getNodeAccess(const Reference< XMultiServiceFactory > &xConfigProvider, const OUString &rNodePath)
std::vector< CustomAnimationPresetPtr > EffectDescriptorList
OUString aLabel