cid#1607171 Data race condition
[LibreOffice.git] / framework / source / uiconfiguration / uicategorydescription.cxx
blob9b3a3b5ccca16444a876c16ecf84d1ab0e8e3bcd
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 <uielement/uicommanddescription.hxx>
22 #include <helper/mischelper.hxx>
24 #include <com/sun/star/configuration/theDefaultProvider.hpp>
25 #include <com/sun/star/container/XNameAccess.hpp>
26 #include <com/sun/star/container/XContainer.hpp>
27 #include <com/sun/star/lang/XServiceInfo.hpp>
29 #include <sal/log.hxx>
30 #include <rtl/ref.hxx>
31 #include <cppuhelper/implbase.hxx>
32 #include <cppuhelper/supportsservice.hxx>
33 #include <unotools/syslocale.hxx>
35 #include <comphelper/propertysequence.hxx>
37 #include <string_view>
38 #include <unordered_map>
40 using namespace com::sun::star::uno;
41 using namespace com::sun::star::lang;
42 using namespace com::sun::star::configuration;
43 using namespace com::sun::star::container;
44 using namespace framework;
46 namespace {
48 class ConfigurationAccess_UICategory : public ::cppu::WeakImplHelper<XNameAccess,XContainerListener>
50 std::mutex aMutex;
51 public:
52 ConfigurationAccess_UICategory( std::u16string_view aModuleName, const Reference< XNameAccess >& xGenericUICommands, const Reference< XComponentContext >& rxContext );
53 virtual ~ConfigurationAccess_UICategory() override;
55 // XNameAccess
56 virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
58 virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override;
60 virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
62 // XElementAccess
63 virtual css::uno::Type SAL_CALL getElementType() override;
65 virtual sal_Bool SAL_CALL hasElements() override;
67 // container.XContainerListener
68 virtual void SAL_CALL elementInserted( const ContainerEvent& aEvent ) override;
69 virtual void SAL_CALL elementRemoved ( const ContainerEvent& aEvent ) override;
70 virtual void SAL_CALL elementReplaced( const ContainerEvent& aEvent ) override;
72 // lang.XEventListener
73 virtual void SAL_CALL disposing( const EventObject& aEvent ) override;
75 protected:
76 Any getUINameFromID( const OUString& rId );
77 Any getUINameFromCache( const OUString& rId );
78 Sequence< OUString > getAllIds();
79 void fillCache();
81 private:
82 typedef std::unordered_map< OUString,
83 OUString > IdToInfoCache;
85 void initializeConfigAccess();
87 OUString m_aConfigCategoryAccess;
88 OUString m_aPropUIName;
89 Reference< XNameAccess > m_xGenericUICategories;
90 Reference< XMultiServiceFactory > m_xConfigProvider;
91 Reference< XNameAccess > m_xConfigAccess;
92 rtl::Reference< WeakContainerListener > m_xConfigListener;
93 bool m_bConfigAccessInitialized;
94 bool m_bCacheFilled;
95 IdToInfoCache m_aIdCache;
98 // XInterface, XTypeProvider
100 ConfigurationAccess_UICategory::ConfigurationAccess_UICategory( std::u16string_view aModuleName, const Reference< XNameAccess >& rGenericUICategories, const Reference< XComponentContext >& rxContext ) :
101 // Create configuration hierarchical access name
102 m_aConfigCategoryAccess(
103 OUString::Concat("/org.openoffice.Office.UI.") + aModuleName + "/Commands/Categories"),
104 m_aPropUIName( u"Name"_ustr ),
105 m_xGenericUICategories( rGenericUICategories ),
106 m_xConfigProvider(theDefaultProvider::get( rxContext )),
107 m_bConfigAccessInitialized( false ),
108 m_bCacheFilled( false )
112 ConfigurationAccess_UICategory::~ConfigurationAccess_UICategory()
114 // SAFE
115 std::unique_lock g(aMutex);
116 Reference< XContainer > xContainer( m_xConfigAccess, UNO_QUERY );
117 if ( xContainer.is() )
118 xContainer->removeContainerListener(m_xConfigListener);
121 // XNameAccess
122 Any SAL_CALL ConfigurationAccess_UICategory::getByName( const OUString& rId )
124 std::unique_lock g(aMutex);
125 if ( !m_bConfigAccessInitialized )
127 initializeConfigAccess();
128 m_bConfigAccessInitialized = true;
129 fillCache();
132 // SAFE
133 Any a = getUINameFromID( rId );
135 if ( !a.hasValue() )
136 throw NoSuchElementException();
138 return a;
141 Sequence< OUString > SAL_CALL ConfigurationAccess_UICategory::getElementNames()
143 return getAllIds();
146 sal_Bool SAL_CALL ConfigurationAccess_UICategory::hasByName( const OUString& rId )
148 return getByName( rId ).hasValue();
151 // XElementAccess
152 Type SAL_CALL ConfigurationAccess_UICategory::getElementType()
154 return cppu::UnoType<OUString>::get();
157 sal_Bool SAL_CALL ConfigurationAccess_UICategory::hasElements()
159 // There must be global categories!
160 return true;
163 void ConfigurationAccess_UICategory::fillCache()
165 SAL_INFO( "fwk", "framework (cd100003) ::ConfigurationAccess_UICategory::fillCache" );
167 if ( m_bCacheFilled )
168 return;
170 OUString aUIName;
171 const Sequence< OUString > aNameSeq = m_xConfigAccess->getElementNames();
173 for ( OUString const & rName : aNameSeq )
177 Reference< XNameAccess > xNameAccess(m_xConfigAccess->getByName( rName ),UNO_QUERY);
178 if ( xNameAccess.is() )
180 xNameAccess->getByName( m_aPropUIName ) >>= aUIName;
182 m_aIdCache.emplace( rName, aUIName );
185 catch ( const css::lang::WrappedTargetException& )
188 catch ( const css::container::NoSuchElementException& )
193 m_bCacheFilled = true;
196 Any ConfigurationAccess_UICategory::getUINameFromID( const OUString& rId )
198 Any a;
202 a = getUINameFromCache( rId );
203 if ( !a.hasValue() )
205 // Try to ask our global commands configuration access
206 if ( m_xGenericUICategories.is() )
210 return m_xGenericUICategories->getByName( rId );
212 catch ( const css::lang::WrappedTargetException& )
215 catch ( const css::container::NoSuchElementException& )
221 catch( const css::container::NoSuchElementException& )
224 catch ( const css::lang::WrappedTargetException& )
228 return a;
231 Any ConfigurationAccess_UICategory::getUINameFromCache( const OUString& rId )
233 Any a;
235 IdToInfoCache::const_iterator pIter = m_aIdCache.find( rId );
236 if ( pIter != m_aIdCache.end() )
237 a <<= pIter->second;
239 return a;
242 Sequence< OUString > ConfigurationAccess_UICategory::getAllIds()
244 // SAFE
245 std::unique_lock g(aMutex);
247 if ( !m_bConfigAccessInitialized )
249 initializeConfigAccess();
250 m_bConfigAccessInitialized = true;
251 fillCache();
254 if ( m_xConfigAccess.is() )
258 Sequence< OUString > aNameSeq = m_xConfigAccess->getElementNames();
260 if ( m_xGenericUICategories.is() )
262 // Create concat list of supported user interface commands of the module
263 Sequence< OUString > aGenericNameSeq = m_xGenericUICategories->getElementNames();
264 sal_uInt32 nCount1 = aNameSeq.getLength();
265 sal_uInt32 nCount2 = aGenericNameSeq.getLength();
267 aNameSeq.realloc( nCount1 + nCount2 );
268 OUString* pNameSeq = aNameSeq.getArray();
269 const OUString* pGenericSeq = aGenericNameSeq.getConstArray();
270 for ( sal_uInt32 i = 0; i < nCount2; i++ )
271 pNameSeq[nCount1+i] = pGenericSeq[i];
274 return aNameSeq;
276 catch( const css::container::NoSuchElementException& )
279 catch ( const css::lang::WrappedTargetException& )
284 return Sequence< OUString >();
287 void ConfigurationAccess_UICategory::initializeConfigAccess()
291 Sequence<Any> aArgs(comphelper::InitAnyPropertySequence(
293 {"nodepath", Any(m_aConfigCategoryAccess)}
294 }));
296 m_xConfigAccess.set( m_xConfigProvider->createInstanceWithArguments(
297 u"com.sun.star.configuration.ConfigurationAccess"_ustr, aArgs ),UNO_QUERY );
298 if ( m_xConfigAccess.is() )
300 // Add as container listener
301 Reference< XContainer > xContainer( m_xConfigAccess, UNO_QUERY );
302 if ( xContainer.is() )
304 m_xConfigListener = new WeakContainerListener(this);
305 xContainer->addContainerListener(m_xConfigListener);
309 catch ( const WrappedTargetException& )
312 catch ( const Exception& )
317 // container.XContainerListener
318 void SAL_CALL ConfigurationAccess_UICategory::elementInserted( const ContainerEvent& )
322 void SAL_CALL ConfigurationAccess_UICategory::elementRemoved ( const ContainerEvent& )
326 void SAL_CALL ConfigurationAccess_UICategory::elementReplaced( const ContainerEvent& )
330 // lang.XEventListener
331 void SAL_CALL ConfigurationAccess_UICategory::disposing( const EventObject& aEvent )
333 // SAFE
334 // remove our reference to the config access
335 std::unique_lock g(aMutex);
337 Reference< XInterface > xIfac1( aEvent.Source, UNO_QUERY );
338 Reference< XInterface > xIfac2( m_xConfigAccess, UNO_QUERY );
339 if ( xIfac1 == xIfac2 )
340 m_xConfigAccess.clear();
343 class UICategoryDescription : public UICommandDescription
345 public:
346 explicit UICategoryDescription( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
348 virtual OUString SAL_CALL getImplementationName() override
350 return u"com.sun.star.comp.framework.UICategoryDescription"_ustr;
353 virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
355 return cppu::supportsService(this, ServiceName);
358 virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
360 return {u"com.sun.star.ui.UICategoryDescription"_ustr};
365 UICategoryDescription::UICategoryDescription( const Reference< XComponentContext >& rxContext ) :
366 UICommandDescription(rxContext,true)
368 SvtSysLocale aSysLocale;
369 const LanguageTag& rCurrentLanguage = aSysLocale.GetUILanguageTag();
370 Reference< XNameAccess > xEmpty;
371 OUString aGenericCategories( u"GenericCategories"_ustr );
372 m_xGenericUICommands[rCurrentLanguage] = new ConfigurationAccess_UICategory( aGenericCategories, xEmpty, rxContext );
374 // insert generic categories mappings
375 m_aModuleToCommandFileMap.emplace( u"generic"_ustr, aGenericCategories );
377 auto& rMap = m_aUICommandsHashMap[rCurrentLanguage];
378 UICommandsHashMap::iterator pCatIter = rMap.find( aGenericCategories );
379 if ( pCatIter != rMap.end() )
380 pCatIter->second = m_xGenericUICommands[rCurrentLanguage];
382 impl_fillElements("ooSetupFactoryCmdCategoryConfigRef");
387 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
388 com_sun_star_comp_framework_UICategoryDescription_get_implementation(
389 css::uno::XComponentContext *context,
390 css::uno::Sequence<css::uno::Any> const &)
392 return cppu::acquire(new UICategoryDescription(context));
395 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */