/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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( std::u16string_view rIn ) { OUStringBuffer aBuffer( "['" ); size_t nCount = rIn.size(); for ( size_t n = 0; n < nCount; ++n ) { const sal_Unicode c = rIn[ n ]; switch ( c ) { case '&': aBuffer.append( "&" ); break; case '"': aBuffer.append( """ ); break; case '\'': aBuffer.append( "'" ); break; case '<': aBuffer.append( "<" ); break; case '>': aBuffer.append( ">" ); break; default: aBuffer.append( c ); break; } } aBuffer.append( "']" ); return aBuffer.makeStringAndClear(); } constexpr OUString STORE_CONTENTPROPERTIES_KEY = u"/org.openoffice.ucb.Store/ContentProperties"_ustr; // describe path of cfg entry constexpr OUString CFGPROPERTY_NODEPATH = u"nodepath"_ustr; class PropertySetInfo_Impl : public cppu::WeakImplHelper < XPropertySetInfo > { std::optional> 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 u"com.sun.star.comp.ucb.UcbStore"_ustr; } sal_Bool SAL_CALL UcbStore::supportsService( const OUString& ServiceName ) { return cppu::supportsService( this, ServiceName ); } css::uno::Sequence< OUString > SAL_CALL UcbStore::getSupportedServiceNames() { return { u"com.sun.star.ucb.Store"_ustr }; } // Service factory implementation. extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* ucb_UcbStore_get_implementation( css::uno::XComponentContext* context , css::uno::Sequence 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. 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 u"com.sun.star.comp.ucb.PropertySetRegistry"_ustr; } sal_Bool SAL_CALL PropertySetRegistry::supportsService( const OUString& ServiceName ) { return cppu::supportsService( this, ServiceName ); } css::uno::Sequence< OUString > SAL_CALL PropertySetRegistry::getSupportedServiceNames() { return { u"com.sun.star.ucb.PropertySetRegistry"_ustr }; } // XPropertySetRegistry methods. // virtual Reference< XPersistentPropertySet > SAL_CALL PropertySetRegistry::openPropertySet( const OUString& key, sal_Bool create ) { if ( key.isEmpty() ) return Reference< XPersistentPropertySet >(); std::unique_lock 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 ); // Create new instance. Reference< XNameAccess > xRootNameAccess( getRootConfigReadAccessImpl(aGuard), UNO_QUERY ); if ( !xRootNameAccess.is() ) { SAL_WARN( "ucb", "no root access" ); return Reference< XPersistentPropertySet >(); } // Propertyset in registry? if ( xRootNameAccess->hasByName( key ) ) { // Yep! return Reference< XPersistentPropertySet >( new PersistentPropertySet( aGuard, *this, key ) ); } else if ( create ) { // No. Create entry for propertyset. Reference< XSingleServiceFactory > xFac( getConfigWriteAccessImpl( aGuard, 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( aGuard, *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; std::unique_lock aGuard( m_aMutex ); Reference< XNameAccess > xRootNameAccess( getRootConfigReadAccessImpl(aGuard), UNO_QUERY ); if ( xRootNameAccess.is() ) { // Propertyset in registry? if ( !xRootNameAccess->hasByName( key ) ) return; Reference< XChangesBatch > xBatch( getConfigWriteAccessImpl( aGuard, 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::get(); } // virtual sal_Bool SAL_CALL PropertySetRegistry::hasElements() { 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 ) { 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() { 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 ) { Reference< XNameAccess > xNameAccess( getRootConfigReadAccess(), UNO_QUERY ); if ( xNameAccess.is() ) { return xNameAccess->hasByName( aName ); } return false; } void PropertySetRegistry::add( std::unique_lock& /*rCreatorGuard*/, PersistentPropertySet* pSet ) { OUString key( pSet->getKey() ); if ( !key.isEmpty() ) { m_aPropSets[ key ] = pSet; } } void PropertySetRegistry::remove( PersistentPropertySet* pSet ) { OUString key( pSet->getKey() ); if ( key.isEmpty() ) return; std::unique_lock 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 += "/"; 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 + makeHierarchalNameSegment( rPropName ); // ... handle OUString aNewKey1 = aKey + "/Handle"; Any aAny = xRootHierNameAccess->getByHierarchicalName( aNewKey1 ); xNewPropNameReplace->replaceByName( u"Handle"_ustr, aAny ); // ... value aNewKey1 = aKey + "/Value"; aAny = xRootHierNameAccess->getByHierarchicalName( aNewKey1 ); xNewPropNameReplace->replaceByName( u"Value"_ustr, aAny ); // ... state aNewKey1 = aKey + "/State"; aAny = xRootHierNameAccess->getByHierarchicalName( aNewKey1 ); xNewPropNameReplace->replaceByName( u"State"_ustr, aAny ); // ... attributes aNewKey1 = aKey + "/Attributes"; aAny = xRootHierNameAccess->getByHierarchicalName( aNewKey1 ); xNewPropNameReplace->replaceByName( u"Attributes"_ustr, 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!" ); } const Reference< XMultiServiceFactory > & PropertySetRegistry::getConfigProvider(std::unique_lock& /*rGuard*/) { 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() { std::unique_lock aGuard( m_aMutex ); return getRootConfigReadAccessImpl(aGuard); } Reference< XInterface > PropertySetRegistry::getRootConfigReadAccessImpl(std::unique_lock& rGuard) { try { if ( !m_xRootReadAccess.is() ) { if ( m_bTriedToGetRootReadAccess ) { OSL_FAIL( "PropertySetRegistry::getRootConfigReadAccess - " "Unable to read any config data! -> #82494#" ); return Reference< XInterface >(); } getConfigProvider(rGuard); if ( m_xConfigProvider.is() ) { Sequence aArguments(comphelper::InitAnyPropertySequence( { {CFGPROPERTY_NODEPATH, Any(STORE_CONTENTPROPERTIES_KEY)} })); m_bTriedToGetRootReadAccess = true; m_xRootReadAccess = m_xConfigProvider->createInstanceWithArguments( u"com.sun.star.configuration.ConfigurationAccess"_ustr, 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 ) { std::unique_lock aGuard( m_aMutex ); return getConfigWriteAccessImpl(aGuard, rPath); } Reference< XInterface > PropertySetRegistry::getConfigWriteAccessImpl(std::unique_lock& rGuard, const OUString& rPath ) { try { if ( !m_xRootWriteAccess.is() ) { if ( m_bTriedToGetRootWriteAccess ) { OSL_FAIL( "PropertySetRegistry::getConfigWriteAccess - " "Unable to write any config data! -> #82494#" ); return Reference< XInterface >(); } getConfigProvider(rGuard); if ( m_xConfigProvider.is() ) { Sequence aArguments(comphelper::InitAnyPropertySequence( { {CFGPROPERTY_NODEPATH, Any(STORE_CONTENTPROPERTIES_KEY)} })); m_bTriedToGetRootWriteAccess = true; m_xRootWriteAccess = m_xConfigProvider->createInstanceWithArguments( u"com.sun.star.configuration.ConfigurationUpdateAccess"_ustr, 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( std::unique_lock& rCreatorGuard, PropertySetRegistry& rCreator, OUString aKey ) : m_pCreator( &rCreator ), m_aKey(std::move( aKey )) { // register at creator. rCreator.add( rCreatorGuard, this ); } // virtual PersistentPropertySet::~PersistentPropertySet() { // deregister at creator. m_pCreator->remove( this ); } // XServiceInfo methods. OUString SAL_CALL PersistentPropertySet::getImplementationName() { return u"com.sun.star.comp.ucb.PersistentPropertySet"_ustr; } sal_Bool SAL_CALL PersistentPropertySet::supportsService( const OUString& ServiceName ) { return cppu::supportsService( this, ServiceName ); } css::uno::Sequence< OUString > SAL_CALL PersistentPropertySet::getSupportedServiceNames() { return { u"com.sun.star.ucb.PersistentPropertySet"_ustr }; } // XComponent methods. // virtual void SAL_CALL PersistentPropertySet::dispose() { std::unique_lock l(m_aMutex); if ( m_aDisposeEventListeners.getLength(l) ) { EventObject aEvt; aEvt.Source = static_cast< XComponent * >( this ); m_aDisposeEventListeners.disposeAndClear( l, aEvt ); } if ( m_aPropSetChangeListeners.getLength(l) ) { EventObject aEvt; aEvt.Source = static_cast< XPropertySetInfoChangeNotifier * >( this ); m_aPropSetChangeListeners.disposeAndClear( l, aEvt ); } if ( m_aPropertyChangeListeners.hasContainedTypes(l) ) { EventObject aEvt; aEvt.Source = static_cast< XPropertySet * >( this ); m_aPropertyChangeListeners.disposeAndClear( l, aEvt ); } } // virtual void SAL_CALL PersistentPropertySet::addEventListener( const Reference< XEventListener >& Listener ) { std::unique_lock l(m_aMutex); m_aDisposeEventListeners.addInterface( l, Listener ); } // virtual void SAL_CALL PersistentPropertySet::removeEventListener( const Reference< XEventListener >& Listener ) { std::unique_lock l(m_aMutex); m_aDisposeEventListeners.removeInterface( l, Listener ); // Note: Don't want to delete empty container here -> performance. } // XPropertySet methods. // virtual Reference< XPropertySetInfo > SAL_CALL PersistentPropertySet::getPropertySetInfo() { std::unique_lock l(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& rValue ) { std::unique_lock aCGuard(m_aMutex); Reference< XHierarchicalNameAccess > xRootHierNameAccess( m_pCreator->getRootConfigReadAccess(), UNO_QUERY ); if ( xRootHierNameAccess.is() ) { OUString aFullPropName( getFullKeyImpl(aCGuard) + "/" + 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() != rValue.getValueType() ) { throw IllegalArgumentException(); } // Write value xNameReplace->replaceByName( u"Value"_ustr, rValue ); // Write state ( Now it is a directly set value ) xNameReplace->replaceByName( u"State"_ustr, Any( sal_Int32( PropertyState_DIRECT_VALUE ) ) ); // Commit changes. xBatch->commitChanges(); PropertyChangeEvent aEvt; if ( m_aPropertyChangeListeners.hasContainedTypes(aCGuard) ) { // Obtain handle aValueName = aFullPropName + "/Handle"; sal_Int32 nHandle = -1; xRootHierNameAccess->getByHierarchicalName( aValueName ) >>= nHandle; aEvt.Source = getXWeak(); aEvt.PropertyName = aPropertyName; aEvt.PropertyHandle = nHandle; aEvt.Further = false; aEvt.OldValue = std::move(aOldValue); aEvt.NewValue = rValue; notifyPropertyChangeEvent( aCGuard, 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 ) { std::unique_lock aGuard(m_aMutex); Reference< XHierarchicalNameAccess > xNameAccess( m_pCreator->getRootConfigReadAccess(), UNO_QUERY ); if ( xNameAccess.is() ) { OUString aFullPropName( getFullKeyImpl(aGuard) + "/" + 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(); std::unique_lock aGuard(m_aMutex); m_aPropertyChangeListeners.addInterface(aGuard, aPropertyName, xListener ); } // virtual void SAL_CALL PersistentPropertySet::removePropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& aListener ) { // load(); std::unique_lock aGuard(m_aMutex); m_aPropertyChangeListeners.removeInterface(aGuard, 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(); std::unique_lock aGuard(m_aMutex); // Property already in set? OUString aFullValuesName; Reference< XHierarchicalNameAccess > xRootHierNameAccess( m_pCreator->getRootConfigReadAccess(), UNO_QUERY ); if ( xRootHierNameAccess.is() ) { aFullValuesName = getFullKeyImpl(aGuard); OUString aFullPropName = aFullValuesName + "/" + 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( u"Handle"_ustr, Any( sal_Int32( -1 ) ) ); // Set default value xNameReplace->replaceByName( u"Value"_ustr, DefaultValue ); // Set state ( always "default" ) xNameReplace->replaceByName( u"State"_ustr, Any( sal_Int32( PropertyState_DEFAULT_VALUE ) ) ); // Set attributes xNameReplace->replaceByName( u"Attributes"_ustr, 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_aPropSetChangeListeners.getLength(aGuard) ) { PropertySetInfoChangeEvent evt( getXWeak(), Name, -1, PropertySetInfoChange::PROPERTY_INSERTED ); notifyPropertySetInfoChange(aGuard, 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 ) { std::unique_lock aGuard(m_aMutex); Reference< XHierarchicalNameAccess > xRootHierNameAccess( m_pCreator->getRootConfigReadAccess(), UNO_QUERY ); if ( xRootHierNameAccess.is() ) { OUString aFullValuesName = getFullKeyImpl(aGuard); OUString aFullPropName = aFullValuesName + "/" + 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_aPropSetChangeListeners.getLength(aGuard) ) { // 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_aPropSetChangeListeners.getLength(aGuard) ) { PropertySetInfoChangeEvent evt( getXWeak(), Name, nHandle, PropertySetInfoChange::PROPERTY_REMOVED ); notifyPropertySetInfoChange( aGuard, 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 ) { std::unique_lock aGuard(m_aMutex); m_aPropSetChangeListeners.addInterface( aGuard, Listener ); } // virtual void SAL_CALL PersistentPropertySet::removePropertySetInfoChangeListener( const Reference< XPropertySetInfoChangeListener >& Listener ) { std::unique_lock aGuard(m_aMutex); m_aPropSetChangeListeners.removeInterface( aGuard, Listener ); } // XPropertyAccess methods. // virtual Sequence< PropertyValue > SAL_CALL PersistentPropertySet::getPropertyValues() { std::unique_lock aGuard(m_aMutex); Reference< XHierarchicalNameAccess > xRootHierNameAccess( m_pCreator->getRootConfigReadAccess(), UNO_QUERY ); if ( xRootHierNameAccess.is() ) { try { Reference< XNameAccess > xNameAccess; xRootHierNameAccess->getByHierarchicalName(getFullKeyImpl(aGuard)) >>= 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 constexpr OUStringLiteral aHandleName(u"/Handle"); static constexpr OUStringLiteral aValueName(u"/Value"); static constexpr OUStringLiteral aStateName(u"/State"); for ( sal_Int32 n = 0; n < nCount; ++n ) { PropertyValue& rValue = pValues[ n ]; const 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; std::unique_lock aCGuard(m_aMutex); Reference< XHierarchicalNameAccess > xRootHierNameAccess( m_pCreator->getRootConfigReadAccess(), UNO_QUERY ); if ( xRootHierNameAccess.is() ) { std::vector< PropertyChangeEvent > aEvents; OUString aFullPropNamePrefix( getFullKeyImpl(aCGuard) + "/" ); // Iterate over given property value sequence. for ( const PropertyValue& rNewValue : aProps ) { const OUString& rName = rNewValue.Name; OUString aFullPropName = aFullPropNamePrefix + 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( u"Handle"_ustr, Any( rNewValue.Handle ) ); // Save old value OUString aValueName = aFullPropName +"/Value"; Any aOldValue = xRootHierNameAccess->getByHierarchicalName( aValueName ); // Write value xNameReplace->replaceByName( u"Value"_ustr, rNewValue.Value ); // Write state ( Now it is a directly set value ) xNameReplace->replaceByName( u"State"_ustr, Any( sal_Int32( PropertyState_DIRECT_VALUE ) ) ); // Commit changes. xBatch->commitChanges(); if ( m_aPropertyChangeListeners.hasContainedTypes(aCGuard) ) { PropertyChangeEvent aEvt; aEvt.Source = getXWeak(); aEvt.PropertyName = rNewValue.Name; aEvt.PropertyHandle = rNewValue.Handle; aEvt.Further = false; aEvt.OldValue = std::move(aOldValue); aEvt.NewValue = rNewValue.Value; aEvents.push_back( aEvt ); } } catch (const IllegalArgumentException&) { // replaceByName } catch (const NoSuchElementException&) { // getByHierarchicalName, replaceByName } catch (const WrappedTargetException&) { // replaceByName, commitChanges } } } } if ( m_aPropertyChangeListeners.hasContainedTypes(aCGuard) ) { // Notify property changes. for (auto const& event : aEvents) { notifyPropertyChangeEvent( aCGuard, event ); } } return; } OSL_FAIL( "PersistentPropertySet::setPropertyValues - Nothing set!" ); } // Non-interface methods void PersistentPropertySet::notifyPropertyChangeEvent( std::unique_lock& rGuard, const PropertyChangeEvent& rEvent ) const { // Get "normal" listeners for the property. OInterfaceContainerHelper4* pContainer = m_aPropertyChangeListeners.getContainer( rGuard, rEvent.PropertyName ); if ( pContainer && pContainer->getLength(rGuard) ) { pContainer->notifyEach( rGuard, &XPropertyChangeListener::propertyChange, rEvent ); } // Get "normal" listeners for all properties. OInterfaceContainerHelper4* pNoNameContainer = m_aPropertyChangeListeners.getContainer( rGuard, OUString() ); if ( pNoNameContainer && pNoNameContainer->getLength(rGuard) ) { pNoNameContainer->notifyEach( rGuard, &XPropertyChangeListener::propertyChange, rEvent ); } } void PersistentPropertySet::notifyPropertySetInfoChange( std::unique_lock& rGuard, const PropertySetInfoChangeEvent& evt ) const { // Notify event listeners. m_aPropSetChangeListeners.notifyEach( rGuard, &XPropertySetInfoChangeListener::propertySetInfoChange, evt ); } OUString PersistentPropertySet::getFullKey() { std::unique_lock aGuard(m_aMutex); return getFullKeyImpl(aGuard); } const OUString& PersistentPropertySet::getFullKeyImpl(std::unique_lock& ) { 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 constexpr OUStringLiteral aHandleName(u"/Handle"); static constexpr OUStringLiteral aValueName(u"/Value"); static constexpr OUStringLiteral aAttrName(u"/Attributes"); Property* pProps = aPropSeq.getArray(); for ( sal_uInt32 n = 0; n < nCount; ++n ) { Property& rProp = pProps[ n ]; const 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() + "/" + 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() + "/" + makeHierarchalNameSegment( Name ) ); return xRootHierNameAccess->hasByHierarchicalName( aFullPropName ); } return false; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */