diff options
author | Stephan Bergmann <sbergman@redhat.com> | 2012-07-25 18:54:38 +0200 |
---|---|---|
committer | Stephan Bergmann <sbergman@redhat.com> | 2012-07-25 19:10:19 +0200 |
commit | cf7c9599e776eba8e14614cecb528d3da5778190 (patch) | |
tree | b71a0f46f1975e298197eac6d70a186b3048ada2 /configmgr | |
parent | 3605cb216faab6659f4bf90e76d9387df3ac08f6 (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.cxx | 75 | ||||
-rw-r--r-- | configmgr/source/childaccess.cxx | 76 | ||||
-rw-r--r-- | configmgr/source/configmgr.component | 2 | ||||
-rw-r--r-- | configmgr/source/readonlyaccess.cxx | 64 | ||||
-rw-r--r-- | configmgr/source/readwriteaccess.cxx | 74 |
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( |