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/io/IOException.hpp>
23 #include <com/sun/star/util/XCloneable.hpp>
24 #include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
25 #include <com/sun/star/container/XNameAccess.hpp>
26 #include <com/sun/star/configuration/theDefaultProvider.hpp>
27 #include <com/sun/star/xml/sax/InputSource.hpp>
28 #include <com/sun/star/xml/sax/Parser.hpp>
29 #include <com/sun/star/xml/sax/SAXParseException.hpp>
30 #include <com/sun/star/presentation/EffectPresetClass.hpp>
31 #include <com/sun/star/beans/NamedValue.hpp>
32 #include <osl/diagnose.h>
33 #include <unotools/streamwrap.hxx>
34 #include <comphelper/getexpandeduri.hxx>
35 #include <comphelper/processfactory.hxx>
36 #include <comphelper/propertysequence.hxx>
37 #include <comphelper/random.hxx>
38 #include <comphelper/lok.hxx>
39 #include <unotools/pathoptions.hxx>
40 #include <unotools/syslocaleoptions.hxx>
41 #include <tools/stream.hxx>
43 #include <tools/debug.hxx>
44 #include <vcl/svapp.hxx>
45 #include <unotools/ucbstreamhelper.hxx>
46 #include <CustomAnimationPreset.hxx>
51 using namespace ::com::sun::star
;
52 using namespace ::com::sun::star::uno
;
53 using namespace ::com::sun::star::animations
;
54 using namespace ::com::sun::star::presentation
;
56 using ::com::sun::star::io::XInputStream
;
57 using ::com::sun::star::lang::XMultiServiceFactory
;
58 using ::com::sun::star::container::XNameAccess
;
59 using ::com::sun::star::util::XCloneable
;
60 using ::com::sun::star::beans::NamedValue
;
64 static Reference
< XNameAccess
> getNodeAccess( const Reference
< XMultiServiceFactory
>& xConfigProvider
, const OUString
& rNodePath
)
66 Reference
< XNameAccess
> xConfigAccess
;
70 Sequence
<Any
> aArgs(comphelper::InitAnyPropertySequence(
72 {"nodepath", uno::Any(rNodePath
)}
76 xConfigProvider
->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", aArgs
),
79 catch (const Exception
&)
81 OSL_FAIL( "sd::getNodeAccess(), Exception caught!" );
87 void implImportLabels( const Reference
< XMultiServiceFactory
>& xConfigProvider
, const OUString
& rNodePath
, UStringMap
& rStringMap
)
91 Reference
< XNameAccess
> xConfigAccess( getNodeAccess( xConfigProvider
, rNodePath
) );
92 if( xConfigAccess
.is() )
94 Reference
< XNameAccess
> xNameAccess
;
95 const Sequence
< OUString
> aNames( xConfigAccess
->getElementNames() );
96 for(const OUString
& rName
: aNames
)
98 xConfigAccess
->getByName( rName
) >>= xNameAccess
;
99 if( xNameAccess
.is() )
102 xNameAccess
->getByName( "Label" ) >>= aUIName
;
103 if( !aUIName
.isEmpty() )
105 rStringMap
[ rName
] = aUIName
;
111 catch (const lang::WrappedTargetException
&)
113 OSL_FAIL( "sd::implImportLabels(), WrappedTargetException caught!" );
115 catch (const Exception
&)
117 OSL_FAIL( "sd::implImportLabels(), Exception caught!" );
121 CustomAnimationPreset::CustomAnimationPreset( const CustomAnimationEffectPtr
& pEffect
)
123 maPresetId
= pEffect
->getPresetId();
124 maProperty
= pEffect
->getProperty();
128 mfDuration
= pEffect
->getDuration();
129 maDefaultSubTyp
= pEffect
->getPresetSubType();
131 Sequence
< NamedValue
> aUserData( pEffect
->getNode()->getUserData() );
133 mbIsTextOnly
= std::any_of(aUserData
.begin(), aUserData
.end(),
134 [](const NamedValue
& rProp
) { return rProp
.Name
== "text-only"; });
137 void CustomAnimationPreset::add( const CustomAnimationEffectPtr
& pEffect
)
139 maSubTypes
[ pEffect
->getPresetSubType() ] = pEffect
;
142 std::vector
<OUString
> CustomAnimationPreset::getSubTypes()
144 std::vector
<OUString
> aSubTypes
;
146 if( maSubTypes
.size() > 1 )
148 std::transform(maSubTypes
.begin(), maSubTypes
.end(), std::back_inserter(aSubTypes
),
149 [](EffectsSubTypeMap::value_type
& rEntry
) -> OUString
{ return rEntry
.first
; });
155 Reference
< XAnimationNode
> CustomAnimationPreset::create( const OUString
& rstrSubType
)
159 OUString
strSubType( rstrSubType
);
160 if( strSubType
.isEmpty() )
161 strSubType
= maDefaultSubTyp
;
163 CustomAnimationEffectPtr pEffect
= maSubTypes
[strSubType
];
166 Reference
< XCloneable
> xCloneable( pEffect
->getNode(), UNO_QUERY_THROW
);
167 Reference
< XAnimationNode
> xNode( xCloneable
->createClone(), UNO_QUERY_THROW
);
171 catch (const Exception
&)
173 OSL_FAIL( "sd::CustomAnimationPresets::create(), exception caught!" );
176 Reference
< XAnimationNode
> xNode
;
180 std::vector
<OUString
> CustomAnimationPreset::getProperties() const
182 std::vector
<OUString
> aPropertyList
;
183 if (!maProperty
.isEmpty())
188 aPropertyList
.push_back(maProperty
.getToken(0, ';', nPos
));
192 return aPropertyList
;
195 bool CustomAnimationPreset::hasProperty( const OUString
& rProperty
)const
197 if (maProperty
.isEmpty())
203 if (maProperty
.getToken(0, ';', nPos
) == rProperty
)
211 CustomAnimationPresets::CustomAnimationPresets()
215 CustomAnimationPresets::~CustomAnimationPresets()
219 Reference
< XAnimationNode
> implImportEffects( const Reference
< XMultiServiceFactory
>& xServiceFactory
, const OUString
& rPath
)
221 Reference
< XAnimationNode
> xRootNode
;
226 std::unique_ptr
<SvStream
> pIStm
= ::utl::UcbStreamHelper::CreateStream( rPath
, StreamMode::READ
);
227 Reference
<XInputStream
> xInputStream( new utl::OInputStreamWrapper( std::move(pIStm
) ) );
229 // prepare ParserInputSrouce
230 xml::sax::InputSource aParserInput
;
231 aParserInput
.sSystemId
= rPath
;
232 aParserInput
.aInputStream
= xInputStream
;
235 Reference
< xml::sax::XParser
> xParser
= xml::sax::Parser::create( comphelper::getComponentContext(xServiceFactory
) );
238 Reference
< xml::sax::XDocumentHandler
> xFilter( xServiceFactory
->createInstance("com.sun.star.comp.Xmloff.AnimationsImport" ), UNO_QUERY
);
240 DBG_ASSERT( xFilter
.is(), "Can't instantiate filter component." );
244 // connect parser and filter
245 xParser
->setDocumentHandler( xFilter
);
247 // finally, parser the stream
248 xParser
->parseStream( aParserInput
);
250 Reference
< XAnimationNodeSupplier
> xAnimationNodeSupplier( xFilter
, UNO_QUERY
);
251 if( xAnimationNodeSupplier
.is() )
252 xRootNode
= xAnimationNodeSupplier
->getAnimationNode();
254 catch (const xml::sax::SAXParseException
&)
256 OSL_FAIL( "sd::implImportEffects(), SAXParseException caught!" );
258 catch (const xml::sax::SAXException
&)
260 OSL_FAIL( "sd::implImportEffects(), SAXException caught!" );
262 catch (const io::IOException
&)
264 OSL_FAIL( "sd::implImportEffects(), IOException caught!" );
266 catch (const Exception
&)
268 OSL_FAIL( "sd::importEffects(), Exception caught!" );
274 void CustomAnimationPresets::importEffects()
278 uno::Reference
< uno::XComponentContext
> xContext(
279 comphelper::getProcessComponentContext() );
280 Reference
< XMultiServiceFactory
> xServiceFactory(
281 xContext
->getServiceManager(), UNO_QUERY_THROW
);
283 Reference
< XMultiServiceFactory
> xConfigProvider
=
284 configuration::theDefaultProvider::get( xContext
);
286 // read path to transition effects files from config
287 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
289 {"nodepath", uno::Any(OUString("/org.openoffice.Office.Impress/Misc"))}
291 Reference
<container::XNameAccess
> xNameAccess(
292 xConfigProvider
->createInstanceWithArguments(
293 "com.sun.star.configuration.ConfigurationAccess",
294 aArgs
), UNO_QUERY_THROW
);
295 uno::Sequence
< OUString
> aFiles
;
296 xNameAccess
->getByName( "EffectFiles" ) >>= aFiles
;
298 for( const auto& rFile
: std::as_const(aFiles
) )
300 OUString aURL
= comphelper::getExpandedUri(xContext
, rFile
);
302 mxRootNode
= implImportEffects( xServiceFactory
, aURL
);
304 if( mxRootNode
.is() )
306 Reference
< XTimeContainer
> xRootContainer( mxRootNode
, UNO_QUERY_THROW
);
307 EffectSequenceHelper
aSequence( xRootContainer
);
309 EffectSequence::iterator
aIter( aSequence
.getBegin() );
310 const EffectSequence::iterator
aEnd( aSequence
.getEnd() );
312 while( aIter
!= aEnd
)
314 CustomAnimationEffectPtr pEffect
= *aIter
;
316 const OUString
aPresetId( pEffect
->getPresetId() );
317 CustomAnimationPresetPtr pDescriptor
= getEffectDescriptor( aPresetId
);
318 if( pDescriptor
.get() )
319 pDescriptor
->add( pEffect
);
322 pDescriptor
.reset( new CustomAnimationPreset( pEffect
) );
323 pDescriptor
->maLabel
= getUINameForPresetId( pEffect
->getPresetId() );
324 maEffectDiscriptorMap
[aPresetId
] = pDescriptor
;
332 catch (const xml::sax::SAXParseException
&)
334 OSL_FAIL( "sd::CustomAnimationPresets::importEffects(), SAXParseException caught!" );
336 catch (const xml::sax::SAXException
&)
338 OSL_FAIL( "sd::CustomAnimationPresets::importEffects(), SAXException caught!" );
340 catch (const io::IOException
&)
342 OSL_FAIL( "sd::CustomAnimationPresets::importEffects(), IOException caught!" );
344 catch (const Exception
&)
346 OSL_FAIL( "sd::CustomAnimationPresets::importEffects(), Exception caught!" );
350 void CustomAnimationPresets::importResources()
354 // Get service factory
355 Reference
< XComponentContext
> xContext( comphelper::getProcessComponentContext() );
357 Reference
< XMultiServiceFactory
> xConfigProvider
=
358 configuration::theDefaultProvider::get( xContext
);
360 const OUString
aPropertyPath("/org.openoffice.Office.UI.Effects/UserInterface/Properties" );
361 implImportLabels( xConfigProvider
, aPropertyPath
, maPropertyNameMap
);
363 const OUString
aEffectsPath( "/org.openoffice.Office.UI.Effects/UserInterface/Effects" );
364 implImportLabels( xConfigProvider
, aEffectsPath
, maEffectNameMap
);
368 const OUString
aEntrancePath( "/org.openoffice.Office.UI.Effects/Presets/Entrance" );
369 importPresets( xConfigProvider
, aEntrancePath
, maEntrancePresets
);
371 const OUString
aEmphasisPath( "/org.openoffice.Office.UI.Effects/Presets/Emphasis" );
372 importPresets( xConfigProvider
, aEmphasisPath
, maEmphasisPresets
);
374 const OUString
aExitPath( "/org.openoffice.Office.UI.Effects/Presets/Exit" );
375 importPresets( xConfigProvider
, aExitPath
, maExitPresets
);
377 const OUString
aMotionPathsPath( "/org.openoffice.Office.UI.Effects/Presets/MotionPaths" );
378 importPresets( xConfigProvider
, aMotionPathsPath
, maMotionPathsPresets
);
380 const OUString
aMiscPath( "/org.openoffice.Office.UI.Effects/Presets/Misc" );
381 importPresets( xConfigProvider
, aMiscPath
, maMiscPresets
);
383 catch (const lang::WrappedTargetException
&)
385 OSL_FAIL( "sd::CustomAnimationPresets::importResources(), WrappedTargetException caught!" );
387 catch (const Exception
&)
389 OSL_FAIL( "sd::CustomAnimationPresets::importResources(), Exception caught!" );
393 void CustomAnimationPresets::importPresets( const Reference
< XMultiServiceFactory
>& xConfigProvider
, const OUString
& rNodePath
, PresetCategoryList
& rPresetMap
)
396 OUString aMissedPresetIds
;
401 Reference
< XNameAccess
> xTypeAccess( getNodeAccess( xConfigProvider
, rNodePath
) );
402 if( xTypeAccess
.is() )
404 Reference
< XNameAccess
> xCategoryAccess
;
406 const Sequence
< OUString
> aNames( xTypeAccess
->getElementNames() );
407 for(const OUString
& rName
: aNames
)
409 xTypeAccess
->getByName( rName
) >>= xCategoryAccess
;
411 if( xCategoryAccess
.is() && xCategoryAccess
->hasByName( "Label" ) && xCategoryAccess
->hasByName( "Effects" ) )
414 xCategoryAccess
->getByName( "Label" ) >>= aLabel
;
416 Sequence
< OUString
> aEffects
;
417 xCategoryAccess
->getByName( "Effects" ) >>= aEffects
;
419 EffectDescriptorList aEffectsList
;
421 for( const OUString
& rEffectName
: std::as_const(aEffects
) )
423 CustomAnimationPresetPtr pEffect
= getEffectDescriptor( rEffectName
);
426 aEffectsList
.push_back( pEffect
);
431 aMissedPresetIds
+= OUString(rEffectName
);
432 aMissedPresetIds
+= "\n";
436 rPresetMap
.push_back( std::make_shared
<PresetCategory
>( aLabel
, aEffectsList
) );
441 catch (const Exception
&)
443 OSL_FAIL( "sd::CustomAnimationPresets::importPresets(), Exception caught!" );
447 SAL_WARN_IF(!aMissedPresetIds
.isEmpty(), "sd", "sd::CustomAnimationPresets::importPresets(), invalid preset id: "
448 << aMissedPresetIds
);
452 CustomAnimationPresetPtr
CustomAnimationPresets::getEffectDescriptor( const OUString
& rPresetId
) const
454 EffectDescriptorMap::const_iterator
aIter( maEffectDiscriptorMap
.find( rPresetId
) );
456 if( aIter
!= maEffectDiscriptorMap
.end() )
458 return (*aIter
).second
;
462 return CustomAnimationPresetPtr(nullptr);
466 const OUString
& CustomAnimationPresets::getUINameForPresetId( const OUString
& rPresetId
) const
468 return translateName( rPresetId
, maEffectNameMap
);
471 const OUString
& CustomAnimationPresets::getUINameForProperty( const OUString
& rPresetId
) const
473 return translateName( rPresetId
, maPropertyNameMap
);
476 const OUString
& CustomAnimationPresets::translateName( const OUString
& rId
, const UStringMap
& rNameMap
)
478 UStringMap::const_iterator
aIter( rNameMap
.find( rId
) );
480 if( aIter
!= rNameMap
.end() )
482 return (*aIter
).second
;
489 void CustomAnimationPresets::changePresetSubType( const CustomAnimationEffectPtr
& pEffect
, const OUString
& rPresetSubType
) const
491 if( pEffect
.get() && pEffect
->getPresetSubType() != rPresetSubType
)
493 CustomAnimationPresetPtr
pDescriptor( getEffectDescriptor( pEffect
->getPresetId() ) );
495 if( pDescriptor
.get() )
497 Reference
< XAnimationNode
> xNewNode( pDescriptor
->create( rPresetSubType
) );
499 pEffect
->replaceNode( xNewNode
);
504 std::map
<OUString
, CustomAnimationPresets
> CustomAnimationPresets::mPresetsMap
;
506 const CustomAnimationPresets
& CustomAnimationPresets::getCustomAnimationPresets()
508 // Support localization per-view. Currently not useful for Desktop
509 // but very much critical for LOK. The cache now is per-language.
510 const OUString aLang
= comphelper::LibreOfficeKit::isActive()
511 ? comphelper::LibreOfficeKit::getLanguageTag().getLanguage()
512 : SvtSysLocaleOptions().GetLanguageTag().getLanguage();
514 SolarMutexGuard aGuard
;
515 const auto it
= mPresetsMap
.find(aLang
);
516 if (it
!= mPresetsMap
.end())
519 CustomAnimationPresets
& rPresets
= mPresetsMap
[aLang
];
520 rPresets
.importResources();
524 Reference
< XAnimationNode
> CustomAnimationPresets::getRandomPreset( sal_Int16 nPresetClass
) const
526 Reference
< XAnimationNode
> xNode
;
528 const PresetCategoryList
* pCategoryList
= nullptr;
529 switch( nPresetClass
)
531 case EffectPresetClass::ENTRANCE
: pCategoryList
= &maEntrancePresets
; break;
532 case EffectPresetClass::EXIT
: pCategoryList
= &maExitPresets
; break;
533 case EffectPresetClass::EMPHASIS
: pCategoryList
= &maEmphasisPresets
; break;
534 case EffectPresetClass::MOTIONPATH
: pCategoryList
= &maMotionPathsPresets
; break;
536 pCategoryList
= nullptr;
539 if( pCategoryList
&& !pCategoryList
->empty() )
541 sal_Int32 nCategory
= comphelper::rng::uniform_size_distribution(0, pCategoryList
->size()-1);
543 PresetCategoryPtr pCategory
= (*pCategoryList
)[nCategory
];
544 if( pCategory
.get() && !pCategory
->maEffects
.empty() )
546 sal_Int32 nDescriptor
= comphelper::rng::uniform_size_distribution(0, pCategory
->maEffects
.size()-1);
547 CustomAnimationPresetPtr pPreset
= pCategory
->maEffects
[nDescriptor
];
550 std::vector
<OUString
> aSubTypes
= pPreset
->getSubTypes();
553 if( !aSubTypes
.empty() )
555 size_t nSubType
= comphelper::rng::uniform_size_distribution(0, aSubTypes
.size()-1);
556 aSubType
= aSubTypes
[nSubType
];
558 xNode
= pPreset
->create( aSubType
);
568 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */