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 <uifactory/configurationaccessfactorymanager.hxx>
23 #include <helper/mischelper.hxx>
25 #include <com/sun/star/beans/PropertyValue.hpp>
26 #include <com/sun/star/beans/XPropertySet.hpp>
27 #include <com/sun/star/configuration/theDefaultProvider.hpp>
28 #include <com/sun/star/container/XContainer.hpp>
29 #include <com/sun/star/container/XContainerListener.hpp>
30 #include <com/sun/star/lang/XServiceInfo.hpp>
31 #include <com/sun/star/loader/CannotActivateFactoryException.hpp>
32 #include <com/sun/star/frame/ModuleManager.hpp>
33 #include <com/sun/star/frame/XFrame.hpp>
34 #include <com/sun/star/frame/XModuleManager2.hpp>
35 #include <com/sun/star/ui/XUIElementFactoryManager.hpp>
37 #include <rtl/ustrbuf.hxx>
38 #include <cppuhelper/basemutex.hxx>
39 #include <cppuhelper/compbase2.hxx>
40 #include <cppuhelper/supportsservice.hxx>
41 #include <vcl/svapp.hxx>
43 using namespace com::sun::star::uno
;
44 using namespace com::sun::star::lang
;
45 using namespace com::sun::star::beans
;
46 using namespace com::sun::star::frame
;
47 using namespace com::sun::star::configuration
;
48 using namespace com::sun::star::container
;
49 using namespace ::com::sun::star::ui
;
50 using namespace ::com::sun::star::frame
;
51 using namespace framework
;
56 // global function needed by both implementations
57 static OUString
getHashKeyFromStrings( const OUString
& aType
, const OUString
& aName
, const OUString
& aModuleName
)
59 OUStringBuffer
aKey( aType
);
60 aKey
.appendAscii( "^" );
62 aKey
.appendAscii( "^" );
63 aKey
.append( aModuleName
);
64 return aKey
.makeStringAndClear();
67 ConfigurationAccess_FactoryManager::ConfigurationAccess_FactoryManager( const Reference
< XComponentContext
>& rxContext
, const OUString
& _sRoot
) :
68 m_aPropType( "Type" ),
69 m_aPropName( "Name" ),
70 m_aPropModule( "Module" ),
71 m_aPropFactory( "FactoryImplementation" ),
73 m_bConfigAccessInitialized( false )
75 m_xConfigProvider
= theDefaultProvider::get( rxContext
);
78 ConfigurationAccess_FactoryManager::~ConfigurationAccess_FactoryManager()
81 osl::MutexGuard
g(m_aMutex
);
83 Reference
< XContainer
> xContainer( m_xConfigAccess
, UNO_QUERY
);
84 if ( xContainer
.is() )
85 xContainer
->removeContainerListener(m_xConfigListener
);
88 OUString
ConfigurationAccess_FactoryManager::getFactorySpecifierFromTypeNameModule( const OUString
& rType
, const OUString
& rName
, const OUString
& rModule
) const
91 osl::MutexGuard
g(m_aMutex
);
93 FactoryManagerMap::const_iterator pIter
=
94 m_aFactoryManagerMap
.find( getHashKeyFromStrings( rType
, rName
, rModule
));
95 if ( pIter
!= m_aFactoryManagerMap
.end() )
99 pIter
= m_aFactoryManagerMap
.find( getHashKeyFromStrings( rType
, rName
, OUString() ));
100 if ( pIter
!= m_aFactoryManagerMap
.end() )
101 return pIter
->second
;
104 // Support factories which uses a defined prefix before the ui name.
105 sal_Int32 nIndex
= rName
.indexOf( '_' );
108 OUString aName
= rName
.copy( 0, nIndex
+1 );
109 pIter
= m_aFactoryManagerMap
.find( getHashKeyFromStrings( rType
, aName
, OUString() ));
110 if ( pIter
!= m_aFactoryManagerMap
.end() )
111 return pIter
->second
;
114 pIter
= m_aFactoryManagerMap
.find( getHashKeyFromStrings( rType
, OUString(), OUString() ));
115 if ( pIter
!= m_aFactoryManagerMap
.end() )
116 return pIter
->second
;
123 void ConfigurationAccess_FactoryManager::addFactorySpecifierToTypeNameModule( const OUString
& rType
, const OUString
& rName
, const OUString
& rModule
, const OUString
& rServiceSpecifier
)
126 osl::MutexGuard
g(m_aMutex
);
128 OUString aHashKey
= getHashKeyFromStrings( rType
, rName
, rModule
);
130 FactoryManagerMap::const_iterator pIter
= m_aFactoryManagerMap
.find( aHashKey
);
132 if ( pIter
!= m_aFactoryManagerMap
.end() )
133 throw ElementExistException();
135 m_aFactoryManagerMap
.insert( FactoryManagerMap::value_type( aHashKey
, rServiceSpecifier
));
138 void ConfigurationAccess_FactoryManager::removeFactorySpecifierFromTypeNameModule( const OUString
& rType
, const OUString
& rName
, const OUString
& rModule
)
141 osl::MutexGuard
g(m_aMutex
);
143 OUString aHashKey
= getHashKeyFromStrings( rType
, rName
, rModule
);
145 FactoryManagerMap::const_iterator pIter
= m_aFactoryManagerMap
.find( aHashKey
);
147 if ( pIter
== m_aFactoryManagerMap
.end() )
148 throw NoSuchElementException();
150 m_aFactoryManagerMap
.erase( aHashKey
);
153 Sequence
< Sequence
< PropertyValue
> > ConfigurationAccess_FactoryManager::getFactoriesDescription() const
156 osl::MutexGuard
g(m_aMutex
);
158 Sequence
< Sequence
< PropertyValue
> > aSeqSeq
;
160 sal_Int32
nIndex( 0 );
161 FactoryManagerMap::const_iterator pIter
= m_aFactoryManagerMap
.begin();
162 while ( pIter
!= m_aFactoryManagerMap
.end() )
164 OUString aFactory
= pIter
->first
;
165 if ( !aFactory
.isEmpty() )
167 sal_Int32 nToken
= 0;
168 Sequence
< PropertyValue
> aSeq( 1 );
170 aSeqSeq
.realloc( aSeqSeq
.getLength() + 1 );
171 aSeq
[0].Name
= m_aPropType
;
172 aSeq
[0].Value
= makeAny( aFactory
.getToken( 0, '^', nToken
));
176 aSeq
[1].Name
= m_aPropName
;
177 aSeq
[1].Value
= makeAny( aFactory
.getToken( 0, '^', nToken
));
181 aSeq
[2].Name
= m_aPropModule
;
182 aSeq
[2].Value
= makeAny( aFactory
.getToken( 0, '^', nToken
));
186 aSeqSeq
[nIndex
++] = aSeq
;
195 // container.XContainerListener
196 void SAL_CALL
ConfigurationAccess_FactoryManager::elementInserted( const ContainerEvent
& aEvent
) throw(RuntimeException
, std::exception
)
204 osl::MutexGuard
g(m_aMutex
);
206 if ( impl_getElementProps( aEvent
.Element
, aType
, aName
, aModule
, aService
))
208 // Create hash key from type, name and module as they are together a primary key to
209 // the UNO service that implements a user interface factory.
210 OUString
aHashKey( getHashKeyFromStrings( aType
, aName
, aModule
));
211 m_aFactoryManagerMap
.insert( FactoryManagerMap::value_type( aHashKey
, aService
));
215 void SAL_CALL
ConfigurationAccess_FactoryManager::elementRemoved ( const ContainerEvent
& aEvent
) throw(RuntimeException
, std::exception
)
223 osl::MutexGuard
g(m_aMutex
);
225 if ( impl_getElementProps( aEvent
.Element
, aType
, aName
, aModule
, aService
))
227 // Create hash key from command and model as they are together a primary key to
228 // the UNO service that implements the popup menu controller.
229 OUString
aHashKey( getHashKeyFromStrings( aType
, aName
, aModule
));
230 m_aFactoryManagerMap
.erase( aHashKey
);
234 void SAL_CALL
ConfigurationAccess_FactoryManager::elementReplaced( const ContainerEvent
& aEvent
) throw(RuntimeException
, std::exception
)
242 osl::MutexGuard
g(m_aMutex
);
244 if ( impl_getElementProps( aEvent
.Element
, aType
, aName
, aModule
, aService
))
246 // Create hash key from command and model as they are together a primary key to
247 // the UNO service that implements the popup menu controller.
248 OUString
aHashKey( getHashKeyFromStrings( aType
, aName
, aModule
));
249 m_aFactoryManagerMap
.erase( aHashKey
);
250 m_aFactoryManagerMap
.insert( FactoryManagerMap::value_type( aHashKey
, aService
));
254 // lang.XEventListener
255 void SAL_CALL
ConfigurationAccess_FactoryManager::disposing( const EventObject
& ) throw(RuntimeException
, std::exception
)
258 // remove our reference to the config access
259 osl::MutexGuard
g(m_aMutex
);
260 m_xConfigAccess
.clear();
263 void ConfigurationAccess_FactoryManager::readConfigurationData()
266 osl::MutexGuard
g(m_aMutex
);
268 if ( !m_bConfigAccessInitialized
)
270 Sequence
< Any
> aArgs( 1 );
271 PropertyValue aPropValue
;
273 aPropValue
.Name
= "nodepath";
274 aPropValue
.Value
<<= m_sRoot
;
275 aArgs
[0] <<= aPropValue
;
279 m_xConfigAccess
.set( m_xConfigProvider
->createInstanceWithArguments(
280 "com.sun.star.configuration.ConfigurationAccess", aArgs
), UNO_QUERY
);
282 catch ( const WrappedTargetException
& )
286 m_bConfigAccessInitialized
= true;
289 if ( m_xConfigAccess
.is() )
291 Sequence
< OUString
> aUIElementFactories
= m_xConfigAccess
->getElementNames();
298 Reference
< XPropertySet
> xPropertySet
;
299 for ( sal_Int32 i
= 0; i
< aUIElementFactories
.getLength(); i
++ )
301 if ( impl_getElementProps( m_xConfigAccess
->getByName( aUIElementFactories
[i
] ), aType
, aName
, aModule
, aService
))
303 // Create hash key from type, name and module as they are together a primary key to
304 // the UNO service that implements the user interface element factory.
305 aHashKey
= getHashKeyFromStrings( aType
, aName
, aModule
);
306 m_aFactoryManagerMap
.insert( FactoryManagerMap::value_type( aHashKey
, aService
));
310 Reference
< XContainer
> xContainer( m_xConfigAccess
, UNO_QUERY
);
311 if ( xContainer
.is() )
313 m_xConfigListener
= new WeakContainerListener(this);
314 xContainer
->addContainerListener(m_xConfigListener
);
319 bool ConfigurationAccess_FactoryManager::impl_getElementProps( const Any
& aElement
, OUString
& rType
, OUString
& rName
, OUString
& rModule
, OUString
& rServiceSpecifier
) const
321 Reference
< XPropertySet
> xPropertySet
;
322 aElement
>>= xPropertySet
;
324 if ( xPropertySet
.is() )
328 xPropertySet
->getPropertyValue( m_aPropType
) >>= rType
;
329 xPropertySet
->getPropertyValue( m_aPropName
) >>= rName
;
330 xPropertySet
->getPropertyValue( m_aPropModule
) >>= rModule
;
331 xPropertySet
->getPropertyValue( m_aPropFactory
) >>= rServiceSpecifier
;
333 catch ( const com::sun::star::beans::UnknownPropertyException
& )
337 catch ( const com::sun::star::lang::WrappedTargetException
& )
350 typedef ::cppu::WeakComponentImplHelper2
<
351 css::lang::XServiceInfo
,
352 css::ui::XUIElementFactoryManager
> UIElementFactoryManager_BASE
;
354 class UIElementFactoryManager
: private cppu::BaseMutex
,
355 public UIElementFactoryManager_BASE
357 virtual void SAL_CALL
disposing() SAL_OVERRIDE
;
359 UIElementFactoryManager( const css::uno::Reference
< css::uno::XComponentContext
>& rxContext
);
360 virtual ~UIElementFactoryManager();
362 virtual OUString SAL_CALL
getImplementationName()
363 throw (css::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
365 return OUString("com.sun.star.comp.framework.UIElementFactoryManager");
368 virtual sal_Bool SAL_CALL
supportsService(OUString
const & ServiceName
)
369 throw (css::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
371 return cppu::supportsService(this, ServiceName
);
374 virtual css::uno::Sequence
<OUString
> SAL_CALL
getSupportedServiceNames()
375 throw (css::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
377 css::uno::Sequence
< OUString
> aSeq(1);
378 aSeq
[0] = "com.sun.star.ui.UIElementFactoryManager";
383 virtual css::uno::Reference
< css::ui::XUIElement
> SAL_CALL
createUIElement( const OUString
& ResourceURL
, const css::uno::Sequence
< css::beans::PropertyValue
>& Args
) throw (css::container::NoSuchElementException
, css::lang::IllegalArgumentException
, css::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
385 // XUIElementFactoryRegistration
386 virtual css::uno::Sequence
< css::uno::Sequence
< css::beans::PropertyValue
> > SAL_CALL
getRegisteredFactories( ) throw (css::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
387 virtual css::uno::Reference
< css::ui::XUIElementFactory
> SAL_CALL
getFactory( const OUString
& ResourceURL
, const OUString
& ModuleIdentifier
) throw (css::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
388 virtual void SAL_CALL
registerFactory( const OUString
& aType
, const OUString
& aName
, const OUString
& aModuleIdentifier
, const OUString
& aFactoryImplementationName
) throw (css::container::ElementExistException
, css::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
389 virtual void SAL_CALL
deregisterFactory( const OUString
& aType
, const OUString
& aName
, const OUString
& aModuleIdentifier
) throw (css::container::NoSuchElementException
, css::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
393 css::uno::Reference
< css::uno::XComponentContext
> m_xContext
;
394 ConfigurationAccess_FactoryManager
* m_pConfigAccess
;
397 UIElementFactoryManager::UIElementFactoryManager( const Reference
< XComponentContext
>& rxContext
) :
398 UIElementFactoryManager_BASE(m_aMutex
),
399 m_bConfigRead( false ),
400 m_xContext(rxContext
)
402 m_pConfigAccess
= new ConfigurationAccess_FactoryManager(rxContext
,
403 "/org.openoffice.Office.UI.Factories/Registered/UIElementFactories");
404 m_pConfigAccess
->acquire();
407 UIElementFactoryManager::~UIElementFactoryManager()
412 void SAL_CALL
UIElementFactoryManager::disposing()
414 osl::MutexGuard
g(rBHelper
.rMutex
);
417 // reduce reference count
418 m_pConfigAccess
->release();
424 Reference
< XUIElement
> SAL_CALL
UIElementFactoryManager::createUIElement(
425 const OUString
& ResourceURL
,
426 const Sequence
< PropertyValue
>& Args
)
427 throw ( ::com::sun::star::container::NoSuchElementException
, ::com::sun::star::lang::IllegalArgumentException
, ::com::sun::star::uno::RuntimeException
, std::exception
)
429 Reference
< XFrame
> xFrame
;
431 osl::MutexGuard
g(rBHelper
.rMutex
);
433 if ( !m_bConfigRead
)
435 m_bConfigRead
= true;
436 m_pConfigAccess
->readConfigurationData();
439 // Retrieve the frame instance from the arguments to determine the module identifier. This must be provided
440 // to the search function. An empty module identifier is provided if the frame is missing or the module id cannot
442 for ( int i
= 0; i
< Args
.getLength(); i
++ )
444 if ( Args
[i
].Name
== "Frame")
445 Args
[i
].Value
>>= xFrame
;
449 Reference
< XModuleManager2
> xManager
= ModuleManager::create( m_xContext
);
451 // Determine the module identifier
455 if ( xFrame
.is() && xManager
.is() )
456 aModuleId
= xManager
->identify( Reference
<XInterface
>( xFrame
, UNO_QUERY
) );
458 Reference
< XUIElementFactory
> xUIElementFactory
= getFactory( ResourceURL
, aModuleId
);
459 if ( xUIElementFactory
.is() )
460 return xUIElementFactory
->createUIElement( ResourceURL
, Args
);
462 catch ( const UnknownModuleException
& )
466 throw NoSuchElementException();
469 // XUIElementFactoryRegistration
470 Sequence
< Sequence
< PropertyValue
> > SAL_CALL
UIElementFactoryManager::getRegisteredFactories()
471 throw ( RuntimeException
, std::exception
)
474 osl::MutexGuard
g(rBHelper
.rMutex
);
476 if ( !m_bConfigRead
)
478 m_bConfigRead
= true;
479 m_pConfigAccess
->readConfigurationData();
482 return m_pConfigAccess
->getFactoriesDescription();
485 Reference
< XUIElementFactory
> SAL_CALL
UIElementFactoryManager::getFactory( const OUString
& aResourceURL
, const OUString
& aModuleId
)
486 throw ( RuntimeException
, std::exception
)
488 OUString aServiceSpecifier
;
490 osl::MutexGuard
g(rBHelper
.rMutex
);
492 if ( !m_bConfigRead
)
494 m_bConfigRead
= true;
495 m_pConfigAccess
->readConfigurationData();
501 RetrieveTypeNameFromResourceURL( aResourceURL
, aType
, aName
);
503 aServiceSpecifier
= m_pConfigAccess
->getFactorySpecifierFromTypeNameModule( aType
, aName
, aModuleId
);
506 if ( !aServiceSpecifier
.isEmpty() ) try
508 return Reference
< XUIElementFactory
>(m_xContext
->getServiceManager()->
509 createInstanceWithContext(aServiceSpecifier
, m_xContext
), UNO_QUERY
);
511 catch ( const css::loader::CannotActivateFactoryException
& )
513 SAL_WARN("fwk.uielement", aServiceSpecifier
<<
514 " not available. This should happen only on mobile platforms.");
516 return Reference
< XUIElementFactory
>();
519 void SAL_CALL
UIElementFactoryManager::registerFactory( const OUString
& aType
, const OUString
& aName
, const OUString
& aModuleId
, const OUString
& aFactoryImplementationName
)
520 throw ( ElementExistException
, RuntimeException
, std::exception
)
523 osl::MutexGuard
g(rBHelper
.rMutex
);
525 if ( !m_bConfigRead
)
527 m_bConfigRead
= true;
528 m_pConfigAccess
->readConfigurationData();
531 m_pConfigAccess
->addFactorySpecifierToTypeNameModule( aType
, aName
, aModuleId
, aFactoryImplementationName
);
535 void SAL_CALL
UIElementFactoryManager::deregisterFactory( const OUString
& aType
, const OUString
& aName
, const OUString
& aModuleId
)
536 throw ( NoSuchElementException
, RuntimeException
, std::exception
)
539 osl::MutexGuard
g(rBHelper
.rMutex
);
541 if ( !m_bConfigRead
)
543 m_bConfigRead
= true;
544 m_pConfigAccess
->readConfigurationData();
547 m_pConfigAccess
->removeFactorySpecifierFromTypeNameModule( aType
, aName
, aModuleId
);
553 css::uno::Reference
<css::uno::XComponentContext
> const & context
):
554 instance(static_cast<cppu::OWeakObject
*>(
555 new UIElementFactoryManager(context
)))
559 css::uno::Reference
<css::uno::XInterface
> instance
;
563 public rtl::StaticWithArg
<
564 Instance
, css::uno::Reference
<css::uno::XComponentContext
>, Singleton
>
569 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
* SAL_CALL
570 com_sun_star_comp_framework_UIElementFactoryManager_get_implementation(
571 css::uno::XComponentContext
*context
,
572 css::uno::Sequence
<css::uno::Any
> const &)
574 return cppu::acquire(static_cast<cppu::OWeakObject
*>(
575 Singleton::get(context
).instance
.get()));
578 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */