Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / framework / source / services / modulemanager.cxx
blobce48cfd4412369ec4f3cebef2450aa1d8818b911
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/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>
39 #include <unotools/configmgr.hxx>
40 #include <utility>
42 namespace {
44 class ModuleManager:
45 public cppu::WeakImplHelper<
46 css::lang::XServiceInfo,
47 css::frame::XModuleManager2,
48 css::container::XContainerQuery >
50 private:
52 /** the global uno service manager.
53 Must be used to create own needed services.
55 css::uno::Reference< css::uno::XComponentContext > m_xContext;
57 /** points to the underlying configuration.
58 This ModuleManager does not cache - it calls directly the
59 configuration API!
61 css::uno::Reference< css::container::XNameAccess > m_xCFG;
63 public:
65 explicit ModuleManager(css::uno::Reference< css::uno::XComponentContext > xContext);
67 ModuleManager(const ModuleManager&) = delete;
68 ModuleManager& operator=(const ModuleManager&) = delete;
70 // XServiceInfo
71 virtual OUString SAL_CALL getImplementationName() override;
73 virtual sal_Bool SAL_CALL supportsService(
74 OUString const & ServiceName) override;
76 virtual css::uno::Sequence< OUString > SAL_CALL
77 getSupportedServiceNames() override;
79 // XModuleManager
80 virtual OUString SAL_CALL identify(const css::uno::Reference< css::uno::XInterface >& xModule) override;
82 // XNameReplace
83 virtual void SAL_CALL replaceByName(const OUString& sName ,
84 const css::uno::Any& aValue) override;
86 // XNameAccess
87 virtual css::uno::Any SAL_CALL getByName(const OUString& sName) override;
89 virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override;
91 virtual sal_Bool SAL_CALL hasByName(const OUString& sName) override;
93 // XElementAccess
94 virtual css::uno::Type SAL_CALL getElementType() override;
96 virtual sal_Bool SAL_CALL hasElements() override;
98 // XContainerQuery
99 virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createSubSetEnumerationByQuery(const OUString& sQuery) override;
101 virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createSubSetEnumerationByProperties(const css::uno::Sequence< css::beans::NamedValue >& lProperties) override;
103 private:
105 /** @short makes the real identification of the module.
107 @descr It checks for the optional but preferred interface
108 XModule first. If this module does not exists at the
109 given component it tries to use XServiceInfo instead.
111 Note: This method try to locate a suitable module name.
112 Nothing else. Selecting the right component and throwing suitable
113 exceptions must be done outside.
115 @see identify()
117 @param xComponent
118 the module for identification.
120 @return The identifier of the given module.
121 Can be empty if given component is not a real module !
123 @threadsafe
125 OUString implts_identify(const css::uno::Reference< css::uno::XInterface >& xComponent);
128 ModuleManager::ModuleManager(css::uno::Reference< css::uno::XComponentContext > xContext)
129 : m_xContext(std::move(xContext))
131 if (!utl::ConfigManager::IsFuzzing())
133 m_xCFG.set( comphelper::ConfigurationHelper::openConfig(
134 m_xContext, "/org.openoffice.Setup/Office/Factories",
135 comphelper::EConfigurationModes::ReadOnly ),
136 css::uno::UNO_QUERY_THROW );
140 OUString ModuleManager::getImplementationName()
142 return "com.sun.star.comp.framework.ModuleManager";
145 sal_Bool ModuleManager::supportsService(OUString const & ServiceName)
147 return cppu::supportsService(this, ServiceName);
150 css::uno::Sequence< OUString > ModuleManager::getSupportedServiceNames()
152 return { "com.sun.star.frame.ModuleManager" };
155 OUString SAL_CALL ModuleManager::identify(const css::uno::Reference< css::uno::XInterface >& xModule)
157 // valid parameter?
158 css::uno::Reference< css::frame::XFrame > xFrame (xModule, css::uno::UNO_QUERY);
159 css::uno::Reference< css::awt::XWindow > xWindow (xModule, css::uno::UNO_QUERY);
160 css::uno::Reference< css::frame::XController > xController(xModule, css::uno::UNO_QUERY);
161 css::uno::Reference< css::frame::XModel > xModel (xModule, css::uno::UNO_QUERY);
163 if (
164 (!xFrame.is() ) &&
165 (!xWindow.is() ) &&
166 (!xController.is()) &&
167 (!xModel.is() )
170 throw css::lang::IllegalArgumentException(
171 "Given module is not a frame nor a window, controller or model.",
172 static_cast< ::cppu::OWeakObject* >(this),
176 if (xFrame.is())
178 xController = xFrame->getController();
179 xWindow = xFrame->getComponentWindow();
181 if (xController.is())
182 xModel = xController->getModel();
184 // modules are implemented by the deepest component in hierarchy ...
185 // Means: model -> controller -> window
186 // No fallbacks to higher components are allowed !
187 // Note : A frame provides access to module components only ... but it's not a module by himself.
189 OUString sModule;
190 if (xModel.is())
191 sModule = implts_identify(xModel);
192 else if (xController.is())
193 sModule = implts_identify(xController);
194 else if (xWindow.is())
195 sModule = implts_identify(xWindow);
197 if (sModule.isEmpty())
198 throw css::frame::UnknownModuleException(
199 "Can not find suitable module for the given component.",
200 static_cast< ::cppu::OWeakObject* >(this));
202 return sModule;
205 void SAL_CALL ModuleManager::replaceByName(const OUString& sName ,
206 const css::uno::Any& aValue)
208 ::comphelper::SequenceAsHashMap lProps(aValue);
209 if (lProps.empty() )
211 throw css::lang::IllegalArgumentException(
212 "No properties given to replace part of module.",
213 static_cast< cppu::OWeakObject * >(this),
217 // get access to the element
218 // Note: Don't use impl_getConfig() method here. Because it creates a readonly access only, further
219 // it cache it as a member of this module manager instance. If we change some props there ... but don't
220 // flush changes (because an error occurred) we will read them later. If we use a different config access
221 // we can close it without a flush... and our read data won't be affected .-)
222 css::uno::Reference< css::uno::XInterface > xCfg = ::comphelper::ConfigurationHelper::openConfig(
223 m_xContext,
224 "/org.openoffice.Setup/Office/Factories",
225 ::comphelper::EConfigurationModes::Standard);
226 css::uno::Reference< css::container::XNameAccess > xModules (xCfg, css::uno::UNO_QUERY_THROW);
227 css::uno::Reference< css::container::XNameReplace > xModule ;
229 xModules->getByName(sName) >>= xModule;
230 if (!xModule.is())
232 throw css::uno::RuntimeException(
233 "Was not able to get write access to the requested module entry inside configuration.",
234 static_cast< cppu::OWeakObject * >(this));
237 for (auto const& prop : lProps)
239 // let "NoSuchElementException" out ! We support the same API ...
240 // and without a flush() at the end all changed data before will be ignored !
241 xModule->replaceByName(prop.first.maString, prop.second);
244 ::comphelper::ConfigurationHelper::flush(xCfg);
247 css::uno::Any SAL_CALL ModuleManager::getByName(const OUString& sName)
249 // get access to the element
250 css::uno::Reference< css::container::XNameAccess > xModule;
251 if (m_xCFG)
252 m_xCFG->getByName(sName) >>= xModule;
253 if (!xModule.is())
255 throw css::uno::RuntimeException(
256 "Was not able to get write access to the requested module entry inside configuration.",
257 static_cast< cppu::OWeakObject * >(this));
260 // convert it to seq< PropertyValue >
261 const css::uno::Sequence< OUString > lPropNames = xModule->getElementNames();
262 comphelper::SequenceAsHashMap lProps;
264 lProps[OUString("ooSetupFactoryModuleIdentifier")] <<= sName;
265 for (const OUString& sPropName : lPropNames)
267 lProps[sPropName] = xModule->getByName(sPropName);
270 return css::uno::Any(lProps.getAsConstPropertyValueList());
273 css::uno::Sequence< OUString > SAL_CALL ModuleManager::getElementNames()
275 return m_xCFG ? m_xCFG->getElementNames() : css::uno::Sequence<OUString>();
278 sal_Bool SAL_CALL ModuleManager::hasByName(const OUString& sName)
280 return m_xCFG && m_xCFG->hasByName(sName);
283 css::uno::Type SAL_CALL ModuleManager::getElementType()
285 return cppu::UnoType<css::uno::Sequence< css::beans::PropertyValue >>::get();
288 sal_Bool SAL_CALL ModuleManager::hasElements()
290 return m_xCFG && m_xCFG->hasElements();
293 css::uno::Reference< css::container::XEnumeration > SAL_CALL ModuleManager::createSubSetEnumerationByQuery(const OUString&)
295 return css::uno::Reference< css::container::XEnumeration >();
298 css::uno::Reference< css::container::XEnumeration > SAL_CALL ModuleManager::createSubSetEnumerationByProperties(const css::uno::Sequence< css::beans::NamedValue >& lProperties)
300 ::comphelper::SequenceAsHashMap lSearchProps(lProperties);
301 const css::uno::Sequence< OUString > lModules = getElementNames();
302 ::std::vector< css::uno::Any > lResult;
304 for (const OUString& rModuleName : lModules)
308 ::comphelper::SequenceAsHashMap lModuleProps = getByName(rModuleName);
309 if (lModuleProps.match(lSearchProps))
310 lResult.push_back(css::uno::Any(lModuleProps.getAsConstPropertyValueList()));
312 catch(const css::uno::Exception&)
317 return new ::comphelper::OAnyEnumeration(comphelper::containerToSequence(lResult));
320 OUString ModuleManager::implts_identify(const css::uno::Reference< css::uno::XInterface >& xComponent)
322 // Search for an optional (!) interface XModule first.
323 // It's used to overrule an existing service name. Used e.g. by our database form designer
324 // which uses a writer module internally.
325 css::uno::Reference< css::frame::XModule > xModule(xComponent, css::uno::UNO_QUERY);
326 if (xModule.is())
327 return xModule->getIdentifier();
329 // detect modules in a generic way...
330 // comparing service names with configured entries...
331 css::uno::Reference< css::lang::XServiceInfo > xInfo(xComponent, css::uno::UNO_QUERY);
332 if (!xInfo.is())
333 return OUString();
335 const css::uno::Sequence< OUString > lKnownModules = getElementNames();
336 for (const OUString& rName : lKnownModules)
338 if (xInfo->supportsService(rName))
339 return rName;
342 return OUString();
347 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
348 com_sun_star_comp_framework_ModuleManager_get_implementation(
349 css::uno::XComponentContext *context,
350 css::uno::Sequence<css::uno::Any> const &)
352 return cppu::acquire(new ModuleManager(context));
355 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */