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