blob: c0fac33bd01956ab26b928d37a3de63db594a796 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_unotools.hxx"
#include "unotools/configitem.hxx"
#include "unotools/configmgr.hxx"
#include "unotools/configpathes.hxx"
#include <comphelper/processfactory.hxx>
#include <com/sun/star/beans/XMultiPropertySet.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/util/XChangesListener.hpp>
#include <com/sun/star/util/XChangesNotifier.hpp>
#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
#include <com/sun/star/container/XHierarchicalName.hpp>
#include <com/sun/star/configuration/XTemplateContainer.hpp>
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/awt/XRequestCallback.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/util/XStringEscape.hpp>
#include <com/sun/star/util/XChangesBatch.hpp>
#include <osl/diagnose.h>
#include <tools/solarmutex.hxx>
#include <rtl/ustrbuf.hxx>
using namespace utl;
using rtl::OUString;
using rtl::OString;
using namespace com::sun::star::uno;
using namespace com::sun::star::util;
using namespace com::sun::star::lang;
using namespace com::sun::star::beans;
using namespace com::sun::star::container;
using namespace com::sun::star::configuration;
#define C2U(cChar) OUString::createFromAscii(cChar)
#include <cppuhelper/implbase1.hxx> // helper for implementations
#ifdef DBG_UTIL
inline void lcl_CFG_DBG_EXCEPTION(const sal_Char* cText, const Exception& rEx)
{
OString sMsg(cText);
sMsg += OString(rEx.Message.getStr(), rEx.Message.getLength(), RTL_TEXTENCODING_ASCII_US);
OSL_ENSURE(sal_False, sMsg.getStr());
}
#define CATCH_INFO(a) \
catch(Exception& rEx) \
{ \
lcl_CFG_DBG_EXCEPTION(a, rEx);\
}
#else
#define lcl_CFG_DBG_EXCEPTION( a, b)
#define CATCH_INFO(a) catch(Exception& ){}
#endif
/*
The ConfigChangeListener_Impl receives notifications from the configuration about changes that
have happened. It forwards this notification to the ConfigItem it knows a pParent by calling its
"CallNotify" method. As ConfigItems are most probably not thread safe, the SolarMutex is acquired
before doing so.
*/
namespace utl{
class ConfigChangeListener_Impl : public cppu::WeakImplHelper1
<
com::sun::star::util::XChangesListener
>
{
public:
ConfigItem* pParent;
const Sequence< OUString > aPropertyNames;
ConfigChangeListener_Impl(ConfigItem& rItem, const Sequence< OUString >& rNames);
~ConfigChangeListener_Impl();
//XChangesListener
virtual void SAL_CALL changesOccurred( const ChangesEvent& Event ) throw(RuntimeException);
//XEventListener
virtual void SAL_CALL disposing( const EventObject& Source ) throw(RuntimeException);
};
/* -----------------------------12.02.01 11:38--------------------------------
---------------------------------------------------------------------------*/
struct ConfigItem_Impl
{
utl::ConfigManager* pManager;
sal_Int16 nMode;
sal_Bool bIsModified;
sal_Bool bEnableInternalNotification;
sal_Int16 nInValueChange;
ConfigItem_Impl() :
pManager(0),
nMode(0),
bIsModified(sal_False),
bEnableInternalNotification(sal_False),
nInValueChange(0)
{}
};
}
/* -----------------------------04.12.00 10:25--------------------------------
---------------------------------------------------------------------------*/
class ValueCounter_Impl
{
sal_Int16& rCnt;
public:
ValueCounter_Impl(sal_Int16& rCounter):
rCnt(rCounter)
{rCnt++;}
~ValueCounter_Impl()
{
OSL_ENSURE(rCnt>0, "RefCount < 0 ??");
rCnt--;
}
};
/* -----------------------------03.12.02 -------------------------------------
---------------------------------------------------------------------------*/
namespace
{
// helper to achieve exception - safe handling of an Item under construction
template <class TYP>
class AutoDeleter // : Noncopyable
{
TYP* m_pItem;
public:
AutoDeleter(TYP * pItem)
: m_pItem(pItem)
{
}
~AutoDeleter()
{
delete m_pItem;
}
void keep() { m_pItem = 0; }
};
}
/* -----------------------------29.08.00 16:34--------------------------------
---------------------------------------------------------------------------*/
ConfigChangeListener_Impl::ConfigChangeListener_Impl(
ConfigItem& rItem, const Sequence< OUString >& rNames) :
pParent(&rItem),
aPropertyNames(rNames)
{
}
/* -----------------------------29.08.00 16:34--------------------------------
---------------------------------------------------------------------------*/
ConfigChangeListener_Impl::~ConfigChangeListener_Impl()
{
}
/* -----------------------------29.08.00 16:34--------------------------------
---------------------------------------------------------------------------*/
sal_Bool lcl_Find(
const rtl::OUString& rTemp,
const OUString* pCheckPropertyNames,
sal_Int32 nLength)
{
//return true if the path is completely correct or if it is longer
//i.e ...Print/Content/Graphic and .../Print
for(sal_Int32 nIndex = 0; nIndex < nLength; nIndex++)
if( isPrefixOfConfigurationPath(rTemp, pCheckPropertyNames[nIndex]) )
return sal_True;
return sal_False;
}
//-----------------------------------------------------------------------------
void ConfigChangeListener_Impl::changesOccurred( const ChangesEvent& rEvent ) throw(RuntimeException)
{
const ElementChange* pElementChanges = rEvent.Changes.getConstArray();
Sequence<OUString> aChangedNames(rEvent.Changes.getLength());
OUString* pNames = aChangedNames.getArray();
const OUString* pCheckPropertyNames = aPropertyNames.getConstArray();
sal_Int32 nNotify = 0;
for(int i = 0; i < aChangedNames.getLength(); i++)
{
OUString sTemp;
pElementChanges[i].Accessor >>= sTemp;
if(lcl_Find(sTemp, pCheckPropertyNames, aPropertyNames.getLength()))
pNames[nNotify++] = sTemp;
}
if( nNotify )
{
if ( ::tools::SolarMutex::Acquire() )
{
aChangedNames.realloc(nNotify);
pParent->CallNotify(aChangedNames);
::tools::SolarMutex::Release();
}
}
}
/* -----------------------------29.08.00 16:34--------------------------------
---------------------------------------------------------------------------*/
void ConfigChangeListener_Impl::disposing( const EventObject& /*rSource*/ ) throw(RuntimeException)
{
pParent->RemoveChangesListener();
}
/* -----------------------------29.08.00 12:50--------------------------------
---------------------------------------------------------------------------*/
ConfigItem::ConfigItem(const OUString rSubTree, sal_Int16 nSetMode ) :
sSubTree(rSubTree),
pImpl(new ConfigItem_Impl)
{
AutoDeleter<ConfigItem_Impl> aNewImpl(pImpl);
pImpl->pManager = ConfigManager::GetConfigManager();
pImpl->nMode = nSetMode;
if(0 != (nSetMode&CONFIG_MODE_RELEASE_TREE))
pImpl->pManager->AddConfigItem(*this);
else
m_xHierarchyAccess = pImpl->pManager->AddConfigItem(*this);
// no more exceptions after c'tor has finished
aNewImpl.keep();
pImpl->nMode &= ~CONFIG_MODE_PROPAGATE_ERRORS;
}
/* -----------------------------17.11.00 13:53--------------------------------
---------------------------------------------------------------------------*/
ConfigItem::ConfigItem(utl::ConfigManager& rManager, const rtl::OUString rSubTree) :
sSubTree(rSubTree),
pImpl(new ConfigItem_Impl)
{
pImpl->pManager = &rManager;
pImpl->nMode = CONFIG_MODE_IMMEDIATE_UPDATE; // does not allow exceptions
m_xHierarchyAccess = pImpl->pManager->AddConfigItem(*this);
}
//---------------------------------------------------------------------
//--- 02.08.2002 16:33:23 -----------------------------------------------
sal_Bool ConfigItem::IsValidConfigMgr() const
{
return ( pImpl->pManager && pImpl->pManager->GetConfigurationProvider().is() );
}
/* -----------------------------29.08.00 12:52--------------------------------
---------------------------------------------------------------------------*/
ConfigItem::~ConfigItem()
{
if(pImpl->pManager)
{
RemoveChangesListener();
pImpl->pManager->RemoveConfigItem(*this);
}
delete pImpl;
}
/* -----------------------------29.08.00 12:52--------------------------------
---------------------------------------------------------------------------*/
void ConfigItem::ReleaseConfigMgr()
{
Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
if(xHierarchyAccess.is())
{
try
{
Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
xBatch->commitChanges();
}
CATCH_INFO("Exception from commitChanges(): ")
}
RemoveChangesListener();
OSL_ENSURE(pImpl->pManager, "ConfigManager already released");
pImpl->pManager = 0;
}
/* -----------------------------29.08.00 12:52--------------------------------
---------------------------------------------------------------------------*/
void ConfigItem::CallNotify( const com::sun::star::uno::Sequence<OUString>& rPropertyNames )
{
// the call is forwarded to the virtual Notify() method
// it is pure virtual, so all classes deriving from ConfigItem have to decide how they
// want to notify listeners
if(!IsInValueChange() || pImpl->bEnableInternalNotification)
Notify(rPropertyNames);
}
/* -----------------------------12.12.00 17:09--------------------------------
---------------------------------------------------------------------------*/
sal_Bool lcl_IsLocalProperty(const OUString& rSubTree, const OUString& rProperty)
{
static const sal_Char* aLocalProperties[] =
{
"Office.Common/Path/Current/Storage",
"Office.Common/Path/Current/Temp"
};
static const int aLocalPropLen[] =
{
34,
31
};
OUString sProperty(rSubTree);
sProperty += C2U("/");
sProperty += rProperty;
if(sProperty.equalsAsciiL( aLocalProperties[0], aLocalPropLen[0]) ||
sProperty.equalsAsciiL( aLocalProperties[1], aLocalPropLen[1]))
return sal_True;
return sal_False;
}
/* -----------------------------10.04.01 15:00--------------------------------
---------------------------------------------------------------------------*/
void ConfigItem::impl_packLocalizedProperties( const Sequence< OUString >& lInNames ,
const Sequence< Any >& lInValues ,
Sequence< Any >& lOutValues )
{
// Safe impossible cases.
// This method should be called for special ConfigItem-mode only!
OSL_ENSURE( ((pImpl->nMode & CONFIG_MODE_ALL_LOCALES ) == CONFIG_MODE_ALL_LOCALES), "ConfigItem::impl_packLocalizedProperties()\nWrong call of this method detected!\n" );
sal_Int32 nSourceCounter ; // used to step during input lists
sal_Int32 nSourceSize ; // marks end of loop over input lists
sal_Int32 nDestinationCounter ; // actual position in output lists
sal_Int32 nPropertyCounter ; // counter of inner loop for Sequence< PropertyValue >
sal_Int32 nPropertiesSize ; // marks end of inner loop
Sequence< OUString > lPropertyNames ; // list of all locales for localized entry
Sequence< PropertyValue > lProperties ; // localized values of an configuration entry packed for return
Reference< XInterface > xLocalizedNode ; // if cfg entry is localized ... lInValues contains an XInterface!
// Optimise follow algorithm ... A LITTLE BIT :-)
// There exist two different possibilities:
// i ) There exist no localized entries ... => size of lOutValues will be the same like lInNames/lInValues!
// ii) There exist some (mostly one or two) localized entries ... => size of lOutValues will be the same like lInNames/lInValues!
// ... Why? If a localized value exist - the any is filled with an XInterface object (is a SetNode-service).
// We read all his child nodes and pack it into Sequence< PropertyValue >.
// The result list we pack into the return any. We never change size of lists!
nSourceSize = lInNames.getLength();
lOutValues.realloc( nSourceSize );
// Algorithm:
// Copy all names and values from in to out lists.
// Look for special localized entries ... You can detect it as "XInterface" packed into an Any.
// Use this XInterface-object to read all localized values and pack it into Sequence< PropertValue >.
// Add this list to out lists then.
nDestinationCounter = 0;
for( nSourceCounter=0; nSourceCounter<nSourceSize; ++nSourceCounter )
{
// If item a special localized one ... convert and pack it ...
if( lInValues[nSourceCounter].getValueTypeName() == C2U("com.sun.star.uno.XInterface") )
{
lInValues[nSourceCounter] >>= xLocalizedNode;
Reference< XNameContainer > xSetAccess( xLocalizedNode, UNO_QUERY );
if( xSetAccess.is() == sal_True )
{
lPropertyNames = xSetAccess->getElementNames() ;
nPropertiesSize = lPropertyNames.getLength() ;
lProperties.realloc( nPropertiesSize ) ;
for( nPropertyCounter=0; nPropertyCounter<nPropertiesSize; ++nPropertyCounter )
{
#if OSL_DEBUG_LEVEL > 1
// Sometimes it's better to see what's going on :-)
OUString sPropName = lInNames[nSourceCounter];
OUString sLocaleName = lPropertyNames[nPropertyCounter];
#endif
lProperties[nPropertyCounter].Name = lPropertyNames[nPropertyCounter] ;
OUString sLocaleValue;
xSetAccess->getByName( lPropertyNames[nPropertyCounter] ) >>= sLocaleValue ;
lProperties[nPropertyCounter].Value <<= sLocaleValue;
}
lOutValues[nDestinationCounter] <<= lProperties;
}
}
// ... or copy normal items to return lists directly.
else
{
lOutValues[nDestinationCounter] = lInValues[nSourceCounter];
}
++nDestinationCounter;
}
}
/* -----------------------------10.04.01 15:00--------------------------------
---------------------------------------------------------------------------*/
void ConfigItem::impl_unpackLocalizedProperties( const Sequence< OUString >& lInNames ,
const Sequence< Any >& lInValues ,
Sequence< OUString >& lOutNames ,
Sequence< Any >& lOutValues )
{
// Safe impossible cases.
// This method should be called for special ConfigItem-mode only!
OSL_ENSURE( ((pImpl->nMode & CONFIG_MODE_ALL_LOCALES ) == CONFIG_MODE_ALL_LOCALES), "ConfigItem::impl_unpackLocalizedProperties()\nWrong call of this method detected!\n" );
sal_Int32 nSourceCounter ; // used to step during input lists
sal_Int32 nSourceSize ; // marks end of loop over input lists
sal_Int32 nDestinationCounter ; // actual position in output lists
sal_Int32 nPropertyCounter ; // counter of inner loop for Sequence< PropertyValue >
sal_Int32 nPropertiesSize ; // marks end of inner loop
OUString sNodeName ; // base name of node ( e.g. "UIName/" ) ... expand to locale ( e.g. "UIName/de" )
Sequence< PropertyValue > lProperties ; // localized values of an configuration entry getted from lInValues-Any
// Optimise follow algorithm ... A LITTLE BIT :-)
// There exist two different possibilities:
// i ) There exist no localized entries ... => size of lOutNames/lOutValues will be the same like lInNames/lInValues!
// ii) There exist some (mostly one or two) localized entries ... => size of lOutNames/lOutValues will be some bytes greater then lInNames/lInValues.
// => I think we should make it fast for i). ii) is a special case and mustn't be SOOOO... fast.
// We should reserve same space for output list like input ones first.
// Follow algorithm looks for these borders and change it for ii) only!
// It will be faster then a "realloc()" call in every loop ...
nSourceSize = lInNames.getLength();
lOutNames.realloc ( nSourceSize );
lOutValues.realloc ( nSourceSize );
// Algorithm:
// Copy all names and values from const to return lists.
// Look for special localized entries ... You can detect it as Sequence< PropertyValue > packed into an Any.
// Split it ... insert PropertyValue.Name to lOutNames and PropertyValue.Value to lOutValues.
nDestinationCounter = 0;
for( nSourceCounter=0; nSourceCounter<nSourceSize; ++nSourceCounter )
{
// If item a special localized one ... split it and insert his parts to output lists ...
if( lInValues[nSourceCounter].getValueType() == ::getCppuType( (const Sequence< PropertyValue >*)NULL ) )
{
lInValues[nSourceCounter] >>= lProperties ;
sNodeName = lInNames[nSourceCounter] ;
sNodeName += C2U("/") ;
nPropertiesSize = lProperties.getLength() ;
if( (nDestinationCounter+nPropertiesSize) > lOutNames.getLength() )
{
lOutNames.realloc ( nDestinationCounter+nPropertiesSize );
lOutValues.realloc ( nDestinationCounter+nPropertiesSize );
}
for( nPropertyCounter=0; nPropertyCounter<nPropertiesSize; ++nPropertyCounter )
{
lOutNames [nDestinationCounter] = sNodeName + lProperties[nPropertyCounter].Name ;
lOutValues[nDestinationCounter] = lProperties[nPropertyCounter].Value ;
++nDestinationCounter;
}
}
// ... or copy normal items to return lists directly.
else
{
if( (nDestinationCounter+1) > lOutNames.getLength() )
{
lOutNames.realloc ( nDestinationCounter+1 );
lOutValues.realloc ( nDestinationCounter+1 );
}
lOutNames [nDestinationCounter] = lInNames [nSourceCounter];
lOutValues[nDestinationCounter] = lInValues[nSourceCounter];
++nDestinationCounter;
}
}
}
/* -----------------------------03.02.2003 14:44------------------------------
---------------------------------------------------------------------------*/
Sequence< sal_Bool > ConfigItem::GetReadOnlyStates(const com::sun::star::uno::Sequence< rtl::OUString >& rNames)
{
sal_Int32 i;
// size of return list is fix!
// Every item must match to length of incoming name list.
sal_Int32 nCount = rNames.getLength();
Sequence< sal_Bool > lStates(nCount);
// We must be shure to return a valid information everytime!
// Set default to non readonly ... similar to the configuration handling of this property.
for ( i=0; i<nCount; ++i)
lStates[i] = sal_False;
// no access - no informations ...
Reference< XHierarchicalNameAccess > xHierarchyAccess = GetTree();
if (!xHierarchyAccess.is())
return lStates;
for (i=0; i<nCount; ++i)
{
try
{
if(pImpl->pManager->IsLocalConfigProvider() && lcl_IsLocalProperty(sSubTree, rNames[i]))
{
OSL_ENSURE(sal_False, "ConfigItem::IsReadonly()\nlocal mode seams to be used!?\n");
continue;
}
OUString sName = rNames[i];
OUString sPath;
OUString sProperty;
::utl::splitLastFromConfigurationPath(sName,sPath,sProperty);
if (!sPath.getLength() && !sProperty.getLength())
{
OSL_ENSURE(sal_False, "ConfigItem::IsReadonly()\nsplitt failed\n");
continue;
}
Reference< XInterface > xNode;
Reference< XPropertySet > xSet ;
Reference< XPropertySetInfo > xInfo;
if (sPath.getLength())
{
Any aNode = xHierarchyAccess->getByHierarchicalName(sPath);
if (!(aNode >>= xNode) || !xNode.is())
{
OSL_ENSURE(sal_False, "ConfigItem::IsReadonly()\nno set available\n");
continue;
}
}
else
{
xNode = Reference< XInterface >(xHierarchyAccess, UNO_QUERY);
}
xSet = Reference< XPropertySet >(xNode, UNO_QUERY);
if (xSet.is())
{
xInfo = xSet->getPropertySetInfo();
OSL_ENSURE(xInfo.is(), "ConfigItem::IsReadonly()\ngetPropertySetInfo failed ...\n");
}
else
{
xInfo = Reference< XPropertySetInfo >(xNode, UNO_QUERY);
OSL_ENSURE(xInfo.is(), "ConfigItem::IsReadonly()\nUNO_QUERY failed ...\n");
}
if (!xInfo.is())
{
OSL_ENSURE(sal_False, "ConfigItem::IsReadonly()\nno prop info available\n");
continue;
}
Property aProp = xInfo->getPropertyByName(sProperty);
lStates[i] = ((aProp.Attributes & PropertyAttribute::READONLY) == PropertyAttribute::READONLY);
}
catch(Exception&){}
}
return lStates;
}
/* -----------------------------29.08.00 15:10--------------------------------
---------------------------------------------------------------------------*/
Sequence< Any > ConfigItem::GetProperties(const Sequence< OUString >& rNames)
{
Sequence< Any > aRet(rNames.getLength());
const OUString* pNames = rNames.getConstArray();
Any* pRet = aRet.getArray();
Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
if(xHierarchyAccess.is())
{
for(int i = 0; i < rNames.getLength(); i++)
{
try
{
if(pImpl->pManager->IsLocalConfigProvider() && lcl_IsLocalProperty(sSubTree, pNames[i]))
{
OUString sProperty(sSubTree);
sProperty += C2U("/");
sProperty += pNames[i];
pRet[i] = pImpl->pManager->GetLocalProperty(sProperty);
}
else
pRet[i] = xHierarchyAccess->getByHierarchicalName(pNames[i]);
}
catch(Exception& rEx)
{
#if OSL_DEBUG_LEVEL > 0
OString sMsg("XHierarchicalNameAccess: ");
sMsg += OString(rEx.Message.getStr(),
rEx.Message.getLength(),
RTL_TEXTENCODING_ASCII_US);
sMsg += OString("\n");
sMsg += OString(ConfigManager::GetConfigBaseURL().getStr(),
ConfigManager::GetConfigBaseURL().getLength(),
RTL_TEXTENCODING_ASCII_US);
sMsg += OString(sSubTree.getStr(),
sSubTree.getLength(),
RTL_TEXTENCODING_ASCII_US);
sMsg += OString("/");
sMsg += OString(pNames[i].getStr(),
pNames[i].getLength(),
RTL_TEXTENCODING_ASCII_US);
OSL_ENSURE(sal_False, sMsg.getStr());
#else
(void) rEx; // avoid warning
#endif
}
}
// In special mode "ALL_LOCALES" we must convert localized values to Sequence< PropertyValue >.
if((pImpl->nMode & CONFIG_MODE_ALL_LOCALES ) == CONFIG_MODE_ALL_LOCALES)
{
Sequence< Any > lValues;
impl_packLocalizedProperties( rNames, aRet, lValues );
aRet = lValues;
}
}
return aRet;
}
/* -----------------------------29.08.00 17:28--------------------------------
---------------------------------------------------------------------------*/
sal_Bool ConfigItem::PutProperties( const Sequence< OUString >& rNames,
const Sequence< Any>& rValues)
{
ValueCounter_Impl aCounter(pImpl->nInValueChange);
Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
Reference<XNameReplace> xTopNodeReplace(xHierarchyAccess, UNO_QUERY);
sal_Bool bRet = xHierarchyAccess.is() && xTopNodeReplace.is();
if(bRet)
{
Sequence< OUString > lNames ;
Sequence< Any > lValues ;
const OUString* pNames = NULL ;
const Any* pValues = NULL ;
sal_Int32 nNameCount ;
if(( pImpl->nMode & CONFIG_MODE_ALL_LOCALES ) == CONFIG_MODE_ALL_LOCALES )
{
// If ConfigItem works in "ALL_LOCALES"-mode ... we must support a Sequence< PropertyValue >
// as value of an localized configuration entry!
// How we can do that?
// We must split all PropertyValues to "Sequence< OUString >" AND "Sequence< Any >"!
impl_unpackLocalizedProperties( rNames, rValues, lNames, lValues );
pNames = lNames.getConstArray ();
pValues = lValues.getConstArray ();
nNameCount = lNames.getLength ();
}
else
{
// This is the normal mode ...
// Use given input lists directly.
pNames = rNames.getConstArray ();
pValues = rValues.getConstArray ();
nNameCount = rNames.getLength ();
}
for(int i = 0; i < nNameCount; i++)
{
if(pImpl->pManager->IsLocalConfigProvider() && lcl_IsLocalProperty(sSubTree, pNames[i]))
{
OUString sProperty(sSubTree);
sProperty += C2U("/");
sProperty += pNames[i];
pImpl->pManager->PutLocalProperty(sProperty, pValues[i]);
}
else
{
try
{
OUString sNode, sProperty;
if (splitLastFromConfigurationPath(pNames[i],sNode, sProperty))
{
Any aNode = xHierarchyAccess->getByHierarchicalName(sNode);
Reference<XNameAccess> xNodeAcc;
aNode >>= xNodeAcc;
Reference<XNameReplace> xNodeReplace(xNodeAcc, UNO_QUERY);
Reference<XNameContainer> xNodeCont (xNodeAcc, UNO_QUERY);
sal_Bool bExist = (xNodeAcc.is() && xNodeAcc->hasByName(sProperty));
if (bExist && xNodeReplace.is())
xNodeReplace->replaceByName(sProperty, pValues[i]);
else
if (!bExist && xNodeCont.is())
xNodeCont->insertByName(sProperty, pValues[i]);
else
bRet = sal_False;
}
else //direct value
{
xTopNodeReplace->replaceByName(sProperty, pValues[i]);
}
}
CATCH_INFO("Exception from PutProperties: ");
}
}
try
{
Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
xBatch->commitChanges();
}
CATCH_INFO("Exception from commitChanges(): ")
}
return bRet;
}
/* -----------------------------08.12.05 15:27--------------------------------
---------------------------------------------------------------------------*/
void ConfigItem::DisableNotification()
{
OSL_ENSURE( xChangeLstnr.is(), "ConfigItem::DisableNotification: notifications not enabled currently!" );
RemoveChangesListener();
}
/* -----------------------------29.08.00 16:19--------------------------------
---------------------------------------------------------------------------*/
sal_Bool ConfigItem::EnableNotification(const Sequence< OUString >& rNames,
sal_Bool bEnableInternalNotification )
{
OSL_ENSURE(0 == (pImpl->nMode&CONFIG_MODE_RELEASE_TREE), "notification in CONFIG_MODE_RELEASE_TREE mode not possible");
pImpl->bEnableInternalNotification = bEnableInternalNotification;
Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
Reference<XChangesNotifier> xChgNot(xHierarchyAccess, UNO_QUERY);
if(!xChgNot.is())
return sal_False;
OSL_ENSURE(!xChangeLstnr.is(), "EnableNotification already called");
if(xChangeLstnr.is())
xChgNot->removeChangesListener( xChangeLstnr );
sal_Bool bRet = sal_True;
try
{
xChangeLstnr = new ConfigChangeListener_Impl(*this, rNames);
xChgNot->addChangesListener( xChangeLstnr );
}
catch(RuntimeException& )
{
bRet = sal_False;
}
return bRet;
}
/* -----------------------------29.08.00 16:47--------------------------------
---------------------------------------------------------------------------*/
void ConfigItem::RemoveChangesListener()
{
Reference<XChangesNotifier> xChgNot(m_xHierarchyAccess, UNO_QUERY);
if(xChgNot.is() && xChangeLstnr.is())
{
try
{
xChgNot->removeChangesListener( xChangeLstnr );
xChangeLstnr = 0;
}
catch(Exception & )
{
}
}
}
/* -----------------------------10.07.00 --------------------------------
---------------------------------------------------------------------------*/
void lcl_normalizeLocalNames(Sequence< OUString >& _rNames, ConfigNameFormat _eFormat, Reference<XInterface> const& _xParentNode)
{
switch (_eFormat)
{
case CONFIG_NAME_LOCAL_NAME:
// unaltered - this is our input format
break;
case CONFIG_NAME_FULL_PATH:
{
Reference<XHierarchicalName> xFormatter(_xParentNode, UNO_QUERY);
if (xFormatter.is())
{
OUString * pNames = _rNames.getArray();
for(int i = 0; i<_rNames.getLength(); ++i)
try
{
pNames[i] = xFormatter->composeHierarchicalName(pNames[i]);
}
CATCH_INFO("Exception from composeHierarchicalName(): ")
break;
}
}
OSL_ENSURE(false, "Cannot create absolute pathes: missing interface");
// make local pathes instaed
case CONFIG_NAME_LOCAL_PATH:
{
Reference<XTemplateContainer> xTypeContainer(_xParentNode, UNO_QUERY);
if (xTypeContainer.is())
{
OUString sTypeName = xTypeContainer->getElementTemplateName();
sTypeName = sTypeName.copy(sTypeName.lastIndexOf('/')+1);
OUString * pNames = _rNames.getArray();
for(int i = 0; i<_rNames.getLength(); ++i)
{
pNames[i] = wrapConfigurationElementName(pNames[i],sTypeName);
}
}
else
{
static const OUString sSetService(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.configuration.SetAccess"));
Reference<XServiceInfo> xSVI(_xParentNode, UNO_QUERY);
if (xSVI.is() && xSVI->supportsService(sSetService))
{
OUString * pNames = _rNames.getArray();
for(int i = 0; i<_rNames.getLength(); ++i)
{
pNames[i] = wrapConfigurationElementName(pNames[i]);
}
}
}
}
break;
case CONFIG_NAME_PLAINTEXT_NAME:
{
Reference<XStringEscape> xEscaper(_xParentNode, UNO_QUERY);
if (xEscaper.is())
{
OUString * pNames = _rNames.getArray();
for(int i = 0; i<_rNames.getLength(); ++i)
try
{
pNames[i] = xEscaper->unescapeString(pNames[i]);
}
CATCH_INFO("Exception from unescapeString(): ")
}
}
break;
}
}
/* -----------------------------10.07.00 --------------------------------
---------------------------------------------------------------------------*/
Sequence< OUString > ConfigItem::GetNodeNames(const OUString& rNode)
{
ConfigNameFormat const eDefaultFormat = CONFIG_NAME_LOCAL_NAME; // CONFIG_NAME_DEFAULT;
return GetNodeNames(rNode, eDefaultFormat);
}
/* -----------------------------15.09.00 12:06--------------------------------
---------------------------------------------------------------------------*/
Sequence< OUString > ConfigItem::GetNodeNames(const OUString& rNode, ConfigNameFormat eFormat)
{
Sequence< OUString > aRet;
Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
if(xHierarchyAccess.is())
{
try
{
Reference<XNameAccess> xCont;
if(rNode.getLength())
{
Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
aNode >>= xCont;
}
else
xCont = Reference<XNameAccess> (xHierarchyAccess, UNO_QUERY);
if(xCont.is())
{
aRet = xCont->getElementNames();
lcl_normalizeLocalNames(aRet,eFormat,xCont);
}
}
CATCH_INFO("Exception from GetNodeNames: ");
}
return aRet;
}
/* -----------------------------15.09.00 15:52--------------------------------
---------------------------------------------------------------------------*/
sal_Bool ConfigItem::ClearNodeSet(const OUString& rNode)
{
ValueCounter_Impl aCounter(pImpl->nInValueChange);
sal_Bool bRet = sal_False;
Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
if(xHierarchyAccess.is())
{
try
{
Reference<XNameContainer> xCont;
if(rNode.getLength())
{
Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
aNode >>= xCont;
}
else
xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
if(!xCont.is())
return sal_False;
Sequence< OUString > aNames = xCont->getElementNames();
const OUString* pNames = aNames.getConstArray();
Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
for(sal_Int32 i = 0; i < aNames.getLength(); i++)
{
try
{
xCont->removeByName(pNames[i]);
}
CATCH_INFO("Exception from removeByName(): ")
}
xBatch->commitChanges();
bRet = sal_True;
}
CATCH_INFO("Exception from ClearNodeSet")
}
return bRet;
}
/* -----------------------------24.11.00 10:58--------------------------------
---------------------------------------------------------------------------*/
sal_Bool ConfigItem::ClearNodeElements(const OUString& rNode, Sequence< OUString >& rElements)
{
ValueCounter_Impl aCounter(pImpl->nInValueChange);
sal_Bool bRet = sal_False;
Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
if(xHierarchyAccess.is())
{
const OUString* pElements = rElements.getConstArray();
try
{
Reference<XNameContainer> xCont;
if(rNode.getLength())
{
Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
aNode >>= xCont;
}
else
xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
if(!xCont.is())
return sal_False;
try
{
for(sal_Int32 nElement = 0; nElement < rElements.getLength(); nElement++)
{
xCont->removeByName(pElements[nElement]);
}
Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
xBatch->commitChanges();
}
CATCH_INFO("Exception from commitChanges(): ")
bRet = sal_True;
}
CATCH_INFO("Exception from GetNodeNames: ")
}
return bRet;
}
//----------------------------------------------------------------------------
static inline
OUString lcl_extractSetPropertyName( const OUString& rInPath, const OUString& rPrefix )
{
OUString const sSubPath = dropPrefixFromConfigurationPath( rInPath, rPrefix);
return extractFirstFromConfigurationPath( sSubPath );
}
//----------------------------------------------------------------------------
static
Sequence< OUString > lcl_extractSetPropertyNames( const Sequence< PropertyValue >& rValues, const OUString& rPrefix )
{
const PropertyValue* pProperties = rValues.getConstArray();
Sequence< OUString > aSubNodeNames(rValues.getLength());
OUString* pSubNodeNames = aSubNodeNames.getArray();
OUString sLastSubNode;
sal_Int32 nSubIndex = 0;
for(sal_Int32 i = 0; i < rValues.getLength(); i++)
{
OUString const sSubPath = dropPrefixFromConfigurationPath( pProperties[i].Name, rPrefix);
OUString const sSubNode = extractFirstFromConfigurationPath( sSubPath );
if(sLastSubNode != sSubNode)
{
pSubNodeNames[nSubIndex++] = sSubNode;
}
sLastSubNode = sSubNode;
}
aSubNodeNames.realloc(nSubIndex);
return aSubNodeNames;
}
/* -----------------------------15.09.00 15:52--------------------------------
add or change properties
---------------------------------------------------------------------------*/
sal_Bool ConfigItem::SetSetProperties(
const OUString& rNode, Sequence< PropertyValue > rValues)
{
ValueCounter_Impl aCounter(pImpl->nInValueChange);
sal_Bool bRet = sal_True;
Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
if(xHierarchyAccess.is())
{
Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
try
{
Reference<XNameContainer> xCont;
if(rNode.getLength())
{
Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
aNode >>= xCont;
}
else
xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
if(!xCont.is())
return sal_False;
Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);
if(xFac.is())
{
const Sequence< OUString > aSubNodeNames = lcl_extractSetPropertyNames(rValues, rNode);
const sal_Int32 nSubNodeCount = aSubNodeNames.getLength();
for(sal_Int32 j = 0; j <nSubNodeCount ; j++)
{
if(!xCont->hasByName(aSubNodeNames[j]))
{
Reference<XInterface> xInst = xFac->createInstance();
Any aVal; aVal <<= xInst;
xCont->insertByName(aSubNodeNames[j], aVal);
}
//set values
}
try
{
xBatch->commitChanges();
}
CATCH_INFO("Exception from commitChanges(): ")
const PropertyValue* pProperties = rValues.getConstArray();
Sequence< OUString > aSetNames(rValues.getLength());
OUString* pSetNames = aSetNames.getArray();
Sequence< Any> aSetValues(rValues.getLength());
Any* pSetValues = aSetValues.getArray();
sal_Bool bEmptyNode = rNode.getLength() == 0;
for(sal_Int32 k = 0; k < rValues.getLength(); k++)
{
pSetNames[k] = pProperties[k].Name.copy( bEmptyNode ? 1 : 0);
pSetValues[k] = pProperties[k].Value;
}
bRet = PutProperties(aSetNames, aSetValues);
}
else
{
//if no factory is available then the node contains basic data elements
const PropertyValue* pValues = rValues.getConstArray();
for(int nValue = 0; nValue < rValues.getLength();nValue++)
{
try
{
OUString sSubNode = lcl_extractSetPropertyName( pValues[nValue].Name, rNode );
if(xCont->hasByName(sSubNode))
xCont->replaceByName(sSubNode, pValues[nValue].Value);
else
xCont->insertByName(sSubNode, pValues[nValue].Value);
OSL_ENSURE( xHierarchyAccess->hasByHierarchicalName(pValues[nValue].Name),
"Invalid config path" );
}
CATCH_INFO("Exception form insert/replaceByName(): ")
}
xBatch->commitChanges();
}
}
#ifdef DBG_UTIL
catch(Exception& rEx)
{
lcl_CFG_DBG_EXCEPTION("Exception from SetSetProperties: ", rEx);
#else
catch(Exception&)
{
#endif
bRet = sal_False;
}
}
return bRet;
}
/* -----------------------------15.09.00 15:52--------------------------------
---------------------------------------------------------------------------*/
sal_Bool ConfigItem::ReplaceSetProperties(
const OUString& rNode, Sequence< PropertyValue > rValues)
{
ValueCounter_Impl aCounter(pImpl->nInValueChange);
sal_Bool bRet = sal_True;
Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
if(xHierarchyAccess.is())
{
Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
try
{
Reference<XNameContainer> xCont;
if(rNode.getLength())
{
Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
aNode >>= xCont;
}
else
xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
if(!xCont.is())
return sal_False;
// JB: Change: now the same name handling for sets of simple values
const Sequence< OUString > aSubNodeNames = lcl_extractSetPropertyNames(rValues, rNode);
const OUString* pSubNodeNames = aSubNodeNames.getConstArray();
const sal_Int32 nSubNodeCount = aSubNodeNames.getLength();
Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);
const bool isSimpleValueSet = !xFac.is();
//remove unknown members first
{
const Sequence<OUString> aContainerSubNodes = xCont->getElementNames();
const OUString* pContainerSubNodes = aContainerSubNodes.getConstArray();
for(sal_Int32 nContSub = 0; nContSub < aContainerSubNodes.getLength(); nContSub++)
{
sal_Bool bFound = sal_False;
for(sal_Int32 j = 0; j < nSubNodeCount; j++)
{
if(pSubNodeNames[j] == pContainerSubNodes[nContSub])
{
bFound = sal_True;
break;
}
}
if(!bFound)
try
{
xCont->removeByName(pContainerSubNodes[nContSub]);
}
catch (Exception & )
{
if (isSimpleValueSet)
try
{
// #i37322#: fallback action: replace with <void/>
xCont->replaceByName(pContainerSubNodes[nContSub], Any());
// fallback successfull: continue looping
continue;
}
catch (Exception &)
{} // propagate original exception, if fallback fails
throw;
}
}
try { xBatch->commitChanges(); }
CATCH_INFO("Exception from commitChanges(): ")
}
if(xFac.is()) // !isSimpleValueSet
{
for(sal_Int32 j = 0; j < nSubNodeCount; j++)
{
if(!xCont->hasByName(pSubNodeNames[j]))
{
//create if not available
Reference<XInterface> xInst = xFac->createInstance();
Any aVal; aVal <<= xInst;
xCont->insertByName(pSubNodeNames[j], aVal);
}
}
try { xBatch->commitChanges(); }
CATCH_INFO("Exception from commitChanges(): ")
const PropertyValue* pProperties = rValues.getConstArray();
Sequence< OUString > aSetNames(rValues.getLength());
OUString* pSetNames = aSetNames.getArray();
Sequence< Any> aSetValues(rValues.getLength());
Any* pSetValues = aSetValues.getArray();
sal_Bool bEmptyNode = rNode.getLength() == 0;
for(sal_Int32 k = 0; k < rValues.getLength(); k++)
{
pSetNames[k] = pProperties[k].Name.copy( bEmptyNode ? 1 : 0);
pSetValues[k] = pProperties[k].Value;
}
bRet = PutProperties(aSetNames, aSetValues);
}
else
{
const PropertyValue* pValues = rValues.getConstArray();
//if no factory is available then the node contains basic data elements
for(int nValue = 0; nValue < rValues.getLength();nValue++)
{
try
{
OUString sSubNode = lcl_extractSetPropertyName( pValues[nValue].Name, rNode );
if(xCont->hasByName(sSubNode))
xCont->replaceByName(sSubNode, pValues[nValue].Value);
else
xCont->insertByName(sSubNode, pValues[nValue].Value);
}
CATCH_INFO("Exception from insert/replaceByName(): ");
}
xBatch->commitChanges();
}
}
#ifdef DBG_UTIL
catch(Exception& rEx)
{
lcl_CFG_DBG_EXCEPTION("Exception from ReplaceSetProperties: ", rEx);
#else
catch(Exception&)
{
#endif
bRet = sal_False;
}
}
return bRet;
}
/* -----------------------------07.05.01 12:15--------------------------------
---------------------------------------------------------------------------*/
sal_Bool ConfigItem::getUniqueSetElementName( const ::rtl::OUString& _rSetNode, ::rtl::OUString& _rName)
{
::rtl::OUString sNewElementName;
Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
sal_Bool bRet = sal_False;
if(xHierarchyAccess.is())
{
try
{
Reference< XNameAccess > xSetNode;
xHierarchyAccess->getByHierarchicalName(_rSetNode) >>= xSetNode;
if (xSetNode.is())
{
const sal_uInt32 nPrime = 65521; // a prime number
const sal_uInt32 nPrimeLess2 = nPrime - 2;
sal_uInt32 nEngendering = (rand() % nPrimeLess2) + 2; // the engendering of the field
// the element which will loop through the field
sal_uInt32 nFieldElement = nEngendering;
for (; 1 != nFieldElement; nFieldElement = (nFieldElement * nEngendering) % nPrime)
{
::rtl::OUString sThisRoundTrial = _rName;
sThisRoundTrial += ::rtl::OUString::valueOf((sal_Int32)nFieldElement);
if (!xSetNode->hasByName(sThisRoundTrial))
{
_rName = sThisRoundTrial;
bRet = sal_True;
break;
}
}
}
}
CATCH_INFO("Exception from getUniqueSetElementName(): ")
}
return bRet;
}
/* -----------------------------23.01.01 12:49--------------------------------
---------------------------------------------------------------------------*/
sal_Bool ConfigItem::AddNode(const rtl::OUString& rNode, const rtl::OUString& rNewNode)
{
ValueCounter_Impl aCounter(pImpl->nInValueChange);
sal_Bool bRet = sal_True;
Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
if(xHierarchyAccess.is())
{
Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
try
{
Reference<XNameContainer> xCont;
if(rNode.getLength())
{
Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
aNode >>= xCont;
}
else
xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
if(!xCont.is())
return sal_False;
Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);
if(xFac.is())
{
if(!xCont->hasByName(rNewNode))
{
Reference<XInterface> xInst = xFac->createInstance();
Any aVal; aVal <<= xInst;
xCont->insertByName(rNewNode, aVal);
}
try
{
xBatch->commitChanges();
}
CATCH_INFO("Exception from commitChanges(): ")
}
else
{
//if no factory is available then the node contains basic data elements
try
{
if(!xCont->hasByName(rNewNode))
xCont->insertByName(rNewNode, Any());
}
CATCH_INFO("Exception from AddNode(): ")
}
xBatch->commitChanges();
}
#ifdef DBG_UTIL
catch(Exception& rEx)
{
lcl_CFG_DBG_EXCEPTION("Exception from AddNode(): ", rEx);
#else
catch(Exception&)
{
#endif
bRet = sal_False;
}
}
return bRet;
}
/* -----------------------------12.02.01 11:38--------------------------------
---------------------------------------------------------------------------*/
sal_Int16 ConfigItem::GetMode() const
{
return pImpl->nMode;
}
/* -----------------------------12.02.01 13:31--------------------------------
---------------------------------------------------------------------------*/
void ConfigItem::SetModified()
{
pImpl->bIsModified = sal_True;
}
/* -----------------------------05.05.01 14:07--------------------------------
---------------------------------------------------------------------------*/
void ConfigItem::ClearModified()
{
pImpl->bIsModified = sal_False;
}
/* -----------------------------12.02.01 13:31--------------------------------
---------------------------------------------------------------------------*/
sal_Bool ConfigItem::IsModified() const
{
return pImpl->bIsModified;
}
/* -----------------------------12.02.01 13:33--------------------------------
---------------------------------------------------------------------------*/
sal_Bool ConfigItem::IsInValueChange() const
{
return pImpl->nInValueChange > 0;
}
/* -----------------------------21.06.01 12:26--------------------------------
---------------------------------------------------------------------------*/
Reference< XHierarchicalNameAccess> ConfigItem::GetTree()
{
Reference< XHierarchicalNameAccess> xRet;
if(!m_xHierarchyAccess.is())
xRet = pImpl->pManager->AcquireTree(*this);
else
xRet = m_xHierarchyAccess;
OSL_ENSURE(xRet.is(), "AcquireTree failed");
return xRet;
}
/* -----------------------------22.06.01 08:42--------------------------------
---------------------------------------------------------------------------*/
void ConfigItem::LockTree()
{
OSL_ENSURE(0 != (pImpl->nMode&CONFIG_MODE_RELEASE_TREE), "call LockTree in CONFIG_MODE_RELEASE_TREE mode, only");
m_xHierarchyAccess = GetTree();
}
/* -----------------------------22.06.01 08:42--------------------------------
---------------------------------------------------------------------------*/
void ConfigItem::UnlockTree()
{
OSL_ENSURE(0 != (pImpl->nMode&CONFIG_MODE_RELEASE_TREE), "call UnlockTree in CONFIG_MODE_RELEASE_TREE mode, only");
if(0 != (pImpl->nMode&CONFIG_MODE_RELEASE_TREE))
m_xHierarchyAccess = 0;
}