/**************************************************************
 * 
 * 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;
}


