LibreOffice Module comphelper (master)  1
configuration.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  */
9 
10 #include <sal/config.h>
11 
12 #include <cassert>
13 #include <map>
14 #include <memory>
15 #include <mutex>
16 #include <string_view>
17 
18 #include <com/sun/star/beans/PropertyAttribute.hpp>
19 #include <com/sun/star/configuration/ReadOnlyAccess.hpp>
20 #include <com/sun/star/configuration/ReadWriteAccess.hpp>
21 #include <com/sun/star/configuration/XReadWriteAccess.hpp>
22 #include <com/sun/star/configuration/theDefaultProvider.hpp>
23 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
24 #include <com/sun/star/container/XHierarchicalNameReplace.hpp>
25 #include <com/sun/star/container/XNameAccess.hpp>
26 #include <com/sun/star/container/XNameContainer.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>
33 #include <rtl/ustring.hxx>
34 #include <sal/log.hxx>
36 
37 namespace com::sun::star::uno { class XComponentContext; }
38 
39 namespace {
40 
41 comphelper::detail::ConfigurationWrapper& GetTheConfigurationWrapper(const css::uno::Reference< css::uno::XComponentContext >& xContext)
42 {
43  static comphelper::detail::ConfigurationWrapper WRAPPER(xContext);
44  return WRAPPER;
45 }
46 
47 OUString getDefaultLocale(
48  css::uno::Reference< css::uno::XComponentContext > const & context)
49 {
50  return LanguageTag(
51  css::uno::Reference< css::lang::XLocalizable >(
52  css::configuration::theDefaultProvider::get(context),
53  css::uno::UNO_QUERY_THROW)->
54  getLocale()).getBcp47(false);
55 }
56 
57 OUString extendLocalizedPath(std::u16string_view path, OUString const & locale) {
59  locale.match("*"), "comphelper",
60  "Locale \"" << locale << "\" starts with \"*\"");
61  assert(locale.indexOf('&') == -1);
62  assert(locale.indexOf('"') == -1);
63  assert(locale.indexOf('\'') == -1);
64  return OUString::Concat(path) + "/['*" + locale + "']";
65 }
66 
67 }
68 
69 std::shared_ptr< comphelper::ConfigurationChanges >
71  css::uno::Reference< css::uno::XComponentContext > const & context)
72 {
73  return GetTheConfigurationWrapper(context).createChanges();
74 }
75 
77 
79  access_->commitChanges();
80 }
81 
83  css::uno::Reference< css::uno::XComponentContext > const & context):
84  access_(
85  css::configuration::ReadWriteAccess::create(
86  context, getDefaultLocale(context)))
87 {}
88 
90  OUString const & path, css::uno::Any const & value) const
91 {
92  access_->replaceByHierarchicalName(path, value);
93 }
94 
95 css::uno::Reference< css::container::XHierarchicalNameReplace >
96 comphelper::ConfigurationChanges::getGroup(OUString const & path) const
97 {
98  return css::uno::Reference< css::container::XHierarchicalNameReplace >(
99  access_->getByHierarchicalName(path), css::uno::UNO_QUERY_THROW);
100 }
101 
102 css::uno::Reference< css::container::XNameContainer >
103 comphelper::ConfigurationChanges::getSet(OUString const & path) const
104 {
105  return css::uno::Reference< css::container::XNameContainer >(
106  access_->getByHierarchicalName(path), css::uno::UNO_QUERY_THROW);
107 }
108 
111  css::uno::Reference< css::uno::XComponentContext > const & context)
112 {
113  return GetTheConfigurationWrapper(context);
114 }
115 
117  css::uno::Reference< css::uno::XComponentContext > const & context):
118  context_(context),
119  access_(css::configuration::ReadWriteAccess::create(context, "*"))
120 {}
121 
123 
125  const
126 {
127  return
128  (access_->getPropertyByHierarchicalName(path).Attributes
129  & css::beans::PropertyAttribute::READONLY)
130  != 0;
131 }
132 
133 css::uno::Any comphelper::detail::ConfigurationWrapper::getPropertyValue(OUString const& path) const
134 {
135  // Cache the configuration access, since some of the keys are used in hot code.
136  // Note that this cache is only used by the officecfg:: auto-generated code, using it for anything
137  // else would be unwise because the cache could end up containing stale entries.
138  static std::mutex gMutex;
139  static std::map<OUString, css::uno::Reference< css::container::XNameAccess >> gAccessMap;
140 
141  sal_Int32 idx = path.lastIndexOf("/");
142  assert(idx!=-1);
143  OUString parentPath = path.copy(0, idx);
144  OUString childName = path.copy(idx+1);
145 
146  std::scoped_lock aGuard(gMutex);
147 
148  // check cache
149  auto it = gAccessMap.find(parentPath);
150  if (it == gAccessMap.end())
151  {
152  // not in the cache, look it up
153  css::uno::Reference<css::container::XNameAccess> access(
154  access_->getByHierarchicalName(parentPath), css::uno::UNO_QUERY_THROW);
155  it = gAccessMap.emplace(parentPath, access).first;
156  }
157  return it->second->getByName(childName);
158 }
159 
161  std::shared_ptr< ConfigurationChanges > const & batch,
162  OUString const & path, css::uno::Any const & value)
163 {
164  assert(batch);
165  batch->setPropertyValue(path, value);
166 }
167 
168 css::uno::Any
170  std::u16string_view path) const
171 {
172  return access_->getByHierarchicalName(
173  extendLocalizedPath(path, getDefaultLocale(context_)));
174 }
175 
177  std::shared_ptr< ConfigurationChanges > const & batch,
178  OUString const & path, css::uno::Any const & value)
179 {
180  assert(batch);
181  batch->setPropertyValue(path, value);
182 }
183 
184 css::uno::Reference< css::container::XHierarchicalNameAccess >
186  OUString const & path) const
187 {
188  return css::uno::Reference< css::container::XHierarchicalNameAccess >(
189  (css::configuration::ReadOnlyAccess::create(
190  context_, getDefaultLocale(context_))->
191  getByHierarchicalName(path)),
192  css::uno::UNO_QUERY_THROW);
193 }
194 
195 css::uno::Reference< css::container::XHierarchicalNameReplace >
197  std::shared_ptr< ConfigurationChanges > const & batch,
198  OUString const & path)
199 {
200  assert(batch);
201  return batch->getGroup(path);
202 }
203 
204 css::uno::Reference< css::container::XNameAccess >
206  OUString const & path) const
207 {
208  return css::uno::Reference< css::container::XNameAccess >(
209  (css::configuration::ReadOnlyAccess::create(
210  context_, getDefaultLocale(context_))->
211  getByHierarchicalName(path)),
212  css::uno::UNO_QUERY_THROW);
213 }
214 
215 css::uno::Reference< css::container::XNameContainer >
217  std::shared_ptr< ConfigurationChanges > const & batch,
218  OUString const & path)
219 {
220  assert(batch);
221  return batch->getSet(path);
222 }
223 
224 std::shared_ptr< comphelper::ConfigurationChanges >
226  return std::shared_ptr< ConfigurationChanges >(
228 }
229 
231 {
232  maListeners.push_back( pListener );
233  mxConfig->addPropertyChangeListener( pListener->maName, this );
234  pListener->setProperty( mxConfig->getPropertyValue( pListener->maName ) );
235 }
236 
238 {
239  auto it = std::find( maListeners.begin(), maListeners.end(), pListener );
240  if ( it != maListeners.end() )
241  {
242  maListeners.erase( it );
243  mxConfig->removePropertyChangeListener( pListener->maName, this );
244  }
245 }
246 
248 {
249  for (auto const& listener : maListeners)
250  {
251  mxConfig->removePropertyChangeListener( listener->maName, this );
252  listener->dispose();
253  }
254  maListeners.clear();
255  mbDisposed = true;
256 }
257 
258 void SAL_CALL comphelper::ConfigurationListener::disposing(css::lang::EventObject const &)
259 {
260  dispose();
261 }
262 
264  css::beans::PropertyChangeEvent const &rEvt )
265 {
266  // Code is commonly used inside the SolarMutexGuard
267  // so to avoid concurrent writes to the property,
268  // and allow fast, lock-less access, guard here.
269  //
270  // Note that we are abusing rtl::Reference here to do acquire/release because,
271  // unlike osl::Guard, it is tolerant of null pointers, and on some code paths, the
272  // SolarMutex does not exist.
274 
275  assert( rEvt.Source == mxConfig );
276  for (auto const& listener : maListeners)
277  {
278  if ( listener->maName == rEvt.PropertyName )
279  {
280  // ignore rEvt.NewValue - in theory it could be stale => not set.
281  css::uno::Any aValue = mxConfig->getPropertyValue( listener->maName );
282  listener->setProperty( aValue );
283  }
284  }
285 }
286 
287 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static void setPropertyValue(std::shared_ptr< ConfigurationChanges > const &batch, OUString const &path, css::uno::Any const &value)
SAL_DLLPRIVATE css::uno::Reference< css::container::XHierarchicalNameReplace > getGroup(OUString const &path) const
static css::uno::Reference< css::container::XHierarchicalNameReplace > getGroupReadWrite(std::shared_ptr< ConfigurationChanges > const &batch, OUString const &path)
const OUString & getBcp47(bool bResolveSystem=true) const
void dispose()
Release various circular references.
uno::Reference< uno::XComponentContext > context_
css::uno::Any getPropertyValue(OUString const &path) const
static std::shared_ptr< ConfigurationChanges > create(css::uno::Reference< css::uno::XComponentContext > const &context=comphelper::getProcessComponentContext())
Reference< deployment::XPackageRegistry > create(Reference< deployment::XPackageRegistry > const &xRootRegistry, OUString const &context, OUString const &cachePath, Reference< XComponentContext > const &xComponentContext)
css::uno::Reference< css::container::XNameAccess > getSetReadOnly(OUString const &path) const
void addListener(ConfigurationListenerPropertyBase *pListener)
Listen for the specific property denoted by the listener.
SAL_DLLPRIVATE ConfigurationWrapper(css::uno::Reference< css::uno::XComponentContext > const &context)
virtual void SAL_CALL disposing(css::lang::EventObject const &) override
css::uno::Any getLocalizedPropertyValue(std::u16string_view path) const
static void setLocalizedPropertyValue(std::shared_ptr< ConfigurationChanges > const &batch, OUString const &path, css::uno::Any const &value)
void removeListener(ConfigurationListenerPropertyBase *pListener)
Stop listening.
exports com.sun.star. configuration
const sal_uInt16 idx[]
static PropertyMapEntry const * find(const rtl::Reference< PropertySetInfo > &mxInfo, const OUString &aName) noexcept
const LanguageTag & getLocale()
Get the current LOK's locale.
Definition: lok.cxx:190
std::mutex mutex
Definition: random.cxx:41
#define SAL_WARN_IF(condition, area, stream)
A batch of configuration changes that is committed as a whole.
virtual void SAL_CALL propertyChange(css::beans::PropertyChangeEvent const &rEvt) override
Notify of the property change.
static SolarMutex * get()
Help components to get the SolarMutex easily.
Definition: solarmutex.cxx:34
bool isReadOnly(OUString const &path) const
css::uno::Reference< css::uno::XInterface > access_
static css::uno::Reference< css::container::XNameContainer > getSetReadWrite(std::shared_ptr< ConfigurationChanges > const &batch, OUString const &path)
css::uno::Reference< css::container::XHierarchicalNameAccess > getGroupReadOnly(OUString const &path) const
SAL_DLLPRIVATE css::uno::Reference< css::container::XNameContainer > getSet(OUString const &path) const
void dispose()
virtual void setProperty(const css::uno::Any &aProperty)=0
SAL_DLLPRIVATE void setPropertyValue(OUString const &path, css::uno::Any const &value) const
std::shared_ptr< ConfigurationChanges > createChanges() const
ConfigurationChanges(const ConfigurationChanges &)=delete
static ConfigurationWrapper const & get(css::uno::Reference< css::uno::XComponentContext > const &context)