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/frame/UnknownModuleException.hpp>
23 #include <com/sun/star/frame/XFrame.hpp>
24 #include <com/sun/star/frame/XController.hpp>
25 #include <com/sun/star/frame/XModel.hpp>
26 #include <com/sun/star/frame/XModule.hpp>
27 #include <com/sun/star/lang/XServiceInfo.hpp>
28 #include <com/sun/star/frame/XModuleManager2.hpp>
29 #include <com/sun/star/container/XNameReplace.hpp>
30 #include <com/sun/star/container/XContainerQuery.hpp>
31 #include <com/sun/star/uno/XComponentContext.hpp>
33 #include <cppuhelper/implbase.hxx>
34 #include <cppuhelper/supportsservice.hxx>
35 #include <comphelper/configurationhelper.hxx>
36 #include <comphelper/sequenceashashmap.hxx>
37 #include <comphelper/sequence.hxx>
38 #include <comphelper/enumhelper.hxx>
44 public cppu::WeakImplHelper
<
45 css::lang::XServiceInfo
,
46 css::frame::XModuleManager2
,
47 css::container::XContainerQuery
>
51 /** the global uno service manager.
52 Must be used to create own needed services.
54 css::uno::Reference
< css::uno::XComponentContext
> m_xContext
;
56 /** points to the underlying configuration.
57 This ModuleManager does not cache - it calls directly the
60 css::uno::Reference
< css::container::XNameAccess
> m_xCFG
;
64 explicit ModuleManager(css::uno::Reference
< css::uno::XComponentContext
> xContext
);
66 ModuleManager(const ModuleManager
&) = delete;
67 ModuleManager
& operator=(const ModuleManager
&) = delete;
70 virtual OUString SAL_CALL
getImplementationName() override
;
72 virtual sal_Bool SAL_CALL
supportsService(
73 OUString
const & ServiceName
) override
;
75 virtual css::uno::Sequence
< OUString
> SAL_CALL
76 getSupportedServiceNames() override
;
79 virtual OUString SAL_CALL
identify(const css::uno::Reference
< css::uno::XInterface
>& xModule
) override
;
82 virtual void SAL_CALL
replaceByName(const OUString
& sName
,
83 const css::uno::Any
& aValue
) override
;
86 virtual css::uno::Any SAL_CALL
getByName(const OUString
& sName
) override
;
88 virtual css::uno::Sequence
< OUString
> SAL_CALL
getElementNames() override
;
90 virtual sal_Bool SAL_CALL
hasByName(const OUString
& sName
) override
;
93 virtual css::uno::Type SAL_CALL
getElementType() override
;
95 virtual sal_Bool SAL_CALL
hasElements() override
;
98 virtual css::uno::Reference
< css::container::XEnumeration
> SAL_CALL
createSubSetEnumerationByQuery(const OUString
& sQuery
) override
;
100 virtual css::uno::Reference
< css::container::XEnumeration
> SAL_CALL
createSubSetEnumerationByProperties(const css::uno::Sequence
< css::beans::NamedValue
>& lProperties
) override
;
104 /** @short makes the real identification of the module.
106 @descr It checks for the optional but preferred interface
107 XModule first. If this module does not exists at the
108 given component it tries to use XServiceInfo instead.
110 Note: This method try to locate a suitable module name.
111 Nothing else. Selecting the right component and throwing suitable
112 exceptions must be done outside.
117 the module for identification.
119 @return The identifier of the given module.
120 Can be empty if given component is not a real module !
124 OUString
implts_identify(const css::uno::Reference
< css::uno::XInterface
>& xComponent
);
127 ModuleManager::ModuleManager(css::uno::Reference
< css::uno::XComponentContext
> xContext
)
128 : m_xContext(std::move(xContext
))
130 m_xCFG
.set( comphelper::ConfigurationHelper::openConfig(
131 m_xContext
, "/org.openoffice.Setup/Office/Factories",
132 comphelper::EConfigurationModes::ReadOnly
),
133 css::uno::UNO_QUERY_THROW
);
136 OUString
ModuleManager::getImplementationName()
138 return "com.sun.star.comp.framework.ModuleManager";
141 sal_Bool
ModuleManager::supportsService(OUString
const & ServiceName
)
143 return cppu::supportsService(this, ServiceName
);
146 css::uno::Sequence
< OUString
> ModuleManager::getSupportedServiceNames()
148 return { "com.sun.star.frame.ModuleManager" };
151 OUString SAL_CALL
ModuleManager::identify(const css::uno::Reference
< css::uno::XInterface
>& xModule
)
154 css::uno::Reference
< css::frame::XFrame
> xFrame (xModule
, css::uno::UNO_QUERY
);
155 css::uno::Reference
< css::awt::XWindow
> xWindow (xModule
, css::uno::UNO_QUERY
);
156 css::uno::Reference
< css::frame::XController
> xController(xModule
, css::uno::UNO_QUERY
);
157 css::uno::Reference
< css::frame::XModel
> xModel (xModule
, css::uno::UNO_QUERY
);
162 (!xController
.is()) &&
166 throw css::lang::IllegalArgumentException(
167 "Given module is not a frame nor a window, controller or model.",
168 static_cast< ::cppu::OWeakObject
* >(this),
174 xController
= xFrame
->getController();
175 xWindow
= xFrame
->getComponentWindow();
177 if (xController
.is())
178 xModel
= xController
->getModel();
180 // modules are implemented by the deepest component in hierarchy ...
181 // Means: model -> controller -> window
182 // No fallbacks to higher components are allowed !
183 // Note : A frame provides access to module components only ... but it's not a module by himself.
187 sModule
= implts_identify(xModel
);
188 else if (xController
.is())
189 sModule
= implts_identify(xController
);
190 else if (xWindow
.is())
191 sModule
= implts_identify(xWindow
);
193 if (sModule
.isEmpty())
194 throw css::frame::UnknownModuleException(
195 "Can not find suitable module for the given component.",
196 static_cast< ::cppu::OWeakObject
* >(this));
201 void SAL_CALL
ModuleManager::replaceByName(const OUString
& sName
,
202 const css::uno::Any
& aValue
)
204 ::comphelper::SequenceAsHashMap
lProps(aValue
);
207 throw css::lang::IllegalArgumentException(
208 "No properties given to replace part of module.",
209 static_cast< cppu::OWeakObject
* >(this),
213 // get access to the element
214 // Note: Don't use impl_getConfig() method here. Because it creates a readonly access only, further
215 // it cache it as a member of this module manager instance. If we change some props there ... but don't
216 // flush changes (because an error occurred) we will read them later. If we use a different config access
217 // we can close it without a flush... and our read data won't be affected .-)
218 css::uno::Reference
< css::uno::XInterface
> xCfg
= ::comphelper::ConfigurationHelper::openConfig(
220 "/org.openoffice.Setup/Office/Factories",
221 ::comphelper::EConfigurationModes::Standard
);
222 css::uno::Reference
< css::container::XNameAccess
> xModules (xCfg
, css::uno::UNO_QUERY_THROW
);
223 css::uno::Reference
< css::container::XNameReplace
> xModule
;
225 xModules
->getByName(sName
) >>= xModule
;
228 throw css::uno::RuntimeException(
229 "Was not able to get write access to the requested module entry inside configuration.",
230 static_cast< cppu::OWeakObject
* >(this));
233 for (auto const& prop
: lProps
)
235 // let "NoSuchElementException" out ! We support the same API ...
236 // and without a flush() at the end all changed data before will be ignored !
237 xModule
->replaceByName(prop
.first
.maString
, prop
.second
);
240 ::comphelper::ConfigurationHelper::flush(xCfg
);
243 css::uno::Any SAL_CALL
ModuleManager::getByName(const OUString
& sName
)
245 // get access to the element
246 css::uno::Reference
< css::container::XNameAccess
> xModule
;
247 m_xCFG
->getByName(sName
) >>= xModule
;
250 throw css::uno::RuntimeException(
251 "Was not able to get write access to the requested module entry inside configuration.",
252 static_cast< cppu::OWeakObject
* >(this));
255 // convert it to seq< PropertyValue >
256 const css::uno::Sequence
< OUString
> lPropNames
= xModule
->getElementNames();
257 comphelper::SequenceAsHashMap lProps
;
259 lProps
[OUString("ooSetupFactoryModuleIdentifier")] <<= sName
;
260 for (const OUString
& sPropName
: lPropNames
)
262 lProps
[sPropName
] = xModule
->getByName(sPropName
);
265 return css::uno::Any(lProps
.getAsConstPropertyValueList());
268 css::uno::Sequence
< OUString
> SAL_CALL
ModuleManager::getElementNames()
270 return m_xCFG
->getElementNames();
273 sal_Bool SAL_CALL
ModuleManager::hasByName(const OUString
& sName
)
275 return m_xCFG
->hasByName(sName
);
278 css::uno::Type SAL_CALL
ModuleManager::getElementType()
280 return cppu::UnoType
<css::uno::Sequence
< css::beans::PropertyValue
>>::get();
283 sal_Bool SAL_CALL
ModuleManager::hasElements()
285 return m_xCFG
->hasElements();
288 css::uno::Reference
< css::container::XEnumeration
> SAL_CALL
ModuleManager::createSubSetEnumerationByQuery(const OUString
&)
290 return css::uno::Reference
< css::container::XEnumeration
>();
293 css::uno::Reference
< css::container::XEnumeration
> SAL_CALL
ModuleManager::createSubSetEnumerationByProperties(const css::uno::Sequence
< css::beans::NamedValue
>& lProperties
)
295 ::comphelper::SequenceAsHashMap
lSearchProps(lProperties
);
296 const css::uno::Sequence
< OUString
> lModules
= getElementNames();
297 ::std::vector
< css::uno::Any
> lResult
;
299 for (const OUString
& rModuleName
: lModules
)
303 ::comphelper::SequenceAsHashMap lModuleProps
= getByName(rModuleName
);
304 if (lModuleProps
.match(lSearchProps
))
305 lResult
.push_back(css::uno::Any(lModuleProps
.getAsConstPropertyValueList()));
307 catch(const css::uno::Exception
&)
312 return new ::comphelper::OAnyEnumeration(comphelper::containerToSequence(lResult
));
315 OUString
ModuleManager::implts_identify(const css::uno::Reference
< css::uno::XInterface
>& xComponent
)
317 // Search for an optional (!) interface XModule first.
318 // It's used to overrule an existing service name. Used e.g. by our database form designer
319 // which uses a writer module internally.
320 css::uno::Reference
< css::frame::XModule
> xModule(xComponent
, css::uno::UNO_QUERY
);
322 return xModule
->getIdentifier();
324 // detect modules in a generic way...
325 // comparing service names with configured entries...
326 css::uno::Reference
< css::lang::XServiceInfo
> xInfo(xComponent
, css::uno::UNO_QUERY
);
330 const css::uno::Sequence
< OUString
> lKnownModules
= getElementNames();
331 for (const OUString
& rName
: lKnownModules
)
333 if (xInfo
->supportsService(rName
))
342 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
343 com_sun_star_comp_framework_ModuleManager_get_implementation(
344 css::uno::XComponentContext
*context
,
345 css::uno::Sequence
<css::uno::Any
> const &)
347 return cppu::acquire(new ModuleManager(context
));
350 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */