summaryrefslogtreecommitdiffstats
path: root/ucb/source/core/ucbstore.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /ucb/source/core/ucbstore.cxx
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ucb/source/core/ucbstore.cxx')
-rw-r--r--ucb/source/core/ucbstore.cxx2205
1 files changed, 2205 insertions, 0 deletions
diff --git a/ucb/source/core/ucbstore.cxx b/ucb/source/core/ucbstore.cxx
new file mode 100644
index 000000000..01f7c70b5
--- /dev/null
+++ b/ucb/source/core/ucbstore.cxx
@@ -0,0 +1,2205 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+/**************************************************************************
+ TODO
+ **************************************************************************
+
+ *************************************************************************/
+
+#include <optional>
+#include <unordered_map>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ref.hxx>
+#include <comphelper/interfacecontainer2.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <com/sun/star/beans/IllegalTypeException.hpp>
+#include <com/sun/star/beans/NotRemoveableException.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyExistException.hpp>
+#include <com/sun/star/beans/PropertySetInfoChange.hpp>
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/container/XNameReplace.hpp>
+#include <com/sun/star/util/XChangesBatch.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/weak.hxx>
+#include "ucbstore.hxx"
+
+using namespace com::sun::star::beans;
+using namespace com::sun::star::configuration;
+using namespace com::sun::star::container;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::ucb;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::util;
+using namespace comphelper;
+using namespace cppu;
+
+static OUString makeHierarchalNameSegment( const OUString & rIn )
+{
+ OUStringBuffer aBuffer;
+ aBuffer.append( "['" );
+
+ sal_Int32 nCount = rIn.getLength();
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ const sal_Unicode c = rIn[ n ];
+ switch ( c )
+ {
+ case '&':
+ aBuffer.append( "&amp;" );
+ break;
+
+ case '"':
+ aBuffer.append( "&quot;" );
+ break;
+
+ case '\'':
+ aBuffer.append( "&apos;" );
+ break;
+
+ case '<':
+ aBuffer.append( "&lt;" );
+ break;
+
+ case '>':
+ aBuffer.append( "&gt;" );
+ break;
+
+ default:
+ aBuffer.append( c );
+ break;
+ }
+ }
+
+ aBuffer.append( "']" );
+ return aBuffer.makeStringAndClear();
+}
+
+constexpr OUStringLiteral STORE_CONTENTPROPERTIES_KEY = u"/org.openoffice.ucb.Store/ContentProperties";
+
+// describe path of cfg entry
+constexpr OUStringLiteral CFGPROPERTY_NODEPATH = u"nodepath";
+
+class PropertySetInfo_Impl : public cppu::WeakImplHelper < XPropertySetInfo >
+{
+ std::optional<Sequence< Property >>
+ m_xProps;
+ PersistentPropertySet* m_pOwner;
+
+public:
+ explicit PropertySetInfo_Impl(PersistentPropertySet* pOwner);
+
+ // XPropertySetInfo
+ virtual Sequence< Property > SAL_CALL getProperties() override;
+ virtual Property SAL_CALL getPropertyByName( const OUString& aName ) override;
+ virtual sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) override;
+
+ // Non-interface methods.
+ void reset() { m_xProps.reset(); }
+};
+
+
+// UcbStore Implementation.
+
+
+UcbStore::UcbStore( const Reference< XComponentContext >& xContext )
+: m_xContext( xContext )
+{
+}
+
+
+// virtual
+UcbStore::~UcbStore()
+{
+}
+
+OUString SAL_CALL UcbStore::getImplementationName()
+{
+ return "com.sun.star.comp.ucb.UcbStore";
+}
+sal_Bool SAL_CALL UcbStore::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+css::uno::Sequence< OUString > SAL_CALL UcbStore::getSupportedServiceNames()
+{
+ return { "com.sun.star.ucb.Store" };
+}
+
+// Service factory implementation.
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ucb_UcbStore_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new UcbStore(context));
+}
+
+
+// XPropertySetRegistryFactory methods.
+
+
+// virtual
+Reference< XPropertySetRegistry > SAL_CALL
+UcbStore::createPropertySetRegistry( const OUString& )
+{
+ // The URL parameter is ignored by this interface implementation. It always
+ // uses the configuration server as storage medium.
+
+ if ( !m_xTheRegistry.is() )
+ {
+ std::unique_lock aGuard( m_aMutex );
+ if ( !m_xTheRegistry.is() )
+ m_xTheRegistry = new PropertySetRegistry( m_xContext, m_aInitArgs );
+ }
+
+ return m_xTheRegistry;
+}
+
+
+// XInitialization methods.
+
+
+// virtual
+void SAL_CALL UcbStore::initialize( const Sequence< Any >& aArguments )
+{
+ std::unique_lock aGuard( m_aMutex );
+ m_aInitArgs = aArguments;
+}
+
+
+
+// PropertySetRegistry Implementation.
+
+
+PropertySetRegistry::PropertySetRegistry(
+ const Reference< XComponentContext >& xContext,
+ const Sequence< Any > &rInitArgs )
+: m_xContext( xContext )
+, m_aInitArgs(rInitArgs)
+, m_bTriedToGetRootReadAccess(false)
+, m_bTriedToGetRootWriteAccess(false)
+{
+}
+
+
+// virtual
+PropertySetRegistry::~PropertySetRegistry()
+{
+}
+
+
+// XServiceInfo methods.
+
+
+OUString SAL_CALL PropertySetRegistry::getImplementationName()
+{
+ return "com.sun.star.comp.ucb.PropertySetRegistry";
+}
+
+sal_Bool SAL_CALL PropertySetRegistry::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+css::uno::Sequence< OUString > SAL_CALL PropertySetRegistry::getSupportedServiceNames()
+{
+ return { "com.sun.star.ucb.PropertySetRegistry" };
+}
+
+
+// XPropertySetRegistry methods.
+
+
+// virtual
+Reference< XPersistentPropertySet > SAL_CALL
+PropertySetRegistry::openPropertySet( const OUString& key, sal_Bool create )
+{
+ if ( !key.isEmpty() )
+ {
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ PropertySetMap_Impl& rSets = m_aPropSets;
+
+ PropertySetMap_Impl::const_iterator it = rSets.find( key );
+ if ( it != rSets.end() )
+ {
+ // Already instantiated.
+ return Reference< XPersistentPropertySet >( (*it).second );
+ }
+ else
+ {
+ // Create new instance.
+ Reference< XNameAccess > xRootNameAccess(
+ getRootConfigReadAccess(), UNO_QUERY );
+ if ( xRootNameAccess.is() )
+ {
+ // Propertyset in registry?
+ if ( xRootNameAccess->hasByName( key ) )
+ {
+ // Yep!
+ return Reference< XPersistentPropertySet >(
+ new PersistentPropertySet(
+ *this, key ) );
+ }
+ else if ( create )
+ {
+ // No. Create entry for propertyset.
+
+ Reference< XSingleServiceFactory > xFac(
+ getConfigWriteAccess( OUString() ), UNO_QUERY );
+ Reference< XChangesBatch > xBatch( xFac, UNO_QUERY );
+ Reference< XNameContainer > xContainer( xFac, UNO_QUERY );
+
+ OSL_ENSURE( xFac.is(),
+ "PropertySetRegistry::openPropertySet - "
+ "No factory!" );
+
+ OSL_ENSURE( xBatch.is(),
+ "PropertySetRegistry::openPropertySet - "
+ "No batch!" );
+
+ OSL_ENSURE( xContainer.is(),
+ "PropertySetRegistry::openPropertySet - "
+ "No container!" );
+
+ if ( xFac.is() && xBatch.is() && xContainer.is() )
+ {
+ try
+ {
+ // Create new "Properties" config item.
+ Reference< XNameReplace > xNameReplace(
+ xFac->createInstance(), UNO_QUERY );
+
+ if ( xNameReplace.is() )
+ {
+ // Fill new item...
+
+ // Insert new item.
+ xContainer->insertByName(
+ key, Any( xNameReplace ) );
+ // Commit changes.
+ xBatch->commitChanges();
+
+ return Reference< XPersistentPropertySet >(
+ new PersistentPropertySet(
+ *this, key ) );
+ }
+ }
+ catch (const IllegalArgumentException&)
+ {
+ // insertByName
+
+ OSL_FAIL( "PropertySetRegistry::openPropertySet - "
+ "caught IllegalArgumentException!" );
+ }
+ catch (const ElementExistException&)
+ {
+ // insertByName
+
+ OSL_FAIL( "PropertySetRegistry::openPropertySet - "
+ "caught ElementExistException!" );
+ }
+ catch (const WrappedTargetException&)
+ {
+ // insertByName, commitChanges
+
+ OSL_FAIL( "PropertySetRegistry::openPropertySet - "
+ "caught WrappedTargetException!" );
+ }
+ catch (const RuntimeException&)
+ {
+ OSL_FAIL( "PropertySetRegistry::openPropertySet - "
+ "caught RuntimeException!" );
+ }
+ catch (const Exception&)
+ {
+ // createInstance
+
+ OSL_FAIL( "PropertySetRegistry::openPropertySet - "
+ "caught Exception!" );
+ }
+ }
+ }
+ else
+ {
+ // No entry. Fail, but no error.
+ return Reference< XPersistentPropertySet >();
+ }
+ }
+
+ SAL_WARN( "ucb", "no root access" );
+ }
+ }
+
+ return Reference< XPersistentPropertySet >();
+}
+
+
+// virtual
+void SAL_CALL PropertySetRegistry::removePropertySet( const OUString& key )
+{
+ if ( key.isEmpty() )
+ return;
+
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ Reference< XNameAccess > xRootNameAccess(
+ getRootConfigReadAccess(), UNO_QUERY );
+ if ( xRootNameAccess.is() )
+ {
+ // Propertyset in registry?
+ if ( !xRootNameAccess->hasByName( key ) )
+ return;
+ Reference< XChangesBatch > xBatch(
+ getConfigWriteAccess( OUString() ), UNO_QUERY );
+ Reference< XNameContainer > xContainer( xBatch, UNO_QUERY );
+
+ if ( xBatch.is() && xContainer.is() )
+ {
+ try
+ {
+ // Remove item.
+ xContainer->removeByName( key );
+ // Commit changes.
+ xBatch->commitChanges();
+
+ // Success.
+ return;
+ }
+ catch (const NoSuchElementException&)
+ {
+ // removeByName
+
+ OSL_FAIL( "PropertySetRegistry::removePropertySet - "
+ "caught NoSuchElementException!" );
+ return;
+ }
+ catch (const WrappedTargetException&)
+ {
+ // commitChanges
+
+ OSL_FAIL( "PropertySetRegistry::removePropertySet - "
+ "caught WrappedTargetException!" );
+ return;
+ }
+ }
+
+ return;
+ }
+
+ SAL_WARN( "ucb", "no root access" );
+}
+
+
+// XElementAccess methods.
+
+
+// virtual
+css::uno::Type SAL_CALL PropertySetRegistry::getElementType()
+{
+ return cppu::UnoType<XPersistentPropertySet>::get();
+}
+
+
+// virtual
+sal_Bool SAL_CALL PropertySetRegistry::hasElements()
+{
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ Reference< XElementAccess > xElemAccess(
+ getRootConfigReadAccess(), UNO_QUERY );
+ if ( xElemAccess.is() )
+ return xElemAccess->hasElements();
+
+ return false;
+}
+
+
+// XNameAccess methods.
+
+
+// virtual
+Any SAL_CALL PropertySetRegistry::getByName( const OUString& aName )
+{
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ Reference< XNameAccess > xNameAccess(
+ getRootConfigReadAccess(), UNO_QUERY );
+ if ( xNameAccess.is() )
+ {
+
+ try
+ {
+ return xNameAccess->getByName( aName );
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByName
+ }
+ catch (const WrappedTargetException&)
+ {
+ // getByName
+ }
+ }
+
+ return Any();
+}
+
+
+// virtual
+Sequence< OUString > SAL_CALL PropertySetRegistry::getElementNames()
+{
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ Reference< XNameAccess > xNameAccess(
+ getRootConfigReadAccess(), UNO_QUERY );
+ if ( xNameAccess.is() )
+ {
+ return xNameAccess->getElementNames();
+ }
+ return Sequence< OUString >( 0 );
+}
+
+
+// virtual
+sal_Bool SAL_CALL PropertySetRegistry::hasByName( const OUString& aName )
+{
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ Reference< XNameAccess > xNameAccess(
+ getRootConfigReadAccess(), UNO_QUERY );
+ if ( xNameAccess.is() )
+ {
+ return xNameAccess->hasByName( aName );
+ }
+
+ return false;
+}
+
+
+void PropertySetRegistry::add( PersistentPropertySet* pSet )
+{
+ OUString key( pSet->getKey() );
+
+ if ( !key.isEmpty() )
+ {
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+ m_aPropSets[ key ] = pSet;
+ }
+}
+
+
+void PropertySetRegistry::remove( PersistentPropertySet* pSet )
+{
+ OUString key( pSet->getKey() );
+
+ if ( key.isEmpty() )
+ return;
+
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ PropertySetMap_Impl& rSets = m_aPropSets;
+
+ PropertySetMap_Impl::iterator it = rSets.find( key );
+ if ( it != rSets.end() )
+ {
+ // Found.
+ rSets.erase( it );
+ }
+}
+
+
+void PropertySetRegistry::renamePropertySet( const OUString& rOldKey,
+ const OUString& rNewKey )
+{
+ if ( rOldKey == rNewKey )
+ return;
+
+ Reference< XNameAccess > xRootNameAccess(
+ getConfigWriteAccess( OUString() ), UNO_QUERY );
+ if ( xRootNameAccess.is() )
+ {
+ // Old key present?
+ if ( xRootNameAccess->hasByName( rOldKey ) )
+ {
+ // New key not present?
+ if ( xRootNameAccess->hasByName( rNewKey ) )
+ {
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "New key exists!" );
+ return;
+ }
+ Reference< XSingleServiceFactory > xFac(
+ xRootNameAccess, UNO_QUERY );
+ Reference< XChangesBatch > xBatch( xFac, UNO_QUERY );
+ Reference< XNameContainer > xContainer( xFac, UNO_QUERY );
+
+ OSL_ENSURE( xFac.is(),
+ "PropertySetRegistry::renamePropertySet - "
+ "No factory!" );
+
+ OSL_ENSURE( xBatch.is(),
+ "PropertySetRegistry::renamePropertySet - "
+ "No batch!" );
+
+ OSL_ENSURE( xContainer.is(),
+ "PropertySetRegistry::renamePropertySet - "
+ "No container!" );
+
+ if ( xFac.is() && xBatch.is() && xContainer.is() )
+ {
+
+ // Create new "Properties" config item.
+
+
+ try
+ {
+ Reference< XNameReplace > xNameReplace(
+ xFac->createInstance(), UNO_QUERY );
+
+ if ( xNameReplace.is() )
+ {
+ // Insert new item.
+ xContainer->insertByName(
+ rNewKey, Any( xNameReplace ) );
+ // Commit changes.
+ xBatch->commitChanges();
+ }
+ }
+ catch (const IllegalArgumentException&)
+ {
+ // insertByName
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught IllegalArgumentException!" );
+ return;
+ }
+ catch (const ElementExistException&)
+ {
+ // insertByName
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught ElementExistException!" );
+ return;
+ }
+ catch (const WrappedTargetException&)
+ {
+ // insertByName, commitChanges
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught WrappedTargetException!" );
+ return;
+ }
+ catch (const RuntimeException&)
+ {
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught RuntimeException!" );
+ return;
+ }
+ catch (const Exception&)
+ {
+ // createInstance
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught Exception!" );
+ return;
+ }
+
+
+ // Copy data...
+
+
+ Reference< XHierarchicalNameAccess > xRootHierNameAccess(
+ xRootNameAccess, UNO_QUERY );
+ if ( !xRootHierNameAccess.is() )
+ {
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "No hierarchical name access!" );
+ return;
+ }
+
+ try
+ {
+ OUString aOldValuesKey
+ = makeHierarchalNameSegment( rOldKey ) + "/Values";
+
+ Reference< XNameAccess > xOldNameAccess;
+ xRootHierNameAccess->getByHierarchicalName(
+ aOldValuesKey )
+ >>= xOldNameAccess;
+ if ( !xOldNameAccess.is() )
+ {
+ OSL_FAIL( "PersistentPropertySet::renamePropertySet - "
+ "No old name access!" );
+ return;
+ }
+
+ // Obtain property names.
+ const Sequence< OUString > aElems
+ = xOldNameAccess->getElementNames();
+ if ( aElems.hasElements() )
+ {
+ OUString aNewValuesKey
+ = makeHierarchalNameSegment( rNewKey ) + "/Values";
+
+ Reference< XSingleServiceFactory > xNewFac;
+ xRootHierNameAccess->getByHierarchicalName(
+ aNewValuesKey )
+ >>= xNewFac;
+ if ( !xNewFac.is() )
+ {
+ OSL_FAIL( "PersistentPropertySet::renamePropertySet - "
+ "No new factory!" );
+ return;
+ }
+
+ Reference< XNameContainer > xNewContainer(
+ xNewFac, UNO_QUERY );
+ if ( !xNewContainer.is() )
+ {
+ OSL_FAIL( "PersistentPropertySet::renamePropertySet - "
+ "No new container!" );
+ return;
+ }
+
+ aOldValuesKey += "/";
+
+ OUString const aHandleKey("/Handle");
+ OUString const aValueKey("/Value");
+ OUString const aStateKey("/State");
+ OUString const aAttrKey("/Attributes");
+
+ for ( const OUString& rPropName : aElems )
+ {
+ // Create new item.
+ Reference< XNameReplace > xNewPropNameReplace(
+ xNewFac->createInstance(), UNO_QUERY );
+
+ if ( !xNewPropNameReplace.is() )
+ {
+ OSL_FAIL( "PersistentPropertySet::renamePropertySet - "
+ "No new prop name replace!" );
+ return;
+ }
+
+ // Fill new item...
+
+ // Set Values
+ OUString aKey = aOldValuesKey;
+ aKey += makeHierarchalNameSegment( rPropName );
+
+ // ... handle
+ OUString aNewKey1 = aKey + aHandleKey;
+ Any aAny =
+ xRootHierNameAccess->getByHierarchicalName(
+ aNewKey1 );
+ xNewPropNameReplace->replaceByName( "Handle", aAny );
+
+ // ... value
+ aNewKey1 = aKey + aValueKey;
+ aAny =
+ xRootHierNameAccess->getByHierarchicalName(
+ aNewKey1 );
+ xNewPropNameReplace->replaceByName( "Value", aAny );
+
+ // ... state
+ aNewKey1 = aKey + aStateKey;
+ aAny =
+ xRootHierNameAccess->getByHierarchicalName(
+ aNewKey1 );
+ xNewPropNameReplace->replaceByName( "State", aAny );
+
+ // ... attributes
+ aNewKey1 = aKey + aAttrKey;
+ aAny =
+ xRootHierNameAccess->getByHierarchicalName(
+ aNewKey1 );
+ xNewPropNameReplace->replaceByName( "Attributes", aAny );
+
+ // Insert new item.
+ xNewContainer->insertByName(
+ rPropName, Any( xNewPropNameReplace ) );
+
+ // Commit changes.
+ xBatch->commitChanges();
+ }
+ }
+ }
+ catch (const IllegalArgumentException&)
+ {
+ // insertByName, replaceByName
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught IllegalArgumentException!" );
+ return;
+ }
+ catch (const ElementExistException&)
+ {
+ // insertByName
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught ElementExistException!" );
+ return;
+ }
+ catch (const WrappedTargetException&)
+ {
+ // insertByName, replaceByName, commitChanges
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught WrappedTargetException!" );
+ return;
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName, replaceByName
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught NoSuchElementException!" );
+ return;
+ }
+ catch (const RuntimeException&)
+ {
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught RuntimeException!" );
+ return;
+ }
+ catch (const Exception&)
+ {
+ // createInstance
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught Exception!" );
+ return;
+ }
+
+
+ // Remove old entry...
+
+
+ try
+ {
+ // Remove item.
+ xContainer->removeByName( rOldKey );
+ // Commit changes.
+ xBatch->commitChanges();
+
+ // Success.
+ return;
+ }
+ catch (const NoSuchElementException&)
+ {
+ // removeByName
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught NoSuchElementException!" );
+ return;
+ }
+ catch (const WrappedTargetException&)
+ {
+ // commitChanges
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught WrappedTargetException!" );
+ return;
+ }
+ }
+ }
+ }
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - Error!" );
+}
+
+
+Reference< XMultiServiceFactory > PropertySetRegistry::getConfigProvider()
+{
+ if ( !m_xConfigProvider.is() )
+ {
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+ if ( !m_xConfigProvider.is() )
+ {
+ const Sequence< Any >& rInitArgs = m_aInitArgs;
+
+ if ( rInitArgs.hasElements() )
+ {
+ // Extract config provider from service init args.
+ rInitArgs[ 0 ] >>= m_xConfigProvider;
+
+ OSL_ENSURE( m_xConfigProvider.is(),
+ "PropertySetRegistry::getConfigProvider - "
+ "No config provider!" );
+ }
+ else
+ {
+ try
+ {
+ m_xConfigProvider = theDefaultProvider::get( m_xContext );
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "ucb", "");
+ }
+ }
+ }
+ }
+
+ return m_xConfigProvider;
+}
+
+
+Reference< XInterface > PropertySetRegistry::getRootConfigReadAccess()
+{
+ try
+ {
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ if ( !m_xRootReadAccess.is() )
+ {
+ if ( m_bTriedToGetRootReadAccess )
+ {
+ OSL_FAIL( "PropertySetRegistry::getRootConfigReadAccess - "
+ "Unable to read any config data! -> #82494#" );
+ return Reference< XInterface >();
+ }
+
+ getConfigProvider();
+
+ if ( m_xConfigProvider.is() )
+ {
+ Sequence<Any> aArguments(comphelper::InitAnyPropertySequence(
+ {
+ {CFGPROPERTY_NODEPATH, Any(OUString( STORE_CONTENTPROPERTIES_KEY ))}
+ }));
+
+ m_bTriedToGetRootReadAccess = true;
+
+ m_xRootReadAccess =
+ m_xConfigProvider->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationAccess",
+ aArguments );
+
+ if ( m_xRootReadAccess.is() )
+ return m_xRootReadAccess;
+ }
+ }
+ else
+ return m_xRootReadAccess;
+ }
+ catch (const RuntimeException&)
+ {
+ throw;
+ }
+ catch (const Exception&)
+ {
+ // createInstance, createInstanceWithArguments
+
+ TOOLS_WARN_EXCEPTION("ucb", "");
+ return Reference< XInterface >();
+ }
+
+ SAL_WARN( "ucb", "Error!" );
+ return Reference< XInterface >();
+}
+
+
+Reference< XInterface > PropertySetRegistry::getConfigWriteAccess(
+ const OUString& rPath )
+{
+ try
+ {
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ if ( !m_xRootWriteAccess.is() )
+ {
+ if ( m_bTriedToGetRootWriteAccess )
+ {
+ OSL_FAIL( "PropertySetRegistry::getConfigWriteAccess - "
+ "Unable to write any config data! -> #82494#" );
+ return Reference< XInterface >();
+ }
+
+ getConfigProvider();
+
+ if ( m_xConfigProvider.is() )
+ {
+ Sequence<Any> aArguments(comphelper::InitAnyPropertySequence(
+ {
+ {CFGPROPERTY_NODEPATH, Any(OUString( STORE_CONTENTPROPERTIES_KEY ))}
+ }));
+
+ m_bTriedToGetRootWriteAccess = true;
+
+ m_xRootWriteAccess =
+ m_xConfigProvider->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationUpdateAccess",
+ aArguments );
+
+ OSL_ENSURE( m_xRootWriteAccess.is(),
+ "PropertySetRegistry::getConfigWriteAccess - "
+ "No config update access!" );
+ }
+ }
+
+ if ( m_xRootWriteAccess.is() )
+ {
+ if ( !rPath.isEmpty() )
+ {
+ Reference< XHierarchicalNameAccess > xNA(
+ m_xRootWriteAccess, UNO_QUERY );
+ if ( xNA.is() )
+ {
+ Reference< XInterface > xInterface;
+ xNA->getByHierarchicalName( rPath ) >>= xInterface;
+
+ if ( xInterface.is() )
+ return xInterface;
+ }
+ }
+ else
+ return m_xRootWriteAccess;
+ }
+ }
+ catch (const RuntimeException&)
+ {
+ throw;
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PropertySetRegistry::getConfigWriteAccess - "
+ "caught NoSuchElementException!" );
+ return Reference< XInterface >();
+ }
+ catch (const Exception&)
+ {
+ // createInstance, createInstanceWithArguments
+
+ OSL_FAIL( "PropertySetRegistry::getConfigWriteAccess - "
+ "caught Exception!" );
+ return Reference< XInterface >();
+ }
+
+ OSL_FAIL( "PropertySetRegistry::getConfigWriteAccess - Error!" );
+ return Reference< XInterface >();
+}
+
+
+// PersistentPropertySet Implementation.
+
+
+PersistentPropertySet::PersistentPropertySet(
+ PropertySetRegistry& rCreator,
+ const OUString& rKey )
+: m_pCreator( &rCreator ), m_aKey( rKey )
+{
+ // register at creator.
+ rCreator.add( this );
+}
+
+
+// virtual
+PersistentPropertySet::~PersistentPropertySet()
+{
+ // deregister at creator.
+ m_pCreator->remove( this );
+}
+
+// XServiceInfo methods.
+
+OUString SAL_CALL PersistentPropertySet::getImplementationName()
+{
+ return "com.sun.star.comp.ucb.PersistentPropertySet";
+}
+
+sal_Bool SAL_CALL PersistentPropertySet::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+css::uno::Sequence< OUString > SAL_CALL PersistentPropertySet::getSupportedServiceNames()
+{
+ return { "com.sun.star.ucb.PersistentPropertySet" };
+}
+
+
+// XComponent methods.
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::dispose()
+{
+ if ( m_pDisposeEventListeners &&
+ m_pDisposeEventListeners->getLength() )
+ {
+ EventObject aEvt;
+ aEvt.Source = static_cast< XComponent * >( this );
+ m_pDisposeEventListeners->disposeAndClear( aEvt );
+ }
+
+ if ( m_pPropSetChangeListeners &&
+ m_pPropSetChangeListeners->getLength() )
+ {
+ EventObject aEvt;
+ aEvt.Source = static_cast< XPropertySetInfoChangeNotifier * >( this );
+ m_pPropSetChangeListeners->disposeAndClear( aEvt );
+ }
+
+ if ( m_pPropertyChangeListeners )
+ {
+ EventObject aEvt;
+ aEvt.Source = static_cast< XPropertySet * >( this );
+ m_pPropertyChangeListeners->disposeAndClear( aEvt );
+ }
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::addEventListener(
+ const Reference< XEventListener >& Listener )
+{
+ if ( !m_pDisposeEventListeners )
+ m_pDisposeEventListeners.reset(
+ new OInterfaceContainerHelper3<css::lang::XEventListener>( m_aMutex ) );
+
+ m_pDisposeEventListeners->addInterface( Listener );
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::removeEventListener(
+ const Reference< XEventListener >& Listener )
+{
+ if ( m_pDisposeEventListeners )
+ m_pDisposeEventListeners->removeInterface( Listener );
+
+ // Note: Don't want to delete empty container here -> performance.
+}
+
+
+// XPropertySet methods.
+
+
+// virtual
+Reference< XPropertySetInfo > SAL_CALL PersistentPropertySet::getPropertySetInfo()
+{
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ if ( !m_pInfo.is() )
+ {
+ m_pInfo = new PropertySetInfo_Impl( this );
+ }
+ return m_pInfo;
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::setPropertyValue( const OUString& aPropertyName,
+ const Any& aValue )
+{
+ osl::ClearableGuard< osl::Mutex > aCGuard( m_aMutex );
+
+ Reference< XHierarchicalNameAccess > xRootHierNameAccess(
+ m_pCreator->getRootConfigReadAccess(), UNO_QUERY );
+ if ( xRootHierNameAccess.is() )
+ {
+ OUString aFullPropName( getFullKey() + "/" );
+ aFullPropName += makeHierarchalNameSegment( aPropertyName );
+
+ // Does property exist?
+ if ( xRootHierNameAccess->hasByHierarchicalName( aFullPropName ) )
+ {
+ Reference< XNameReplace > xNameReplace(
+ m_pCreator->getConfigWriteAccess(
+ aFullPropName ), UNO_QUERY );
+ Reference< XChangesBatch > xBatch(
+ m_pCreator->getConfigWriteAccess(
+ OUString() ), UNO_QUERY );
+
+ if ( xNameReplace.is() && xBatch.is() )
+ {
+ try
+ {
+ // Obtain old value
+ OUString aValueName = aFullPropName + "/Value";
+ Any aOldValue
+ = xRootHierNameAccess->getByHierarchicalName(
+ aValueName );
+ // Check value type.
+ if ( aOldValue.getValueType() != aValue.getValueType() )
+ {
+ aCGuard.clear();
+ throw IllegalArgumentException();
+ }
+
+ // Write value
+ xNameReplace->replaceByName( "Value", aValue );
+
+ // Write state ( Now it is a directly set value )
+ xNameReplace->replaceByName(
+ "State",
+ Any(
+ sal_Int32(
+ PropertyState_DIRECT_VALUE ) ) );
+
+ // Commit changes.
+ xBatch->commitChanges();
+
+ PropertyChangeEvent aEvt;
+ if ( m_pPropertyChangeListeners )
+ {
+ // Obtain handle
+ aValueName = aFullPropName + "/Handle";
+ sal_Int32 nHandle = -1;
+ xRootHierNameAccess->getByHierarchicalName( aValueName )
+ >>= nHandle;
+
+ aEvt.Source = static_cast<OWeakObject*>(this);
+ aEvt.PropertyName = aPropertyName;
+ aEvt.PropertyHandle = nHandle;
+ aEvt.Further = false;
+ aEvt.OldValue = aOldValue;
+ aEvt.NewValue = aValue;
+
+ // Callback follows!
+ aCGuard.clear();
+
+ notifyPropertyChangeEvent( aEvt );
+ }
+ return;
+ }
+ catch (const IllegalArgumentException&)
+ {
+ // replaceByName
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName, replaceByName
+ }
+ catch (const WrappedTargetException&)
+ {
+ // replaceByName, commitChanges
+ }
+ }
+ }
+ }
+
+ throw UnknownPropertyException(aPropertyName);
+}
+
+
+// virtual
+Any SAL_CALL PersistentPropertySet::getPropertyValue(
+ const OUString& PropertyName )
+{
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ Reference< XHierarchicalNameAccess > xNameAccess(
+ m_pCreator->getRootConfigReadAccess(), UNO_QUERY );
+ if ( xNameAccess.is() )
+ {
+ OUString aFullPropName( getFullKey() + "/" );
+ aFullPropName += makeHierarchalNameSegment( PropertyName ) + "/Value";
+ try
+ {
+ return xNameAccess->getByHierarchicalName( aFullPropName );
+ }
+ catch (const NoSuchElementException&)
+ {
+ throw UnknownPropertyException(aFullPropName);
+ }
+ }
+
+ throw UnknownPropertyException(PropertyName);
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::addPropertyChangeListener(
+ const OUString& aPropertyName,
+ const Reference< XPropertyChangeListener >& xListener )
+{
+// load();
+
+ if ( !m_pPropertyChangeListeners )
+ m_pPropertyChangeListeners.reset(
+ new PropertyListeners_Impl( m_aMutex ) );
+
+ m_pPropertyChangeListeners->addInterface(
+ aPropertyName, xListener );
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::removePropertyChangeListener(
+ const OUString& aPropertyName,
+ const Reference< XPropertyChangeListener >& aListener )
+{
+// load();
+
+ if ( m_pPropertyChangeListeners )
+ m_pPropertyChangeListeners->removeInterface(
+ aPropertyName, aListener );
+
+ // Note: Don't want to delete empty container here -> performance.
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::addVetoableChangeListener(
+ const OUString&,
+ const Reference< XVetoableChangeListener >& )
+{
+// load();
+// OSL_FAIL( // "PersistentPropertySet::addVetoableChangeListener - N.Y.I." );
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::removeVetoableChangeListener(
+ const OUString&,
+ const Reference< XVetoableChangeListener >& )
+{
+// load();
+// OSL_FAIL( // "PersistentPropertySet::removeVetoableChangeListener - N.Y.I." );
+}
+
+
+// XPersistentPropertySet methods.
+
+
+// virtual
+Reference< XPropertySetRegistry > SAL_CALL PersistentPropertySet::getRegistry()
+{
+ return m_pCreator;
+}
+
+
+// virtual
+OUString SAL_CALL PersistentPropertySet::getKey()
+{
+ return m_aKey;
+}
+
+
+// XNamed methods.
+
+
+// virtual
+OUString SAL_CALL PersistentPropertySet::getName()
+{
+ // same as getKey()
+ return m_aKey;
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::setName( const OUString& aName )
+{
+ if ( aName != m_aKey )
+ m_pCreator->renamePropertySet( m_aKey, aName );
+}
+
+
+// XPropertyContainer methods.
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::addProperty(
+ const OUString& Name, sal_Int16 Attributes, const Any& DefaultValue )
+{
+ if ( Name.isEmpty() )
+ throw IllegalArgumentException();
+
+ // @@@ What other types can't be written to config server?
+
+ // Check type class ( Not all types can be written to storage )
+ TypeClass eTypeClass = DefaultValue.getValueTypeClass();
+ if ( eTypeClass == TypeClass_INTERFACE )
+ throw IllegalTypeException();
+
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ // Property already in set?
+
+ OUString aFullValuesName;
+
+ Reference< XHierarchicalNameAccess > xRootHierNameAccess(
+ m_pCreator->getRootConfigReadAccess(), UNO_QUERY );
+ if ( xRootHierNameAccess.is() )
+ {
+ aFullValuesName = getFullKey();
+ OUString aFullPropName = aFullValuesName + "/";
+ aFullPropName += makeHierarchalNameSegment( Name );
+
+ if ( xRootHierNameAccess->hasByHierarchicalName( aFullPropName ) )
+ {
+ // Already in set.
+ throw PropertyExistException();
+ }
+ }
+
+ // Property is always removable.
+ Attributes |= PropertyAttribute::REMOVABLE;
+
+ // Add property.
+
+ Reference< XSingleServiceFactory > xFac(
+ m_pCreator->getConfigWriteAccess( aFullValuesName ),
+ UNO_QUERY );
+ Reference< XNameContainer > xContainer( xFac, UNO_QUERY );
+ Reference< XChangesBatch > xBatch(
+ m_pCreator->getConfigWriteAccess( OUString() ),
+ UNO_QUERY );
+
+ OSL_ENSURE( xFac.is(),
+ "PersistentPropertySet::addProperty - No factory!" );
+
+ OSL_ENSURE( xBatch.is(),
+ "PersistentPropertySet::addProperty - No batch!" );
+
+ OSL_ENSURE( xContainer.is(),
+ "PersistentPropertySet::addProperty - No container!" );
+
+ if ( xFac.is() && xBatch.is() && xContainer.is() )
+ {
+ try
+ {
+ // Create new "PropertyValue" config item.
+ Reference< XNameReplace > xNameReplace(
+ xFac->createInstance(), UNO_QUERY );
+
+ if ( xNameReplace.is() )
+ {
+ // Fill new item...
+
+ // Set handle
+ xNameReplace->replaceByName(
+ "Handle",
+ Any( sal_Int32( -1 ) ) );
+
+ // Set default value
+ xNameReplace->replaceByName(
+ "Value",
+ DefaultValue );
+
+ // Set state ( always "default" )
+ xNameReplace->replaceByName(
+ "State",
+ Any(
+ sal_Int32(
+ PropertyState_DEFAULT_VALUE ) ) );
+
+ // Set attributes
+ xNameReplace->replaceByName(
+ "Attributes",
+ Any( sal_Int32( Attributes ) ) );
+
+ // Insert new item.
+ xContainer->insertByName( Name, Any( xNameReplace ) );
+
+ // Commit changes.
+ xBatch->commitChanges();
+
+ // Property set info is invalid.
+ if ( m_pInfo.is() )
+ m_pInfo->reset();
+
+ // Notify propertyset info change listeners.
+ if ( m_pPropSetChangeListeners &&
+ m_pPropSetChangeListeners->getLength() )
+ {
+ PropertySetInfoChangeEvent evt(
+ static_cast< OWeakObject * >( this ),
+ Name,
+ -1,
+ PropertySetInfoChange::PROPERTY_INSERTED );
+ notifyPropertySetInfoChange( evt );
+ }
+
+ // Success.
+ return;
+ }
+ }
+ catch (const IllegalArgumentException&)
+ {
+ // insertByName
+
+ OSL_FAIL( "PersistentPropertySet::addProperty - "
+ "caught IllegalArgumentException!" );
+ return;
+ }
+ catch (const ElementExistException&)
+ {
+ // insertByName
+
+ OSL_FAIL( "PersistentPropertySet::addProperty - "
+ "caught ElementExistException!" );
+ return;
+ }
+ catch (const WrappedTargetException&)
+ {
+ // replaceByName, insertByName, commitChanges
+
+ OSL_FAIL( "PersistentPropertySet::addProperty - "
+ "caught WrappedTargetException!" );
+ return;
+ }
+ catch (const RuntimeException&)
+ {
+ throw;
+ }
+ catch (const Exception&)
+ {
+ // createInstance
+
+ OSL_FAIL( "PersistentPropertySet::addProperty - "
+ "caught Exception!" );
+ return;
+ }
+ }
+
+ OSL_FAIL( "PersistentPropertySet::addProperty - Error!" );
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::removeProperty( const OUString& Name )
+{
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ Reference< XHierarchicalNameAccess > xRootHierNameAccess(
+ m_pCreator->getRootConfigReadAccess(), UNO_QUERY );
+ if ( xRootHierNameAccess.is() )
+ {
+ OUString aFullValuesName = getFullKey();
+ OUString aFullPropName = aFullValuesName + "/";
+ aFullPropName += makeHierarchalNameSegment( Name );
+
+ // Property in set?
+ if ( !xRootHierNameAccess->hasByHierarchicalName( aFullPropName ) )
+ throw UnknownPropertyException(aFullPropName);
+
+ // Property removable?
+ try
+ {
+ OUString aFullAttrName = aFullPropName + "/Attributes";
+
+ sal_Int32 nAttribs = 0;
+ if ( xRootHierNameAccess->getByHierarchicalName( aFullAttrName )
+ >>= nAttribs )
+ {
+ if ( !( nAttribs & PropertyAttribute::REMOVABLE ) )
+ {
+ // Not removable!
+ throw NotRemoveableException();
+ }
+ }
+ else
+ {
+ OSL_FAIL( "PersistentPropertySet::removeProperty - "
+ "No attributes!" );
+ return;
+ }
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PersistentPropertySet::removeProperty - "
+ "caught NoSuchElementException!" );
+ }
+
+ // Remove property...
+
+ Reference< XNameContainer > xContainer(
+ m_pCreator->getConfigWriteAccess( aFullValuesName ),
+ UNO_QUERY );
+ Reference< XChangesBatch > xBatch(
+ m_pCreator->getConfigWriteAccess( OUString() ),
+ UNO_QUERY );
+
+ OSL_ENSURE( xBatch.is(),
+ "PersistentPropertySet::removeProperty - No batch!" );
+
+ OSL_ENSURE( xContainer.is(),
+ "PersistentPropertySet::removeProperty - No container!" );
+
+ if ( xBatch.is() && xContainer.is() )
+ {
+ try
+ {
+ sal_Int32 nHandle = -1;
+
+ if ( m_pPropSetChangeListeners &&
+ m_pPropSetChangeListeners->getLength() )
+ {
+ // Obtain property handle ( needed for propertysetinfo
+ // change event )...
+
+ try
+ {
+ OUString aFullHandleName = aFullPropName + "/Handle";
+
+ if ( ! ( xRootHierNameAccess->getByHierarchicalName(
+ aFullHandleName ) >>= nHandle ) )
+ nHandle = -1;
+
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PersistentPropertySet::removeProperty - "
+ "caught NoSuchElementException!" );
+ nHandle = -1;
+ }
+ }
+
+ xContainer->removeByName( Name );
+ xBatch->commitChanges();
+
+ // Property set info is invalid.
+ if ( m_pInfo.is() )
+ m_pInfo->reset();
+
+ // Notify propertyset info change listeners.
+ if ( m_pPropSetChangeListeners &&
+ m_pPropSetChangeListeners->getLength() )
+ {
+ PropertySetInfoChangeEvent evt(
+ static_cast< OWeakObject * >( this ),
+ Name,
+ nHandle,
+ PropertySetInfoChange::PROPERTY_REMOVED );
+ notifyPropertySetInfoChange( evt );
+ }
+
+ // Success.
+ return;
+ }
+ catch (const NoSuchElementException&)
+ {
+ // removeByName
+
+ OSL_FAIL( "PersistentPropertySet::removeProperty - "
+ "caught NoSuchElementException!" );
+ return;
+ }
+ catch (const WrappedTargetException&)
+ {
+ // commitChanges
+
+ OSL_FAIL( "PersistentPropertySet::removeProperty - "
+ "caught WrappedTargetException!" );
+ return;
+ }
+ }
+ }
+
+ OSL_FAIL( "PersistentPropertySet::removeProperty - Error!" );
+}
+
+
+// XPropertySetInfoChangeNotifier methods.
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::addPropertySetInfoChangeListener(
+ const Reference< XPropertySetInfoChangeListener >& Listener )
+{
+ if ( !m_pPropSetChangeListeners )
+ m_pPropSetChangeListeners.reset(
+ new OInterfaceContainerHelper3<XPropertySetInfoChangeListener>( m_aMutex ) );
+
+ m_pPropSetChangeListeners->addInterface( Listener );
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::removePropertySetInfoChangeListener(
+ const Reference< XPropertySetInfoChangeListener >& Listener )
+{
+ if ( m_pPropSetChangeListeners )
+ m_pPropSetChangeListeners->removeInterface( Listener );
+}
+
+
+// XPropertyAccess methods.
+
+
+// virtual
+Sequence< PropertyValue > SAL_CALL PersistentPropertySet::getPropertyValues()
+{
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ Reference< XHierarchicalNameAccess > xRootHierNameAccess(
+ m_pCreator->getRootConfigReadAccess(), UNO_QUERY );
+ if ( xRootHierNameAccess.is() )
+ {
+ try
+ {
+ Reference< XNameAccess > xNameAccess;
+ xRootHierNameAccess->getByHierarchicalName(getFullKey())
+ >>= xNameAccess;
+ if ( xNameAccess.is() )
+ {
+ // Obtain property names.
+
+ Sequence< OUString > aElems = xNameAccess->getElementNames();
+
+ sal_Int32 nCount = aElems.getLength();
+ if ( nCount )
+ {
+ Reference< XHierarchicalNameAccess > xHierNameAccess(
+ xNameAccess, UNO_QUERY );
+
+ OSL_ENSURE( xHierNameAccess.is(),
+ "PersistentPropertySet::getPropertyValues - "
+ "No hierarchical name access!" );
+
+ if ( xHierNameAccess.is() )
+ {
+ Sequence< PropertyValue > aValues( nCount );
+ auto pValues = aValues.getArray();
+
+ static const OUStringLiteral aHandleName(u"/Handle");
+ static const OUStringLiteral aValueName(u"/Value");
+ static const OUStringLiteral aStateName(u"/State");
+
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ PropertyValue& rValue = pValues[ n ];
+ OUString rName = aElems[ n ];
+ OUString aXMLName
+ = makeHierarchalNameSegment( rName );
+
+ // Set property name.
+
+ rValue.Name = rName;
+
+ try
+ {
+ // Obtain and set property handle
+ OUString aHierName = aXMLName + aHandleName;
+ Any aKeyValue
+ = xHierNameAccess->getByHierarchicalName(
+ aHierName );
+
+ if ( !( aKeyValue >>= rValue.Handle ) )
+ OSL_FAIL( "PersistentPropertySet::getPropertyValues - "
+ "Error getting property handle!" );
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PersistentPropertySet::getPropertyValues - "
+ "NoSuchElementException!" );
+ }
+
+ try
+ {
+ // Obtain and set property value
+ OUString aHierName = aXMLName + aValueName;
+ rValue.Value
+ = xHierNameAccess->getByHierarchicalName(
+ aHierName );
+
+ // Note: The value may be void if addProperty
+ // was called with a default value
+ // of type void.
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PersistentPropertySet::getPropertyValues - "
+ "NoSuchElementException!" );
+ }
+
+ try
+ {
+ // Obtain and set property state
+ OUString aHierName = aXMLName +aStateName;
+ Any aKeyValue
+ = xHierNameAccess->getByHierarchicalName(
+ aHierName );
+
+ sal_Int32 nState = 0;
+ if ( !( aKeyValue >>= nState ) )
+ OSL_FAIL( "PersistentPropertySet::getPropertyValues - "
+ "Error getting property state!" );
+ else
+ rValue.State = PropertyState( nState );
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PersistentPropertySet::getPropertyValues - "
+ "NoSuchElementException!" );
+ }
+ }
+
+ return aValues;
+ }
+ }
+ }
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+ }
+ }
+
+ return Sequence< PropertyValue >( 0 );
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::setPropertyValues(
+ const Sequence< PropertyValue >& aProps )
+{
+ if ( !aProps.hasElements() )
+ return;
+
+ osl::ClearableGuard< osl::Mutex > aCGuard( m_aMutex );
+
+ Reference< XHierarchicalNameAccess > xRootHierNameAccess(
+ m_pCreator->getRootConfigReadAccess(), UNO_QUERY );
+ if ( xRootHierNameAccess.is() )
+ {
+ std::vector< PropertyChangeEvent > aEvents;
+
+ OUString aFullPropNamePrefix( getFullKey() + "/" );
+
+ // Iterate over given property value sequence.
+ for ( const PropertyValue& rNewValue : aProps )
+ {
+ const OUString& rName = rNewValue.Name;
+
+ OUString aFullPropName = aFullPropNamePrefix;
+ aFullPropName += makeHierarchalNameSegment( rName );
+
+ // Does property exist?
+ if ( xRootHierNameAccess->hasByHierarchicalName( aFullPropName ) )
+ {
+ Reference< XNameReplace > xNameReplace(
+ m_pCreator->getConfigWriteAccess(
+ aFullPropName ), UNO_QUERY );
+ Reference< XChangesBatch > xBatch(
+ m_pCreator->getConfigWriteAccess(
+ OUString() ), UNO_QUERY );
+
+ if ( xNameReplace.is() && xBatch.is() )
+ {
+ try
+ {
+ // Write handle
+ xNameReplace->replaceByName(
+ "Handle",
+ Any( rNewValue.Handle ) );
+
+ // Save old value
+ OUString aValueName = aFullPropName +"/Value";
+ Any aOldValue
+ = xRootHierNameAccess->getByHierarchicalName(
+ aValueName );
+ // Write value
+ xNameReplace->replaceByName(
+ "Value",
+ rNewValue.Value );
+
+ // Write state ( Now it is a directly set value )
+ xNameReplace->replaceByName(
+ "State",
+ Any(
+ sal_Int32(
+ PropertyState_DIRECT_VALUE ) ) );
+
+ // Commit changes.
+ xBatch->commitChanges();
+
+ if ( m_pPropertyChangeListeners )
+ {
+ PropertyChangeEvent aEvt;
+ aEvt.Source = static_cast<OWeakObject*>(this);
+ aEvt.PropertyName = rNewValue.Name;
+ aEvt.PropertyHandle = rNewValue.Handle;
+ aEvt.Further = false;
+ aEvt.OldValue = aOldValue;
+ aEvt.NewValue = rNewValue.Value;
+
+ aEvents.push_back( aEvt );
+ }
+ }
+ catch (const IllegalArgumentException&)
+ {
+ // replaceByName
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName, replaceByName
+ }
+ catch (const WrappedTargetException&)
+ {
+ // replaceByName, commitChanges
+ }
+ }
+ }
+ }
+
+ // Callback follows!
+ aCGuard.clear();
+
+ if ( m_pPropertyChangeListeners )
+ {
+ // Notify property changes.
+ for (auto const& event : aEvents)
+ {
+ notifyPropertyChangeEvent( event );
+ }
+ }
+
+ return;
+ }
+
+ OSL_FAIL( "PersistentPropertySet::setPropertyValues - Nothing set!" );
+}
+
+
+// Non-interface methods
+
+
+void PersistentPropertySet::notifyPropertyChangeEvent(
+ const PropertyChangeEvent& rEvent ) const
+{
+ // Get "normal" listeners for the property.
+ OInterfaceContainerHelper3<XPropertyChangeListener>* pContainer =
+ m_pPropertyChangeListeners->getContainer( rEvent.PropertyName );
+ if ( pContainer && pContainer->getLength() )
+ {
+ pContainer->notifyEach( &XPropertyChangeListener::propertyChange, rEvent );
+ }
+
+ // Get "normal" listeners for all properties.
+ OInterfaceContainerHelper3<XPropertyChangeListener>* pNoNameContainer =
+ m_pPropertyChangeListeners->getContainer( OUString() );
+ if ( pNoNameContainer && pNoNameContainer->getLength() )
+ {
+ pNoNameContainer->notifyEach( &XPropertyChangeListener::propertyChange, rEvent );
+ }
+}
+
+
+void PersistentPropertySet::notifyPropertySetInfoChange(
+ const PropertySetInfoChangeEvent& evt ) const
+{
+ if ( !m_pPropSetChangeListeners )
+ return;
+
+ // Notify event listeners.
+ m_pPropSetChangeListeners->notifyEach( &XPropertySetInfoChangeListener::propertySetInfoChange, evt );
+}
+
+
+const OUString& PersistentPropertySet::getFullKey()
+{
+ if ( m_aFullKey.isEmpty() )
+ {
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+ if ( m_aFullKey.isEmpty() )
+ {
+ m_aFullKey = makeHierarchalNameSegment( m_aKey );
+ m_aFullKey += "/Values";
+ }
+ }
+
+ return m_aFullKey;
+}
+
+
+PropertySetRegistry& PersistentPropertySet::getPropertySetRegistry()
+{
+ return *m_pCreator;
+}
+
+
+// PropertySetInfo_Impl Implementation.
+
+
+PropertySetInfo_Impl::PropertySetInfo_Impl(
+ PersistentPropertySet* pOwner )
+: m_pOwner( pOwner )
+{
+}
+
+
+// XPropertySetInfo methods.
+
+
+// virtual
+Sequence< Property > SAL_CALL PropertySetInfo_Impl::getProperties()
+{
+ if ( !m_xProps )
+ {
+ Reference< XHierarchicalNameAccess > xRootHierNameAccess(
+ m_pOwner->getPropertySetRegistry().getRootConfigReadAccess(),
+ UNO_QUERY );
+ if ( xRootHierNameAccess.is() )
+ {
+ try
+ {
+ Reference< XNameAccess > xNameAccess;
+ xRootHierNameAccess->getByHierarchicalName(
+ m_pOwner->getFullKey() )
+ >>= xNameAccess;
+ if ( xNameAccess.is() )
+ {
+ // Obtain property names.
+
+ Sequence< OUString > aElems
+ = xNameAccess->getElementNames();
+
+ sal_uInt32 nCount = aElems.getLength();
+ Sequence< Property > aPropSeq( nCount );
+
+ if ( nCount )
+ {
+ Reference< XHierarchicalNameAccess > xHierNameAccess(
+ xNameAccess, UNO_QUERY );
+
+ OSL_ENSURE( xHierNameAccess.is(),
+ "PropertySetInfo_Impl::getProperties - "
+ "No hierarchical name access!" );
+
+ if ( xHierNameAccess.is() )
+ {
+ static const OUStringLiteral aHandleName(u"/Handle");
+ static const OUStringLiteral aValueName(u"/Value");
+ static const OUStringLiteral aAttrName(u"/Attributes");
+
+ Property* pProps = aPropSeq.getArray();
+
+ for ( sal_uInt32 n = 0; n < nCount; ++n )
+ {
+ Property& rProp = pProps[ n ];
+ OUString rName = aElems[ n ];
+ OUString aXMLName
+ = makeHierarchalNameSegment( rName );
+
+ // Set property name.
+
+ rProp.Name = rName;
+
+ try
+ {
+ // Obtain and set property handle
+ OUString aHierName = aXMLName + aHandleName;
+ Any aKeyValue
+ = xHierNameAccess->getByHierarchicalName(
+ aHierName );
+
+ if ( !( aKeyValue >>= rProp.Handle ) )
+ OSL_FAIL( "PropertySetInfo_Impl::getProperties - "
+ "Error getting property handle!" );
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PropertySetInfo_Impl::getProperties - "
+ "NoSuchElementException!" );
+ }
+
+ try
+ {
+ // Obtain and set property type
+ OUString aHierName = aXMLName + aValueName;
+ Any aKeyValue
+ = xHierNameAccess->getByHierarchicalName(
+ aHierName );
+
+ // Note: The type may be void if addProperty
+ // was called with a default value
+ // of type void.
+
+ rProp.Type = aKeyValue.getValueType();
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PropertySetInfo_Impl::getProperties - "
+ "NoSuchElementException!" );
+ }
+
+ try
+ {
+ // Obtain and set property attributes
+ OUString aHierName = aXMLName + aAttrName;
+ Any aKeyValue
+ = xHierNameAccess->getByHierarchicalName(
+ aHierName );
+
+ sal_Int32 nAttribs = 0;
+ if ( aKeyValue >>= nAttribs )
+ rProp.Attributes
+ = sal_Int16( nAttribs );
+ else
+ OSL_FAIL( "PropertySetInfo_Impl::getProperties - "
+ "Error getting property attributes!" );
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PropertySetInfo_Impl::getProperties - "
+ "NoSuchElementException!" );
+ }
+ }
+ }
+ }
+
+ // Success.
+ m_xProps = std::move(aPropSeq);
+ return *m_xProps;
+ }
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+ }
+ }
+
+ OSL_FAIL( "PropertySetInfo_Impl::getProperties - Error!" );
+ m_xProps.emplace();
+ }
+
+ return *m_xProps;
+}
+
+
+// virtual
+Property SAL_CALL PropertySetInfo_Impl::getPropertyByName(
+ const OUString& aName )
+{
+ Reference< XHierarchicalNameAccess > xRootHierNameAccess(
+ m_pOwner->getPropertySetRegistry().getRootConfigReadAccess(),
+ UNO_QUERY );
+ if ( xRootHierNameAccess.is() )
+ {
+ OUString aFullPropName( m_pOwner->getFullKey() + "/" );
+ aFullPropName += makeHierarchalNameSegment( aName );
+
+ // Does property exist?
+ if ( !xRootHierNameAccess->hasByHierarchicalName( aFullPropName ) )
+ throw UnknownPropertyException(aFullPropName);
+
+ try
+ {
+ Property aProp;
+
+ // Obtain handle.
+ OUString aKey = aFullPropName + "/Handle";
+
+ if ( !( xRootHierNameAccess->getByHierarchicalName( aKey )
+ >>= aProp.Handle ) )
+ {
+ OSL_FAIL( "PropertySetInfo_Impl::getPropertyByName - "
+ "No handle!" );
+ return Property();
+ }
+
+ // Obtain Value and extract type.
+ aKey = aFullPropName + "/Value";
+
+ Any aValue = xRootHierNameAccess->getByHierarchicalName( aKey );
+ if ( !aValue.hasValue() )
+ {
+ OSL_FAIL( "PropertySetInfo_Impl::getPropertyByName - "
+ "No Value!" );
+ return Property();
+ }
+
+ aProp.Type = aValue.getValueType();
+
+ // Obtain Attributes.
+ aKey = aFullPropName + "/Attributes";
+
+ sal_Int32 nAttribs = 0;
+ if ( xRootHierNameAccess->getByHierarchicalName( aKey )
+ >>= nAttribs )
+ aProp.Attributes = sal_Int16( nAttribs );
+ else
+ {
+ OSL_FAIL( "PropertySetInfo_Impl::getPropertyByName - "
+ "No attributes!" );
+ return Property();
+ }
+
+ // set name.
+ aProp.Name = aName;
+
+ // Success.
+ return aProp;
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PropertySetInfo_Impl::getPropertyByName - "
+ "caught NoSuchElementException!" );
+ }
+
+ }
+
+ OSL_FAIL( "PropertySetInfo_Impl::getPropertyByName - Error!" );
+ return Property();
+}
+
+
+// virtual
+sal_Bool SAL_CALL PropertySetInfo_Impl::hasPropertyByName(
+ const OUString& Name )
+{
+ Reference< XHierarchicalNameAccess > xRootHierNameAccess(
+ m_pOwner->getPropertySetRegistry().getRootConfigReadAccess(),
+ UNO_QUERY );
+ if ( xRootHierNameAccess.is() )
+ {
+ OUString aFullPropName( m_pOwner->getFullKey() + "/" );
+ aFullPropName += makeHierarchalNameSegment( Name );
+
+ return xRootHierNameAccess->hasByHierarchicalName( aFullPropName );
+ }
+
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */