1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_unotools.hxx"
30 #include "unotools/configitem.hxx"
31 #include "unotools/configmgr.hxx"
32 #include "unotools/configpathes.hxx"
33 #include <comphelper/processfactory.hxx>
34 #include <com/sun/star/beans/XMultiPropertySet.hpp>
35 #include <com/sun/star/beans/XPropertySet.hpp>
36 #include <com/sun/star/util/XChangesListener.hpp>
37 #include <com/sun/star/util/XChangesNotifier.hpp>
38 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
39 #include <com/sun/star/container/XHierarchicalName.hpp>
40 #include <com/sun/star/configuration/XTemplateContainer.hpp>
41 #include <com/sun/star/container/XNameContainer.hpp>
42 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
43 #include <com/sun/star/lang/XServiceInfo.hpp>
44 #include <com/sun/star/awt/XRequestCallback.hpp>
45 #include <com/sun/star/beans/PropertyValue.hpp>
46 #include <com/sun/star/beans/PropertyAttribute.hpp>
47 #include <com/sun/star/util/XStringEscape.hpp>
48 #include <com/sun/star/util/XChangesBatch.hpp>
49 #include <osl/diagnose.h>
50 #include <tools/solarmutex.hxx>
51 #include <rtl/ustrbuf.hxx>
52 
53 using namespace utl;
54 using rtl::OUString;
55 using rtl::OString;
56 using namespace com::sun::star::uno;
57 using namespace com::sun::star::util;
58 using namespace com::sun::star::lang;
59 using namespace com::sun::star::beans;
60 using namespace com::sun::star::container;
61 using namespace com::sun::star::configuration;
62 
63 #define C2U(cChar) OUString::createFromAscii(cChar)
64 #include <cppuhelper/implbase1.hxx> // helper for implementations
65 
66 #ifdef DBG_UTIL
67 inline void lcl_CFG_DBG_EXCEPTION(const sal_Char* cText, const Exception& rEx)
68 {
69 	OString sMsg(cText);
70 	sMsg += OString(rEx.Message.getStr(), rEx.Message.getLength(), RTL_TEXTENCODING_ASCII_US);
71 	OSL_ENSURE(sal_False, sMsg.getStr());
72 }
73 #define CATCH_INFO(a) \
74 catch(Exception& rEx)   \
75 {                       \
76     lcl_CFG_DBG_EXCEPTION(a, rEx);\
77 }
78 #else
79 	#define lcl_CFG_DBG_EXCEPTION( a, b)
80     #define CATCH_INFO(a) catch(Exception& ){}
81 #endif
82 
83 /*
84 	The ConfigChangeListener_Impl receives notifications from the configuration about changes that
85 	have happened. It forwards this notification to the ConfigItem it knows a pParent by calling its
86 	"CallNotify" method. As ConfigItems are most probably not thread safe, the SolarMutex is acquired
87 	before doing so.
88 */
89 
90 namespace utl{
91     class ConfigChangeListener_Impl : public cppu::WeakImplHelper1
92 	<
93         com::sun::star::util::XChangesListener
94 	>
95 	{
96 		public:
97 			ConfigItem* 				pParent;
98 			const Sequence< OUString > 	aPropertyNames;
99 			ConfigChangeListener_Impl(ConfigItem& rItem, const Sequence< OUString >& rNames);
100 			~ConfigChangeListener_Impl();
101 
102 		//XChangesListener
103     	virtual void SAL_CALL changesOccurred( const ChangesEvent& Event ) throw(RuntimeException);
104 
105 		//XEventListener
106     	virtual void SAL_CALL disposing( const EventObject& Source ) throw(RuntimeException);
107 	};
108 /* -----------------------------12.02.01 11:38--------------------------------
109 
110  ---------------------------------------------------------------------------*/
111 struct ConfigItem_Impl
112 {
113 	utl::ConfigManager* 		pManager;
114    	sal_Int16 					nMode;
115 	sal_Bool					bIsModified;
116     sal_Bool                    bEnableInternalNotification;
117 
118 	sal_Int16					nInValueChange;
119 	ConfigItem_Impl() :
120 		pManager(0),
121 		nMode(0),
122 		bIsModified(sal_False),
123         bEnableInternalNotification(sal_False),
124 		nInValueChange(0)
125     {}
126 };
127 }
128 /* -----------------------------04.12.00 10:25--------------------------------
129 
130  ---------------------------------------------------------------------------*/
131 class ValueCounter_Impl
132 {
133 	sal_Int16& rCnt;
134 public:
135 	ValueCounter_Impl(sal_Int16& rCounter):
136 		rCnt(rCounter)
137 			{rCnt++;}
138 	~ValueCounter_Impl()
139 			{
140 				OSL_ENSURE(rCnt>0, "RefCount < 0 ??");
141 				rCnt--;
142 			}
143 };
144 /* -----------------------------03.12.02 -------------------------------------
145 
146  ---------------------------------------------------------------------------*/
147 namespace
148 {
149     // helper to achieve exception - safe handling of an Item under construction
150     template <class TYP>
151     class AutoDeleter // : Noncopyable
152     {
153         TYP* m_pItem;
154     public:
155         AutoDeleter(TYP * pItem)
156         : m_pItem(pItem)
157         {
158         }
159 
160         ~AutoDeleter()
161         {
162             delete m_pItem;
163         }
164 
165         void keep() { m_pItem = 0; }
166     };
167 }
168 /* -----------------------------29.08.00 16:34--------------------------------
169 
170  ---------------------------------------------------------------------------*/
171 ConfigChangeListener_Impl::ConfigChangeListener_Impl(
172 			 ConfigItem& rItem, const Sequence< OUString >& rNames) :
173 	pParent(&rItem),
174 	aPropertyNames(rNames)
175 {
176 }
177 /* -----------------------------29.08.00 16:34--------------------------------
178 
179  ---------------------------------------------------------------------------*/
180 ConfigChangeListener_Impl::~ConfigChangeListener_Impl()
181 {
182 }
183 /* -----------------------------29.08.00 16:34--------------------------------
184 
185  ---------------------------------------------------------------------------*/
186 sal_Bool lcl_Find(
187 		const rtl::OUString& rTemp,
188 		const OUString* pCheckPropertyNames,
189 		sal_Int32 nLength)
190 {
191 	//return true if the path is completely correct or if it is longer
192 	//i.e ...Print/Content/Graphic and .../Print
193 	for(sal_Int32 nIndex = 0; nIndex < nLength; nIndex++)
194 		if( isPrefixOfConfigurationPath(rTemp, pCheckPropertyNames[nIndex]) )
195 			return sal_True;
196 	return sal_False;
197 }
198 //-----------------------------------------------------------------------------
199 void ConfigChangeListener_Impl::changesOccurred( const ChangesEvent& rEvent ) throw(RuntimeException)
200 {
201 	const ElementChange* pElementChanges = rEvent.Changes.getConstArray();
202 
203 	Sequence<OUString>	aChangedNames(rEvent.Changes.getLength());
204 	OUString* pNames = aChangedNames.getArray();
205 
206 	const OUString* pCheckPropertyNames = aPropertyNames.getConstArray();
207 
208 	sal_Int32 nNotify = 0;
209 	for(int i = 0; i < aChangedNames.getLength(); i++)
210 	{
211 		OUString sTemp;
212 		pElementChanges[i].Accessor >>= sTemp;
213 		if(lcl_Find(sTemp, pCheckPropertyNames, aPropertyNames.getLength()))
214 			pNames[nNotify++] = sTemp;
215 	}
216 	if( nNotify )
217 	{
218 		if ( ::tools::SolarMutex::Acquire() )
219 		{
220 			aChangedNames.realloc(nNotify);
221 			pParent->CallNotify(aChangedNames);
222 			::tools::SolarMutex::Release();
223 		}
224 	}
225 }
226 
227 /* -----------------------------29.08.00 16:34--------------------------------
228 
229  ---------------------------------------------------------------------------*/
230 void ConfigChangeListener_Impl::disposing( const EventObject& /*rSource*/ ) throw(RuntimeException)
231 {
232 	pParent->RemoveChangesListener();
233 }
234 /* -----------------------------29.08.00 12:50--------------------------------
235 
236  ---------------------------------------------------------------------------*/
237 ConfigItem::ConfigItem(const OUString rSubTree, sal_Int16 nSetMode ) :
238 	sSubTree(rSubTree),
239 	pImpl(new ConfigItem_Impl)
240 {
241     AutoDeleter<ConfigItem_Impl> aNewImpl(pImpl);
242 
243 	pImpl->pManager = ConfigManager::GetConfigManager();
244 	pImpl->nMode = nSetMode;
245     if(0 != (nSetMode&CONFIG_MODE_RELEASE_TREE))
246         pImpl->pManager->AddConfigItem(*this);
247     else
248         m_xHierarchyAccess = pImpl->pManager->AddConfigItem(*this);
249 
250     // no more exceptions after c'tor has finished
251     aNewImpl.keep();
252 	pImpl->nMode &= ~CONFIG_MODE_PROPAGATE_ERRORS;
253 }
254 /* -----------------------------17.11.00 13:53--------------------------------
255 
256  ---------------------------------------------------------------------------*/
257 ConfigItem::ConfigItem(utl::ConfigManager& 	rManager, const rtl::OUString rSubTree) :
258 	sSubTree(rSubTree),
259 	pImpl(new ConfigItem_Impl)
260 {
261 	pImpl->pManager = &rManager;
262 	pImpl->nMode = CONFIG_MODE_IMMEDIATE_UPDATE; // does not allow exceptions
263     m_xHierarchyAccess = pImpl->pManager->AddConfigItem(*this);
264 }
265 //---------------------------------------------------------------------
266 //--- 02.08.2002 16:33:23 -----------------------------------------------
267 sal_Bool ConfigItem::IsValidConfigMgr() const
268 {
269 	return ( pImpl->pManager && pImpl->pManager->GetConfigurationProvider().is() );
270 }
271 
272 /* -----------------------------29.08.00 12:52--------------------------------
273 
274  ---------------------------------------------------------------------------*/
275 ConfigItem::~ConfigItem()
276 {
277 	if(pImpl->pManager)
278 	{
279         RemoveChangesListener();
280 		pImpl->pManager->RemoveConfigItem(*this);
281 	}
282 	delete pImpl;
283 }
284 /* -----------------------------29.08.00 12:52--------------------------------
285 
286  ---------------------------------------------------------------------------*/
287 void	ConfigItem::ReleaseConfigMgr()
288 {
289     Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
290     if(xHierarchyAccess.is())
291 	{
292 		try
293 		{
294 			Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
295 			xBatch->commitChanges();
296 		}
297         CATCH_INFO("Exception from commitChanges(): ")
298 	}
299 	RemoveChangesListener();
300 	OSL_ENSURE(pImpl->pManager, "ConfigManager already released");
301 	pImpl->pManager = 0;
302 }
303 /* -----------------------------29.08.00 12:52--------------------------------
304 
305  ---------------------------------------------------------------------------*/
306 void ConfigItem::CallNotify( const com::sun::star::uno::Sequence<OUString>& rPropertyNames )
307 {
308 	// the call is forwarded to the virtual Notify() method
309 	// it is pure virtual, so all classes deriving from ConfigItem have to decide how they
310 	// want to notify listeners
311     if(!IsInValueChange() || pImpl->bEnableInternalNotification)
312 		Notify(rPropertyNames);
313 }
314 
315 /* -----------------------------12.12.00 17:09--------------------------------
316 
317  ---------------------------------------------------------------------------*/
318 sal_Bool lcl_IsLocalProperty(const OUString& rSubTree, const OUString& rProperty)
319 {
320 	static const sal_Char* aLocalProperties[] =
321 	{
322 		"Office.Common/Path/Current/Storage",
323         "Office.Common/Path/Current/Temp"
324 	};
325 	static const int aLocalPropLen[] =
326 	{
327 		34,
328         31
329 	};
330 	OUString sProperty(rSubTree);
331 	sProperty += C2U("/");
332 	sProperty += rProperty;
333 
334 	if(sProperty.equalsAsciiL( aLocalProperties[0], aLocalPropLen[0]) ||
335         sProperty.equalsAsciiL( aLocalProperties[1], aLocalPropLen[1]))
336 		return sal_True;
337 
338 	return sal_False;
339 }
340 /* -----------------------------10.04.01 15:00--------------------------------
341 
342  ---------------------------------------------------------------------------*/
343 void ConfigItem::impl_packLocalizedProperties(	const	Sequence< OUString >&	lInNames	,
344 												const	Sequence< Any >&		lInValues	,
345 														Sequence< Any >&		lOutValues	)
346 {
347 	// Safe impossible cases.
348 	// This method should be called for special ConfigItem-mode only!
349     OSL_ENSURE( ((pImpl->nMode & CONFIG_MODE_ALL_LOCALES ) == CONFIG_MODE_ALL_LOCALES), "ConfigItem::impl_packLocalizedProperties()\nWrong call of this method detected!\n" );
350 
351 	sal_Int32					nSourceCounter		;	// used to step during input lists
352 	sal_Int32					nSourceSize			;	// marks end of loop over input lists
353 	sal_Int32					nDestinationCounter	;	// actual position in output lists
354 	sal_Int32					nPropertyCounter	;	// counter of inner loop for Sequence< PropertyValue >
355 	sal_Int32					nPropertiesSize		;	// marks end of inner loop
356 	Sequence< OUString >		lPropertyNames		;	// list of all locales for localized entry
357 	Sequence< PropertyValue >	lProperties			;	// localized values of an configuration entry packed for return
358 	Reference< XInterface >		xLocalizedNode		;	// if cfg entry is localized ... lInValues contains an XInterface!
359 
360 	// Optimise follow algorithm ... A LITTLE BIT :-)
361 	// There exist two different possibilities:
362 	//	i )	There exist no localized entries ...						=>	size of lOutValues will be the same like lInNames/lInValues!
363 	//	ii)	There exist some (mostly one or two) localized entries ...	=>	size of lOutValues will be the same like lInNames/lInValues!
364 	//	... Why? If a localized value exist - the any is filled with an XInterface object (is a SetNode-service).
365 	//		We read all his child nodes and pack it into Sequence< PropertyValue >.
366 	//		The result list we pack into the return any. We never change size of lists!
367 	nSourceSize = lInNames.getLength();
368 	lOutValues.realloc( nSourceSize );
369 
370 	// Algorithm:
371 	// Copy all names and values from in to out lists.
372 	// Look for special localized entries ... You can detect it as "XInterface" packed into an Any.
373 	// Use this XInterface-object to read all localized values and pack it into Sequence< PropertValue >.
374 	// Add this list to out lists then.
375 
376 	nDestinationCounter = 0;
377 	for( nSourceCounter=0; nSourceCounter<nSourceSize; ++nSourceCounter )
378 	{
379 		// If item a special localized one ... convert and pack it ...
380 		if( lInValues[nSourceCounter].getValueTypeName() == C2U("com.sun.star.uno.XInterface") )
381 		{
382 			lInValues[nSourceCounter] >>= xLocalizedNode;
383 			Reference< XNameContainer > xSetAccess( xLocalizedNode, UNO_QUERY );
384 			if( xSetAccess.is() == sal_True )
385 			{
386 				lPropertyNames	=	xSetAccess->getElementNames()	;
387 				nPropertiesSize	=	lPropertyNames.getLength()		;
388 				lProperties.realloc( nPropertiesSize )				;
389 
390 				for( nPropertyCounter=0; nPropertyCounter<nPropertiesSize; ++nPropertyCounter )
391 				{
392                     #if OSL_DEBUG_LEVEL > 1
393 					// Sometimes it's better to see what's going on :-)
394                     OUString sPropName   = lInNames[nSourceCounter];
395                     OUString sLocaleName = lPropertyNames[nPropertyCounter];
396 					#endif
397 					lProperties[nPropertyCounter].Name	=	lPropertyNames[nPropertyCounter]							;
398 					OUString sLocaleValue;
399 					xSetAccess->getByName( lPropertyNames[nPropertyCounter] ) >>= sLocaleValue	;
400 					lProperties[nPropertyCounter].Value	<<=	sLocaleValue;
401 				}
402 
403 				lOutValues[nDestinationCounter] <<= lProperties;
404 			}
405 		}
406 		// ... or copy normal items to return lists directly.
407 		else
408 		{
409 			lOutValues[nDestinationCounter] = lInValues[nSourceCounter];
410 		}
411 		++nDestinationCounter;
412 	}
413 }
414 /* -----------------------------10.04.01 15:00--------------------------------
415 
416  ---------------------------------------------------------------------------*/
417 void ConfigItem::impl_unpackLocalizedProperties(	const	Sequence< OUString >&	lInNames	,
418 													const	Sequence< Any >&		lInValues	,
419 															Sequence< OUString >&	lOutNames	,
420 															Sequence< Any >&		lOutValues	)
421 {
422 	// Safe impossible cases.
423 	// This method should be called for special ConfigItem-mode only!
424     OSL_ENSURE( ((pImpl->nMode & CONFIG_MODE_ALL_LOCALES ) == CONFIG_MODE_ALL_LOCALES), "ConfigItem::impl_unpackLocalizedProperties()\nWrong call of this method detected!\n" );
425 
426 	sal_Int32					nSourceCounter		;	// used to step during input lists
427 	sal_Int32					nSourceSize			;	// marks end of loop over input lists
428 	sal_Int32					nDestinationCounter	;	// actual position in output lists
429 	sal_Int32					nPropertyCounter	;	// counter of inner loop for Sequence< PropertyValue >
430 	sal_Int32					nPropertiesSize		;	// marks end of inner loop
431 	OUString					sNodeName			;	// base name of node ( e.g. "UIName/" ) ... expand to locale ( e.g. "UIName/de" )
432 	Sequence< PropertyValue >	lProperties			;	// localized values of an configuration entry getted from lInValues-Any
433 
434 	// Optimise follow algorithm ... A LITTLE BIT :-)
435 	// There exist two different possibilities:
436 	//	i )	There exist no localized entries ...						=>	size of lOutNames/lOutValues will be the same like lInNames/lInValues!
437 	//	ii)	There exist some (mostly one or two) localized entries ...	=>	size of lOutNames/lOutValues will be some bytes greater then lInNames/lInValues.
438 	//	=>	I think we should make it fast for i). ii) is a special case and mustn't be SOOOO... fast.
439 	//		We should reserve same space for output list like input ones first.
440 	//		Follow algorithm looks for these borders and change it for ii) only!
441 	//		It will be faster then a "realloc()" call in every loop ...
442 	nSourceSize = lInNames.getLength();
443 
444 	lOutNames.realloc	( nSourceSize );
445 	lOutValues.realloc	( nSourceSize );
446 
447 	// Algorithm:
448 	// Copy all names and values from const to return lists.
449 	// Look for special localized entries ... You can detect it as Sequence< PropertyValue > packed into an Any.
450 	// Split it ... insert PropertyValue.Name to lOutNames and PropertyValue.Value to lOutValues.
451 
452 	nDestinationCounter = 0;
453 	for( nSourceCounter=0; nSourceCounter<nSourceSize; ++nSourceCounter )
454 	{
455 		// If item a special localized one ... split it and insert his parts to output lists ...
456 		if( lInValues[nSourceCounter].getValueType() == ::getCppuType( (const Sequence< PropertyValue >*)NULL ) )
457 		{
458 			lInValues[nSourceCounter]	>>=	lProperties				;
459 			sNodeName				=	lInNames[nSourceCounter] 	;
460 			sNodeName				+=	C2U("/")					;
461 			nPropertiesSize			=	lProperties.getLength()		;
462 
463 			if( (nDestinationCounter+nPropertiesSize) > lOutNames.getLength() )
464 			{
465 				lOutNames.realloc	( nDestinationCounter+nPropertiesSize );
466 				lOutValues.realloc	( nDestinationCounter+nPropertiesSize );
467 			}
468 
469 			for( nPropertyCounter=0; nPropertyCounter<nPropertiesSize; ++nPropertyCounter )
470 			{
471  				lOutNames [nDestinationCounter] = sNodeName + lProperties[nPropertyCounter].Name	;
472 				lOutValues[nDestinationCounter] = lProperties[nPropertyCounter].Value				;
473 				++nDestinationCounter;
474 			}
475 		}
476 		// ... or copy normal items to return lists directly.
477 		else
478 		{
479 			if( (nDestinationCounter+1) > lOutNames.getLength() )
480 			{
481 				lOutNames.realloc	( nDestinationCounter+1 );
482 				lOutValues.realloc	( nDestinationCounter+1 );
483 			}
484 
485 			lOutNames [nDestinationCounter] = lInNames [nSourceCounter];
486 			lOutValues[nDestinationCounter] = lInValues[nSourceCounter];
487 			++nDestinationCounter;
488 		}
489 	}
490 }
491 /* -----------------------------03.02.2003 14:44------------------------------
492 
493  ---------------------------------------------------------------------------*/
494 Sequence< sal_Bool > ConfigItem::GetReadOnlyStates(const com::sun::star::uno::Sequence< rtl::OUString >& rNames)
495 {
496     sal_Int32 i;
497 
498     // size of return list is fix!
499     // Every item must match to length of incoming name list.
500     sal_Int32 nCount = rNames.getLength();
501     Sequence< sal_Bool > lStates(nCount);
502 
503     // We must be shure to return a valid information everytime!
504     // Set default to non readonly ... similar to the configuration handling of this property.
505     for ( i=0; i<nCount; ++i)
506         lStates[i] = sal_False;
507 
508     // no access - no informations ...
509     Reference< XHierarchicalNameAccess > xHierarchyAccess = GetTree();
510     if (!xHierarchyAccess.is())
511         return lStates;
512 
513     for (i=0; i<nCount; ++i)
514     {
515         try
516         {
517             if(pImpl->pManager->IsLocalConfigProvider() && lcl_IsLocalProperty(sSubTree, rNames[i]))
518             {
519                 OSL_ENSURE(sal_False, "ConfigItem::IsReadonly()\nlocal mode seams to be used!?\n");
520                 continue;
521             }
522 
523             OUString sName = rNames[i];
524             OUString sPath;
525             OUString sProperty;
526 
527             ::utl::splitLastFromConfigurationPath(sName,sPath,sProperty);
528             if (!sPath.getLength() && !sProperty.getLength())
529             {
530                 OSL_ENSURE(sal_False, "ConfigItem::IsReadonly()\nsplitt failed\n");
531                 continue;
532             }
533 
534             Reference< XInterface >       xNode;
535             Reference< XPropertySet >     xSet ;
536             Reference< XPropertySetInfo > xInfo;
537             if (sPath.getLength())
538             {
539                 Any aNode = xHierarchyAccess->getByHierarchicalName(sPath);
540                 if (!(aNode >>= xNode) || !xNode.is())
541                 {
542                     OSL_ENSURE(sal_False, "ConfigItem::IsReadonly()\nno set available\n");
543                     continue;
544                 }
545             }
546             else
547             {
548                 xNode = Reference< XInterface >(xHierarchyAccess, UNO_QUERY);
549             }
550 
551 	    xSet = Reference< XPropertySet >(xNode, UNO_QUERY);
552             if (xSet.is())
553 	    {
554 	        xInfo = xSet->getPropertySetInfo();
555                 OSL_ENSURE(xInfo.is(), "ConfigItem::IsReadonly()\ngetPropertySetInfo failed ...\n");
556 	    }
557             else
558 	    {
559 	       	xInfo = Reference< XPropertySetInfo >(xNode, UNO_QUERY);
560                 OSL_ENSURE(xInfo.is(), "ConfigItem::IsReadonly()\nUNO_QUERY failed ...\n");
561 	    }
562 
563             if (!xInfo.is())
564             {
565                 OSL_ENSURE(sal_False, "ConfigItem::IsReadonly()\nno prop info available\n");
566                 continue;
567             }
568 
569             Property aProp = xInfo->getPropertyByName(sProperty);
570             lStates[i] = ((aProp.Attributes & PropertyAttribute::READONLY) == PropertyAttribute::READONLY);
571         }
572         catch(Exception&){}
573     }
574 
575     return lStates;
576 }
577 
578 /* -----------------------------29.08.00 15:10--------------------------------
579 
580  ---------------------------------------------------------------------------*/
581 Sequence< Any > ConfigItem::GetProperties(const Sequence< OUString >& rNames)
582 {
583 	Sequence< Any > aRet(rNames.getLength());
584 	const OUString* pNames = rNames.getConstArray();
585 	Any* pRet = aRet.getArray();
586     Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
587     if(xHierarchyAccess.is())
588 	{
589 		for(int i = 0; i < rNames.getLength(); i++)
590 		{
591 			try
592 			{
593 				if(pImpl->pManager->IsLocalConfigProvider() && lcl_IsLocalProperty(sSubTree, pNames[i]))
594 				{
595 					OUString sProperty(sSubTree);
596 					sProperty += C2U("/");
597 					sProperty += pNames[i];
598 					pRet[i] = pImpl->pManager->GetLocalProperty(sProperty);
599 				}
600 				else
601 					pRet[i] = xHierarchyAccess->getByHierarchicalName(pNames[i]);
602 			}
603 			catch(Exception& rEx)
604 			{
605 #if OSL_DEBUG_LEVEL > 0
606 				OString sMsg("XHierarchicalNameAccess: ");
607 				sMsg += OString(rEx.Message.getStr(),
608 					rEx.Message.getLength(),
609 				 	RTL_TEXTENCODING_ASCII_US);
610 				sMsg += OString("\n");
611 				sMsg += OString(ConfigManager::GetConfigBaseURL().getStr(),
612 					ConfigManager::GetConfigBaseURL().getLength(),
613 				 	RTL_TEXTENCODING_ASCII_US);
614 				sMsg += OString(sSubTree.getStr(),
615 					sSubTree.getLength(),
616 				 	RTL_TEXTENCODING_ASCII_US);
617 				sMsg += OString("/");
618 				sMsg += OString(pNames[i].getStr(),
619 					pNames[i].getLength(),
620 				 	RTL_TEXTENCODING_ASCII_US);
621 				OSL_ENSURE(sal_False, sMsg.getStr());
622 #else
623                 (void) rEx; // avoid warning
624 #endif
625 			}
626 		}
627 
628 		// In special mode "ALL_LOCALES" we must convert localized values to Sequence< PropertyValue >.
629         if((pImpl->nMode & CONFIG_MODE_ALL_LOCALES ) == CONFIG_MODE_ALL_LOCALES)
630 		{
631 			Sequence< Any > lValues;
632 			impl_packLocalizedProperties( rNames, aRet, lValues );
633 			aRet = lValues;
634 		}
635 	}
636 	return aRet;
637 }
638 /* -----------------------------29.08.00 17:28--------------------------------
639 
640  ---------------------------------------------------------------------------*/
641 sal_Bool ConfigItem::PutProperties( const Sequence< OUString >& rNames,
642 												const Sequence< Any>& rValues)
643 {
644 	ValueCounter_Impl aCounter(pImpl->nInValueChange);
645     Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
646     Reference<XNameReplace> xTopNodeReplace(xHierarchyAccess, UNO_QUERY);
647 	sal_Bool bRet = xHierarchyAccess.is() && xTopNodeReplace.is();
648 	if(bRet)
649 	{
650 		Sequence< OUString >	lNames			;
651 		Sequence< Any >			lValues			;
652 		const OUString*			pNames	= NULL	;
653 		const Any*				pValues	= NULL	;
654 		sal_Int32				nNameCount		;
655         if(( pImpl->nMode & CONFIG_MODE_ALL_LOCALES ) == CONFIG_MODE_ALL_LOCALES )
656 		{
657 			// If ConfigItem works in "ALL_LOCALES"-mode ... we must support a Sequence< PropertyValue >
658 			// as value of an localized configuration entry!
659 			// How we can do that?
660 			// We must split all PropertyValues to "Sequence< OUString >" AND "Sequence< Any >"!
661 			impl_unpackLocalizedProperties( rNames, rValues, lNames, lValues );
662 			pNames		= lNames.getConstArray	();
663 			pValues		= lValues.getConstArray	();
664 			nNameCount	= lNames.getLength		();
665 		}
666 		else
667 		{
668 			// This is the normal mode ...
669 			// Use given input lists directly.
670 			pNames		= rNames.getConstArray	();
671 			pValues		= rValues.getConstArray	();
672 			nNameCount	= rNames.getLength		();
673 		}
674 		for(int i = 0; i < nNameCount; i++)
675 		{
676 			if(pImpl->pManager->IsLocalConfigProvider() && lcl_IsLocalProperty(sSubTree, pNames[i]))
677 			{
678 				OUString sProperty(sSubTree);
679 				sProperty += C2U("/");
680 				sProperty += pNames[i];
681 				pImpl->pManager->PutLocalProperty(sProperty, pValues[i]);
682 			}
683 			else
684 			{
685 				try
686 				{
687                     OUString sNode, sProperty;
688                     if (splitLastFromConfigurationPath(pNames[i],sNode, sProperty))
689                     {
690 						Any aNode = xHierarchyAccess->getByHierarchicalName(sNode);
691 
692                         Reference<XNameAccess> xNodeAcc;
693 						aNode >>= xNodeAcc;
694 						Reference<XNameReplace>   xNodeReplace(xNodeAcc, UNO_QUERY);
695 						Reference<XNameContainer> xNodeCont   (xNodeAcc, UNO_QUERY);
696 
697                         sal_Bool bExist = (xNodeAcc.is() && xNodeAcc->hasByName(sProperty));
698                         if (bExist && xNodeReplace.is())
699 						    xNodeReplace->replaceByName(sProperty, pValues[i]);
700                         else
701 						if (!bExist && xNodeCont.is())
702 						    xNodeCont->insertByName(sProperty, pValues[i]);
703 						else
704 							bRet = sal_False;
705 					}
706 					else //direct value
707 					{
708 						xTopNodeReplace->replaceByName(sProperty, pValues[i]);
709 					}
710 				}
711                 CATCH_INFO("Exception from PutProperties: ");
712 			}
713 		}
714 		try
715 		{
716 			Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
717 			xBatch->commitChanges();
718 		}
719         CATCH_INFO("Exception from commitChanges(): ")
720 	}
721 
722 	return bRet;
723 }
724 /* -----------------------------08.12.05 15:27--------------------------------
725 
726  ---------------------------------------------------------------------------*/
727 void ConfigItem::DisableNotification()
728 {
729     OSL_ENSURE( xChangeLstnr.is(), "ConfigItem::DisableNotification: notifications not enabled currently!" );
730     RemoveChangesListener();
731 }
732 /* -----------------------------29.08.00 16:19--------------------------------
733 
734  ---------------------------------------------------------------------------*/
735 sal_Bool    ConfigItem::EnableNotification(const Sequence< OUString >& rNames,
736                 sal_Bool bEnableInternalNotification )
737 
738 {
739     OSL_ENSURE(0 == (pImpl->nMode&CONFIG_MODE_RELEASE_TREE), "notification in CONFIG_MODE_RELEASE_TREE mode not possible");
740     pImpl->bEnableInternalNotification = bEnableInternalNotification;
741     Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
742     Reference<XChangesNotifier> xChgNot(xHierarchyAccess, UNO_QUERY);
743 	if(!xChgNot.is())
744 		return sal_False;
745 
746 	OSL_ENSURE(!xChangeLstnr.is(), "EnableNotification already called");
747 	if(xChangeLstnr.is())
748 		xChgNot->removeChangesListener( xChangeLstnr );
749 	sal_Bool bRet = sal_True;
750 
751 	try
752 	{
753 		xChangeLstnr = new ConfigChangeListener_Impl(*this, rNames);
754 		xChgNot->addChangesListener( xChangeLstnr );
755 	}
756 	catch(RuntimeException& )
757 	{
758 		bRet = sal_False;
759 	}
760 	return bRet;
761 }
762 /* -----------------------------29.08.00 16:47--------------------------------
763 
764  ---------------------------------------------------------------------------*/
765 void ConfigItem::RemoveChangesListener()
766 {
767     Reference<XChangesNotifier> xChgNot(m_xHierarchyAccess, UNO_QUERY);
768 	if(xChgNot.is() && xChangeLstnr.is())
769 	{
770 		try
771 		{
772 			xChgNot->removeChangesListener( xChangeLstnr );
773             xChangeLstnr = 0;
774 		}
775 		catch(Exception & )
776 		{
777 		}
778 	}
779 }
780 /* -----------------------------10.07.00      --------------------------------
781 
782  ---------------------------------------------------------------------------*/
783 void lcl_normalizeLocalNames(Sequence< OUString >& _rNames, ConfigNameFormat _eFormat, Reference<XInterface> const& _xParentNode)
784 {
785     switch (_eFormat)
786     {
787     case CONFIG_NAME_LOCAL_NAME:
788         // unaltered - this is our input format
789         break;
790 
791     case CONFIG_NAME_FULL_PATH:
792         {
793             Reference<XHierarchicalName> xFormatter(_xParentNode, UNO_QUERY);
794             if (xFormatter.is())
795             {
796                 OUString * pNames = _rNames.getArray();
797                 for(int i = 0; i<_rNames.getLength(); ++i)
798                 try
799                 {
800                     pNames[i] = xFormatter->composeHierarchicalName(pNames[i]);
801                 }
802                 CATCH_INFO("Exception from composeHierarchicalName(): ")
803                 break;
804             }
805         }
806         OSL_ENSURE(false, "Cannot create absolute pathes: missing interface");
807         // make local pathes instaed
808 
809     case CONFIG_NAME_LOCAL_PATH:
810         {
811             Reference<XTemplateContainer> xTypeContainer(_xParentNode, UNO_QUERY);
812             if (xTypeContainer.is())
813             {
814                 OUString sTypeName = xTypeContainer->getElementTemplateName();
815                 sTypeName = sTypeName.copy(sTypeName.lastIndexOf('/')+1);
816 
817                 OUString * pNames = _rNames.getArray();
818                 for(int i = 0; i<_rNames.getLength(); ++i)
819                 {
820                     pNames[i] = wrapConfigurationElementName(pNames[i],sTypeName);
821                 }
822             }
823             else
824             {
825                 static const OUString sSetService(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.configuration.SetAccess"));
826                 Reference<XServiceInfo> xSVI(_xParentNode, UNO_QUERY);
827                 if (xSVI.is() && xSVI->supportsService(sSetService))
828                 {
829                     OUString * pNames = _rNames.getArray();
830                     for(int i = 0; i<_rNames.getLength(); ++i)
831                     {
832                         pNames[i] = wrapConfigurationElementName(pNames[i]);
833                     }
834                 }
835             }
836         }
837         break;
838 
839     case CONFIG_NAME_PLAINTEXT_NAME:
840         {
841             Reference<XStringEscape> xEscaper(_xParentNode, UNO_QUERY);
842             if (xEscaper.is())
843             {
844                 OUString * pNames = _rNames.getArray();
845                 for(int i = 0; i<_rNames.getLength(); ++i)
846                 try
847                 {
848                     pNames[i] = xEscaper->unescapeString(pNames[i]);
849                 }
850                 CATCH_INFO("Exception from unescapeString(): ")
851             }
852         }
853         break;
854 
855     }
856 }
857 /* -----------------------------10.07.00      --------------------------------
858 
859  ---------------------------------------------------------------------------*/
860 Sequence< OUString > ConfigItem::GetNodeNames(const OUString& rNode)
861 {
862     ConfigNameFormat const eDefaultFormat = CONFIG_NAME_LOCAL_NAME; // CONFIG_NAME_DEFAULT;
863 
864     return GetNodeNames(rNode, eDefaultFormat);
865 }
866 /* -----------------------------15.09.00 12:06--------------------------------
867 
868  ---------------------------------------------------------------------------*/
869 Sequence< OUString > ConfigItem::GetNodeNames(const OUString& rNode, ConfigNameFormat eFormat)
870 {
871 	Sequence< OUString > aRet;
872     Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
873     if(xHierarchyAccess.is())
874 	{
875 		try
876 		{
877 			Reference<XNameAccess> xCont;
878 			if(rNode.getLength())
879 			{
880 				Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
881 				aNode >>= xCont;
882 			}
883 			else
884 				xCont = Reference<XNameAccess> (xHierarchyAccess, UNO_QUERY);
885 			if(xCont.is())
886 			{
887 				aRet = xCont->getElementNames();
888                 lcl_normalizeLocalNames(aRet,eFormat,xCont);
889             }
890 
891 		}
892         CATCH_INFO("Exception from GetNodeNames: ");
893 	}
894 	return aRet;
895 }
896 /* -----------------------------15.09.00 15:52--------------------------------
897 
898  ---------------------------------------------------------------------------*/
899 sal_Bool ConfigItem::ClearNodeSet(const OUString& rNode)
900 {
901 	ValueCounter_Impl aCounter(pImpl->nInValueChange);
902     sal_Bool bRet = sal_False;
903     Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
904     if(xHierarchyAccess.is())
905 	{
906 		try
907 		{
908 			Reference<XNameContainer> xCont;
909 			if(rNode.getLength())
910 			{
911 				Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
912 				aNode >>= xCont;
913 			}
914 			else
915 				xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
916 			if(!xCont.is())
917 				return sal_False;
918 			Sequence< OUString > aNames = xCont->getElementNames();
919 			const OUString* pNames = aNames.getConstArray();
920 			Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
921 			for(sal_Int32 i = 0; i < aNames.getLength(); i++)
922 			{
923 				try
924 				{
925 					xCont->removeByName(pNames[i]);
926 				}
927                 CATCH_INFO("Exception from removeByName(): ")
928 			}
929 			xBatch->commitChanges();
930             bRet = sal_True;
931 		}
932         CATCH_INFO("Exception from ClearNodeSet")
933 	}
934 	return bRet;
935 }
936 /* -----------------------------24.11.00 10:58--------------------------------
937 
938  ---------------------------------------------------------------------------*/
939 sal_Bool ConfigItem::ClearNodeElements(const OUString& rNode, Sequence< OUString >& rElements)
940 {
941 	ValueCounter_Impl aCounter(pImpl->nInValueChange);
942     sal_Bool bRet = sal_False;
943     Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
944     if(xHierarchyAccess.is())
945 	{
946 		const OUString* pElements = rElements.getConstArray();
947 		try
948 		{
949 			Reference<XNameContainer> xCont;
950 			if(rNode.getLength())
951 			{
952 				Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
953 				aNode >>= xCont;
954 			}
955 			else
956 				xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
957 			if(!xCont.is())
958 				return sal_False;
959 			try
960 			{
961 				for(sal_Int32 nElement = 0; nElement < rElements.getLength(); nElement++)
962 				{
963 					xCont->removeByName(pElements[nElement]);
964 				}
965 				Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
966 				xBatch->commitChanges();
967 			}
968             CATCH_INFO("Exception from commitChanges(): ")
969             bRet = sal_True;
970         }
971         CATCH_INFO("Exception from GetNodeNames: ")
972 	}
973 	return bRet;
974 }
975 //----------------------------------------------------------------------------
976 static inline
977 OUString lcl_extractSetPropertyName( const OUString& rInPath, const OUString& rPrefix )
978 {
979     OUString const sSubPath = dropPrefixFromConfigurationPath( rInPath, rPrefix);
980     return extractFirstFromConfigurationPath( sSubPath );
981 }
982 //----------------------------------------------------------------------------
983 static
984 Sequence< OUString > lcl_extractSetPropertyNames( const Sequence< PropertyValue >& rValues, const OUString& rPrefix )
985 {
986     const PropertyValue* pProperties = rValues.getConstArray();
987 
988     Sequence< OUString > aSubNodeNames(rValues.getLength());
989     OUString* pSubNodeNames = aSubNodeNames.getArray();
990 
991     OUString sLastSubNode;
992     sal_Int32 nSubIndex = 0;
993 
994     for(sal_Int32 i = 0; i < rValues.getLength(); i++)
995     {
996         OUString const sSubPath = dropPrefixFromConfigurationPath( pProperties[i].Name, rPrefix);
997         OUString const sSubNode = extractFirstFromConfigurationPath( sSubPath );
998 
999         if(sLastSubNode != sSubNode)
1000 	    {
1001 		    pSubNodeNames[nSubIndex++] = sSubNode;
1002 	    }
1003 
1004 	    sLastSubNode = sSubNode;
1005     }
1006     aSubNodeNames.realloc(nSubIndex);
1007 
1008     return aSubNodeNames;
1009 }
1010 /* -----------------------------15.09.00 15:52--------------------------------
1011 	add or change properties
1012  ---------------------------------------------------------------------------*/
1013 sal_Bool ConfigItem::SetSetProperties(
1014 	const OUString& rNode, Sequence< PropertyValue > rValues)
1015 {
1016 	ValueCounter_Impl aCounter(pImpl->nInValueChange);
1017     sal_Bool bRet = sal_True;
1018     Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
1019     if(xHierarchyAccess.is())
1020 	{
1021 		Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
1022 		try
1023 		{
1024 			Reference<XNameContainer> xCont;
1025 			if(rNode.getLength())
1026 			{
1027 				Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
1028 				aNode >>= xCont;
1029 			}
1030 			else
1031 				xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
1032 			if(!xCont.is())
1033 				return sal_False;
1034 
1035 			Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);
1036 
1037             if(xFac.is())
1038 			{
1039 				const Sequence< OUString > aSubNodeNames = lcl_extractSetPropertyNames(rValues, rNode);
1040 
1041                 const sal_Int32 nSubNodeCount = aSubNodeNames.getLength();
1042 
1043 				for(sal_Int32 j = 0; j <nSubNodeCount ; j++)
1044 				{
1045 					if(!xCont->hasByName(aSubNodeNames[j]))
1046 					{
1047 						Reference<XInterface> xInst = xFac->createInstance();
1048 						Any aVal; aVal <<= xInst;
1049 						xCont->insertByName(aSubNodeNames[j], aVal);
1050 					}
1051 					//set values
1052 				}
1053 				try
1054 				{
1055 					xBatch->commitChanges();
1056 				}
1057                 CATCH_INFO("Exception from commitChanges(): ")
1058 
1059 				const PropertyValue* pProperties = rValues.getConstArray();
1060 
1061 				Sequence< OUString > aSetNames(rValues.getLength());
1062 				OUString* pSetNames = aSetNames.getArray();
1063 
1064 				Sequence< Any> aSetValues(rValues.getLength());
1065 				Any* pSetValues = aSetValues.getArray();
1066 
1067 				sal_Bool bEmptyNode = rNode.getLength() == 0;
1068 				for(sal_Int32 k = 0; k < rValues.getLength(); k++)
1069 				{
1070 					pSetNames[k] =  pProperties[k].Name.copy( bEmptyNode ? 1 : 0);
1071 					pSetValues[k] = pProperties[k].Value;
1072 				}
1073 				bRet = PutProperties(aSetNames, aSetValues);
1074 			}
1075 			else
1076 			{
1077 				//if no factory is available then the node contains basic data elements
1078 				const PropertyValue* pValues = rValues.getConstArray();
1079 				for(int nValue = 0; nValue < rValues.getLength();nValue++)
1080 				{
1081 					try
1082 					{
1083 						OUString sSubNode = lcl_extractSetPropertyName( pValues[nValue].Name, rNode );
1084 
1085                         if(xCont->hasByName(sSubNode))
1086 							xCont->replaceByName(sSubNode, pValues[nValue].Value);
1087 						else
1088 							xCont->insertByName(sSubNode, pValues[nValue].Value);
1089 
1090 						OSL_ENSURE( xHierarchyAccess->hasByHierarchicalName(pValues[nValue].Name),
1091 							"Invalid config path" );
1092 					}
1093                     CATCH_INFO("Exception form insert/replaceByName(): ")
1094 				}
1095 				xBatch->commitChanges();
1096 			}
1097 		}
1098 #ifdef DBG_UTIL
1099         catch(Exception& rEx)
1100 		{
1101             lcl_CFG_DBG_EXCEPTION("Exception from SetSetProperties: ", rEx);
1102 #else
1103         catch(Exception&)
1104 		{
1105 #endif
1106 			bRet = sal_False;
1107 		}
1108     }
1109 	return bRet;
1110 }
1111 /* -----------------------------15.09.00 15:52--------------------------------
1112 
1113  ---------------------------------------------------------------------------*/
1114 sal_Bool ConfigItem::ReplaceSetProperties(
1115 	const OUString& rNode, Sequence< PropertyValue > rValues)
1116 {
1117 	ValueCounter_Impl aCounter(pImpl->nInValueChange);
1118     sal_Bool bRet = sal_True;
1119     Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
1120     if(xHierarchyAccess.is())
1121 	{
1122 		Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
1123 		try
1124 		{
1125 			Reference<XNameContainer> xCont;
1126 			if(rNode.getLength())
1127 			{
1128 				Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
1129 				aNode >>= xCont;
1130 			}
1131 			else
1132 				xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
1133 			if(!xCont.is())
1134 				return sal_False;
1135 
1136             // JB: Change: now the same name handling for sets of simple values
1137 			const Sequence< OUString > aSubNodeNames = lcl_extractSetPropertyNames(rValues, rNode);
1138 			const OUString* pSubNodeNames = aSubNodeNames.getConstArray();
1139             const sal_Int32 nSubNodeCount = aSubNodeNames.getLength();
1140 
1141 			Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);
1142             const bool isSimpleValueSet = !xFac.is();
1143 
1144 		    //remove unknown members first
1145             {
1146 				const Sequence<OUString> aContainerSubNodes = xCont->getElementNames();
1147 				const OUString* pContainerSubNodes = aContainerSubNodes.getConstArray();
1148 
1149 				for(sal_Int32 nContSub = 0; nContSub < aContainerSubNodes.getLength(); nContSub++)
1150 				{
1151 					sal_Bool bFound = sal_False;
1152 					for(sal_Int32 j = 0; j < nSubNodeCount; j++)
1153                     {
1154 						if(pSubNodeNames[j] == pContainerSubNodes[nContSub])
1155 						{
1156 							bFound = sal_True;
1157 							break;
1158 						}
1159                     }
1160 					if(!bFound)
1161                     try
1162 					{
1163 						xCont->removeByName(pContainerSubNodes[nContSub]);
1164 					}
1165                     catch (Exception & )
1166                     {
1167                         if (isSimpleValueSet)
1168                         try
1169                         {
1170                             // #i37322#: fallback action: replace with <void/>
1171                             xCont->replaceByName(pContainerSubNodes[nContSub], Any());
1172                             // fallback successfull: continue looping
1173                             continue;
1174                         }
1175                         catch (Exception &)
1176                         {} // propagate original exception, if fallback fails
1177 
1178                         throw;
1179                     }
1180 				}
1181 				try { xBatch->commitChanges(); }
1182                 CATCH_INFO("Exception from commitChanges(): ")
1183             }
1184 
1185 			if(xFac.is()) // !isSimpleValueSet
1186 			{
1187 				for(sal_Int32 j = 0; j < nSubNodeCount; j++)
1188 				{
1189 					if(!xCont->hasByName(pSubNodeNames[j]))
1190 					{
1191 						//create if not available
1192 						Reference<XInterface> xInst = xFac->createInstance();
1193 						Any aVal; aVal <<= xInst;
1194 						xCont->insertByName(pSubNodeNames[j], aVal);
1195 					}
1196 				}
1197 				try	{ xBatch->commitChanges(); }
1198                 CATCH_INFO("Exception from commitChanges(): ")
1199 
1200 				const PropertyValue* pProperties = rValues.getConstArray();
1201 
1202 				Sequence< OUString > aSetNames(rValues.getLength());
1203 				OUString* pSetNames = aSetNames.getArray();
1204 
1205 				Sequence< Any> aSetValues(rValues.getLength());
1206 				Any* pSetValues = aSetValues.getArray();
1207 
1208                 sal_Bool bEmptyNode = rNode.getLength() == 0;
1209                 for(sal_Int32 k = 0; k < rValues.getLength(); k++)
1210 				{
1211                     pSetNames[k] =  pProperties[k].Name.copy( bEmptyNode ? 1 : 0);
1212 					pSetValues[k] = pProperties[k].Value;
1213 				}
1214 				bRet = PutProperties(aSetNames, aSetValues);
1215 			}
1216 			else
1217 			{
1218 				const PropertyValue* pValues = rValues.getConstArray();
1219 
1220 				//if no factory is available then the node contains basic data elements
1221 				for(int nValue = 0; nValue < rValues.getLength();nValue++)
1222 				{
1223 					try
1224 					{
1225 						OUString sSubNode = lcl_extractSetPropertyName( pValues[nValue].Name, rNode );
1226 
1227                         if(xCont->hasByName(sSubNode))
1228 							xCont->replaceByName(sSubNode, pValues[nValue].Value);
1229 						else
1230 							xCont->insertByName(sSubNode, pValues[nValue].Value);
1231 					}
1232                     CATCH_INFO("Exception from insert/replaceByName(): ");
1233                 }
1234 				xBatch->commitChanges();
1235 			}
1236 		}
1237 #ifdef DBG_UTIL
1238         catch(Exception& rEx)
1239 		{
1240             lcl_CFG_DBG_EXCEPTION("Exception from ReplaceSetProperties: ", rEx);
1241 #else
1242         catch(Exception&)
1243 		{
1244 #endif
1245 			bRet = sal_False;
1246 		}
1247     }
1248 	return bRet;
1249 }
1250 /* -----------------------------07.05.01 12:15--------------------------------
1251 
1252  ---------------------------------------------------------------------------*/
1253 sal_Bool ConfigItem::getUniqueSetElementName( const ::rtl::OUString& _rSetNode, ::rtl::OUString& _rName)
1254 {
1255 	::rtl::OUString sNewElementName;
1256     Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
1257     sal_Bool bRet = sal_False;
1258     if(xHierarchyAccess.is())
1259     {
1260         try
1261         {
1262             Reference< XNameAccess > xSetNode;
1263             xHierarchyAccess->getByHierarchicalName(_rSetNode) >>= xSetNode;
1264             if (xSetNode.is())
1265             {
1266                 const sal_uInt32 nPrime = 65521;                            // a prime number
1267                 const sal_uInt32 nPrimeLess2 = nPrime - 2;
1268                 sal_uInt32 nEngendering     = (rand() % nPrimeLess2) + 2;   // the engendering of the field
1269 
1270                 // the element which will loop through the field
1271                 sal_uInt32 nFieldElement = nEngendering;
1272 
1273                 for (; 1 != nFieldElement; nFieldElement = (nFieldElement * nEngendering) % nPrime)
1274                 {
1275                     ::rtl::OUString sThisRoundTrial = _rName;
1276                     sThisRoundTrial += ::rtl::OUString::valueOf((sal_Int32)nFieldElement);
1277 
1278                     if (!xSetNode->hasByName(sThisRoundTrial))
1279                     {
1280                         _rName = sThisRoundTrial;
1281                         bRet =  sal_True;
1282 						break;
1283                     }
1284                 }
1285             }
1286         }
1287         CATCH_INFO("Exception from getUniqueSetElementName(): ")
1288     }
1289     return bRet;
1290 }
1291 /* -----------------------------23.01.01 12:49--------------------------------
1292 
1293  ---------------------------------------------------------------------------*/
1294 sal_Bool ConfigItem::AddNode(const rtl::OUString& rNode, const rtl::OUString& rNewNode)
1295 {
1296 	ValueCounter_Impl aCounter(pImpl->nInValueChange);
1297     sal_Bool bRet = sal_True;
1298     Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
1299     if(xHierarchyAccess.is())
1300 	{
1301 		Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
1302 		try
1303 		{
1304 			Reference<XNameContainer> xCont;
1305 			if(rNode.getLength())
1306 			{
1307 				Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
1308 				aNode >>= xCont;
1309 			}
1310 			else
1311 				xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
1312 			if(!xCont.is())
1313 				return sal_False;
1314 
1315 			Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);
1316 
1317             if(xFac.is())
1318 			{
1319 				if(!xCont->hasByName(rNewNode))
1320 				{
1321 					Reference<XInterface> xInst = xFac->createInstance();
1322 					Any aVal; aVal <<= xInst;
1323 					xCont->insertByName(rNewNode, aVal);
1324 				}
1325 				try
1326 				{
1327 					xBatch->commitChanges();
1328 				}
1329                 CATCH_INFO("Exception from commitChanges(): ")
1330 			}
1331 			else
1332 			{
1333 				//if no factory is available then the node contains basic data elements
1334 				try
1335 				{
1336 					if(!xCont->hasByName(rNewNode))
1337 						xCont->insertByName(rNewNode, Any());
1338 				}
1339                 CATCH_INFO("Exception from AddNode(): ")
1340 			}
1341 			xBatch->commitChanges();
1342 		}
1343 #ifdef DBG_UTIL
1344         catch(Exception& rEx)
1345 		{
1346             lcl_CFG_DBG_EXCEPTION("Exception from AddNode(): ", rEx);
1347 #else
1348         catch(Exception&)
1349 		{
1350 #endif
1351 			bRet = sal_False;
1352 		}
1353 	}
1354 	return bRet;
1355 }
1356 /* -----------------------------12.02.01 11:38--------------------------------
1357 
1358  ---------------------------------------------------------------------------*/
1359 sal_Int16 	ConfigItem::GetMode() const
1360 {
1361 	return pImpl->nMode;
1362 }
1363 /* -----------------------------12.02.01 13:31--------------------------------
1364 
1365  ---------------------------------------------------------------------------*/
1366 void 	ConfigItem::SetModified()
1367 {
1368 	pImpl->bIsModified = sal_True;
1369 }
1370 /* -----------------------------05.05.01 14:07--------------------------------
1371 
1372  ---------------------------------------------------------------------------*/
1373 void    ConfigItem::ClearModified()
1374 {
1375     pImpl->bIsModified = sal_False;
1376 }
1377 /* -----------------------------12.02.01 13:31--------------------------------
1378 
1379  ---------------------------------------------------------------------------*/
1380 sal_Bool ConfigItem::IsModified() const
1381 {
1382 	return pImpl->bIsModified;
1383 }
1384 /* -----------------------------12.02.01 13:33--------------------------------
1385 
1386  ---------------------------------------------------------------------------*/
1387 sal_Bool ConfigItem::IsInValueChange() const
1388 {
1389 	return pImpl->nInValueChange > 0;
1390 }
1391 /* -----------------------------21.06.01 12:26--------------------------------
1392 
1393  ---------------------------------------------------------------------------*/
1394 Reference< XHierarchicalNameAccess> ConfigItem::GetTree()
1395 {
1396     Reference< XHierarchicalNameAccess> xRet;
1397     if(!m_xHierarchyAccess.is())
1398         xRet = pImpl->pManager->AcquireTree(*this);
1399     else
1400         xRet = m_xHierarchyAccess;
1401     OSL_ENSURE(xRet.is(), "AcquireTree failed");
1402     return xRet;
1403 }
1404 /* -----------------------------22.06.01 08:42--------------------------------
1405 
1406  ---------------------------------------------------------------------------*/
1407 void ConfigItem::LockTree()
1408 {
1409     OSL_ENSURE(0 != (pImpl->nMode&CONFIG_MODE_RELEASE_TREE), "call LockTree in CONFIG_MODE_RELEASE_TREE mode, only");
1410     m_xHierarchyAccess = GetTree();
1411 }
1412 /* -----------------------------22.06.01 08:42--------------------------------
1413 
1414  ---------------------------------------------------------------------------*/
1415 void ConfigItem::UnlockTree()
1416 {
1417     OSL_ENSURE(0 != (pImpl->nMode&CONFIG_MODE_RELEASE_TREE), "call UnlockTree in CONFIG_MODE_RELEASE_TREE mode, only");
1418     if(0 != (pImpl->nMode&CONFIG_MODE_RELEASE_TREE))
1419         m_xHierarchyAccess = 0;
1420 }
1421 
1422 
1423