loplugin:sequenceloop in sd
[LibreOffice.git] / sd / source / core / CustomAnimationPreset.cxx
blobb068fe1ff7d34011b919a1f60c0fe989d0b5bdf2
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 .
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>
48 #include <algorithm>
49 #include <vector>
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;
62 namespace sd {
64 static Reference< XNameAccess > getNodeAccess( const Reference< XMultiServiceFactory >& xConfigProvider, const OUString& rNodePath )
66 Reference< XNameAccess > xConfigAccess;
68 try
70 Sequence<Any> aArgs(comphelper::InitAnyPropertySequence(
72 {"nodepath", uno::Any(rNodePath)}
73 }));
75 xConfigAccess.set(
76 xConfigProvider->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", aArgs ),
77 UNO_QUERY);
79 catch (const Exception&)
81 OSL_FAIL( "sd::getNodeAccess(), Exception caught!" );
84 return xConfigAccess;
87 void implImportLabels( const Reference< XMultiServiceFactory >& xConfigProvider, const OUString& rNodePath, UStringMap& rStringMap )
89 try
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() )
101 OUString aUIName;
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();
126 add( pEffect );
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; });
152 return aSubTypes;
155 Reference< XAnimationNode > CustomAnimationPreset::create( const OUString& rstrSubType )
159 OUString strSubType( rstrSubType );
160 if( strSubType.isEmpty() )
161 strSubType = maDefaultSubTyp;
163 CustomAnimationEffectPtr pEffect = maSubTypes[strSubType];
164 if( pEffect.get() )
166 Reference< XCloneable > xCloneable( pEffect->getNode(), UNO_QUERY_THROW );
167 Reference< XAnimationNode > xNode( xCloneable->createClone(), UNO_QUERY_THROW );
168 return xNode;
171 catch (const Exception&)
173 OSL_FAIL( "sd::CustomAnimationPresets::create(), exception caught!" );
176 Reference< XAnimationNode > xNode;
177 return xNode;
180 std::vector<OUString> CustomAnimationPreset::getProperties() const
182 std::vector<OUString> aPropertyList;
183 if (!maProperty.isEmpty())
185 sal_Int32 nPos = 0;
188 aPropertyList.push_back(maProperty.getToken(0, ';', nPos));
190 while (nPos >= 0);
192 return aPropertyList;
195 bool CustomAnimationPreset::hasProperty( const OUString& rProperty )const
197 if (maProperty.isEmpty())
198 return false;
200 sal_Int32 nPos = 0;
203 if (maProperty.getToken(0, ';', nPos) == rProperty)
204 return true;
206 while (nPos >= 0);
208 return false;
211 CustomAnimationPresets::CustomAnimationPresets()
215 CustomAnimationPresets::~CustomAnimationPresets()
219 Reference< XAnimationNode > implImportEffects( const Reference< XMultiServiceFactory >& xServiceFactory, const OUString& rPath )
221 Reference< XAnimationNode > xRootNode;
225 // create stream
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;
234 // get parser
235 Reference< xml::sax::XParser > xParser = xml::sax::Parser::create( comphelper::getComponentContext(xServiceFactory) );
237 // get filter
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." );
241 if( !xFilter.is() )
242 return xRootNode;
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!" );
271 return xRootNode;
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"))}
290 }));
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 );
320 else
322 pDescriptor.reset( new CustomAnimationPreset( pEffect ) );
323 pDescriptor->maLabel = getUINameForPresetId( pEffect->getPresetId() );
324 maEffectDiscriptorMap[aPresetId] = pDescriptor;
327 ++aIter;
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 );
366 importEffects();
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 )
395 #ifdef DEBUG
396 OUString aMissedPresetIds;
397 #endif
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" ) )
413 OUString aLabel;
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 );
424 if( pEffect.get() )
426 aEffectsList.push_back( pEffect );
428 #ifdef DEBUG
429 else
431 aMissedPresetIds += OUString(rEffectName);
432 aMissedPresetIds += "\n";
434 #endif
436 rPresetMap.push_back( std::make_shared<PresetCategory>( aLabel, aEffectsList ) );
441 catch (const Exception&)
443 OSL_FAIL( "sd::CustomAnimationPresets::importPresets(), Exception caught!" );
446 #ifdef DEBUG
447 SAL_WARN_IF(!aMissedPresetIds.isEmpty(), "sd", "sd::CustomAnimationPresets::importPresets(), invalid preset id: "
448 << aMissedPresetIds);
449 #endif
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;
460 else
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;
484 else
486 return rId;
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 ) );
498 if( xNewNode.is() )
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())
517 return it->second;
519 CustomAnimationPresets& rPresets = mPresetsMap[aLang];
520 rPresets.importResources();
521 return rPresets;
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;
535 default:
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];
548 if( pPreset.get() )
550 std::vector<OUString> aSubTypes = pPreset->getSubTypes();
552 OUString aSubType;
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 );
563 return xNode;
568 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */