xref: /AOO41X/main/unotools/source/config/configitem.cxx (revision b5088357f810cb81479bbbd0e021cd3c9835ca0d)
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
lcl_CFG_DBG_EXCEPTION(const sal_Char * cText,const Exception & rEx)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;
ConfigItem_Implutl::ConfigItem_Impl115     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:
ValueCounter_Impl(sal_Int16 & rCounter)131     ValueCounter_Impl(sal_Int16& rCounter):
132         rCnt(rCounter)
133             {rCnt++;}
~ValueCounter_Impl()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:
AutoDeleter(TYP * pItem)151         AutoDeleter(TYP * pItem)
152         : m_pItem(pItem)
153         {
154         }
155 
~AutoDeleter()156         ~AutoDeleter()
157         {
158             delete m_pItem;
159         }
160 
keep()161         void keep() { m_pItem = 0; }
162     };
163 }
164 /* -----------------------------29.08.00 16:34--------------------------------
165 
166  ---------------------------------------------------------------------------*/
ConfigChangeListener_Impl(ConfigItem & rItem,const Sequence<OUString> & rNames)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  ---------------------------------------------------------------------------*/
~ConfigChangeListener_Impl()176 ConfigChangeListener_Impl::~ConfigChangeListener_Impl()
177 {
178 }
179 /* -----------------------------29.08.00 16:34--------------------------------
180 
181  ---------------------------------------------------------------------------*/
lcl_Find(const rtl::OUString & rTemp,const OUString * pCheckPropertyNames,sal_Int32 nLength)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 //-----------------------------------------------------------------------------
changesOccurred(const ChangesEvent & rEvent)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  ---------------------------------------------------------------------------*/
disposing(const EventObject &)226 void ConfigChangeListener_Impl::disposing( const EventObject& /*rSource*/ ) throw(RuntimeException)
227 {
228     pParent->RemoveChangesListener();
229 }
230 /* -----------------------------29.08.00 12:50--------------------------------
231 
232  ---------------------------------------------------------------------------*/
ConfigItem(const OUString rSubTree,sal_Int16 nSetMode)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  ---------------------------------------------------------------------------*/
ConfigItem(utl::ConfigManager & rManager,const rtl::OUString rSubTree)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 -----------------------------------------------
IsValidConfigMgr() const263 sal_Bool ConfigItem::IsValidConfigMgr() const
264 {
265     return ( pImpl->pManager && pImpl->pManager->GetConfigurationProvider().is() );
266 }
267 
268 /* -----------------------------29.08.00 12:52--------------------------------
269 
270  ---------------------------------------------------------------------------*/
~ConfigItem()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  ---------------------------------------------------------------------------*/
ReleaseConfigMgr()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  ---------------------------------------------------------------------------*/
CallNotify(const com::sun::star::uno::Sequence<OUString> & rPropertyNames)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  ---------------------------------------------------------------------------*/
lcl_IsLocalProperty(const OUString & rSubTree,const OUString & rProperty)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  ---------------------------------------------------------------------------*/
impl_packLocalizedProperties(const Sequence<OUString> & lInNames,const Sequence<Any> & lInValues,Sequence<Any> & lOutValues)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  ---------------------------------------------------------------------------*/
impl_unpackLocalizedProperties(const Sequence<OUString> & lInNames,const Sequence<Any> & lInValues,Sequence<OUString> & lOutNames,Sequence<Any> & lOutValues)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  ---------------------------------------------------------------------------*/
GetReadOnlyStates(const com::sun::star::uno::Sequence<rtl::OUString> & rNames)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 shure to return a valid information everytime!
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  ---------------------------------------------------------------------------*/
GetProperties(const Sequence<OUString> & rNames)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  ---------------------------------------------------------------------------*/
PutProperties(const Sequence<OUString> & rNames,const Sequence<Any> & rValues)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  ---------------------------------------------------------------------------*/
DisableNotification()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  ---------------------------------------------------------------------------*/
EnableNotification(const Sequence<OUString> & rNames,sal_Bool bEnableInternalNotification)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  ---------------------------------------------------------------------------*/
RemoveChangesListener()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  ---------------------------------------------------------------------------*/
lcl_normalizeLocalNames(Sequence<OUString> & _rNames,ConfigNameFormat _eFormat,Reference<XInterface> const & _xParentNode)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 pathes: missing interface");
803         // make local pathes 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  ---------------------------------------------------------------------------*/
GetNodeNames(const OUString & rNode)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  ---------------------------------------------------------------------------*/
GetNodeNames(const OUString & rNode,ConfigNameFormat eFormat)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  ---------------------------------------------------------------------------*/
ClearNodeSet(const OUString & rNode)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  ---------------------------------------------------------------------------*/
ClearNodeElements(const OUString & rNode,Sequence<OUString> & rElements)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
lcl_extractSetPropertyName(const OUString & rInPath,const OUString & rPrefix)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
lcl_extractSetPropertyNames(const Sequence<PropertyValue> & rValues,const OUString & rPrefix)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  ---------------------------------------------------------------------------*/
SetSetProperties(const OUString & rNode,Sequence<PropertyValue> rValues)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 successfull: 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