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/.
10 #include <sal/config.h>
14 #include <com/sun/star/beans/NamedValue.hpp>
15 #include <com/sun/star/beans/PropertyAttribute.hpp>
16 #include <com/sun/star/configuration/ReadOnlyAccess.hpp>
17 #include <com/sun/star/configuration/ReadWriteAccess.hpp>
18 #include <com/sun/star/configuration/XReadWriteAccess.hpp>
19 #include <com/sun/star/configuration/theDefaultProvider.hpp>
20 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
21 #include <com/sun/star/container/XHierarchicalNameReplace.hpp>
22 #include <com/sun/star/container/XNameAccess.hpp>
23 #include <com/sun/star/container/XNameContainer.hpp>
24 #include <com/sun/star/util/XChangesListener.hpp>
25 #include <com/sun/star/util/XChangesNotifier.hpp>
26 #include <com/sun/star/lang/DisposedException.hpp>
27 #include <com/sun/star/lang/XLocalizable.hpp>
28 #include <com/sun/star/uno/Any.hxx>
29 #include <com/sun/star/uno/Reference.hxx>
30 #include <comphelper/solarmutex.hxx>
31 #include <comphelper/configuration.hxx>
32 #include <comphelper/configurationlistener.hxx>
33 #include <cppuhelper/implbase.hxx>
34 #include <rtl/ustring.hxx>
35 #include <sal/log.hxx>
36 #include <i18nlangtag/languagetag.hxx>
38 namespace com::sun::star::uno
{ class XComponentContext
; }
42 OUString
getDefaultLocale(
43 css::uno::Reference
< css::uno::XComponentContext
> const & context
)
46 css::uno::Reference
< css::lang::XLocalizable
>(
47 css::configuration::theDefaultProvider::get(context
),
48 css::uno::UNO_QUERY_THROW
)->
49 getLocale()).getBcp47(false);
52 OUString
extendLocalizedPath(std::u16string_view path
, OUString
const & locale
) {
54 locale
.match("*"), "comphelper",
55 "Locale \"" << locale
<< "\" starts with \"*\"");
56 assert(locale
.indexOf('&') == -1);
57 assert(locale
.indexOf('"') == -1);
58 assert(locale
.indexOf('\'') == -1);
59 return OUString::Concat(path
) + "/['*" + locale
+ "']";
64 std::shared_ptr
< comphelper::ConfigurationChanges
>
65 comphelper::ConfigurationChanges::create()
67 return detail::ConfigurationWrapper::get().createChanges();
70 comphelper::ConfigurationChanges::~ConfigurationChanges() {}
72 void comphelper::ConfigurationChanges::commit() const {
73 access_
->commitChanges();
76 comphelper::ConfigurationChanges::ConfigurationChanges(
77 css::uno::Reference
< css::uno::XComponentContext
> const & context
):
79 css::configuration::ReadWriteAccess::create(
80 context
, getDefaultLocale(context
)))
83 void comphelper::ConfigurationChanges::setPropertyValue(
84 OUString
const & path
, css::uno::Any
const & value
) const
86 access_
->replaceByHierarchicalName(path
, value
);
89 css::uno::Reference
< css::container::XHierarchicalNameReplace
>
90 comphelper::ConfigurationChanges::getGroup(OUString
const & path
) const
92 return css::uno::Reference
< css::container::XHierarchicalNameReplace
>(
93 access_
->getByHierarchicalName(path
), css::uno::UNO_QUERY_THROW
);
96 css::uno::Reference
< css::container::XNameContainer
>
97 comphelper::ConfigurationChanges::getSet(OUString
const & path
) const
99 return css::uno::Reference
< css::container::XNameContainer
>(
100 access_
->getByHierarchicalName(path
), css::uno::UNO_QUERY_THROW
);
103 comphelper::detail::ConfigurationWrapper
const &
104 comphelper::detail::ConfigurationWrapper::get()
106 static comphelper::detail::ConfigurationWrapper WRAPPER
;
110 class comphelper::detail::ConfigurationChangesListener
111 : public ::cppu::WeakImplHelper
<css::util::XChangesListener
>
113 comphelper::detail::ConfigurationWrapper
& mrConfigurationWrapper
;
115 ConfigurationChangesListener(comphelper::detail::ConfigurationWrapper
& rWrapper
)
116 : mrConfigurationWrapper(rWrapper
)
118 // util::XChangesListener
119 virtual void SAL_CALL
changesOccurred( const css::util::ChangesEvent
& ) override
121 std::scoped_lock
aGuard(mrConfigurationWrapper
.maMutex
);
122 mrConfigurationWrapper
.maPropertyCache
.clear();
124 virtual void SAL_CALL
disposing(const css::lang::EventObject
&) override
126 std::scoped_lock
aGuard(mrConfigurationWrapper
.maMutex
);
127 mrConfigurationWrapper
.mbDisposed
= true;
128 mrConfigurationWrapper
.maPropertyCache
.clear();
129 mrConfigurationWrapper
.maNotifier
.clear();
130 mrConfigurationWrapper
.maListener
.clear();
134 comphelper::detail::ConfigurationWrapper::ConfigurationWrapper():
135 context_(comphelper::getProcessComponentContext()),
136 access_(css::configuration::ReadWriteAccess::create(context_
, "*")),
139 // Set up a configuration notifier to invalidate the cache as needed.
142 css::uno::Reference
< css::lang::XMultiServiceFactory
> xConfigProvider(
143 css::configuration::theDefaultProvider::get( context_
) );
146 css::uno::Sequence
< css::uno::Any
> params
{
147 css::uno::Any( css::beans::NamedValue
{ "nodepath", css::uno::Any( OUString("/"))} ),
148 css::uno::Any( css::beans::NamedValue
{ "locale", css::uno::Any( OUString("*"))} ) };
150 css::uno::Reference
< css::uno::XInterface
> xCfg
151 = xConfigProvider
->createInstanceWithArguments(u
"com.sun.star.configuration.ConfigurationAccess",
154 maNotifier
= css::uno::Reference
< css::util::XChangesNotifier
>(xCfg
, css::uno::UNO_QUERY
);
155 assert(maNotifier
.is());
156 maListener
= css::uno::Reference
< ConfigurationChangesListener
>(new ConfigurationChangesListener(*this));
157 maNotifier
->addChangesListener(maListener
);
159 catch(const css::uno::Exception
&)
165 comphelper::detail::ConfigurationWrapper::~ConfigurationWrapper()
167 maPropertyCache
.clear();
172 bool comphelper::detail::ConfigurationWrapper::isReadOnly(OUString
const & path
)
176 (access_
->getPropertyByHierarchicalName(path
).Attributes
177 & css::beans::PropertyAttribute::READONLY
)
181 css::uno::Any
comphelper::detail::ConfigurationWrapper::getPropertyValue(OUString
const& path
) const
183 std::scoped_lock
aGuard(maMutex
);
185 throw css::lang::DisposedException();
186 // Cache the configuration access, since some of the keys are used in hot code.
187 auto it
= maPropertyCache
.find(path
);
188 if( it
!= maPropertyCache
.end())
191 sal_Int32 idx
= path
.lastIndexOf("/");
193 OUString parentPath
= path
.copy(0, idx
);
194 OUString childName
= path
.copy(idx
+1);
196 css::uno::Reference
<css::container::XNameAccess
> access(
197 access_
->getByHierarchicalName(parentPath
), css::uno::UNO_QUERY_THROW
);
198 css::uno::Any property
= access
->getByName(childName
);
199 maPropertyCache
.emplace(path
, property
);
203 void comphelper::detail::ConfigurationWrapper::setPropertyValue(
204 std::shared_ptr
< ConfigurationChanges
> const & batch
,
205 OUString
const & path
, css::uno::Any
const & value
)
208 batch
->setPropertyValue(path
, value
);
212 comphelper::detail::ConfigurationWrapper::getLocalizedPropertyValue(
213 std::u16string_view path
) const
215 return access_
->getByHierarchicalName(
216 extendLocalizedPath(path
, getDefaultLocale(context_
)));
219 void comphelper::detail::ConfigurationWrapper::setLocalizedPropertyValue(
220 std::shared_ptr
< ConfigurationChanges
> const & batch
,
221 OUString
const & path
, css::uno::Any
const & value
)
224 batch
->setPropertyValue(path
, value
);
227 css::uno::Reference
< css::container::XHierarchicalNameAccess
>
228 comphelper::detail::ConfigurationWrapper::getGroupReadOnly(
229 OUString
const & path
) const
231 return css::uno::Reference
< css::container::XHierarchicalNameAccess
>(
232 (css::configuration::ReadOnlyAccess::create(
233 context_
, getDefaultLocale(context_
))->
234 getByHierarchicalName(path
)),
235 css::uno::UNO_QUERY_THROW
);
238 css::uno::Reference
< css::container::XHierarchicalNameReplace
>
239 comphelper::detail::ConfigurationWrapper::getGroupReadWrite(
240 std::shared_ptr
< ConfigurationChanges
> const & batch
,
241 OUString
const & path
)
244 return batch
->getGroup(path
);
247 css::uno::Reference
< css::container::XNameAccess
>
248 comphelper::detail::ConfigurationWrapper::getSetReadOnly(
249 OUString
const & path
) const
251 return css::uno::Reference
< css::container::XNameAccess
>(
252 (css::configuration::ReadOnlyAccess::create(
253 context_
, getDefaultLocale(context_
))->
254 getByHierarchicalName(path
)),
255 css::uno::UNO_QUERY_THROW
);
258 css::uno::Reference
< css::container::XNameContainer
>
259 comphelper::detail::ConfigurationWrapper::getSetReadWrite(
260 std::shared_ptr
< ConfigurationChanges
> const & batch
,
261 OUString
const & path
)
264 return batch
->getSet(path
);
267 std::shared_ptr
< comphelper::ConfigurationChanges
>
268 comphelper::detail::ConfigurationWrapper::createChanges() const {
269 return std::shared_ptr
< ConfigurationChanges
>(
270 new ConfigurationChanges(context_
));
273 void comphelper::ConfigurationListener::addListener(ConfigurationListenerPropertyBase
*pListener
)
275 maListeners
.push_back( pListener
);
276 mxConfig
->addPropertyChangeListener( pListener
->maName
, this );
277 pListener
->setProperty( mxConfig
->getPropertyValue( pListener
->maName
) );
280 void comphelper::ConfigurationListener::removeListener(ConfigurationListenerPropertyBase
*pListener
)
282 auto it
= std::find( maListeners
.begin(), maListeners
.end(), pListener
);
283 if ( it
!= maListeners
.end() )
285 maListeners
.erase( it
);
286 mxConfig
->removePropertyChangeListener( pListener
->maName
, this );
290 void comphelper::ConfigurationListener::dispose()
292 for (auto const& listener
: maListeners
)
294 mxConfig
->removePropertyChangeListener( listener
->maName
, this );
301 void SAL_CALL
comphelper::ConfigurationListener::disposing(css::lang::EventObject
const &)
306 void SAL_CALL
comphelper::ConfigurationListener::propertyChange(
307 css::beans::PropertyChangeEvent
const &rEvt
)
309 // Code is commonly used inside the SolarMutexGuard
310 // so to avoid concurrent writes to the property,
311 // and allow fast, lock-less access, guard here.
313 // Note that we are abusing rtl::Reference here to do acquire/release because,
314 // unlike osl::Guard, it is tolerant of null pointers, and on some code paths, the
315 // SolarMutex does not exist.
316 rtl::Reference
<comphelper::SolarMutex
> xMutexGuard( comphelper::SolarMutex::get() );
318 assert( rEvt
.Source
== mxConfig
);
319 for (auto const& listener
: maListeners
)
321 if ( listener
->maName
== rEvt
.PropertyName
)
323 // ignore rEvt.NewValue - in theory it could be stale => not set.
324 css::uno::Any aValue
= mxConfig
->getPropertyValue( listener
->maName
);
325 listener
->setProperty( aValue
);
330 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */