[Libreoffice-commits] .: configmgr/source offapi/com offapi/UnoApi_offapi.mk officecfg/Module_officecfg.mk officecfg/Package_cppheader.mk officecfg/registry svl/inc svl/source unotools/inc unotools/Library_utl.mk unotools/Package_inc.mk unotools/source

Stephan Bergmann sbergmann at kemper.freedesktop.org
Tue Dec 13 03:51:19 PST 2011


 configmgr/source/access.cxx                            | 1432 ++++++++---------
 configmgr/source/access.hxx                            |  136 -
 configmgr/source/components.cxx                        |    6 
 configmgr/source/configmgr.component                   |    6 
 configmgr/source/data.cxx                              |   18 
 configmgr/source/data.hxx                              |    4 
 configmgr/source/groupnode.cxx                         |    4 
 configmgr/source/groupnode.hxx                         |    2 
 configmgr/source/localizedpropertynode.cxx             |    4 
 configmgr/source/localizedpropertynode.hxx             |    2 
 configmgr/source/makefile.mk                           |    3 
 configmgr/source/node.cxx                              |   22 
 configmgr/source/node.hxx                              |    5 
 configmgr/source/readonlyaccess.cxx                    |  126 +
 configmgr/source/readonlyaccess.hxx                    |   61 
 configmgr/source/readwriteaccess.cxx                   |  151 +
 configmgr/source/readwriteaccess.hxx                   |   61 
 configmgr/source/rootaccess.cxx                        |  179 +-
 configmgr/source/rootaccess.hxx                        |   40 
 configmgr/source/rootnode.cxx                          |   66 
 configmgr/source/rootnode.hxx                          |   65 
 configmgr/source/services.cxx                          |   10 
 configmgr/source/setnode.cxx                           |    4 
 configmgr/source/setnode.hxx                           |    2 
 configmgr/source/valueparser.cxx                       |    9 
 configmgr/source/writemodfile.cxx                      |    7 
 configmgr/source/xcsparser.cxx                         |   46 
 configmgr/source/xcuparser.cxx                         |   48 
 offapi/UnoApi_offapi.mk                                |    3 
 offapi/com/sun/star/configuration/ReadOnlyAccess.idl   |   49 
 offapi/com/sun/star/configuration/ReadWriteAccess.idl  |   49 
 offapi/com/sun/star/configuration/XReadWriteAccess.idl |   54 
 officecfg/Module_officecfg.mk                          |    1 
 officecfg/Package_cppheader.mk                         |   45 
 officecfg/registry/Makefile                            |   56 
 officecfg/registry/cppheader.xsl                       |  275 +++
 officecfg/registry/files.mk                            |  100 +
 svl/inc/svl/asiancfg.hxx                               |    2 
 svl/source/config/asiancfg.cxx                         |   99 -
 unotools/Library_utl.mk                                |    1 
 unotools/Package_inc.mk                                |    1 
 unotools/inc/unotools/configuration.hxx                |  270 +++
 unotools/source/config/configuration.cxx               |  207 ++
 43 files changed, 2729 insertions(+), 1002 deletions(-)

New commits:
commit bcdea3b379637a98e5bbc304078149ca6c2b6e03
Author: Stephan Bergmann <sbergman at redhat.com>
Date:   Tue Dec 13 12:37:00 2011 +0100

    Simplified, type-safe C++ configuration access.
    
    * New offapi com.sun.star.configuration entities to access the complete
      configuration read-only or read/write...
    * ...configmgr adapted to support those new services/singletons...
    * ...new unotools/configuration.hxx is the type-safe C++ plumbing on top of
      that...
    * ...officecfg now generates C++ headers to access all the properties and sets
      given in the .xcs files...
    * ...and svl's asiancfg.cxx exemplarily makes use of the new
      officecfg/Office/Common.hxx to access the configuration.
    * There is still TODOs:  For one, see those listed in
      officecfg/registry/cppheader.xsl.  For another, at least a notification
      mechanism for the new read-only configuration access and the C++ wrapper is
      missing.

diff --git a/configmgr/source/access.cxx b/configmgr/source/access.cxx
index dab5e21..c34a8ac 100644
--- a/configmgr/source/access.cxx
+++ b/configmgr/source/access.cxx
@@ -54,6 +54,7 @@
 #include "com/sun/star/container/XElementAccess.hpp"
 #include "com/sun/star/container/XHierarchicalName.hpp"
 #include "com/sun/star/container/XHierarchicalNameAccess.hpp"
+#include "com/sun/star/container/XHierarchicalNameReplace.hpp"
 #include "com/sun/star/container/XNameAccess.hpp"
 #include "com/sun/star/container/XNameContainer.hpp"
 #include "com/sun/star/container/XNamed.hpp"
@@ -163,689 +164,6 @@ void Access::initBroadcaster(
     initBroadcasterAndChanges(modifications, broadcaster, 0);
 }
 
-Access::Access(Components & components):
-    components_(components), disposed_(false)
-{
-    lock_ = lock();
-}
-
-Access::~Access() {}
-
-void Access::initDisposeBroadcaster(Broadcaster * broadcaster) {
-    assert(broadcaster != 0);
-    for (DisposeListeners::iterator i(disposeListeners_.begin());
-         i != disposeListeners_.end(); ++i)
-    {
-        broadcaster->addDisposeNotification(
-            *i,
-            css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
-    }
-    for (ContainerListeners::iterator i(containerListeners_.begin());
-         i != containerListeners_.end(); ++i)
-    {
-        broadcaster->addDisposeNotification(
-            i->get(),
-            css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
-    }
-    for (PropertyChangeListeners::iterator i(propertyChangeListeners_.begin());
-         i != propertyChangeListeners_.end(); ++i)
-    {
-        for (PropertyChangeListenersElement::iterator j(i->second.begin());
-             j != i->second.end(); ++j)
-        {
-            broadcaster->addDisposeNotification(
-                j->get(),
-                css::lang::EventObject(
-                    static_cast< cppu::OWeakObject * >(this)));
-        }
-    }
-    for (VetoableChangeListeners::iterator i(vetoableChangeListeners_.begin());
-         i != vetoableChangeListeners_.end(); ++i)
-    {
-        for (VetoableChangeListenersElement::iterator j(i->second.begin());
-             j != i->second.end(); ++j)
-        {
-            broadcaster->addDisposeNotification(
-                j->get(),
-                css::lang::EventObject(
-                    static_cast< cppu::OWeakObject * >(this)));
-        }
-    }
-    for (PropertiesChangeListeners::iterator i(
-             propertiesChangeListeners_.begin());
-         i != propertiesChangeListeners_.end(); ++i)
-    {
-        broadcaster->addDisposeNotification(
-            i->get(),
-            css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
-    }
-    //TODO: iterate over children w/ listeners (incl. unmodified ones):
-    for (ModifiedChildren::iterator i(modifiedChildren_.begin());
-         i != modifiedChildren_.end(); ++i)
-    {
-        rtl::Reference< ChildAccess > child(getModifiedChild(i));
-        if (child.is()) {
-            child->initDisposeBroadcaster(broadcaster);
-        }
-    }
-}
-
-void Access::clearListeners() throw() {
-    disposeListeners_.clear();
-    containerListeners_.clear();
-    propertyChangeListeners_.clear();
-    vetoableChangeListeners_.clear();
-    propertiesChangeListeners_.clear();
-    //TODO: iterate over children w/ listeners (incl. unmodified ones):
-    for (ModifiedChildren::iterator i(modifiedChildren_.begin());
-         i != modifiedChildren_.end(); ++i)
-    {
-        rtl::Reference< ChildAccess > child(getModifiedChild(i));
-        if (child.is()) {
-            child->clearListeners();
-        }
-    }
-}
-
-css::uno::Any Access::queryInterface(css::uno::Type const & aType)
-    throw (css::uno::RuntimeException)
-{
-    css::uno::Any res(OWeakObject::queryInterface(aType));
-    if (res.hasValue()) {
-        return res;
-    }
-    res = cppu::queryInterface(
-        aType, static_cast< css::lang::XTypeProvider * >(this),
-        static_cast< css::lang::XServiceInfo * >(this),
-        static_cast< css::lang::XComponent * >(this),
-        static_cast< css::container::XHierarchicalNameAccess * >(this),
-        static_cast< css::container::XContainer * >(this),
-        static_cast< css::beans::XExactName * >(this),
-        static_cast< css::container::XHierarchicalName * >(this),
-        static_cast< css::container::XNamed * >(this),
-        static_cast< css::beans::XProperty * >(this),
-        static_cast< css::container::XElementAccess * >(this),
-        static_cast< css::container::XNameAccess * >(this));
-    if (res.hasValue()) {
-        return res;
-    }
-    if (getNode()->kind() == Node::KIND_GROUP) {
-        res = cppu::queryInterface(
-            aType, static_cast< css::beans::XPropertySetInfo * >(this),
-            static_cast< css::beans::XPropertySet * >(this),
-            static_cast< css::beans::XMultiPropertySet * >(this),
-            static_cast< css::beans::XHierarchicalPropertySet * >(this),
-            static_cast< css::beans::XMultiHierarchicalPropertySet * >(this),
-            static_cast< css::beans::XHierarchicalPropertySetInfo * >(this));
-        if (res.hasValue()) {
-            return res;
-        }
-    }
-    if (getRootAccess()->isUpdate()) {
-        res = cppu::queryInterface(
-            aType, static_cast< css::container::XNameReplace * >(this));
-        if (res.hasValue()) {
-            return res;
-        }
-        if (getNode()->kind() != Node::KIND_GROUP ||
-            dynamic_cast< GroupNode * >(getNode().get())->isExtensible())
-        {
-            res = cppu::queryInterface(
-                aType, static_cast< css::container::XNameContainer * >(this));
-            if (res.hasValue()) {
-                return res;
-            }
-        }
-        if (getNode()->kind() == Node::KIND_SET) {
-            res = cppu::queryInterface(
-                aType, static_cast< css::lang::XSingleServiceFactory * >(this));
-        }
-    }
-    return res;
-}
-
-Components & Access::getComponents() const {
-    return components_;
-}
-
-void Access::checkLocalizedPropertyAccess() {
-    if (getNode()->kind() == Node::KIND_LOCALIZED_PROPERTY &&
-        !Components::allLocales(getRootAccess()->getLocale()))
-    {
-        throw css::uno::RuntimeException(
-            rtl::OUString(
-                RTL_CONSTASCII_USTRINGPARAM(
-                    "configmgr Access to specialized LocalizedPropertyNode")),
-            static_cast< cppu::OWeakObject * >(this));
-    }
-}
-
-rtl::Reference< Node > Access::getParentNode() {
-    rtl::Reference< Access > parent(getParentAccess());
-    return parent.is() ? parent->getNode() : rtl::Reference< Node >();
-}
-
-rtl::Reference< ChildAccess > Access::getChild(rtl::OUString const & name) {
-    ModifiedChildren::iterator i(modifiedChildren_.find(name));
-    return i == modifiedChildren_.end()
-        ? getUnmodifiedChild(name) : getModifiedChild(i);
-}
-
-std::vector< rtl::Reference< ChildAccess > > Access::getAllChildren() {
-    std::vector< rtl::Reference< ChildAccess > > vec;
-    NodeMap & members = getNode()->getMembers();
-    for (NodeMap::iterator i(members.begin()); i != members.end(); ++i) {
-        if (modifiedChildren_.find(i->first) == modifiedChildren_.end()) {
-            vec.push_back(getUnmodifiedChild(i->first));
-            assert(vec.back().is());
-        }
-    }
-    for (ModifiedChildren::iterator i(modifiedChildren_.begin());
-         i != modifiedChildren_.end(); ++i)
-    {
-        rtl::Reference< ChildAccess > child(getModifiedChild(i));
-        if (child.is()) {
-            vec.push_back(child);
-        }
-    }
-    return vec;
-}
-
-void Access::checkValue(css::uno::Any const & value, Type type, bool nillable) {
-    bool ok;
-    switch (type) {
-    case TYPE_NIL:
-        assert(false);
-        // fall through (cannot happen)
-    case TYPE_ERROR:
-        ok = false;
-        break;
-    case TYPE_ANY:
-        switch (getDynamicType(value)) {
-        case TYPE_ANY:
-            assert(false);
-            // fall through (cannot happen)
-        case TYPE_ERROR:
-            ok = false;
-            break;
-        case TYPE_NIL:
-            ok = nillable;
-            break;
-        default:
-            ok = true;
-            break;
-        }
-        break;
-    default:
-        ok = value.hasValue() ? value.isExtractableTo(mapType(type)) : nillable;
-        break;
-    }
-    if (!ok) {
-        throw css::lang::IllegalArgumentException(
-            rtl::OUString(
-                RTL_CONSTASCII_USTRINGPARAM(
-                    "configmgr inappropriate property value")),
-            static_cast< cppu::OWeakObject * >(this), -1);
-    }
-}
-
-void Access::insertLocalizedValueChild(
-    rtl::OUString const & name, css::uno::Any const & value,
-    Modifications * localModifications)
-{
-    assert(localModifications != 0);
-    LocalizedPropertyNode * locprop = dynamic_cast< LocalizedPropertyNode * >(
-        getNode().get());
-    checkValue(value, locprop->getStaticType(), locprop->isNillable());
-    rtl::Reference< ChildAccess > child(
-        new ChildAccess(
-            components_, getRootAccess(), this, name,
-            new LocalizedValueNode(Data::NO_LAYER, value)));
-    markChildAsModified(child);
-    localModifications->add(child->getRelativePath());
-}
-
-void Access::reportChildChanges(
-    std::vector< css::util::ElementChange > * changes)
-{
-    assert(changes != 0);
-    for (ModifiedChildren::iterator i(modifiedChildren_.begin());
-         i != modifiedChildren_.end(); ++i)
-    {
-        rtl::Reference< ChildAccess > child(getModifiedChild(i));
-        if (child.is()) {
-            child->reportChildChanges(changes);
-            changes->push_back(css::util::ElementChange());
-                //TODO: changed value and/or inserted node
-        } else {
-            changes->push_back(css::util::ElementChange()); //TODO: removed node
-        }
-    }
-}
-
-void Access::commitChildChanges(
-    bool valid, Modifications * globalModifications)
-{
-    assert(globalModifications != 0);
-    while (!modifiedChildren_.empty()) {
-        bool childValid = valid;
-        ModifiedChildren::iterator i(modifiedChildren_.begin());
-        rtl::Reference< ChildAccess > child(getModifiedChild(i));
-        if (child.is()) {
-            childValid = childValid && !child->isFinalized();
-            child->commitChanges(childValid, globalModifications);
-                //TODO: currently, this is called here for directly inserted
-                // children as well as for children whose sub-children were
-                // modified (and should never be called for directly removed
-                // children); clarify what exactly should happen here for
-                // directly inserted children
-        }
-        NodeMap & members = getNode()->getMembers();
-        NodeMap::iterator j(members.find(i->first));
-        if (child.is()) {
-            // Inserted:
-            if (j != members.end()) {
-                childValid = childValid &&
-                    j->second->getFinalized() == Data::NO_LAYER;
-                if (childValid) {
-                    child->getNode()->setMandatory(j->second->getMandatory());
-                }
-            }
-            if (childValid) {
-                members[i->first] = child->getNode();
-            }
-        } else {
-            // Removed:
-            childValid = childValid && j != members.end() &&
-                j->second->getFinalized() == Data::NO_LAYER &&
-                j->second->getMandatory() == Data::NO_LAYER;
-            if (childValid) {
-                members.erase(j);
-            }
-        }
-        if (childValid && i->second.directlyModified) {
-            Path path(getAbsolutePath());
-            path.push_back(i->first);
-            components_.addModification(path);
-            globalModifications->add(path);
-        }
-        i->second.child->committed();
-        modifiedChildren_.erase(i);
-    }
-}
-
-void Access::initBroadcasterAndChanges(
-    Modifications::Node const & modifications, Broadcaster * broadcaster,
-    std::vector< css::util::ElementChange > * allChanges)
-{
-    assert(broadcaster != 0);
-    comphelper::SequenceAsVector< css::beans::PropertyChangeEvent > propChanges;
-    bool collectPropChanges = !propertiesChangeListeners_.empty();
-    for (Modifications::Node::Children::const_iterator i(
-             modifications.children.begin());
-         i != modifications.children.end(); ++i)
-    {
-        rtl::Reference< ChildAccess > child(getChild(i->first));
-        if (child.is()) {
-            switch (child->getNode()->kind()) {
-            case Node::KIND_LOCALIZED_PROPERTY:
-                if (!i->second.children.empty()) {
-                    if (Components::allLocales(getRootAccess()->getLocale())) {
-                        child->initBroadcasterAndChanges(
-                            i->second, broadcaster, allChanges);
-                            //TODO: if allChanges==0, recurse only into children
-                            // w/ listeners
-                    } else {
-                        //TODO: filter child mods that are irrelevant for
-                        // locale:
-                        for (ContainerListeners::iterator j(
-                                 containerListeners_.begin());
-                             j != containerListeners_.end(); ++j)
-                        {
-                            broadcaster->
-                                addContainerElementReplacedNotification(
-                                    *j,
-                                    css::container::ContainerEvent(
-                                        static_cast< cppu::OWeakObject * >(
-                                            this),
-                                        css::uno::makeAny(i->first),
-                                        css::uno::Any(), css::uno::Any()));
-                                //TODO: non-void Element, ReplacedElement
-                        }
-                        PropertyChangeListeners::iterator j(
-                            propertyChangeListeners_.find(i->first));
-                        if (j != propertyChangeListeners_.end()) {
-                            for (PropertyChangeListenersElement::iterator k(
-                                     j->second.begin());
-                                 k != j->second.end(); ++k)
-                            {
-                                broadcaster->addPropertyChangeNotification(
-                                    *k,
-                                    css::beans::PropertyChangeEvent(
-                                        static_cast< cppu::OWeakObject * >(
-                                            this),
-                                        i->first, false, -1, css::uno::Any(),
-                                        css::uno::Any()));
-                            }
-                        }
-                        j = propertyChangeListeners_.find(rtl::OUString());
-                        if (j != propertyChangeListeners_.end()) {
-                            for (PropertyChangeListenersElement::iterator k(
-                                     j->second.begin());
-                                 k != j->second.end(); ++k)
-                            {
-                                broadcaster->addPropertyChangeNotification(
-                                    *k,
-                                    css::beans::PropertyChangeEvent(
-                                        static_cast< cppu::OWeakObject * >(
-                                            this),
-                                        i->first, false, -1, css::uno::Any(),
-                                        css::uno::Any()));
-                            }
-                        }
-                        if (allChanges != 0) {
-                            allChanges->push_back(
-                                css::util::ElementChange(
-                                    css::uno::makeAny(
-                                        child->getRelativePathRepresentation()),
-                                    css::uno::Any(), css::uno::Any()));
-                                //TODO: non-void Element, ReplacedElement
-                        }
-                        if (collectPropChanges) {
-                            propChanges.push_back(
-                                css::beans::PropertyChangeEvent(
-                                    static_cast< cppu::OWeakObject * >(this),
-                                    i->first, false, -1, css::uno::Any(),
-                                    css::uno::Any()));
-                        }
-                    }
-                }
-                // else: spurious Modifications::Node not representing a change
-                break;
-            case Node::KIND_LOCALIZED_VALUE:
-                assert(Components::allLocales(getRootAccess()->getLocale()));
-                for (ContainerListeners::iterator j(
-                         containerListeners_.begin());
-                     j != containerListeners_.end(); ++j)
-                {
-                    broadcaster->addContainerElementReplacedNotification(
-                        *j,
-                        css::container::ContainerEvent(
-                            static_cast< cppu::OWeakObject * >(this),
-                            css::uno::makeAny(i->first), child->asValue(),
-                            css::uno::Any()));
-                        //TODO: distinguish add/modify; non-void ReplacedElement
-                }
-                if (allChanges != 0) {
-                    allChanges->push_back(
-                        css::util::ElementChange(
-                            css::uno::makeAny(
-                                child->getRelativePathRepresentation()),
-                            child->asValue(), css::uno::Any()));
-                        //TODO: non-void ReplacedElement
-                }
-                assert(!collectPropChanges);
-                break;
-            case Node::KIND_PROPERTY:
-                {
-                    for (ContainerListeners::iterator j(
-                             containerListeners_.begin());
-                         j != containerListeners_.end(); ++j)
-                    {
-                        broadcaster->addContainerElementReplacedNotification(
-                            *j,
-                            css::container::ContainerEvent(
-                                static_cast< cppu::OWeakObject * >(this),
-                                css::uno::makeAny(i->first), child->asValue(),
-                                css::uno::Any()));
-                            //TODO: distinguish add/remove/modify; non-void
-                            // ReplacedElement
-                    }
-                    PropertyChangeListeners::iterator j(
-                        propertyChangeListeners_.find(i->first));
-                    if (j != propertyChangeListeners_.end()) {
-                        for (PropertyChangeListenersElement::iterator k(
-                                 j->second.begin());
-                             k != j->second.end(); ++k)
-                        {
-                            broadcaster->addPropertyChangeNotification(
-                                *k,
-                                css::beans::PropertyChangeEvent(
-                                    static_cast< cppu::OWeakObject * >(this),
-                                    i->first, false, -1, css::uno::Any(),
-                                    css::uno::Any()));
-                        }
-                    }
-                    j = propertyChangeListeners_.find(rtl::OUString());
-                    if (j != propertyChangeListeners_.end()) {
-                        for (PropertyChangeListenersElement::iterator k(
-                                 j->second.begin());
-                             k != j->second.end(); ++k)
-                        {
-                            broadcaster->addPropertyChangeNotification(
-                                *k,
-                                css::beans::PropertyChangeEvent(
-                                    static_cast< cppu::OWeakObject * >(this),
-                                    i->first, false, -1, css::uno::Any(),
-                                    css::uno::Any()));
-                        }
-                    }
-                    if (allChanges != 0) {
-                        allChanges->push_back(
-                            css::util::ElementChange(
-                                css::uno::makeAny(
-                                    child->getRelativePathRepresentation()),
-                                child->asValue(), css::uno::Any()));
-                            //TODO: non-void ReplacedElement
-                    }
-                    if (collectPropChanges) {
-                        propChanges.push_back(
-                            css::beans::PropertyChangeEvent(
-                                static_cast< cppu::OWeakObject * >(this),
-                                i->first, false, -1, css::uno::Any(),
-                                css::uno::Any()));
-                    }
-                }
-                break;
-            case Node::KIND_GROUP:
-            case Node::KIND_SET:
-                if (i->second.children.empty()) {
-                    if (child->getNode()->getTemplateName().getLength() != 0) {
-                        for (ContainerListeners::iterator j(
-                                 containerListeners_.begin());
-                             j != containerListeners_.end(); ++j)
-                        {
-                            broadcaster->
-                                addContainerElementInsertedNotification(
-                                    *j,
-                                    css::container::ContainerEvent(
-                                        static_cast< cppu::OWeakObject * >(
-                                            this),
-                                        css::uno::makeAny(i->first),
-                                        child->asValue(), css::uno::Any()));
-                        }
-                        if (allChanges != 0) {
-                            allChanges->push_back(
-                                css::util::ElementChange(
-                                    css::uno::makeAny(
-                                        child->getRelativePathRepresentation()),
-                                    css::uno::Any(), css::uno::Any()));
-                                //TODO: non-void Element, ReplacedElement
-                        }
-                    }
-                    // else: spurious Modifications::Node not representing a
-                    // change
-                } else {
-                    child->initBroadcasterAndChanges(
-                        i->second, broadcaster, allChanges);
-                        //TODO: if allChanges==0, recurse only into children w/
-                        // listeners
-                }
-                break;
-            }
-        } else {
-            switch (getNode()->kind()) {
-            case Node::KIND_LOCALIZED_PROPERTY:
-                // Removed localized property value:
-                assert(Components::allLocales(getRootAccess()->getLocale()));
-                for (ContainerListeners::iterator j(
-                         containerListeners_.begin());
-                     j != containerListeners_.end(); ++j)
-                {
-                    broadcaster->addContainerElementRemovedNotification(
-                        *j,
-                        css::container::ContainerEvent(
-                            static_cast< cppu::OWeakObject * >(this),
-                            css::uno::makeAny(i->first), css::uno::Any(),
-                            css::uno::Any()));
-                        //TODO: non-void ReplacedElement
-                }
-                if (allChanges != 0) {
-                    rtl::OUStringBuffer path(getRelativePathRepresentation());
-                    if (path.getLength() != 0) {
-                        path.append(sal_Unicode('/'));
-                    }
-                    path.append(
-                        Data::createSegment(
-                            rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")),
-                            i->first));
-                    allChanges->push_back(
-                        css::util::ElementChange(
-                            css::uno::makeAny(path.makeStringAndClear()),
-                            css::uno::Any(), css::uno::Any()));
-                        //TODO: non-void ReplacedElement
-                }
-                assert(!collectPropChanges);
-                break;
-            case Node::KIND_GROUP:
-                {
-                    // Removed (non-localized) extension property:
-                    for (ContainerListeners::iterator j(
-                             containerListeners_.begin());
-                         j != containerListeners_.end(); ++j)
-                    {
-                        broadcaster->addContainerElementRemovedNotification(
-                            *j,
-                            css::container::ContainerEvent(
-                                static_cast< cppu::OWeakObject * >(this),
-                                css::uno::makeAny(i->first), css::uno::Any(),
-                                css::uno::Any()));
-                            //TODO: non-void ReplacedElement
-                    }
-                    PropertyChangeListeners::iterator j(
-                        propertyChangeListeners_.find(i->first));
-                    if (j != propertyChangeListeners_.end()) {
-                        for (PropertyChangeListenersElement::iterator k(
-                                 j->second.begin());
-                             k != j->second.end(); ++k)
-                        {
-                            broadcaster->addPropertyChangeNotification(
-                                *k,
-                                css::beans::PropertyChangeEvent(
-                                    static_cast< cppu::OWeakObject * >(this),
-                                    i->first, false, -1, css::uno::Any(),
-                                    css::uno::Any()));
-                        }
-                    }
-                    j = propertyChangeListeners_.find(rtl::OUString());
-                    if (j != propertyChangeListeners_.end()) {
-                        for (PropertyChangeListenersElement::iterator k(
-                                 j->second.begin());
-                             k != j->second.end(); ++k)
-                        {
-                            broadcaster->addPropertyChangeNotification(
-                                *k,
-                                css::beans::PropertyChangeEvent(
-                                    static_cast< cppu::OWeakObject * >(this),
-                                    i->first, false, -1, css::uno::Any(),
-                                    css::uno::Any()));
-                        }
-                    }
-                    if (allChanges != 0) {
-                        rtl::OUStringBuffer path(
-                            getRelativePathRepresentation());
-                        if (path.getLength() != 0) {
-                            path.append(sal_Unicode('/'));
-                        }
-                        path.append(i->first);
-                        allChanges->push_back(
-                            css::util::ElementChange(
-                                css::uno::makeAny(path.makeStringAndClear()),
-                                css::uno::Any(), css::uno::Any()));
-                            //TODO: non-void ReplacedElement
-                    }
-                    if (collectPropChanges) {
-                        propChanges.push_back(
-                            css::beans::PropertyChangeEvent(
-                                static_cast< cppu::OWeakObject * >(this),
-                                i->first, false, -1, css::uno::Any(),
-                                css::uno::Any()));
-                    }
-                }
-                break;
-            case Node::KIND_SET:
-                // Removed set member:
-                if (i->second.children.empty()) {
-                    for (ContainerListeners::iterator j(
-                             containerListeners_.begin());
-                         j != containerListeners_.end(); ++j)
-                    {
-                        broadcaster->addContainerElementRemovedNotification(
-                            *j,
-                            css::container::ContainerEvent(
-                                static_cast< cppu::OWeakObject * >(this),
-                                css::uno::makeAny(i->first),
-                                css::uno::Any(), css::uno::Any()));
-                            //TODO: non-void ReplacedElement
-                    }
-                    if (allChanges != 0) {
-                        rtl::OUStringBuffer path(
-                            getRelativePathRepresentation());
-                        if (path.getLength() != 0) {
-                            path.append(sal_Unicode('/'));
-                        }
-                        path.append(
-                            Data::createSegment(
-                                rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")),
-                                i->first));
-                        allChanges->push_back(
-                            css::util::ElementChange(
-                                css::uno::makeAny(path.makeStringAndClear()),
-                                css::uno::Any(), css::uno::Any()));
-                            //TODO: non-void ReplacedElement
-                    }
-                }
-                // else: spurious Modifications::Node not representing a change
-                break;
-            default:
-                assert(false); // this cannot happen
-                break;
-            }
-        }
-    }
-    if (!propChanges.empty()) {
-        css::uno::Sequence< css::beans::PropertyChangeEvent > seq(
-            propChanges.getAsConstList());
-        for (PropertiesChangeListeners::iterator i(
-                 propertiesChangeListeners_.begin());
-             i != propertiesChangeListeners_.end(); ++i)
-        {
-            broadcaster->addPropertiesChangeNotification(*i, seq);
-        }
-    }
-}
-
-bool Access::isDisposed() const {
-    return disposed_;
-}
-
-Access::ModifiedChild::ModifiedChild() {}
-
-Access::ModifiedChild::ModifiedChild(
-    rtl::Reference< ChildAccess > const & theChild, bool theDirectlyModified):
-    child(theChild), directlyModified(theDirectlyModified)
-{}
-
 css::uno::Sequence< css::uno::Type > Access::getTypes()
     throw (css::uno::RuntimeException)
 {
@@ -858,8 +176,6 @@ css::uno::Sequence< css::uno::Type > Access::getTypes()
     types.push_back(cppu::UnoType< css::lang::XTypeProvider >::get());
     types.push_back(cppu::UnoType< css::lang::XServiceInfo >::get());
     types.push_back(cppu::UnoType< css::lang::XComponent >::get());
-    types.push_back(
-        cppu::UnoType< css::container::XHierarchicalNameAccess >::get());
     types.push_back(cppu::UnoType< css::container::XContainer >::get());
     types.push_back(cppu::UnoType< css::beans::XExactName >::get());
     types.push_back(cppu::UnoType< css::container::XHierarchicalName >::get());
@@ -880,6 +196,8 @@ css::uno::Sequence< css::uno::Type > Access::getTypes()
     }
     if (getRootAccess()->isUpdate()) {
         types.push_back(cppu::UnoType< css::container::XNameReplace >::get());
+        types.push_back(
+            cppu::UnoType< css::container::XHierarchicalNameReplace >::get());
         if (getNode()->kind() != Node::KIND_GROUP ||
             dynamic_cast< GroupNode * >(getNode().get())->isExtensible())
         {
@@ -890,6 +208,9 @@ css::uno::Sequence< css::uno::Type > Access::getTypes()
             types.push_back(
                 cppu::UnoType< css::lang::XSingleServiceFactory >::get());
         }
+    } else {
+        types.push_back(
+            cppu::UnoType< css::container::XHierarchicalNameAccess >::get());
     }
     addTypes(&types);
     return types.getAsConstList();
@@ -1148,6 +469,57 @@ sal_Bool Access::hasByHierarchicalName(rtl::OUString const & aName)
     return getSubChild(aName).is();
 }
 
+void Access::replaceByHierarchicalName(
+    rtl::OUString const & aName, css::uno::Any const & aElement)
+    throw (
+        css::lang::IllegalArgumentException,
+        css::container::NoSuchElementException,
+        css::lang::WrappedTargetException, css::uno::RuntimeException)
+{
+    //TODO: Actually support sets and combine with replaceByName:
+    assert(thisIs(IS_UPDATE));
+    Broadcaster bc;
+    {
+        osl::MutexGuard g(*lock_);
+        checkLocalizedPropertyAccess();
+        rtl::Reference< ChildAccess > child(getSubChild(aName));
+        if (!child.is()) {
+            throw css::container::NoSuchElementException(
+                aName, static_cast< cppu::OWeakObject * >(this));
+        }
+        child->checkFinalized();
+        rtl::Reference< Node > parent(child->getParentNode());
+        assert(parent.is());
+        Modifications localMods;
+        switch (parent->kind()) {
+        case Node::KIND_LOCALIZED_PROPERTY:
+        case Node::KIND_GROUP:
+            child->setProperty(aElement, &localMods);
+            break;
+        case Node::KIND_SET:
+            throw css::lang::IllegalArgumentException(
+                rtl::OUString(
+                    RTL_CONSTASCII_USTRINGPARAM(
+                        "configmgr::Access::replaceByHierarchicalName does not"
+                        " currently support set members")),
+                static_cast< cppu::OWeakObject * >(this), 0);
+        case Node::KIND_ROOT:
+            throw css::lang::IllegalArgumentException(
+                (rtl::OUString(
+                    RTL_CONSTASCII_USTRINGPARAM(
+                        "configmgr::Access::replaceByHierarchicalName does not"
+                        " allow changing component "))
+                 + aName),
+                static_cast< cppu::OWeakObject * >(this), 0);
+        default:
+            assert(false); // this cannot happen
+            break;
+        }
+        getNotificationRoot()->initBroadcaster(localMods.getRoot(), &bc);
+    }
+    bc.send();
+}
+
 void Access::addContainerListener(
     css::uno::Reference< css::container::XContainerListener > const & xListener)
     throw (css::uno::RuntimeException)
@@ -1957,6 +1329,696 @@ css::uno::Reference< css::uno::XInterface > Access::createInstanceWithArguments(
     return createInstance();
 }
 
+Access::Access(Components & components):
+    components_(components), disposed_(false)
+{
+    lock_ = lock();
+}
+
+Access::~Access() {}
+
+void Access::initDisposeBroadcaster(Broadcaster * broadcaster) {
+    assert(broadcaster != 0);
+    for (DisposeListeners::iterator i(disposeListeners_.begin());
+         i != disposeListeners_.end(); ++i)
+    {
+        broadcaster->addDisposeNotification(
+            *i,
+            css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
+    }
+    for (ContainerListeners::iterator i(containerListeners_.begin());
+         i != containerListeners_.end(); ++i)
+    {
+        broadcaster->addDisposeNotification(
+            i->get(),
+            css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
+    }
+    for (PropertyChangeListeners::iterator i(propertyChangeListeners_.begin());
+         i != propertyChangeListeners_.end(); ++i)
+    {
+        for (PropertyChangeListenersElement::iterator j(i->second.begin());
+             j != i->second.end(); ++j)
+        {
+            broadcaster->addDisposeNotification(
+                j->get(),
+                css::lang::EventObject(
+                    static_cast< cppu::OWeakObject * >(this)));
+        }
+    }
+    for (VetoableChangeListeners::iterator i(vetoableChangeListeners_.begin());
+         i != vetoableChangeListeners_.end(); ++i)
+    {
+        for (VetoableChangeListenersElement::iterator j(i->second.begin());
+             j != i->second.end(); ++j)
+        {
+            broadcaster->addDisposeNotification(
+                j->get(),
+                css::lang::EventObject(
+                    static_cast< cppu::OWeakObject * >(this)));
+        }
+    }
+    for (PropertiesChangeListeners::iterator i(
+             propertiesChangeListeners_.begin());
+         i != propertiesChangeListeners_.end(); ++i)
+    {
+        broadcaster->addDisposeNotification(
+            i->get(),
+            css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
+    }
+    //TODO: iterate over children w/ listeners (incl. unmodified ones):
+    for (ModifiedChildren::iterator i(modifiedChildren_.begin());
+         i != modifiedChildren_.end(); ++i)
+    {
+        rtl::Reference< ChildAccess > child(getModifiedChild(i));
+        if (child.is()) {
+            child->initDisposeBroadcaster(broadcaster);
+        }
+    }
+}
+
+void Access::clearListeners() throw() {
+    disposeListeners_.clear();
+    containerListeners_.clear();
+    propertyChangeListeners_.clear();
+    vetoableChangeListeners_.clear();
+    propertiesChangeListeners_.clear();
+    //TODO: iterate over children w/ listeners (incl. unmodified ones):
+    for (ModifiedChildren::iterator i(modifiedChildren_.begin());
+         i != modifiedChildren_.end(); ++i)
+    {
+        rtl::Reference< ChildAccess > child(getModifiedChild(i));
+        if (child.is()) {
+            child->clearListeners();
+        }
+    }
+}
+
+css::uno::Any Access::queryInterface(css::uno::Type const & aType)
+    throw (css::uno::RuntimeException)
+{
+    css::uno::Any res(OWeakObject::queryInterface(aType));
+    if (res.hasValue()) {
+        return res;
+    }
+    res = cppu::queryInterface(
+        aType, static_cast< css::lang::XTypeProvider * >(this),
+        static_cast< css::lang::XServiceInfo * >(this),
+        static_cast< css::lang::XComponent * >(this),
+        static_cast< css::container::XHierarchicalNameAccess * >(this),
+        static_cast< css::container::XContainer * >(this),
+        static_cast< css::beans::XExactName * >(this),
+        static_cast< css::container::XHierarchicalName * >(this),
+        static_cast< css::container::XNamed * >(this),
+        static_cast< css::beans::XProperty * >(this),
+        static_cast< css::container::XElementAccess * >(this),
+        static_cast< css::container::XNameAccess * >(this));
+    if (res.hasValue()) {
+        return res;
+    }
+    if (getNode()->kind() == Node::KIND_GROUP) {
+        res = cppu::queryInterface(
+            aType, static_cast< css::beans::XPropertySetInfo * >(this),
+            static_cast< css::beans::XPropertySet * >(this),
+            static_cast< css::beans::XMultiPropertySet * >(this),
+            static_cast< css::beans::XHierarchicalPropertySet * >(this),
+            static_cast< css::beans::XMultiHierarchicalPropertySet * >(this),
+            static_cast< css::beans::XHierarchicalPropertySetInfo * >(this));
+        if (res.hasValue()) {
+            return res;
+        }
+    }
+    if (getRootAccess()->isUpdate()) {
+        res = cppu::queryInterface(
+            aType, static_cast< css::container::XNameReplace * >(this),
+            static_cast< css::container::XHierarchicalNameReplace * >(this));
+        if (res.hasValue()) {
+            return res;
+        }
+        if (getNode()->kind() != Node::KIND_GROUP ||
+            dynamic_cast< GroupNode * >(getNode().get())->isExtensible())
+        {
+            res = cppu::queryInterface(
+                aType, static_cast< css::container::XNameContainer * >(this));
+            if (res.hasValue()) {
+                return res;
+            }
+        }
+        if (getNode()->kind() == Node::KIND_SET) {
+            res = cppu::queryInterface(
+                aType, static_cast< css::lang::XSingleServiceFactory * >(this));
+        }
+    }
+    return res;
+}
+
+Components & Access::getComponents() const {
+    return components_;
+}
+
+void Access::checkLocalizedPropertyAccess() {
+    if (getNode()->kind() == Node::KIND_LOCALIZED_PROPERTY &&
+        !Components::allLocales(getRootAccess()->getLocale()))
+    {
+        throw css::uno::RuntimeException(
+            rtl::OUString(
+                RTL_CONSTASCII_USTRINGPARAM(
+                    "configmgr Access to specialized LocalizedPropertyNode")),
+            static_cast< cppu::OWeakObject * >(this));
+    }
+}
+
+rtl::Reference< Node > Access::getParentNode() {
+    rtl::Reference< Access > parent(getParentAccess());
+    return parent.is() ? parent->getNode() : rtl::Reference< Node >();
+}
+
+rtl::Reference< ChildAccess > Access::getChild(rtl::OUString const & name) {
+    ModifiedChildren::iterator i(modifiedChildren_.find(name));
+    return i == modifiedChildren_.end()
+        ? getUnmodifiedChild(name) : getModifiedChild(i);
+}
+
+std::vector< rtl::Reference< ChildAccess > > Access::getAllChildren() {
+    std::vector< rtl::Reference< ChildAccess > > vec;
+    NodeMap const & members = getNode()->getMembers();
+    for (NodeMap::const_iterator i(members.begin()); i != members.end(); ++i) {
+        if (modifiedChildren_.find(i->first) == modifiedChildren_.end()) {
+            vec.push_back(getUnmodifiedChild(i->first));
+            assert(vec.back().is());
+        }
+    }
+    for (ModifiedChildren::iterator i(modifiedChildren_.begin());
+         i != modifiedChildren_.end(); ++i)
+    {
+        rtl::Reference< ChildAccess > child(getModifiedChild(i));
+        if (child.is()) {
+            vec.push_back(child);
+        }
+    }
+    return vec;
+}
+
+void Access::checkValue(css::uno::Any const & value, Type type, bool nillable) {
+    bool ok;
+    switch (type) {
+    case TYPE_NIL:
+        assert(false);
+        // fall through (cannot happen)
+    case TYPE_ERROR:
+        ok = false;
+        break;
+    case TYPE_ANY:
+        switch (getDynamicType(value)) {
+        case TYPE_ANY:
+            assert(false);
+            // fall through (cannot happen)
+        case TYPE_ERROR:
+            ok = false;
+            break;
+        case TYPE_NIL:
+            ok = nillable;
+            break;
+        default:
+            ok = true;
+            break;
+        }
+        break;
+    default:
+        ok = value.hasValue() ? value.isExtractableTo(mapType(type)) : nillable;
+        break;
+    }
+    if (!ok) {
+        throw css::lang::IllegalArgumentException(
+            rtl::OUString(
+                RTL_CONSTASCII_USTRINGPARAM(
+                    "configmgr inappropriate property value")),
+            static_cast< cppu::OWeakObject * >(this), -1);
+    }
+}
+
+void Access::insertLocalizedValueChild(
+    rtl::OUString const & name, css::uno::Any const & value,
+    Modifications * localModifications)
+{
+    assert(localModifications != 0);
+    LocalizedPropertyNode * locprop = dynamic_cast< LocalizedPropertyNode * >(
+        getNode().get());
+    checkValue(value, locprop->getStaticType(), locprop->isNillable());
+    rtl::Reference< ChildAccess > child(
+        new ChildAccess(
+            components_, getRootAccess(), this, name,
+            new LocalizedValueNode(Data::NO_LAYER, value)));
+    markChildAsModified(child);
+    localModifications->add(child->getRelativePath());
+}
+
+void Access::reportChildChanges(
+    std::vector< css::util::ElementChange > * changes)
+{
+    assert(changes != 0);
+    for (ModifiedChildren::iterator i(modifiedChildren_.begin());
+         i != modifiedChildren_.end(); ++i)
+    {
+        rtl::Reference< ChildAccess > child(getModifiedChild(i));
+        if (child.is()) {
+            child->reportChildChanges(changes);
+            changes->push_back(css::util::ElementChange());
+                //TODO: changed value and/or inserted node
+        } else {
+            changes->push_back(css::util::ElementChange()); //TODO: removed node
+        }
+    }
+}
+
+void Access::commitChildChanges(
+    bool valid, Modifications * globalModifications)
+{
+    assert(globalModifications != 0);
+    while (!modifiedChildren_.empty()) {
+        bool childValid = valid;
+        ModifiedChildren::iterator i(modifiedChildren_.begin());
+        rtl::Reference< ChildAccess > child(getModifiedChild(i));
+        if (child.is()) {
+            childValid = childValid && !child->isFinalized();
+            child->commitChanges(childValid, globalModifications);
+                //TODO: currently, this is called here for directly inserted
+                // children as well as for children whose sub-children were
+                // modified (and should never be called for directly removed
+                // children); clarify what exactly should happen here for
+                // directly inserted children
+        }
+        NodeMap * members = getNode()->getMemberMap();
+        if (members != 0) {
+            NodeMap::const_iterator j(members->find(i->first));
+            if (child.is()) {
+                // Inserted:
+                if (j != members->end()) {
+                    childValid = childValid &&
+                        j->second->getFinalized() == Data::NO_LAYER;
+                    if (childValid) {
+                        child->getNode()->setMandatory(
+                            j->second->getMandatory());
+                    }
+                }
+                if (childValid) {
+                    (*members)[i->first] = child->getNode();
+                }
+            } else {
+                // Removed:
+                childValid = childValid && j != members->end() &&
+                    j->second->getFinalized() == Data::NO_LAYER &&
+                    j->second->getMandatory() == Data::NO_LAYER;
+                if (childValid) {
+                    members->erase(j);
+                }
+            }
+        }
+        if (childValid && i->second.directlyModified) {
+            Path path(getAbsolutePath());
+            path.push_back(i->first);
+            components_.addModification(path);
+            globalModifications->add(path);
+        }
+        i->second.child->committed();
+        modifiedChildren_.erase(i);
+    }
+}
+
+void Access::initBroadcasterAndChanges(
+    Modifications::Node const & modifications, Broadcaster * broadcaster,
+    std::vector< css::util::ElementChange > * allChanges)
+{
+    assert(broadcaster != 0);
+    comphelper::SequenceAsVector< css::beans::PropertyChangeEvent > propChanges;
+    bool collectPropChanges = !propertiesChangeListeners_.empty();
+    for (Modifications::Node::Children::const_iterator i(
+             modifications.children.begin());
+         i != modifications.children.end(); ++i)
+    {
+        rtl::Reference< ChildAccess > child(getChild(i->first));
+        if (child.is()) {
+            switch (child->getNode()->kind()) {
+            case Node::KIND_LOCALIZED_PROPERTY:
+                if (!i->second.children.empty()) {
+                    if (Components::allLocales(getRootAccess()->getLocale())) {
+                        child->initBroadcasterAndChanges(
+                            i->second, broadcaster, allChanges);
+                            //TODO: if allChanges==0, recurse only into children
+                            // w/ listeners
+                    } else {
+                        //TODO: filter child mods that are irrelevant for
+                        // locale:
+                        for (ContainerListeners::iterator j(
+                                 containerListeners_.begin());
+                             j != containerListeners_.end(); ++j)
+                        {
+                            broadcaster->
+                                addContainerElementReplacedNotification(
+                                    *j,
+                                    css::container::ContainerEvent(
+                                        static_cast< cppu::OWeakObject * >(
+                                            this),
+                                        css::uno::makeAny(i->first),
+                                        css::uno::Any(), css::uno::Any()));
+                                //TODO: non-void Element, ReplacedElement
+                        }
+                        PropertyChangeListeners::iterator j(
+                            propertyChangeListeners_.find(i->first));
+                        if (j != propertyChangeListeners_.end()) {
+                            for (PropertyChangeListenersElement::iterator k(
+                                     j->second.begin());
+                                 k != j->second.end(); ++k)
+                            {
+                                broadcaster->addPropertyChangeNotification(
+                                    *k,
+                                    css::beans::PropertyChangeEvent(
+                                        static_cast< cppu::OWeakObject * >(
+                                            this),
+                                        i->first, false, -1, css::uno::Any(),
+                                        css::uno::Any()));
+                            }
+                        }
+                        j = propertyChangeListeners_.find(rtl::OUString());
+                        if (j != propertyChangeListeners_.end()) {
+                            for (PropertyChangeListenersElement::iterator k(
+                                     j->second.begin());
+                                 k != j->second.end(); ++k)
+                            {
+                                broadcaster->addPropertyChangeNotification(
+                                    *k,
+                                    css::beans::PropertyChangeEvent(
+                                        static_cast< cppu::OWeakObject * >(
+                                            this),
+                                        i->first, false, -1, css::uno::Any(),
+                                        css::uno::Any()));
+                            }
+                        }
+                        if (allChanges != 0) {
+                            allChanges->push_back(
+                                css::util::ElementChange(
+                                    css::uno::makeAny(
+                                        child->getRelativePathRepresentation()),
+                                    css::uno::Any(), css::uno::Any()));
+                                //TODO: non-void Element, ReplacedElement
+                        }
+                        if (collectPropChanges) {
+                            propChanges.push_back(
+                                css::beans::PropertyChangeEvent(
+                                    static_cast< cppu::OWeakObject * >(this),
+                                    i->first, false, -1, css::uno::Any(),
+                                    css::uno::Any()));
+                        }
+                    }
+                }
+                // else: spurious Modifications::Node not representing a change
+                break;
+            case Node::KIND_LOCALIZED_VALUE:
+                assert(Components::allLocales(getRootAccess()->getLocale()));
+                for (ContainerListeners::iterator j(
+                         containerListeners_.begin());
+                     j != containerListeners_.end(); ++j)
+                {
+                    broadcaster->addContainerElementReplacedNotification(
+                        *j,
+                        css::container::ContainerEvent(
+                            static_cast< cppu::OWeakObject * >(this),
+                            css::uno::makeAny(i->first), child->asValue(),
+                            css::uno::Any()));
+                        //TODO: distinguish add/modify; non-void ReplacedElement
+                }
+                if (allChanges != 0) {
+                    allChanges->push_back(
+                        css::util::ElementChange(
+                            css::uno::makeAny(
+                                child->getRelativePathRepresentation()),
+                            child->asValue(), css::uno::Any()));
+                        //TODO: non-void ReplacedElement
+                }
+                assert(!collectPropChanges);
+                break;
+            case Node::KIND_PROPERTY:
+                {
+                    for (ContainerListeners::iterator j(
+                             containerListeners_.begin());
+                         j != containerListeners_.end(); ++j)
+                    {
+                        broadcaster->addContainerElementReplacedNotification(
+                            *j,
+                            css::container::ContainerEvent(
+                                static_cast< cppu::OWeakObject * >(this),
+                                css::uno::makeAny(i->first), child->asValue(),
+                                css::uno::Any()));
+                            //TODO: distinguish add/remove/modify; non-void
+                            // ReplacedElement
+                    }
+                    PropertyChangeListeners::iterator j(
+                        propertyChangeListeners_.find(i->first));
+                    if (j != propertyChangeListeners_.end()) {
+                        for (PropertyChangeListenersElement::iterator k(
+                                 j->second.begin());
+                             k != j->second.end(); ++k)
+                        {
+                            broadcaster->addPropertyChangeNotification(
+                                *k,
+                                css::beans::PropertyChangeEvent(
+                                    static_cast< cppu::OWeakObject * >(this),
+                                    i->first, false, -1, css::uno::Any(),
+                                    css::uno::Any()));
+                        }
+                    }
+                    j = propertyChangeListeners_.find(rtl::OUString());
+                    if (j != propertyChangeListeners_.end()) {
+                        for (PropertyChangeListenersElement::iterator k(
+                                 j->second.begin());
+                             k != j->second.end(); ++k)
+                        {
+                            broadcaster->addPropertyChangeNotification(
+                                *k,
+                                css::beans::PropertyChangeEvent(
+                                    static_cast< cppu::OWeakObject * >(this),
+                                    i->first, false, -1, css::uno::Any(),
+                                    css::uno::Any()));
+                        }
+                    }
+                    if (allChanges != 0) {
+                        allChanges->push_back(
+                            css::util::ElementChange(
+                                css::uno::makeAny(
+                                    child->getRelativePathRepresentation()),
+                                child->asValue(), css::uno::Any()));
+                            //TODO: non-void ReplacedElement
+                    }
+                    if (collectPropChanges) {
+                        propChanges.push_back(
+                            css::beans::PropertyChangeEvent(
+                                static_cast< cppu::OWeakObject * >(this),
+                                i->first, false, -1, css::uno::Any(),
+                                css::uno::Any()));
+                    }
+                }
+                break;
+            case Node::KIND_GROUP:
+            case Node::KIND_SET:
+                if (i->second.children.empty()) {
+                    if (child->getNode()->getTemplateName().getLength() != 0) {
+                        for (ContainerListeners::iterator j(
+                                 containerListeners_.begin());
+                             j != containerListeners_.end(); ++j)
+                        {
+                            broadcaster->
+                                addContainerElementInsertedNotification(
+                                    *j,
+                                    css::container::ContainerEvent(
+                                        static_cast< cppu::OWeakObject * >(
+                                            this),
+                                        css::uno::makeAny(i->first),
+                                        child->asValue(), css::uno::Any()));
+                        }
+                        if (allChanges != 0) {
+                            allChanges->push_back(
+                                css::util::ElementChange(
+                                    css::uno::makeAny(
+                                        child->getRelativePathRepresentation()),
+                                    css::uno::Any(), css::uno::Any()));
+                                //TODO: non-void Element, ReplacedElement
+                        }
+                    }
+                    // else: spurious Modifications::Node not representing a
+                    // change
+                } else {
+                    child->initBroadcasterAndChanges(
+                        i->second, broadcaster, allChanges);
+                        //TODO: if allChanges==0, recurse only into children w/
+                        // listeners
+                }
+                break;
+            case Node::KIND_ROOT:
+                assert(false); // this cannot happen
+                break;
+            }
+        } else {
+            switch (getNode()->kind()) {
+            case Node::KIND_LOCALIZED_PROPERTY:
+                // Removed localized property value:
+                assert(Components::allLocales(getRootAccess()->getLocale()));
+                for (ContainerListeners::iterator j(
+                         containerListeners_.begin());
+                     j != containerListeners_.end(); ++j)
+                {
+                    broadcaster->addContainerElementRemovedNotification(
+                        *j,
+                        css::container::ContainerEvent(
+                            static_cast< cppu::OWeakObject * >(this),
+                            css::uno::makeAny(i->first), css::uno::Any(),
+                            css::uno::Any()));
+                        //TODO: non-void ReplacedElement
+                }
+                if (allChanges != 0) {
+                    rtl::OUStringBuffer path(getRelativePathRepresentation());
+                    if (path.getLength() != 0) {
+                        path.append(sal_Unicode('/'));
+                    }
+                    path.append(
+                        Data::createSegment(
+                            rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")),
+                            i->first));
+                    allChanges->push_back(
+                        css::util::ElementChange(
+                            css::uno::makeAny(path.makeStringAndClear()),
+                            css::uno::Any(), css::uno::Any()));
+                        //TODO: non-void ReplacedElement
+                }
+                assert(!collectPropChanges);
+                break;
+            case Node::KIND_GROUP:
+                {
+                    // Removed (non-localized) extension property:
+                    for (ContainerListeners::iterator j(
+                             containerListeners_.begin());
+                         j != containerListeners_.end(); ++j)
+                    {
+                        broadcaster->addContainerElementRemovedNotification(
+                            *j,
+                            css::container::ContainerEvent(
+                                static_cast< cppu::OWeakObject * >(this),
+                                css::uno::makeAny(i->first), css::uno::Any(),
+                                css::uno::Any()));
+                            //TODO: non-void ReplacedElement
+                    }
+                    PropertyChangeListeners::iterator j(
+                        propertyChangeListeners_.find(i->first));
+                    if (j != propertyChangeListeners_.end()) {
+                        for (PropertyChangeListenersElement::iterator k(
+                                 j->second.begin());
+                             k != j->second.end(); ++k)
+                        {
+                            broadcaster->addPropertyChangeNotification(
+                                *k,
+                                css::beans::PropertyChangeEvent(
+                                    static_cast< cppu::OWeakObject * >(this),
+                                    i->first, false, -1, css::uno::Any(),
+                                    css::uno::Any()));
+                        }
+                    }
+                    j = propertyChangeListeners_.find(rtl::OUString());
+                    if (j != propertyChangeListeners_.end()) {
+                        for (PropertyChangeListenersElement::iterator k(
+                                 j->second.begin());
+                             k != j->second.end(); ++k)
+                        {
+                            broadcaster->addPropertyChangeNotification(
+                                *k,
+                                css::beans::PropertyChangeEvent(
+                                    static_cast< cppu::OWeakObject * >(this),
+                                    i->first, false, -1, css::uno::Any(),
+                                    css::uno::Any()));
+                        }
+                    }
+                    if (allChanges != 0) {
+                        rtl::OUStringBuffer path(
+                            getRelativePathRepresentation());
+                        if (path.getLength() != 0) {
+                            path.append(sal_Unicode('/'));
+                        }
+                        path.append(i->first);
+                        allChanges->push_back(
+                            css::util::ElementChange(
+                                css::uno::makeAny(path.makeStringAndClear()),
+                                css::uno::Any(), css::uno::Any()));
+                            //TODO: non-void ReplacedElement
+                    }
+                    if (collectPropChanges) {
+                        propChanges.push_back(
+                            css::beans::PropertyChangeEvent(
+                                static_cast< cppu::OWeakObject * >(this),
+                                i->first, false, -1, css::uno::Any(),
+                                css::uno::Any()));
+                    }
+                }
+                break;
+            case Node::KIND_SET:
+                // Removed set member:
+                if (i->second.children.empty()) {
+                    for (ContainerListeners::iterator j(
+                             containerListeners_.begin());
+                         j != containerListeners_.end(); ++j)
+                    {
+                        broadcaster->addContainerElementRemovedNotification(
+                            *j,
+                            css::container::ContainerEvent(
+                                static_cast< cppu::OWeakObject * >(this),
+                                css::uno::makeAny(i->first),
+                                css::uno::Any(), css::uno::Any()));
+                            //TODO: non-void ReplacedElement
+                    }
+                    if (allChanges != 0) {
+                        rtl::OUStringBuffer path(
+                            getRelativePathRepresentation());
+                        if (path.getLength() != 0) {
+                            path.append(sal_Unicode('/'));
+                        }
+                        path.append(
+                            Data::createSegment(
+                                rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")),
+                                i->first));
+                        allChanges->push_back(
+                            css::util::ElementChange(
+                                css::uno::makeAny(path.makeStringAndClear()),
+                                css::uno::Any(), css::uno::Any()));
+                            //TODO: non-void ReplacedElement
+                    }
+                }
+                // else: spurious Modifications::Node not representing a change
+                break;
+            default:
+                assert(false); // this cannot happen
+                break;
+            }
+        }
+    }
+    if (!propChanges.empty()) {
+        css::uno::Sequence< css::beans::PropertyChangeEvent > seq(
+            propChanges.getAsConstList());
+        for (PropertiesChangeListeners::iterator i(
+                 propertiesChangeListeners_.begin());
+             i != propertiesChangeListeners_.end(); ++i)
+        {
+            broadcaster->addPropertiesChangeNotification(*i, seq);
+        }
+    }
+}
+
+bool Access::isDisposed() const {
+    return disposed_;
+}
+
+Access::ModifiedChild::ModifiedChild() {}
+
+Access::ModifiedChild::ModifiedChild(
+    rtl::Reference< ChildAccess > const & theChild, bool theDirectlyModified):
+    child(theChild), directlyModified(theDirectlyModified)
+{}
+
 rtl::Reference< ChildAccess > Access::getModifiedChild(
     ModifiedChildren::iterator const & childIterator)
 {
diff --git a/configmgr/source/access.hxx b/configmgr/source/access.hxx
index d2409cb..6401df3 100644
--- a/configmgr/source/access.hxx
+++ b/configmgr/source/access.hxx
@@ -51,7 +51,7 @@
 #include "com/sun/star/container/NoSuchElementException.hpp"
 #include "com/sun/star/container/XContainer.hpp"
 #include "com/sun/star/container/XHierarchicalName.hpp"
-#include "com/sun/star/container/XHierarchicalNameAccess.hpp"
+#include "com/sun/star/container/XHierarchicalNameReplace.hpp"
 #include "com/sun/star/container/XNameContainer.hpp"
 #include "com/sun/star/container/XNamed.hpp"
 #include "com/sun/star/lang/IllegalArgumentException.hpp"
@@ -106,7 +106,7 @@ class Access:
     public cppu::OWeakObject, public com::sun::star::lang::XTypeProvider,
     public com::sun::star::lang::XServiceInfo,
     public com::sun::star::lang::XComponent,
-    public com::sun::star::container::XHierarchicalNameAccess,
+    public com::sun::star::container::XHierarchicalNameReplace,
     public com::sun::star::container::XContainer,
     public com::sun::star::beans::XExactName,
     public com::sun::star::beans::XPropertySetInfo,
@@ -146,68 +146,6 @@ public:
     using OWeakObject::acquire;
     using OWeakObject::release;
 
-protected:
-    Access(Components & components);
-
-    virtual ~Access();
-
-    virtual rtl::OUString getNameInternal() = 0;
-    virtual rtl::Reference< RootAccess > getRootAccess() = 0;
-    virtual rtl::Reference< Access > getParentAccess() = 0;
-
-    virtual void addTypes(std::vector< com::sun::star::uno::Type > * types)
-        const = 0;
-
-    virtual void addSupportedServiceNames(
-        std::vector< rtl::OUString > * services) = 0;
-
-    virtual void initDisposeBroadcaster(Broadcaster * broadcaster);
-    virtual void clearListeners() throw ();
-
-    virtual com::sun::star::uno::Any SAL_CALL queryInterface(
-        com::sun::star::uno::Type const & aType)
-        throw (com::sun::star::uno::RuntimeException);
-
-    Components & getComponents() const;
-
-    void checkLocalizedPropertyAccess();
-
-    rtl::Reference< Node > getParentNode();
-    rtl::Reference< ChildAccess > getChild(rtl::OUString const & name);
-    std::vector< rtl::Reference< ChildAccess > > getAllChildren();
-
-    void checkValue(
-        com::sun::star::uno::Any const & value, Type type, bool nillable);
-
-    void insertLocalizedValueChild(
-        rtl::OUString const & name, com::sun::star::uno::Any const & value,
-        Modifications * localModifications);
-
-    void reportChildChanges(
-        std::vector< com::sun::star::util::ElementChange > * changes);
-
-    void commitChildChanges(bool valid, Modifications * globalModifications);
-
-    void initBroadcasterAndChanges(
-        Modifications::Node const & modifications, Broadcaster * broadcaster,
-        std::vector< com::sun::star::util::ElementChange > * changes);
-
-    bool isDisposed() const;
-
-private:
-    struct ModifiedChild {
-        rtl::Reference< ChildAccess > child;
-        bool directlyModified;
-
-        ModifiedChild();
-
-        ModifiedChild(
-            rtl::Reference< ChildAccess > const & theChild,
-            bool theDirectlyModified);
-    };
-
-    typedef std::map< rtl::OUString, ModifiedChild > ModifiedChildren;
-
     virtual com::sun::star::uno::Sequence< com::sun::star::uno::Type > SAL_CALL
     getTypes() throw (com::sun::star::uno::RuntimeException);
 
@@ -264,6 +202,14 @@ private:
     virtual sal_Bool SAL_CALL hasByHierarchicalName(rtl::OUString const & aName)
         throw (com::sun::star::uno::RuntimeException);
 
+    virtual void SAL_CALL replaceByHierarchicalName(
+        rtl::OUString const & aName, com::sun::star::uno::Any const & aElement)
+        throw (
+            com::sun::star::lang::IllegalArgumentException,
+            com::sun::star::container::NoSuchElementException,
+            com::sun::star::lang::WrappedTargetException,
+            com::sun::star::uno::RuntimeException);
+
     virtual void SAL_CALL addContainerListener(
         com::sun::star::uno::Reference<
             com::sun::star::container::XContainerListener > const & xListener)
@@ -491,6 +437,68 @@ private:
             com::sun::star::uno::Exception,
             com::sun::star::uno::RuntimeException);
 
+protected:
+    Access(Components & components);
+
+    virtual ~Access();
+
+    virtual rtl::OUString getNameInternal() = 0;
+    virtual rtl::Reference< RootAccess > getRootAccess() = 0;
+    virtual rtl::Reference< Access > getParentAccess() = 0;
+
+    virtual void addTypes(std::vector< com::sun::star::uno::Type > * types)
+        const = 0;
+
+    virtual void addSupportedServiceNames(
+        std::vector< rtl::OUString > * services) = 0;
+
+    virtual void initDisposeBroadcaster(Broadcaster * broadcaster);
+    virtual void clearListeners() throw ();
+
+    virtual com::sun::star::uno::Any SAL_CALL queryInterface(
+        com::sun::star::uno::Type const & aType)
+        throw (com::sun::star::uno::RuntimeException);
+
+    Components & getComponents() const;
+
+    void checkLocalizedPropertyAccess();
+
+    rtl::Reference< Node > getParentNode();
+    rtl::Reference< ChildAccess > getChild(rtl::OUString const & name);
+    std::vector< rtl::Reference< ChildAccess > > getAllChildren();
+
+    void checkValue(
+        com::sun::star::uno::Any const & value, Type type, bool nillable);
+
+    void insertLocalizedValueChild(
+        rtl::OUString const & name, com::sun::star::uno::Any const & value,
+        Modifications * localModifications);
+
+    void reportChildChanges(
+        std::vector< com::sun::star::util::ElementChange > * changes);
+
+    void commitChildChanges(bool valid, Modifications * globalModifications);
+
+    void initBroadcasterAndChanges(
+        Modifications::Node const & modifications, Broadcaster * broadcaster,
+        std::vector< com::sun::star::util::ElementChange > * changes);
+
+    bool isDisposed() const;
+
+private:
+    struct ModifiedChild {
+        rtl::Reference< ChildAccess > child;
+        bool directlyModified;
+
+        ModifiedChild();
+
+        ModifiedChild(
+            rtl::Reference< ChildAccess > const & theChild,
+            bool theDirectlyModified);
+    };
+
+    typedef std::map< rtl::OUString, ModifiedChild > ModifiedChildren;
+
     rtl::Reference< ChildAccess > getModifiedChild(
         ModifiedChildren::iterator const & childIterator);
 
diff --git a/configmgr/source/components.cxx b/configmgr/source/components.cxx
index 48d555e..56c5975 100644
--- a/configmgr/source/components.cxx
+++ b/configmgr/source/components.cxx
@@ -137,7 +137,7 @@ bool canRemoveFromLayer(int layer, rtl::Reference< Node > const & node) {
     switch (node->kind()) {
     case Node::KIND_LOCALIZED_PROPERTY:
     case Node::KIND_GROUP:
-        for (NodeMap::iterator i(node->getMembers().begin());
+        for (NodeMap::const_iterator i(node->getMembers().begin());
              i != node->getMembers().end(); ++i)
         {
             if (!canRemoveFromLayer(layer, i->second)) {
@@ -402,7 +402,9 @@ void Components::removeExtensionXcuFile(
                         node->kind() == Node::KIND_GROUP ||
                         node->kind() == Node::KIND_SET);
                     if (canRemoveFromLayer(item->layer, node)) {
-                        parent->getMembers().erase(i->back());
+                        NodeMap * members = parent->getMemberMap();
+                        assert(members != 0);
+                        members->erase(i->back());
                         data_.modifications.remove(*i);
                         modifications->add(*i);
                     }
diff --git a/configmgr/source/configmgr.component b/configmgr/source/configmgr.component
index 6ed5125..9ad4c79 100755
--- a/configmgr/source/configmgr.component
+++ b/configmgr/source/configmgr.component
@@ -38,6 +38,12 @@
     <service name="com.sun.star.configuration.DefaultProvider"/>
     <singleton name="com.sun.star.configuration.theDefaultProvider"/>
   </implementation>
+  <implementation name="com.sun.star.comp.configuration.ReadOnlyAccess">
+    <singleton name="com.sun.star.configuration.ReadOnlyAccess"/>
+  </implementation>
+  <implementation name="com.sun.star.comp.configuration.ReadWriteAccess">
+    <service name="com.sun.star.configuration.ReadWriteAccess"/>
+  </implementation>
   <implementation name="com.sun.star.comp.configuration.Update">
     <service name="com.sun.star.configuration.Update_Service"/>
     <singleton name="com.sun.star.configuration.Update"/>
diff --git a/configmgr/source/data.cxx b/configmgr/source/data.cxx
index 0fdc1e5..fcc42e9 100644
--- a/configmgr/source/data.cxx
+++ b/configmgr/source/data.cxx
@@ -48,6 +48,7 @@
 #include "groupnode.hxx"
 #include "node.hxx"
 #include "nodemap.hxx"
+#include "rootnode.hxx"
 #include "setnode.hxx"
 
 namespace configmgr {
@@ -207,6 +208,8 @@ rtl::Reference< Node > Data::findNode(
         ? rtl::Reference< Node >() : i->second;
 }
 
+Data::Data(): root_(new RootNode(components)) {}
+
 rtl::Reference< Node > Data::resolvePathRepresentation(
     rtl::OUString const & pathRepresentation,
     rtl::OUString * canonicRepresentation, Path * path, int * finalizedLayer)
@@ -218,6 +221,18 @@ rtl::Reference< Node > Data::resolvePathRepresentation(
              pathRepresentation),
             css::uno::Reference< css::uno::XInterface >());
     }
+    if (path != 0) {
+        path->clear();
+    }
+    if (pathRepresentation.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("/"))) {
+        if (canonicRepresentation != 0) {
+            *canonicRepresentation = pathRepresentation;
+        }
+        if (finalizedLayer != 0) {
+            *finalizedLayer = NO_LAYER;
+        }
+        return root_;
+    }
     rtl::OUString seg;
     bool setElement;
     rtl::OUString templateName;
@@ -231,9 +246,6 @@ rtl::Reference< Node > Data::resolvePathRepresentation(
     }
     NodeMap::const_iterator i(components.find(seg));
     rtl::OUStringBuffer canonic;
-    if (path != 0) {
-        path->clear();
-    }
     rtl::Reference< Node > parent;
     int finalized = NO_LAYER;
     for (rtl::Reference< Node > p(i == components.end() ? 0 : i->second);;) {
diff --git a/configmgr/source/data.hxx b/configmgr/source/data.hxx
index f60ecfa..64980ee 100644
--- a/configmgr/source/data.hxx
+++ b/configmgr/source/data.hxx
@@ -81,6 +81,8 @@ struct Data: private boost::noncopyable {
     static rtl::Reference< Node > findNode(
         int layer, NodeMap const & map, rtl::OUString const & name);
 
+    Data();
+
     rtl::Reference< Node > resolvePathRepresentation(
         rtl::OUString const & pathRepresentation,
         rtl::OUString * canonicRepresenation, Path * path, int * finalizedLayer)
@@ -99,6 +101,8 @@ private:
     typedef std::map< rtl::OUString, rtl::Reference< ExtensionXcu > >
         ExtensionXcuAdditions;
 
+    rtl::Reference< Node > root_;
+
     ExtensionXcuAdditions extensionXcuAdditions_;
 };
 
diff --git a/configmgr/source/groupnode.cxx b/configmgr/source/groupnode.cxx
index 5591acb..0965856 100644
--- a/configmgr/source/groupnode.cxx
+++ b/configmgr/source/groupnode.cxx
@@ -48,8 +48,8 @@ rtl::Reference< Node > GroupNode::clone(bool keepTemplateName) const {
     return new GroupNode(*this, keepTemplateName);
 }
 
-NodeMap & GroupNode::getMembers() {
-    return members_;
+NodeMap * GroupNode::getMemberMap() {
+    return &members_;
 }
 
 rtl::OUString GroupNode::getTemplateName() const {
diff --git a/configmgr/source/groupnode.hxx b/configmgr/source/groupnode.hxx
index 02f1679..1d14a92 100644
--- a/configmgr/source/groupnode.hxx
+++ b/configmgr/source/groupnode.hxx
@@ -45,7 +45,7 @@ public:
 
     virtual rtl::Reference< Node > clone(bool keepTemplateName) const;
 
-    virtual NodeMap & getMembers();
+    virtual NodeMap * getMemberMap();
 
     virtual rtl::OUString getTemplateName() const;
 
diff --git a/configmgr/source/localizedpropertynode.cxx b/configmgr/source/localizedpropertynode.cxx
index 2704858..196e57f 100644
--- a/configmgr/source/localizedpropertynode.cxx
+++ b/configmgr/source/localizedpropertynode.cxx
@@ -55,8 +55,8 @@ rtl::Reference< Node > LocalizedPropertyNode::clone(bool) const {
     return new LocalizedPropertyNode(*this);
 }
 
-NodeMap & LocalizedPropertyNode::getMembers() {
-    return members_;
+NodeMap * LocalizedPropertyNode::getMemberMap() {
+    return &members_;
 }
 
 Type LocalizedPropertyNode::getStaticType() const {
diff --git a/configmgr/source/localizedpropertynode.hxx b/configmgr/source/localizedpropertynode.hxx
index bbe934e..b49f375 100644
--- a/configmgr/source/localizedpropertynode.hxx
+++ b/configmgr/source/localizedpropertynode.hxx
@@ -50,7 +50,7 @@ public:
 
     virtual rtl::Reference< Node > clone(bool keepTemplateName) const;
 
-    virtual NodeMap & getMembers();
+    virtual NodeMap * getMemberMap();
 
     Type getStaticType() const;
 
diff --git a/configmgr/source/makefile.mk b/configmgr/source/makefile.mk
index e75af0d..f52b4f4 100644
--- a/configmgr/source/makefile.mk
+++ b/configmgr/source/makefile.mk
@@ -55,7 +55,10 @@ SLOFILES = \
     $(SLO)/parsemanager.obj \
     $(SLO)/partial.obj \
     $(SLO)/propertynode.obj \
+    $(SLO)/readonlyaccess.obj \
+    $(SLO)/readwriteaccess.obj \
     $(SLO)/rootaccess.obj \
+    $(SLO)/rootnode.obj \
     $(SLO)/services.obj \
     $(SLO)/setnode.obj \
     $(SLO)/type.obj \
diff --git a/configmgr/source/node.cxx b/configmgr/source/node.cxx
index 892cdaa..b648082 100644
--- a/configmgr/source/node.cxx
+++ b/configmgr/source/node.cxx
@@ -30,11 +30,7 @@
 
 #include <cassert>
 
-#include "com/sun/star/uno/Reference.hxx"
-#include "com/sun/star/uno/RuntimeException.hpp"
-#include "com/sun/star/uno/XInterface.hpp"
 #include "rtl/ref.hxx"
-#include "rtl/ustring.h"
 #include "rtl/ustring.hxx"
 
 #include "data.hxx"
@@ -43,17 +39,15 @@
 
 namespace configmgr {
 
-namespace {
-
-namespace css = com::sun::star;
-
+NodeMap const & Node::getMembers() const {
+    NodeMap * members = const_cast< Node * >(this)->getMemberMap();
+    assert(members != 0);
+    return *members;
 }
 
-NodeMap & Node::getMembers() {
+NodeMap * Node::getMemberMap() {
     assert(false);
-    throw css::uno::RuntimeException(
-        rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("this cannot happen")),
-        css::uno::Reference< css::uno::XInterface >());
+    return 0;
 }
 
 rtl::OUString Node::getTemplateName() const {
@@ -87,8 +81,8 @@ int Node::getFinalized() const {
 }
 
 rtl::Reference< Node > Node::getMember(rtl::OUString const & name) {
-    NodeMap & members = getMembers();
-    NodeMap::iterator i(members.find(name));
+    NodeMap const & members = getMembers();
+    NodeMap::const_iterator i(members.find(name));
     return i == members.end() ? rtl::Reference< Node >() : i->second;
 }
 
diff --git a/configmgr/source/node.hxx b/configmgr/source/node.hxx
index 932d11c..01aef18 100644
--- a/configmgr/source/node.hxx
+++ b/configmgr/source/node.hxx
@@ -44,13 +44,14 @@ class Node: public salhelper::SimpleReferenceObject {
 public:
     enum Kind {
         KIND_PROPERTY, KIND_LOCALIZED_PROPERTY, KIND_LOCALIZED_VALUE,
-        KIND_GROUP, KIND_SET };
+        KIND_GROUP, KIND_SET, KIND_ROOT };
 
     virtual Kind kind() const = 0;
 
     virtual rtl::Reference< Node > clone(bool keepTemplateName) const = 0;
 
-    virtual NodeMap & getMembers();
+    virtual NodeMap const & getMembers() const;
+    virtual NodeMap * getMemberMap();
     virtual rtl::OUString getTemplateName() const;
 
     virtual void setMandatory(int layer);
diff --git a/configmgr/source/readonlyaccess.cxx b/configmgr/source/readonlyaccess.cxx
new file mode 100644
index 0000000..d9ab2dc
--- /dev/null
+++ b/configmgr/source/readonlyaccess.cxx
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Version: MPL 1.1 / GPLv3+ / LGPLv3+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 Red Hat, Inc., Stephan Bergmann <sbergman at redhat.com>
+ * (initial developer)
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
+ * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
+ * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
+ * instead of those above.
+ */
+
+#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/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 "osl/mutex.hxx"
+#include "rtl/ref.hxx"
+#include "rtl/ustring.h"
+#include "rtl/ustring.hxx"
+#include "sal/types.h"
+
+#include "components.hxx"
+#include "lock.hxx"
+#include "readonlyaccess.hxx"
+#include "rootaccess.hxx"
+
+namespace configmgr { namespace read_only_access {
+
+namespace {
+
+namespace css = com::sun::star;
+
+class Service:
+    public cppu::WeakImplHelper2<
+        css::lang::XServiceInfo, css::container::XHierarchicalNameAccess >,
+    private boost::noncopyable
+{
+public:
+    Service(css::uno::Reference< css::uno::XComponentContext > const & context);
+
+private:
+    virtual ~Service() {}
+
+    virtual rtl::OUString SAL_CALL getImplementationName()
+        throw (css::uno::RuntimeException)
+    { return read_only_access::getImplementationName(); }
+
+    virtual sal_Bool SAL_CALL supportsService(rtl::OUString const &)
+        throw (css::uno::RuntimeException)
+    { return false; }
+
+    virtual css::uno::Sequence< rtl::OUString > SAL_CALL
+    getSupportedServiceNames() throw (css::uno::RuntimeException)
+    { return read_only_access::getSupportedServiceNames(); }
+
+    virtual css::uno::Any SAL_CALL getByHierarchicalName(
+        rtl::OUString const & aName)
+        throw (
+            css::container::NoSuchElementException, css::uno::RuntimeException)
+    { return root_->getByHierarchicalName(aName); }
+
+    virtual sal_Bool SAL_CALL hasByHierarchicalName(rtl::OUString const & aName)
+        throw (css::uno::RuntimeException)
+    { return root_->hasByHierarchicalName(aName); }
+
+    rtl::Reference< RootAccess > root_;
+};
+
+Service::Service(
+    css::uno::Reference< css::uno::XComponentContext > const & context)
+{
+    osl::MutexGuard guard(*lock());
+    Components & components = Components::getSingleton(context);
+    root_ = new RootAccess(
+        components, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/")),
+        rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")), false);
+    components.addRootAccess(root_);
+}
+
+}
+
+css::uno::Reference< css::uno::XInterface > create(
+    css::uno::Reference< css::uno::XComponentContext > const & context)
+{
+    return static_cast< cppu::OWeakObject * >(new Service(context));
+}
+
+rtl::OUString getImplementationName() {
+    return rtl::OUString(
+        RTL_CONSTASCII_USTRINGPARAM(
+            "com.sun.star.comp.configuration.ReadOnlyAccess"));
+}
+
+css::uno::Sequence< rtl::OUString > getSupportedServiceNames() {
+    return css::uno::Sequence< rtl::OUString >();
+}
+
+} }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/configmgr/source/readonlyaccess.hxx b/configmgr/source/readonlyaccess.hxx
new file mode 100644
index 0000000..9549789
--- /dev/null
+++ b/configmgr/source/readonlyaccess.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Version: MPL 1.1 / GPLv3+ / LGPLv3+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 Red Hat, Inc., Stephan Bergmann <sbergman at redhat.com>
+ * (initial developer)
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
+ * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
+ * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
+ * instead of those above.
+ */
+
+#ifndef INCLUDED_CONFIGMGR_SOURCE_READONLYACCESS_HXX
+#define INCLUDED_CONFIGMGR_SOURCE_READONLYACCESS_HXX
+
+#include "com/sun/star/uno/Reference.hxx"
+#include "com/sun/star/uno/Sequence.hxx"
+#include "sal/types.h"
+
+namespace com { namespace sun { namespace star {
+    namespace uno {
+        class XComponentContext;
+        class XInterface;
+    }
+} } }
+namespace rtl { class OUString; }
+
+namespace configmgr { namespace read_only_access {
+
+com::sun::star::uno::Reference< com::sun::star::uno::XInterface > SAL_CALL
+create(
+    com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext >
+        const &);
+
+rtl::OUString SAL_CALL getImplementationName();
+
+com::sun::star::uno::Sequence< rtl::OUString > SAL_CALL
+getSupportedServiceNames();
+
+} }
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/configmgr/source/readwriteaccess.cxx b/configmgr/source/readwriteaccess.cxx
new file mode 100644
index 0000000..0e4415f
--- /dev/null
+++ b/configmgr/source/readwriteaccess.cxx
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Version: MPL 1.1 / GPLv3+ / LGPLv3+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 Red Hat, Inc., Stephan Bergmann <sbergman at redhat.com>
+ * (initial developer)
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
+ * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
+ * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
+ * instead of those above.
+ */
+
+#include "sal/config.h"
+
+#include "boost/noncopyable.hpp"
+#include "cppuhelper/implbase2.hxx"
+#include "com/sun/star/lang/IllegalArgumentException.hpp"
+#include "com/sun/star/lang/WrappedTargetException.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/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 "rtl/ref.hxx"
+#include "rtl/ustring.h"
+#include "rtl/ustring.hxx"
+#include "sal/types.h"
+
+#include "components.hxx"
+#include "lock.hxx"
+#include "readwriteaccess.hxx"
+#include "rootaccess.hxx"
+
+namespace configmgr { namespace read_write_access {
+
+namespace {
+
+namespace css = com::sun::star;
+
+class Service:
+    public cppu::WeakImplHelper2<
+        css::lang::XServiceInfo, css::configuration::XReadWriteAccess >,
+    private boost::noncopyable
+{
+public:
+    Service(css::uno::Reference< css::uno::XComponentContext > const & context);
+
+private:
+    virtual ~Service() {}
+
+    virtual rtl::OUString SAL_CALL getImplementationName()
+        throw (css::uno::RuntimeException)
+    { return read_write_access::getImplementationName(); }
+
+    virtual sal_Bool SAL_CALL supportsService(rtl::OUString const &)
+        throw (css::uno::RuntimeException)
+    { return false; }
+
+    virtual css::uno::Sequence< rtl::OUString > SAL_CALL
+    getSupportedServiceNames() throw (css::uno::RuntimeException)
+    { return read_write_access::getSupportedServiceNames(); }
+
+    virtual css::uno::Any SAL_CALL getByHierarchicalName(
+        rtl::OUString const & aName)
+        throw (
+            css::container::NoSuchElementException, css::uno::RuntimeException)
+    { return root_->getByHierarchicalName(aName); }
+
+    virtual sal_Bool SAL_CALL hasByHierarchicalName(rtl::OUString const & aName)
+        throw (css::uno::RuntimeException)
+    { return root_->hasByHierarchicalName(aName); }
+
+    virtual void SAL_CALL replaceByHierarchicalName(
+        rtl::OUString const & aName, css::uno::Any const & aElement)
+        throw (
+            css::lang::IllegalArgumentException,
+            css::container::NoSuchElementException,
+            css::lang::WrappedTargetException, css::uno::RuntimeException)
+    { root_->replaceByHierarchicalName(aName, aElement); }
+
+    virtual void SAL_CALL commitChanges()
+        throw (css::lang::WrappedTargetException, css::uno::RuntimeException)
+    { root_->commitChanges(); }
+
+    virtual sal_Bool SAL_CALL hasPendingChanges()
+        throw (css::uno::RuntimeException)
+    { return root_->hasPendingChanges(); }
+
+    virtual css::util::ChangesSet SAL_CALL getPendingChanges()
+        throw (css::uno::RuntimeException)
+    { return root_->getPendingChanges(); }
+
+    rtl::Reference< RootAccess > root_;
+};
+
+Service::Service(
+    css::uno::Reference< css::uno::XComponentContext > const & context)
+{
+    osl::MutexGuard guard(*lock());
+    Components & components = Components::getSingleton(context);
+    root_ = new RootAccess(
+        components, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/")),
+        rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")), true);
+    components.addRootAccess(root_);
+}
+
+}
+
+css::uno::Reference< css::uno::XInterface > create(
+    css::uno::Reference< css::uno::XComponentContext > const & context)
+{
+    return static_cast< cppu::OWeakObject * >(new Service(context));
+}
+
+rtl::OUString getImplementationName() {
+    return rtl::OUString(
+        RTL_CONSTASCII_USTRINGPARAM(
+            "com.sun.star.comp.configuration.ReadWriteAccess"));
+}
+
+css::uno::Sequence< rtl::OUString > getSupportedServiceNames() {
+    rtl::OUString name(
+        RTL_CONSTASCII_USTRINGPARAM(
+            "com.sun.star.configuration.ReadWriteAccess"));
+    return css::uno::Sequence< rtl::OUString >(&name, 1);
+}
+
+} }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/configmgr/source/readwriteaccess.hxx b/configmgr/source/readwriteaccess.hxx
new file mode 100644
index 0000000..b559b2a
--- /dev/null
+++ b/configmgr/source/readwriteaccess.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Version: MPL 1.1 / GPLv3+ / LGPLv3+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 Red Hat, Inc., Stephan Bergmann <sbergman at redhat.com>
+ * (initial developer)
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
+ * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
+ * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
+ * instead of those above.
+ */
+
+#ifndef INCLUDED_CONFIGMGR_SOURCE_READWRITEACCESS_HXX
+#define INCLUDED_CONFIGMGR_SOURCE_READWRITEACCESS_HXX
+
+#include "com/sun/star/uno/Reference.hxx"
+#include "com/sun/star/uno/Sequence.hxx"
+#include "sal/types.h"
+
+namespace com { namespace sun { namespace star {
+    namespace uno {
+        class XComponentContext;
+        class XInterface;
+    }
+} } }
+namespace rtl { class OUString; }
+
+namespace configmgr { namespace read_write_access {
+
+com::sun::star::uno::Reference< com::sun::star::uno::XInterface > SAL_CALL
+create(
+    com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext >
+        const &);
+
+rtl::OUString SAL_CALL getImplementationName();
+
+com::sun::star::uno::Sequence< rtl::OUString > SAL_CALL
+getSupportedServiceNames();
+
+} }
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/configmgr/source/rootaccess.cxx b/configmgr/source/rootaccess.cxx
index fc1fe39..03ee3b8 100644
--- a/configmgr/source/rootaccess.cxx
+++ b/configmgr/source/rootaccess.cxx
@@ -133,6 +133,91 @@ void RootAccess::setAlive(bool b) {
     alive_ = b;
 }
 
+void RootAccess::addChangesListener(
+    css::uno::Reference< css::util::XChangesListener > const & aListener)
+    throw (css::uno::RuntimeException)
+{
+    assert(thisIs(IS_ANY));
+    {
+        osl::MutexGuard g(*lock_);
+        checkLocalizedPropertyAccess();
+        if (!aListener.is()) {
+            throw css::uno::RuntimeException(
+                rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("null listener")),
+                static_cast< cppu::OWeakObject * >(this));
+        }
+        if (!isDisposed()) {
+            changesListeners_.insert(aListener);
+            return;
+        }
+    }
+    try {
+        aListener->disposing(
+            css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
+    } catch (css::lang::DisposedException &) {}
+}
+
+void RootAccess::removeChangesListener(
+    css::uno::Reference< css::util::XChangesListener > const & aListener)
+    throw (css::uno::RuntimeException)
+{
+    assert(thisIs(IS_ANY));
+    osl::MutexGuard g(*lock_);
+    checkLocalizedPropertyAccess();
+    ChangesListeners::iterator i(changesListeners_.find(aListener));
+    if (i != changesListeners_.end()) {
+        changesListeners_.erase(i);
+    }
+}
+
+void RootAccess::commitChanges()
+    throw (css::lang::WrappedTargetException, css::uno::RuntimeException)
+{
+    assert(thisIs(IS_UPDATE));
+    if (!alive_)
+    {
+        return;
+    }
+    Broadcaster bc;
+    {
+        osl::MutexGuard g(*lock_);
+
+        checkLocalizedPropertyAccess();
+        int finalizedLayer;
+        Modifications globalMods;
+        commitChildChanges(
+            ((getComponents().resolvePathRepresentation(
+                  pathRepresentation_, 0, 0, &finalizedLayer)
+              == node_) &&
+             finalizedLayer == Data::NO_LAYER),
+            &globalMods);
+        getComponents().writeModifications();
+        getComponents().initGlobalBroadcaster(globalMods, this, &bc);
+    }
+    bc.send();
+}
+
+sal_Bool RootAccess::hasPendingChanges() throw (css::uno::RuntimeException) {
+    assert(thisIs(IS_UPDATE));
+    osl::MutexGuard g(*lock_);
+    checkLocalizedPropertyAccess();
+    //TODO: Optimize:
+    std::vector< css::util::ElementChange > changes;

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list