summaryrefslogtreecommitdiff
path: root/configmgr
diff options
context:
space:
mode:
authorStephan Bergmann <sbergman@redhat.com>2012-07-25 18:54:38 +0200
committerStephan Bergmann <sbergman@redhat.com>2012-07-25 19:10:19 +0200
commitcf7c9599e776eba8e14614cecb528d3da5778190 (patch)
treeb71a0f46f1975e298197eac6d70a186b3048ada2 /configmgr
parent3605cb216faab6659f4bf90e76d9387df3ac08f6 (diff)
Make comphelper/configuration.hxx work for localized properties
See aebf5bf22304c73e121b16dc0b51f909c5f34c28 "fdo#52232 ConfigurationSet wrapper unusable for localized properties" for a discussion of the problems with the original design. 1 Redesigned configmgr's localized property access to understand ['*<locale>'] paths that select the best existing value match for the requested <locale>. Adapted ConfigurationWrapper::getLocalizedPropertyValue accordingly. 2 Redesigned ConfigurationChanges to fix the locale at instantiation time. That takes care of ConfigurationWrapper::setLocalizedPropertyValue, ConfigurationWrapper::getGroupReadWrite, and ConfigurationWrapper::getSetReadWrite. (This required an additional constructor parameter for the ReadWriteAccess service, to specify a locale at instantiation time.) 3 Redesigned ReadOnlyAccess to be a service that fixes the locale at instantiation time. That allows to take care of ConfigurationWrapper::getGroupReadOnly and ConfigurationWrapper::getSetReadOnly. Change-Id: I2ae7342b278b6f4222a0189a1deb2a53e204059f
Diffstat (limited to 'configmgr')
-rw-r--r--configmgr/source/access.cxx75
-rw-r--r--configmgr/source/childaccess.cxx76
-rw-r--r--configmgr/source/configmgr.component2
-rw-r--r--configmgr/source/readonlyaccess.cxx64
-rw-r--r--configmgr/source/readwriteaccess.cxx74
5 files changed, 186 insertions, 105 deletions
diff --git a/configmgr/source/access.cxx b/configmgr/source/access.cxx
index 30d05420573d..8d6d9cf4cdd5 100644
--- a/configmgr/source/access.cxx
+++ b/configmgr/source/access.cxx
@@ -1484,6 +1484,81 @@ rtl::Reference< Node > Access::getParentNode() {
}
rtl::Reference< ChildAccess > Access::getChild(rtl::OUString const & name) {
+ if (getNode()->kind() == Node::KIND_LOCALIZED_PROPERTY && name.match("*")) {
+ OUString locale(name.copy(1));
+ if (locale.match("*")) {
+ SAL_WARN(
+ "configmgr",
+ ("access best-matching localized property value via"
+ " \"*<locale>\" with <locale> \"")
+ << locale << "\" recursively starting with \"*\"");
+ return getChild(locale);
+ }
+ SAL_WARN_IF(
+ locale.isEmpty(), "configmgr",
+ ("access best-matching localized property value via \"*<locale>\""
+ " with empty <locale>; falling back to defaults"));
+ if (!locale.isEmpty()) {
+ // Find best match using an adaption of RFC 4647 lookup matching
+ // rules, removing "-" or "_" delimited segments from the end:
+ for (;;) {
+ rtl::Reference< ChildAccess > child(getChild(locale));
+ if (child.is()) {
+ return child;
+ }
+ sal_Int32 i = locale.getLength() - 1;
+ while (i > 0 && locale[i] != '-' && locale[i] != '_') {
+ --i;
+ }
+ if (i <= 0) {
+ break;
+ }
+ locale = locale.copy(0, i);
+ }
+ // As a workaround for broken xcu data that does not use shortest
+ // xml:lang attributes, look for the first entry with the same first
+ // segment as the requested language tag before falling back to
+ // defaults (see fdo#33638):
+ assert(
+ !locale.isEmpty() && locale.indexOf('-') == -1 &&
+ locale.indexOf('_') == -1);
+ std::vector< rtl::Reference< ChildAccess > > children(
+ getAllChildren());
+ for (std::vector< rtl::Reference< ChildAccess > >::iterator i(
+ children.begin());
+ i != children.end(); ++i)
+ {
+ OUString name2((*i)->getNameInternal());
+ if (name2.match(locale) &&
+ (name2.getLength() == locale.getLength() ||
+ name2[locale.getLength()] == '-' ||
+ name2[locale.getLength()] == '_'))
+ {
+ return *i;
+ }
+ }
+ }
+ // Defaults are the "en-US" locale, the "en" locale, the empty string
+ // locale, the first child (if any), or a null ChildAccess, in that
+ // order:
+ rtl::Reference< ChildAccess > child(getChild("en-US"));
+ if (child.is()) {
+ return child;
+ }
+ child = getChild("en");
+ if (child.is()) {
+ return child;
+ }
+ child = getChild(OUString());
+ if (child.is()) {
+ return child;
+ }
+ std::vector< rtl::Reference< ChildAccess > > children(getAllChildren());
+ if (!children.empty()) {
+ return children.front();
+ }
+ return rtl::Reference< ChildAccess >();
+ }
ModifiedChildren::iterator i(modifiedChildren_.find(name));
return i == modifiedChildren_.end()
? getUnmodifiedChild(name) : getModifiedChild(i);
diff --git a/configmgr/source/childaccess.cxx b/configmgr/source/childaccess.cxx
index 3b5a8e289420..99c4d2df587c 100644
--- a/configmgr/source/childaccess.cxx
+++ b/configmgr/source/childaccess.cxx
@@ -259,17 +259,6 @@ void ChildAccess::setProperty(
localModifications->add(getRelativePath());
}
-namespace
-{
- rtl::OUString lcl_StripSegment(const rtl::OUString &rLocale)
- {
- sal_Int32 i = !rLocale.isEmpty() ? rLocale.getLength() - 1 : 0;
- while (i > 0 && rLocale[i] != '-' && rLocale[i] != '_')
- --i;
- return rLocale.copy(0, i);
- }
-}
-
css::uno::Any ChildAccess::asValue() {
if (changedValue_.get() != 0) {
return *changedValue_;
@@ -280,66 +269,11 @@ css::uno::Any ChildAccess::asValue() {
getComponents());
case Node::KIND_LOCALIZED_PROPERTY:
{
- rtl::OUString sLocale(getRootAccess()->getLocale());
- if (!Components::allLocales(sLocale))
- {
- rtl::Reference< ChildAccess > child;
- // Find best match using an adaption of RFC 4647 lookup matching
- // rules, removing "-" or "_" delimited segments from the end
- while (1)
- {
- child = getChild(sLocale);
- if (child.is())
- break;
- rtl::OUString sTmpLocale = lcl_StripSegment(sLocale);
- if (sTmpLocale.isEmpty())
- break;
- sLocale = sTmpLocale;
- }
-
- //Resolves: fdo#33638 Look for the first entry with the same
- //first segment as the requested language tag, before falling
- //back to en-US, etc.
- typedef std::vector< rtl::Reference< ChildAccess > > ChildVector;
- if (!child.is())
- {
- const ChildVector &rAllChildren = getAllChildren();
- for (ChildVector::const_iterator aI = rAllChildren.begin(),
- aEnd = rAllChildren.end(); aI != aEnd; ++aI)
- {
- rtl::OUString sLanguage = lcl_StripSegment((*aI)->getNameInternal());
- if (sLocale == sLanguage)
- {
- child = *aI;
- break;
- }
- }
- }
-
- // defaults are the "en-US" locale, the "en" locale, the empty
- // string locale, the first child (if any), or a nil value (even
- // though it may be illegal for the given property), in that
- // order:
- if (!child.is())
- {
- child = getChild(
- rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("en-US")));
- if (!child.is())
- {
- child = getChild(
- rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("en")));
- if (!child.is())
- {
- child = getChild(rtl::OUString());
- if (!child.is())
- {
- ChildVector all(getAllChildren());
- if (!all.empty())
- child = all.front();
- }
- }
- }
- }
+ OUString locale(getRootAccess()->getLocale());
+ if (!Components::allLocales(locale)) {
+ rtl::Reference< ChildAccess > child(getChild("*" + locale));
+ // As a last resort, return a nil value even though it may be
+ // illegal for the given property:
return child.is() ? child->asValue() : css::uno::Any();
}
}
diff --git a/configmgr/source/configmgr.component b/configmgr/source/configmgr.component
index 34d03998e548..b409478291fb 100644
--- a/configmgr/source/configmgr.component
+++ b/configmgr/source/configmgr.component
@@ -30,7 +30,7 @@
<singleton name="com.sun.star.configuration.theDefaultProvider"/>
</implementation>
<implementation name="com.sun.star.comp.configuration.ReadOnlyAccess">
- <singleton name="com.sun.star.configuration.ReadOnlyAccess"/>
+ <service name="com.sun.star.configuration.ReadOnlyAccess"/>
</implementation>
<implementation name="com.sun.star.comp.configuration.ReadWriteAccess">
<service name="com.sun.star.configuration.ReadWriteAccess"/>
diff --git a/configmgr/source/readonlyaccess.cxx b/configmgr/source/readonlyaccess.cxx
index d9ab2dccd837..264eae14b3dd 100644
--- a/configmgr/source/readonlyaccess.cxx
+++ b/configmgr/source/readonlyaccess.cxx
@@ -30,15 +30,21 @@
#include "sal/config.h"
#include "boost/noncopyable.hpp"
-#include "cppuhelper/implbase2.hxx"
-#include "com/sun/star/lang/XServiceInfo.hpp"
#include "com/sun/star/container/NoSuchElementException.hpp"
#include "com/sun/star/container/XHierarchicalNameAccess.hpp"
+#include "com/sun/star/lang/IllegalArgumentException.hpp"
+#include "com/sun/star/lang/NotInitializedException.hpp"
+#include "com/sun/star/lang/XInitialization.hpp"
+#include "com/sun/star/lang/XServiceInfo.hpp"
+#include "com/sun/star/uno/Any.hxx"
+#include "com/sun/star/uno/Exception.hpp"
#include "com/sun/star/uno/Reference.hxx"
#include "com/sun/star/uno/RuntimeException.hpp"
#include "com/sun/star/uno/Sequence.hxx"
#include "com/sun/star/uno/XComponentContext.hpp"
#include "com/sun/star/uno/XInterface.hpp"
+#include "cppuhelper/implbase3.hxx"
+#include "cppuhelper/weak.hxx"
#include "osl/mutex.hxx"
#include "rtl/ref.hxx"
#include "rtl/ustring.h"
@@ -57,12 +63,15 @@ namespace {
namespace css = com::sun::star;
class Service:
- public cppu::WeakImplHelper2<
- css::lang::XServiceInfo, css::container::XHierarchicalNameAccess >,
+ public cppu::WeakImplHelper3<
+ css::lang::XServiceInfo, css::lang::XInitialization,
+ css::container::XHierarchicalNameAccess >,
private boost::noncopyable
{
public:
- Service(css::uno::Reference< css::uno::XComponentContext > const & context);
+ explicit Service(
+ css::uno::Reference< css::uno::XComponentContext > const & context):
+ context_(context) {}
private:
virtual ~Service() {}
@@ -79,30 +88,57 @@ private:
getSupportedServiceNames() throw (css::uno::RuntimeException)
{ return read_only_access::getSupportedServiceNames(); }
+ virtual void SAL_CALL initialize(
+ css::uno::Sequence< css::uno::Any > const & aArguments)
+ throw (css::uno::Exception, css::uno::RuntimeException);
+
virtual css::uno::Any SAL_CALL getByHierarchicalName(
rtl::OUString const & aName)
throw (
css::container::NoSuchElementException, css::uno::RuntimeException)
- { return root_->getByHierarchicalName(aName); }
+ { return getRoot()->getByHierarchicalName(aName); }
virtual sal_Bool SAL_CALL hasByHierarchicalName(rtl::OUString const & aName)
throw (css::uno::RuntimeException)
- { return root_->hasByHierarchicalName(aName); }
+ { return getRoot()->hasByHierarchicalName(aName); }
+
+ rtl::Reference< RootAccess > getRoot();
+ css::uno::Reference< css::uno::XComponentContext > context_;
+
+ osl::Mutex mutex_;
rtl::Reference< RootAccess > root_;
};
-Service::Service(
- css::uno::Reference< css::uno::XComponentContext > const & context)
+void Service::initialize(css::uno::Sequence< css::uno::Any > const & aArguments)
+ throw (css::uno::Exception, css::uno::RuntimeException)
{
- osl::MutexGuard guard(*lock());
- Components & components = Components::getSingleton(context);
- root_ = new RootAccess(
- components, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/")),
- rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")), false);
+ OUString locale;
+ if (aArguments.getLength() != 1 || !(aArguments[0] >>= locale)) {
+ throw css::lang::IllegalArgumentException(
+ "not exactly one string argument",
+ static_cast< cppu::OWeakObject * >(this), -1);
+ }
+ osl::MutexGuard g1(mutex_);
+ if (root_.is()) {
+ throw css::uno::RuntimeException(
+ "already initialized", static_cast< cppu::OWeakObject * >(this));
+ }
+ osl::MutexGuard g2(*lock());
+ Components & components = Components::getSingleton(context_);
+ root_ = new RootAccess(components, "/", locale, false);
components.addRootAccess(root_);
}
+rtl::Reference< RootAccess > Service::getRoot() {
+ osl::MutexGuard g(mutex_);
+ if (!root_.is()) {
+ throw css::lang::NotInitializedException(
+ "not initialized", static_cast< cppu::OWeakObject * >(this));
+ }
+ return root_;
+}
+
}
css::uno::Reference< css::uno::XInterface > create(
diff --git a/configmgr/source/readwriteaccess.cxx b/configmgr/source/readwriteaccess.cxx
index 0e4415fd44ed..5d8d1dedd800 100644
--- a/configmgr/source/readwriteaccess.cxx
+++ b/configmgr/source/readwriteaccess.cxx
@@ -30,18 +30,24 @@
#include "sal/config.h"
#include "boost/noncopyable.hpp"
-#include "cppuhelper/implbase2.hxx"
+#include "com/sun/star/configuration/XReadWriteAccess.hpp"
+#include "com/sun/star/container/NoSuchElementException.hpp"
#include "com/sun/star/lang/IllegalArgumentException.hpp"
+#include "com/sun/star/lang/NotInitializedException.hpp"
#include "com/sun/star/lang/WrappedTargetException.hpp"
+#include "com/sun/star/lang/XInitialization.hpp"
#include "com/sun/star/lang/XServiceInfo.hpp"
-#include "com/sun/star/container/NoSuchElementException.hpp"
-#include "com/sun/star/configuration/XReadWriteAccess.hpp"
+#include "com/sun/star/uno/Any.hxx"
+#include "com/sun/star/uno/Exception.hpp"
#include "com/sun/star/uno/Reference.hxx"
#include "com/sun/star/uno/RuntimeException.hpp"
#include "com/sun/star/uno/Sequence.hxx"
#include "com/sun/star/uno/XComponentContext.hpp"
#include "com/sun/star/uno/XInterface.hpp"
#include "com/sun/star/util/ChangesSet.hpp"
+#include "cppuhelper/implbase3.hxx"
+#include "cppuhelper/weak.hxx"
+#include "osl/mutex.hxx"
#include "rtl/ref.hxx"
#include "rtl/ustring.h"
#include "rtl/ustring.hxx"
@@ -59,12 +65,15 @@ namespace {
namespace css = com::sun::star;
class Service:
- public cppu::WeakImplHelper2<
- css::lang::XServiceInfo, css::configuration::XReadWriteAccess >,
+ public cppu::WeakImplHelper3<
+ css::lang::XServiceInfo, css::lang::XInitialization,
+ css::configuration::XReadWriteAccess >,
private boost::noncopyable
{
public:
- Service(css::uno::Reference< css::uno::XComponentContext > const & context);
+ explicit Service(
+ css::uno::Reference< css::uno::XComponentContext > const & context):
+ context_(context) {}
private:
virtual ~Service() {}
@@ -81,15 +90,19 @@ private:
getSupportedServiceNames() throw (css::uno::RuntimeException)
{ return read_write_access::getSupportedServiceNames(); }
+ virtual void SAL_CALL initialize(
+ css::uno::Sequence< css::uno::Any > const & aArguments)
+ throw (css::uno::Exception, css::uno::RuntimeException);
+
virtual css::uno::Any SAL_CALL getByHierarchicalName(
rtl::OUString const & aName)
throw (
css::container::NoSuchElementException, css::uno::RuntimeException)
- { return root_->getByHierarchicalName(aName); }
+ { return getRoot()->getByHierarchicalName(aName); }
virtual sal_Bool SAL_CALL hasByHierarchicalName(rtl::OUString const & aName)
throw (css::uno::RuntimeException)
- { return root_->hasByHierarchicalName(aName); }
+ { return getRoot()->hasByHierarchicalName(aName); }
virtual void SAL_CALL replaceByHierarchicalName(
rtl::OUString const & aName, css::uno::Any const & aElement)
@@ -97,34 +110,57 @@ private:
css::lang::IllegalArgumentException,
css::container::NoSuchElementException,
css::lang::WrappedTargetException, css::uno::RuntimeException)
- { root_->replaceByHierarchicalName(aName, aElement); }
+ { getRoot()->replaceByHierarchicalName(aName, aElement); }
virtual void SAL_CALL commitChanges()
throw (css::lang::WrappedTargetException, css::uno::RuntimeException)
- { root_->commitChanges(); }
+ { getRoot()->commitChanges(); }
virtual sal_Bool SAL_CALL hasPendingChanges()
throw (css::uno::RuntimeException)
- { return root_->hasPendingChanges(); }
+ { return getRoot()->hasPendingChanges(); }
virtual css::util::ChangesSet SAL_CALL getPendingChanges()
throw (css::uno::RuntimeException)
- { return root_->getPendingChanges(); }
+ { return getRoot()->getPendingChanges(); }
+ rtl::Reference< RootAccess > getRoot();
+
+ css::uno::Reference< css::uno::XComponentContext > context_;
+
+ osl::Mutex mutex_;
rtl::Reference< RootAccess > root_;
};
-Service::Service(
- css::uno::Reference< css::uno::XComponentContext > const & context)
+void Service::initialize(css::uno::Sequence< css::uno::Any > const & aArguments)
+ throw (css::uno::Exception, css::uno::RuntimeException)
{
- osl::MutexGuard guard(*lock());
- Components & components = Components::getSingleton(context);
- root_ = new RootAccess(
- components, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/")),
- rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")), true);
+ OUString locale;
+ if (aArguments.getLength() != 1 || !(aArguments[0] >>= locale)) {
+ throw css::lang::IllegalArgumentException(
+ "not exactly one string argument",
+ static_cast< cppu::OWeakObject * >(this), -1);
+ }
+ osl::MutexGuard g1(mutex_);
+ if (root_.is()) {
+ throw css::uno::RuntimeException(
+ "already initialized", static_cast< cppu::OWeakObject * >(this));
+ }
+ osl::MutexGuard g2(*lock());
+ Components & components = Components::getSingleton(context_);
+ root_ = new RootAccess(components, "/", locale, true);
components.addRootAccess(root_);
}
+rtl::Reference< RootAccess > Service::getRoot() {
+ osl::MutexGuard g(mutex_);
+ if (!root_.is()) {
+ throw css::lang::NotInitializedException(
+ "not initialized", static_cast< cppu::OWeakObject * >(this));
+ }
+ return root_;
+}
+
}
css::uno::Reference< css::uno::XInterface > create(