1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <sal/config.h>
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>
30 #include <unotools/streamwrap.hxx>
31 #include <comphelper/getexpandeduri.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <comphelper/propertysequence.hxx>
34 #include <comphelper/random.hxx>
35 #include <comphelper/lok.hxx>
36 #include <unotools/syslocaleoptions.hxx>
37 #include <tools/stream.hxx>
38 #include <comphelper/diagnose_ex.hxx>
39 #include <o3tl/string_view.hxx>
40 #include <officecfg/Office/Impress.hxx>
42 #include <vcl/svapp.hxx>
43 #include <unotools/ucbstreamhelper.hxx>
44 #include <CustomAnimationPreset.hxx>
49 using namespace ::com::sun::star
;
50 using namespace ::com::sun::star::uno
;
51 using namespace ::com::sun::star::animations
;
52 using namespace ::com::sun::star::presentation
;
54 using ::com::sun::star::lang::XMultiServiceFactory
;
55 using ::com::sun::star::container::XNameAccess
;
56 using ::com::sun::star::util::XCloneable
;
57 using ::com::sun::star::beans::NamedValue
;
61 static Reference
< XNameAccess
> getNodeAccess( const Reference
< XMultiServiceFactory
>& xConfigProvider
, const OUString
& rNodePath
)
63 Reference
< XNameAccess
> xConfigAccess
;
67 Sequence
<Any
> aArgs(comphelper::InitAnyPropertySequence(
69 {"nodepath", uno::Any(rNodePath
)}
73 xConfigProvider
->createInstanceWithArguments( u
"com.sun.star.configuration.ConfigurationAccess"_ustr
, aArgs
),
76 catch (const Exception
&)
78 TOOLS_WARN_EXCEPTION( "sd", "sd::getNodeAccess()" );
84 void implImportLabels( const Reference
< XMultiServiceFactory
>& xConfigProvider
, const OUString
& rNodePath
, UStringMap
& rStringMap
)
88 Reference
< XNameAccess
> xConfigAccess( getNodeAccess( xConfigProvider
, rNodePath
) );
89 if( xConfigAccess
.is() )
91 Reference
< XNameAccess
> xNameAccess
;
92 const Sequence
< OUString
> aNames( xConfigAccess
->getElementNames() );
93 for(const OUString
& rName
: aNames
)
95 xConfigAccess
->getByName( rName
) >>= xNameAccess
;
96 if( xNameAccess
.is() )
99 xNameAccess
->getByName( u
"Label"_ustr
) >>= aUIName
;
100 if( !aUIName
.isEmpty() )
102 rStringMap
[ rName
] = aUIName
;
108 catch (const Exception
&)
110 TOOLS_WARN_EXCEPTION( "sd", "sd::implImportLabels()" );
114 CustomAnimationPreset::CustomAnimationPreset( const CustomAnimationEffectPtr
& pEffect
)
116 maPresetId
= pEffect
->getPresetId();
117 maProperty
= pEffect
->getProperty();
121 mfDuration
= pEffect
->getDuration();
122 maDefaultSubTyp
= pEffect
->getPresetSubType();
124 const Sequence
< NamedValue
> aUserData( pEffect
->getNode()->getUserData() );
126 mbIsTextOnly
= std::any_of(aUserData
.begin(), aUserData
.end(),
127 [](const NamedValue
& rProp
) { return rProp
.Name
== "text-only"; });
130 void CustomAnimationPreset::add( const CustomAnimationEffectPtr
& pEffect
)
132 maSubTypes
[ pEffect
->getPresetSubType() ] = pEffect
;
135 std::vector
<OUString
> CustomAnimationPreset::getSubTypes()
137 std::vector
<OUString
> aSubTypes
;
139 if( maSubTypes
.size() > 1 )
141 std::transform(maSubTypes
.begin(), maSubTypes
.end(), std::back_inserter(aSubTypes
),
142 [](EffectsSubTypeMap::value_type
& rEntry
) -> OUString
{ return rEntry
.first
; });
148 Reference
< XAnimationNode
> CustomAnimationPreset::create( const OUString
& rstrSubType
)
152 OUString
strSubType( rstrSubType
);
153 if( strSubType
.isEmpty() )
154 strSubType
= maDefaultSubTyp
;
156 CustomAnimationEffectPtr pEffect
= maSubTypes
[strSubType
];
159 Reference
< XCloneable
> xCloneable( pEffect
->getNode(), UNO_QUERY_THROW
);
160 Reference
< XAnimationNode
> xNode( xCloneable
->createClone(), UNO_QUERY_THROW
);
164 catch (const Exception
&)
166 TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPresets::create()" );
169 Reference
< XAnimationNode
> xNode
;
173 std::vector
<OUString
> CustomAnimationPreset::getProperties() const
175 std::vector
<OUString
> aPropertyList
;
176 if (!maProperty
.isEmpty())
181 aPropertyList
.push_back(maProperty
.getToken(0, ';', nPos
));
185 return aPropertyList
;
188 bool CustomAnimationPreset::hasProperty( std::u16string_view rProperty
)const
190 if (maProperty
.isEmpty())
196 if (o3tl::getToken(maProperty
, 0, ';', nPos
) == rProperty
)
204 CustomAnimationPresets::CustomAnimationPresets()
208 CustomAnimationPresets::~CustomAnimationPresets()
212 Reference
< XAnimationNode
> implImportEffects( const Reference
< XMultiServiceFactory
>& xServiceFactory
, const OUString
& rPath
)
214 Reference
< XAnimationNode
> xRootNode
;
219 std::unique_ptr
<SvStream
> pIStm
= ::utl::UcbStreamHelper::CreateStream( rPath
, StreamMode::READ
);
221 // prepare ParserInputSource
222 xml::sax::InputSource aParserInput
;
223 aParserInput
.sSystemId
= rPath
;
224 aParserInput
.aInputStream
.set(new utl::OInputStreamWrapper(std::move(pIStm
)));
227 Reference
< xml::sax::XFastParser
> xFilter( xServiceFactory
->createInstance(u
"com.sun.star.comp.Xmloff.AnimationsImport"_ustr
), UNO_QUERY_THROW
);
229 xFilter
->parseStream( aParserInput
);
231 Reference
< XAnimationNodeSupplier
> xAnimationNodeSupplier( xFilter
, UNO_QUERY_THROW
);
232 xRootNode
= xAnimationNodeSupplier
->getAnimationNode();
234 catch (const Exception
&)
236 TOOLS_WARN_EXCEPTION("sd", "");
242 void CustomAnimationPresets::importEffects()
246 const uno::Reference
< uno::XComponentContext
>& xContext(
247 comphelper::getProcessComponentContext() );
248 Reference
< XMultiServiceFactory
> xServiceFactory(
249 xContext
->getServiceManager(), UNO_QUERY_THROW
);
251 Reference
< XMultiServiceFactory
> xConfigProvider
=
252 configuration::theDefaultProvider::get( xContext
);
254 // read path to transition effects files from config
255 uno::Sequence
< OUString
> aFiles
;
256 aFiles
= officecfg::Office::Impress::Misc::EffectFiles::get();
257 for (const auto& rFile
: aFiles
)
259 OUString aURL
= comphelper::getExpandedUri(xContext
, rFile
);
261 mxRootNode
= implImportEffects( xServiceFactory
, aURL
);
263 if( mxRootNode
.is() )
265 Reference
< XTimeContainer
> xRootContainer( mxRootNode
, UNO_QUERY_THROW
);
266 EffectSequenceHelper
aSequence( xRootContainer
);
268 EffectSequence::iterator
aIter( aSequence
.getBegin() );
269 const EffectSequence::iterator
aEnd( aSequence
.getEnd() );
271 while( aIter
!= aEnd
)
273 CustomAnimationEffectPtr pEffect
= *aIter
;
275 const OUString
aPresetId( pEffect
->getPresetId() );
276 CustomAnimationPresetPtr pDescriptor
= getEffectDescriptor( aPresetId
);
278 pDescriptor
->add( pEffect
);
281 pDescriptor
= std::make_shared
<CustomAnimationPreset
>( pEffect
);
282 pDescriptor
->maLabel
= getUINameForPresetId( pEffect
->getPresetId() );
283 maEffectDescriptorMap
[aPresetId
] = std::move(pDescriptor
);
291 catch (const Exception
&)
293 TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPresets::importEffects()" );
297 void CustomAnimationPresets::importResources()
301 // Get service factory
302 const Reference
< XComponentContext
>& xContext( comphelper::getProcessComponentContext() );
304 Reference
< XMultiServiceFactory
> xConfigProvider
=
305 configuration::theDefaultProvider::get( xContext
);
307 implImportLabels( xConfigProvider
, u
"/org.openoffice.Office.UI.Effects/UserInterface/Properties"_ustr
, maPropertyNameMap
);
309 implImportLabels( xConfigProvider
, u
"/org.openoffice.Office.UI.Effects/UserInterface/Effects"_ustr
, maEffectNameMap
);
313 importPresets( xConfigProvider
, u
"/org.openoffice.Office.UI.Effects/Presets/Entrance"_ustr
, maEntrancePresets
);
315 importPresets( xConfigProvider
, u
"/org.openoffice.Office.UI.Effects/Presets/Emphasis"_ustr
, maEmphasisPresets
);
317 importPresets( xConfigProvider
, u
"/org.openoffice.Office.UI.Effects/Presets/Exit"_ustr
, maExitPresets
);
319 importPresets( xConfigProvider
, u
"/org.openoffice.Office.UI.Effects/Presets/MotionPaths"_ustr
, maMotionPathsPresets
);
321 importPresets( xConfigProvider
, u
"/org.openoffice.Office.UI.Effects/Presets/Misc"_ustr
, maMiscPresets
);
323 catch (const Exception
&)
325 TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPresets::importResources()" );
329 void CustomAnimationPresets::importPresets( const Reference
< XMultiServiceFactory
>& xConfigProvider
, const OUString
& rNodePath
, PresetCategoryList
& rPresetMap
)
331 #if OSL_DEBUG_LEVEL >= 2
332 OUString aMissedPresetIds
;
337 Reference
< XNameAccess
> xTypeAccess( getNodeAccess( xConfigProvider
, rNodePath
) );
338 if( xTypeAccess
.is() )
340 Reference
< XNameAccess
> xCategoryAccess
;
342 const Sequence
< OUString
> aNames( xTypeAccess
->getElementNames() );
343 for(const OUString
& rName
: aNames
)
345 xTypeAccess
->getByName( rName
) >>= xCategoryAccess
;
347 if( xCategoryAccess
.is() && xCategoryAccess
->hasByName( u
"Label"_ustr
) && xCategoryAccess
->hasByName( u
"Effects"_ustr
) )
350 xCategoryAccess
->getByName( u
"Label"_ustr
) >>= aLabel
;
352 Sequence
< OUString
> aEffects
;
353 xCategoryAccess
->getByName( u
"Effects"_ustr
) >>= aEffects
;
355 EffectDescriptorList aEffectsList
;
357 for (const OUString
& rEffectName
: aEffects
)
359 CustomAnimationPresetPtr pEffect
= getEffectDescriptor( rEffectName
);
362 aEffectsList
.push_back( pEffect
);
364 #if OSL_DEBUG_LEVEL >= 2
367 aMissedPresetIds
+= OUString(rEffectName
);
368 aMissedPresetIds
+= "\n";
372 rPresetMap
.push_back( std::make_shared
<PresetCategory
>( aLabel
, std::move(aEffectsList
) ) );
377 catch (const Exception
&)
379 TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationPresets::importPresets()" );
382 #if OSL_DEBUG_LEVEL >= 2
383 SAL_WARN_IF(!aMissedPresetIds
.isEmpty(), "sd", "sd::CustomAnimationPresets::importPresets(), invalid preset id: "
384 << aMissedPresetIds
);
388 CustomAnimationPresetPtr
CustomAnimationPresets::getEffectDescriptor( const OUString
& rPresetId
) const
390 EffectDescriptorMap::const_iterator
aIter( maEffectDescriptorMap
.find( rPresetId
) );
392 if( aIter
!= maEffectDescriptorMap
.end() )
394 return (*aIter
).second
;
398 return CustomAnimationPresetPtr(nullptr);
402 const OUString
& CustomAnimationPresets::getUINameForPresetId( const OUString
& rPresetId
) const
404 return translateName( rPresetId
, maEffectNameMap
);
407 const OUString
& CustomAnimationPresets::getUINameForProperty( const OUString
& rPresetId
) const
409 return translateName( rPresetId
, maPropertyNameMap
);
412 const OUString
& CustomAnimationPresets::translateName( const OUString
& rId
, const UStringMap
& rNameMap
)
414 UStringMap::const_iterator
aIter( rNameMap
.find( rId
) );
416 if( aIter
!= rNameMap
.end() )
418 return (*aIter
).second
;
425 void CustomAnimationPresets::changePresetSubType( const CustomAnimationEffectPtr
& pEffect
, const OUString
& rPresetSubType
) const
427 if( pEffect
&& pEffect
->getPresetSubType() != rPresetSubType
)
429 CustomAnimationPresetPtr
pDescriptor( getEffectDescriptor( pEffect
->getPresetId() ) );
433 Reference
< XAnimationNode
> xNewNode( pDescriptor
->create( rPresetSubType
) );
435 pEffect
->replaceNode( xNewNode
);
440 std::map
<OUString
, CustomAnimationPresets
> CustomAnimationPresets::mPresetsMap
;
442 const CustomAnimationPresets
& CustomAnimationPresets::getCustomAnimationPresets()
444 // Support localization per-view. Currently not useful for Desktop
445 // but very much critical for LOK. The cache now is per-language.
446 const OUString aLang
= comphelper::LibreOfficeKit::isActive()
447 ? comphelper::LibreOfficeKit::getLanguageTag().getBcp47()
448 : SvtSysLocaleOptions().GetLanguageTag().getBcp47();
450 SolarMutexGuard aGuard
;
451 const auto it
= mPresetsMap
.find(aLang
);
452 if (it
!= mPresetsMap
.end())
455 CustomAnimationPresets
& rPresets
= mPresetsMap
[aLang
];
456 rPresets
.importResources();
460 Reference
< XAnimationNode
> CustomAnimationPresets::getRandomPreset( sal_Int16 nPresetClass
) const
462 Reference
< XAnimationNode
> xNode
;
464 const PresetCategoryList
* pCategoryList
= nullptr;
465 switch( nPresetClass
)
467 case EffectPresetClass::ENTRANCE
: pCategoryList
= &maEntrancePresets
; break;
468 case EffectPresetClass::EXIT
: pCategoryList
= &maExitPresets
; break;
469 case EffectPresetClass::EMPHASIS
: pCategoryList
= &maEmphasisPresets
; break;
470 case EffectPresetClass::MOTIONPATH
: pCategoryList
= &maMotionPathsPresets
; break;
472 pCategoryList
= nullptr;
475 if( pCategoryList
&& !pCategoryList
->empty() )
477 sal_Int32 nCategory
= comphelper::rng::uniform_size_distribution(0, pCategoryList
->size()-1);
479 PresetCategoryPtr pCategory
= (*pCategoryList
)[nCategory
];
480 if( pCategory
&& !pCategory
->maEffects
.empty() )
482 sal_Int32 nDescriptor
= comphelper::rng::uniform_size_distribution(0, pCategory
->maEffects
.size()-1);
483 CustomAnimationPresetPtr pPreset
= pCategory
->maEffects
[nDescriptor
];
486 std::vector
<OUString
> aSubTypes
= pPreset
->getSubTypes();
489 if( !aSubTypes
.empty() )
491 size_t nSubType
= comphelper::rng::uniform_size_distribution(0, aSubTypes
.size()-1);
492 aSubType
= aSubTypes
[nSubType
];
494 xNode
= pPreset
->create( aSubType
);
504 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */