xref: /trunk/main/framework/source/services/pathsettings.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_framework.hxx"
24 // ______________________________________________
25 // my own includes
26 
27 /** Attention: stl headers must(!) be included at first. Otherwise it can make trouble
28                with solaris headers ...
29 */
30 #include <vector>
31 #include <services/pathsettings.hxx>
32 #include <threadhelp/readguard.hxx>
33 #include <threadhelp/writeguard.hxx>
34 #include <services.h>
35 
36 // ______________________________________________
37 // interface includes
38 #include <com/sun/star/beans/Property.hpp>
39 #include <com/sun/star/beans/XProperty.hpp>
40 #include <com/sun/star/beans/PropertyAttribute.hpp>
41 #include <com/sun/star/container/XContainer.hpp>
42 #include <com/sun/star/beans/XPropertySet.hpp>
43 #include <com/sun/star/util/XChangesNotifier.hpp>
44 
45 // ______________________________________________
46 // includes of other projects
47 #include <tools/urlobj.hxx>
48 #include <rtl/ustrbuf.hxx>
49 #include <rtl/logfile.hxx>
50 
51 #include <comphelper/configurationhelper.hxx>
52 #include <unotools/configpathes.hxx>
53 
54 #include <fwkdllapi.h>
55 
56 // ______________________________________________
57 //  non exported const
58 
59 #define CFG_READONLY_DEFAULT    sal_False
60 
61 const ::rtl::OUString CFGPROP_INTERNALPATHES = ::rtl::OUString::createFromAscii("InternalPaths");
62 const ::rtl::OUString CFGPROP_USERPATHES     = ::rtl::OUString::createFromAscii("UserPaths"    );
63 const ::rtl::OUString CFGPROP_WRITEPATH      = ::rtl::OUString::createFromAscii("WritePath"    );
64 const ::rtl::OUString CFGPROP_ISSINGLEPATH   = ::rtl::OUString::createFromAscii("IsSinglePath" );
65 
66 /*
67     0 : old style              "Template"              string using ";" as seperator
68     1 : internal paths         "Template_internal"     string list
69     2 : user paths             "Template_user"         string list
70     3 : write path             "Template_write"        string
71  */
72 
73 const ::rtl::OUString POSTFIX_INTERNAL_PATHES = ::rtl::OUString::createFromAscii("_internal");
74 const ::rtl::OUString POSTFIX_USER_PATHES     = ::rtl::OUString::createFromAscii("_user"    );
75 const ::rtl::OUString POSTFIX_WRITE_PATH      = ::rtl::OUString::createFromAscii("_writable");
76 
77 const sal_Int32 IDGROUP_OLDSTYLE        = 0;
78 const sal_Int32 IDGROUP_INTERNAL_PATHES = 1;
79 const sal_Int32 IDGROUP_USER_PATHES     = 2;
80 const sal_Int32 IDGROUP_WRITE_PATH      = 3;
81 
82 const sal_Int32 IDGROUP_COUNT           = 4;
83 
impl_getPropGroup(sal_Int32 nID)84 sal_Int32 impl_getPropGroup(sal_Int32 nID)
85 {
86     return (nID % IDGROUP_COUNT);
87 }
88 
89 // ______________________________________________
90 //  namespace
91 
92 namespace framework
93 {
94 
95 //-----------------------------------------------------------------------------
96 // XInterface, XTypeProvider, XServiceInfo
97 
DEFINE_XINTERFACE_7(PathSettings,OWeakObject,DIRECT_INTERFACE (css::lang::XTypeProvider),DIRECT_INTERFACE (css::lang::XServiceInfo),DERIVED_INTERFACE (css::lang::XEventListener,css::util::XChangesListener),DIRECT_INTERFACE (css::util::XChangesListener),DIRECT_INTERFACE (css::beans::XPropertySet),DIRECT_INTERFACE (css::beans::XFastPropertySet),DIRECT_INTERFACE (css::beans::XMultiPropertySet))98 DEFINE_XINTERFACE_7                     (   PathSettings                                             ,
99                                             OWeakObject                                              ,
100                                             DIRECT_INTERFACE ( css::lang::XTypeProvider              ),
101                                             DIRECT_INTERFACE ( css::lang::XServiceInfo               ),
102                                             DERIVED_INTERFACE( css::lang::XEventListener, css::util::XChangesListener),
103                                             DIRECT_INTERFACE ( css::util::XChangesListener           ),
104                                             DIRECT_INTERFACE ( css::beans::XPropertySet              ),
105                                             DIRECT_INTERFACE ( css::beans::XFastPropertySet          ),
106                                             DIRECT_INTERFACE ( css::beans::XMultiPropertySet        )
107                                         )
108 
109 DEFINE_XTYPEPROVIDER_7                  (   PathSettings                                            ,
110                                             css::lang::XTypeProvider                                ,
111                                             css::lang::XServiceInfo                                 ,
112                                             css::lang::XEventListener                               ,
113                                             css::util::XChangesListener                             ,
114                                             css::beans::XPropertySet                                ,
115                                             css::beans::XFastPropertySet                            ,
116                                             css::beans::XMultiPropertySet
117                                         )
118 
119 DEFINE_XSERVICEINFO_ONEINSTANCESERVICE  (   PathSettings                                            ,
120                                             ::cppu::OWeakObject                                     ,
121                                             SERVICENAME_PATHSETTINGS                                ,
122                                             IMPLEMENTATIONNAME_PATHSETTINGS
123                                         )
124 
125 DEFINE_INIT_SERVICE                     (   PathSettings,
126                                             {
127                                                 /*Attention
128                                                     I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
129                                                     to create a new instance of this class by our own supported service factory.
130                                                     see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further information!
131                                                 */
132 
133                                                 // fill cache
134                                                 impl_readAll();
135                                             }
136                                         )
137 
138 //-----------------------------------------------------------------------------
139 PathSettings::PathSettings( const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR )
140     //  Init baseclasses first
141     //  Attention: Don't change order of initialization!
142     //      ThreadHelpBase is a struct with a lock as member. We can't use a lock as direct member!
143     //      We must garant right initialization and a valid value of this to initialize other baseclasses!
144     :   ThreadHelpBase()
145     ,   ::cppu::OBroadcastHelperVar< ::cppu::OMultiTypeInterfaceContainerHelper, ::cppu::OMultiTypeInterfaceContainerHelper::keyType >(m_aLock.getShareableOslMutex())
146     ,   ::cppu::OPropertySetHelper(*(static_cast< ::cppu::OBroadcastHelper* >(this)))
147     ,   ::cppu::OWeakObject()
148     // Init member
149     ,   m_xSMGR    (xSMGR)
150     ,   m_pPropHelp(0    )
151     ,  m_bIgnoreEvents(sal_False)
152 {
153     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::PathSettings" );
154 }
155 
156 //-----------------------------------------------------------------------------
~PathSettings()157 PathSettings::~PathSettings()
158 {
159     if (m_pPropHelp)
160        delete m_pPropHelp;
161 }
162 
163 //-----------------------------------------------------------------------------
changesOccurred(const css::util::ChangesEvent & aEvent)164 void SAL_CALL PathSettings::changesOccurred(const css::util::ChangesEvent& aEvent)
165 {
166     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::changesOccurred" );
167     /*
168     if (m_bIgnoreEvents)
169         return;
170     */
171 
172     sal_Int32 c                 = aEvent.Changes.getLength();
173     sal_Int32 i                 = 0;
174     sal_Bool  bUpdateDescriptor = sal_False;
175 
176     for (i=0; i<c; ++i)
177     {
178         const css::util::ElementChange& aChange = aEvent.Changes[i];
179 
180         ::rtl::OUString sChanged;
181         aChange.Accessor >>= sChanged;
182 
183         ::rtl::OUString sPath = ::utl::extractFirstFromConfigurationPath(sChanged);
184         if (sPath.getLength())
185         {
186             PathSettings::EChangeOp eOp = impl_updatePath(sPath, sal_True);
187             if (
188                 (eOp == PathSettings::E_ADDED  ) ||
189                 (eOp == PathSettings::E_REMOVED)
190                )
191                 bUpdateDescriptor = sal_True;
192         }
193     }
194 
195     if (bUpdateDescriptor)
196         impl_rebuildPropertyDescriptor();
197 }
198 
199 //-----------------------------------------------------------------------------
disposing(const css::lang::EventObject & aSource)200 void SAL_CALL PathSettings::disposing(const css::lang::EventObject& aSource)
201 {
202     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::disposing" );
203     // SAFE ->
204     WriteGuard aWriteLock(m_aLock);
205 
206     if (aSource.Source == m_xCfgNew)
207         m_xCfgNew.clear();
208 
209     aWriteLock.unlock();
210     // <- SAFE
211 }
212 
213 //-----------------------------------------------------------------------------
impl_readAll()214 void PathSettings::impl_readAll()
215 {
216     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::impl_readAll" );
217     RTL_LOGFILE_CONTEXT(aLog, "framework (as96863) ::PathSettings::load config (all)");
218 
219     // TODO think about me
220     css::uno::Reference< css::container::XNameAccess > xCfg    = fa_getCfgNew();
221     css::uno::Sequence< ::rtl::OUString >              lPaths = xCfg->getElementNames();
222 
223     sal_Int32 c = lPaths.getLength();
224     sal_Int32 i = 0;
225 
226     for (i=0; i<c; ++i)
227     {
228         const ::rtl::OUString& sPath = lPaths[i];
229         impl_updatePath(sPath, sal_False);
230     }
231 
232     impl_rebuildPropertyDescriptor();
233 }
234 
235 //-----------------------------------------------------------------------------
236 // NO substitution here ! It's done outside ...
impl_readOldFormat(const::rtl::OUString & sPath)237 OUStringList PathSettings::impl_readOldFormat(const ::rtl::OUString& sPath)
238 {
239     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::impl_readOldFormat" );
240     css::uno::Reference< css::container::XNameAccess > xCfg( fa_getCfgOld() );
241     OUStringList aPathVal;
242 
243     if( xCfg->hasByName(sPath) )
244     {
245         css::uno::Any aVal( xCfg->getByName(sPath) );
246 
247         ::rtl::OUString                       sStringVal;
248         css::uno::Sequence< ::rtl::OUString > lStringListVal;
249 
250         if (aVal >>= sStringVal)
251         {
252             aPathVal.push_back(sStringVal);
253         }
254         else if (aVal >>= lStringListVal)
255         {
256             aPathVal << lStringListVal;
257         }
258     }
259 
260     return aPathVal;
261 }
262 
263 //-----------------------------------------------------------------------------
264 // NO substitution here ! It's done outside ...
impl_readNewFormat(const::rtl::OUString & sPath)265 PathSettings::PathInfo PathSettings::impl_readNewFormat(const ::rtl::OUString& sPath)
266 {
267     css::uno::Reference< css::container::XNameAccess > xCfg = fa_getCfgNew();
268 
269     // get access to the "queried" path
270     css::uno::Reference< css::container::XNameAccess > xPath;
271     xCfg->getByName(sPath) >>= xPath;
272 
273     PathSettings::PathInfo aPathVal;
274 
275     // read internal path list
276     css::uno::Reference< css::container::XNameAccess > xIPath;
277     xPath->getByName(CFGPROP_INTERNALPATHES) >>= xIPath;
278     aPathVal.lInternalPaths << xIPath->getElementNames();
279 
280     // read user defined path list
281     aPathVal.lUserPaths << xPath->getByName(CFGPROP_USERPATHES);
282 
283     // read the writeable path
284     xPath->getByName(CFGPROP_WRITEPATH) >>= aPathVal.sWritePath;
285 
286     // read state props
287     xPath->getByName(CFGPROP_ISSINGLEPATH) >>= aPathVal.bIsSinglePath;
288 
289     // analyze finalized/mandatory states
290     aPathVal.bIsReadonly = sal_False;
291     css::uno::Reference< css::beans::XProperty > xInfo(xPath, css::uno::UNO_QUERY);
292     if (xInfo.is())
293     {
294         css::beans::Property aInfo = xInfo->getAsProperty();
295         sal_Bool bFinalized = ((aInfo.Attributes & css::beans::PropertyAttribute::READONLY ) == css::beans::PropertyAttribute::READONLY );
296         //sal_Bool bMandatory = ((aInfo.Attributes & css::beans::PropertyAttribute::REMOVEABLE) != css::beans::PropertyAttribute::REMOVEABLE);
297 
298         // Note: Till we support finalized / mandatory on our API more in detail we handle
299         // all states simple as READONLY ! But because all really needed paths are "mandatory" by default
300         // we have to handle "finalized" as the real "readonly" indicator .
301         aPathVal.bIsReadonly = bFinalized;
302     }
303 
304     return aPathVal;
305 }
306 
307 //-----------------------------------------------------------------------------
impl_storePath(const PathSettings::PathInfo & aPath)308 void PathSettings::impl_storePath(const PathSettings::PathInfo& aPath)
309 {
310     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::impl_storePath" );
311     m_bIgnoreEvents = sal_True;
312 
313     css::uno::Reference< css::container::XNameAccess > xCfgNew = fa_getCfgNew();
314     css::uno::Reference< css::container::XNameAccess > xCfgOld = fa_getCfgOld();
315 
316     // try to replace path-parts with well known and supported variables.
317     // So an office can be moved easily to another location without losing
318     // its related paths.
319     PathInfo aResubstPath(aPath);
320     impl_subst(aResubstPath, sal_True);
321 
322     // update new configuration
323     if (! aResubstPath.bIsSinglePath)
324     {
325         ::comphelper::ConfigurationHelper::writeRelativeKey(xCfgNew,
326                                                             aResubstPath.sPathName,
327                                                             CFGPROP_USERPATHES,
328                                                             css::uno::makeAny(aResubstPath.lUserPaths.getAsConstList()));
329     }
330 
331     ::comphelper::ConfigurationHelper::writeRelativeKey(xCfgNew,
332                                                         aResubstPath.sPathName,
333                                                         CFGPROP_WRITEPATH,
334                                                         css::uno::makeAny(aResubstPath.sWritePath));
335 
336     ::comphelper::ConfigurationHelper::flush(xCfgNew);
337 
338     // remove the whole path from the old configuration !
339     // Otherwise we can't make sure that the diff between new and old configuration
340     // on loading time really represent an user setting !!!
341 
342     // Check if the given path exists inside the old configuration.
343     // Because our new configuration knows more then the list of old paths ... !
344     if (xCfgOld->hasByName(aResubstPath.sPathName))
345     {
346         css::uno::Reference< css::beans::XPropertySet > xProps(xCfgOld, css::uno::UNO_QUERY_THROW);
347         xProps->setPropertyValue(aResubstPath.sPathName, css::uno::Any());
348         ::comphelper::ConfigurationHelper::flush(xCfgOld);
349     }
350 
351     m_bIgnoreEvents = sal_False;
352 }
353 
354 //-----------------------------------------------------------------------------
355 #ifdef MIGRATE_OLD_USER_PATHES
impl_mergeOldUserPaths(PathSettings::PathInfo & rPath,const OUStringList & lOld)356 void PathSettings::impl_mergeOldUserPaths(      PathSettings::PathInfo& rPath,
357                                           const OUStringList&           lOld )
358 {
359     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "PathSettings::impl_mergeOldUserPaths" );
360     OUStringList::const_iterator pIt;
361     for (  pIt  = lOld.begin();
362            pIt != lOld.end()  ;
363          ++pIt                )
364     {
365         const ::rtl::OUString& sOld = *pIt;
366 
367         if (rPath.bIsSinglePath)
368         {
369             LOG_ASSERT2(lOld.size()>1, "PathSettings::impl_mergeOldUserPaths()", "Single path has more then one path value inside old configuration (Common.xcu)!")
370             if (! rPath.sWritePath.equals(sOld))
371                rPath.sWritePath = sOld;
372         }
373         else
374         {
375             if (
376                 (  rPath.lInternalPaths.findConst(sOld) == rPath.lInternalPaths.end()) &&
377                 (  rPath.lUserPaths.findConst(sOld)     == rPath.lUserPaths.end()    ) &&
378                 (! rPath.sWritePath.equals(sOld)                                     )
379                )
380                rPath.lUserPaths.push_back(sOld);
381         }
382     }
383 }
384 #endif // MIGRATE_OLD_USER_PATHES
385 
386 //-----------------------------------------------------------------------------
impl_updatePath(const::rtl::OUString & sPath,sal_Bool bNotifyListener)387 PathSettings::EChangeOp PathSettings::impl_updatePath(const ::rtl::OUString& sPath          ,
388                                                             sal_Bool         bNotifyListener)
389 {
390     // SAFE ->
391     WriteGuard aWriteLock(m_aLock);
392 
393     PathSettings::PathInfo* pPathOld = 0;
394     PathSettings::PathInfo* pPathNew = 0;
395     PathSettings::EChangeOp eOp      = PathSettings::E_UNDEFINED;
396     PathSettings::PathInfo  aPath;
397 
398     try
399     {
400         aPath = impl_readNewFormat(sPath);
401         aPath.sPathName = sPath;
402         // replace all might existing variables with real values
403         // Do it before these old paths will be compared against the
404         // new path configuration. Otherwise some strings uses different variables ... but substitution
405         // will produce strings with same content (because some variables are redundant!)
406         impl_subst(aPath, sal_False);
407     }
408     catch(const css::uno::RuntimeException& exRun)
409         { throw exRun; }
410     catch(const css::container::NoSuchElementException&)
411         { eOp = PathSettings::E_REMOVED; }
412     catch(const css::uno::Exception& exAny)
413         { throw exAny; }
414 
415     #ifdef MIGRATE_OLD_USER_PATHES
416     try
417     {
418         // migration of old user defined values on demand
419         // can be disabled for a new major
420         OUStringList lOldVals = impl_readOldFormat(sPath);
421         // replace all might existing variables with real values
422         // Do it before these old paths will be compared against the
423         // new path configuration. Otherwise some strings uses different variables ... but substitution
424         // will produce strings with same content (because some variables are redundant!)
425         impl_subst(lOldVals, fa_getSubstitution(), sal_False);
426         impl_mergeOldUserPaths(aPath, lOldVals);
427     }
428     catch(const css::uno::RuntimeException& exRun)
429         { throw exRun; }
430     // Normal(!) exceptions can be ignored!
431     // E.g. in case an addon installs a new path, which was not well known for an OOo 1.x installation
432     // we can't find a value for it inside the "old" configuration. So a NoSuchElementException
433     // will be normal .-)
434     catch(const css::uno::Exception&)
435         {}
436     #endif // MIGRATE_OLD_USER_PATHES
437 
438     PathSettings::PathHash::iterator pPath = m_lPaths.find(sPath);
439     if (eOp == PathSettings::E_UNDEFINED)
440     {
441         if (pPath != m_lPaths.end())
442             eOp = PathSettings::E_CHANGED;
443         else
444             eOp = PathSettings::E_ADDED;
445     }
446 
447     switch(eOp)
448     {
449         case PathSettings::E_ADDED :
450              {
451                 if (bNotifyListener)
452                 {
453                     pPathOld = 0;
454                     pPathNew = &aPath;
455                     impl_notifyPropListener(eOp, sPath, pPathOld, pPathNew);
456                 }
457                 m_lPaths[sPath] = aPath;
458              }
459              break;
460 
461         case PathSettings::E_CHANGED :
462              {
463                 if (bNotifyListener)
464                 {
465                     pPathOld = &(pPath->second);
466                     pPathNew = &aPath;
467                     impl_notifyPropListener(eOp, sPath, pPathOld, pPathNew);
468                 }
469                 m_lPaths[sPath] = aPath;
470              }
471              break;
472 
473         case PathSettings::E_REMOVED :
474              {
475                 if (pPath != m_lPaths.end())
476                 {
477                     if (bNotifyListener)
478                     {
479                         pPathOld = &(pPath->second);
480                         pPathNew = 0;
481                         impl_notifyPropListener(eOp, sPath, pPathOld, pPathNew);
482                     }
483                     m_lPaths.erase(pPath);
484                 }
485              }
486              break;
487 
488         default: // to let compiler be happy
489              break;
490     }
491 
492     return eOp;
493 }
494 
495 //-----------------------------------------------------------------------------
impl_mapPathName2IDList(const::rtl::OUString & sPath)496 css::uno::Sequence< sal_Int32 > PathSettings::impl_mapPathName2IDList(const ::rtl::OUString& sPath)
497 {
498     ::rtl::OUString sOldStyleProp = sPath;
499     ::rtl::OUString sInternalProp = sPath+POSTFIX_INTERNAL_PATHES;
500     ::rtl::OUString sUserProp     = sPath+POSTFIX_USER_PATHES;
501     ::rtl::OUString sWriteProp    = sPath+POSTFIX_WRITE_PATH;
502 
503     // Attention: The default set of IDs is fix and must follow these schema.
504     // Otherwise the outside code ant work for new added properties.
505     // Why ?
506     // The outside code must fire N events for every changed property.
507     // And the knowing about packaging of variables of the structure PathInfo
508     // follow these group IDs ! But if such ID isn't in the range of [0..IDGROUP_COUNT]
509     // the outside can't determine the right group ... and can't fire the right events .-)
510 
511     css::uno::Sequence< sal_Int32 > lIDs(IDGROUP_COUNT);
512     lIDs[0] = IDGROUP_OLDSTYLE       ;
513     lIDs[1] = IDGROUP_INTERNAL_PATHES;
514     lIDs[2] = IDGROUP_USER_PATHES    ;
515     lIDs[3] = IDGROUP_WRITE_PATH     ;
516 
517     sal_Int32 c = m_lPropDesc.getLength();
518     sal_Int32 i = 0;
519     for (i=0; i<c; ++i)
520     {
521         const css::beans::Property& rProp = m_lPropDesc[i];
522 
523         if (rProp.Name.equals(sOldStyleProp))
524             lIDs[IDGROUP_OLDSTYLE] = rProp.Handle;
525         else
526         if (rProp.Name.equals(sInternalProp))
527             lIDs[IDGROUP_INTERNAL_PATHES] = rProp.Handle;
528         else
529         if (rProp.Name.equals(sUserProp))
530             lIDs[IDGROUP_USER_PATHES] = rProp.Handle;
531         else
532         if (rProp.Name.equals(sWriteProp))
533             lIDs[IDGROUP_WRITE_PATH] = rProp.Handle;
534     }
535 
536     return lIDs;
537 }
538 
539 //-----------------------------------------------------------------------------
impl_notifyPropListener(PathSettings::EChangeOp,const::rtl::OUString & sPath,const PathSettings::PathInfo * pPathOld,const PathSettings::PathInfo * pPathNew)540 void PathSettings::impl_notifyPropListener(      PathSettings::EChangeOp /*eOp*/     ,
541                                            const ::rtl::OUString&        sPath   ,
542                                            const PathSettings::PathInfo* pPathOld,
543                                            const PathSettings::PathInfo* pPathNew)
544 {
545     css::uno::Sequence< sal_Int32 >     lHandles(1);
546     css::uno::Sequence< css::uno::Any > lOldVals(1);
547     css::uno::Sequence< css::uno::Any > lNewVals(1);
548 
549     css::uno::Sequence< sal_Int32 > lIDs   = impl_mapPathName2IDList(sPath);
550     sal_Int32                       c      = lIDs.getLength();
551     sal_Int32                       i      = 0;
552     sal_Int32                       nMaxID = m_lPropDesc.getLength()-1;
553     for (i=0; i<c; ++i)
554     {
555         sal_Int32 nID = lIDs[i];
556 
557         if (
558             (nID < 0     ) ||
559             (nID > nMaxID)
560            )
561            continue;
562 
563         lHandles[0] = nID;
564         switch(impl_getPropGroup(nID))
565         {
566             case IDGROUP_OLDSTYLE :
567                  {
568                     if (pPathOld)
569                     {
570                         ::rtl::OUString sVal = impl_convertPath2OldStyle(*pPathOld);
571                         lOldVals[0] <<= sVal;
572                     }
573                     if (pPathNew)
574                     {
575                         ::rtl::OUString sVal = impl_convertPath2OldStyle(*pPathNew);
576                         lNewVals[0] <<= sVal;
577                     }
578                  }
579                  break;
580 
581             case IDGROUP_INTERNAL_PATHES :
582                  {
583                     if (pPathOld)
584                         lOldVals[0] <<= pPathOld->lInternalPaths.getAsConstList();
585                     if (pPathNew)
586                         lNewVals[0] <<= pPathNew->lInternalPaths.getAsConstList();
587                  }
588                  break;
589 
590             case IDGROUP_USER_PATHES :
591                  {
592                     if (pPathOld)
593                         lOldVals[0] <<= pPathOld->lUserPaths.getAsConstList();
594                     if (pPathNew)
595                         lNewVals[0] <<= pPathNew->lUserPaths.getAsConstList();
596                  }
597                  break;
598 
599             case IDGROUP_WRITE_PATH :
600                  {
601                     if (pPathOld)
602                         lOldVals[0] <<= pPathOld->sWritePath;
603                     if (pPathNew)
604                         lNewVals[0] <<= pPathNew->sWritePath;
605                  }
606                  break;
607         }
608 
609         fire(lHandles.getArray(),
610              lNewVals.getArray(),
611              lOldVals.getArray(),
612              1,
613              sal_False);
614     }
615 }
616 
617 //-----------------------------------------------------------------------------
impl_subst(OUStringList & lVals,const css::uno::Reference<css::util::XStringSubstitution> & xSubst,sal_Bool bReSubst)618 void PathSettings::impl_subst(      OUStringList&                                          lVals   ,
619                               const css::uno::Reference< css::util::XStringSubstitution >& xSubst  ,
620                                     sal_Bool                                               bReSubst)
621 {
622     OUStringList::iterator pIt;
623 
624     for (  pIt  = lVals.begin();
625            pIt != lVals.end()  ;
626          ++pIt                 )
627     {
628         const ::rtl::OUString& sOld = *pIt;
629               ::rtl::OUString  sNew ;
630         if (bReSubst)
631             sNew = xSubst->reSubstituteVariables(sOld);
632         else
633             sNew = xSubst->substituteVariables(sOld, sal_False);
634 
635         *pIt = sNew;
636     }
637 }
638 
639 //-----------------------------------------------------------------------------
impl_subst(PathSettings::PathInfo & aPath,sal_Bool bReSubst)640 void PathSettings::impl_subst(PathSettings::PathInfo& aPath   ,
641                               sal_Bool                bReSubst)
642 {
643     css::uno::Reference< css::util::XStringSubstitution > xSubst = fa_getSubstitution();
644 
645     impl_subst(aPath.lInternalPaths, xSubst, bReSubst);
646     impl_subst(aPath.lUserPaths    , xSubst, bReSubst);
647     if (bReSubst)
648         aPath.sWritePath = xSubst->reSubstituteVariables(aPath.sWritePath);
649     else
650         aPath.sWritePath = xSubst->substituteVariables(aPath.sWritePath, sal_False);
651 }
652 
653 //-----------------------------------------------------------------------------
impl_convertPath2OldStyle(const PathSettings::PathInfo & rPath) const654 ::rtl::OUString PathSettings::impl_convertPath2OldStyle(const PathSettings::PathInfo& rPath) const
655 {
656     OUStringList::const_iterator pIt;
657     OUStringList                 lTemp;
658     lTemp.reserve(rPath.lInternalPaths.size() + rPath.lUserPaths.size() + 1);
659 
660     for (  pIt  = rPath.lInternalPaths.begin();
661            pIt != rPath.lInternalPaths.end()  ;
662          ++pIt                                 )
663     {
664         lTemp.push_back(*pIt);
665     }
666     for (  pIt  = rPath.lUserPaths.begin();
667            pIt != rPath.lUserPaths.end()  ;
668          ++pIt                             )
669     {
670         lTemp.push_back(*pIt);
671     }
672 
673     if (rPath.sWritePath.getLength() > 0)
674         lTemp.push_back(rPath.sWritePath);
675 
676     ::rtl::OUStringBuffer sPathVal(256);
677     for (  pIt  = lTemp.begin();
678            pIt != lTemp.end()  ;
679                                )
680     {
681         sPathVal.append(*pIt);
682         ++pIt;
683         if (pIt != lTemp.end())
684             sPathVal.appendAscii(";");
685     }
686 
687     return sPathVal.makeStringAndClear();
688 }
689 
690 //-----------------------------------------------------------------------------
impl_convertOldStyle2Path(const::rtl::OUString & sOldStylePath) const691 OUStringList PathSettings::impl_convertOldStyle2Path(const ::rtl::OUString& sOldStylePath) const
692 {
693     OUStringList lList;
694     sal_Int32    nToken = 0;
695     do
696     {
697         ::rtl::OUString sToken = sOldStylePath.getToken(0, ';', nToken);
698         if (sToken.getLength())
699             lList.push_back(sToken);
700     }
701     while(nToken >= 0);
702 
703     return lList;
704 }
705 
706 //-----------------------------------------------------------------------------
impl_purgeKnownPaths(const PathSettings::PathInfo & rPath,OUStringList & lList)707 void PathSettings::impl_purgeKnownPaths(const PathSettings::PathInfo& rPath,
708                                                OUStringList&           lList)
709 {
710     OUStringList::const_iterator pIt;
711     for (  pIt  = rPath.lInternalPaths.begin();
712            pIt != rPath.lInternalPaths.end()  ;
713          ++pIt                                 )
714     {
715         const ::rtl::OUString& rItem = *pIt;
716         OUStringList::iterator pItem = lList.find(rItem);
717         if (pItem != lList.end())
718             lList.erase(pItem);
719     }
720     for (  pIt  = rPath.lUserPaths.begin();
721            pIt != rPath.lUserPaths.end()  ;
722          ++pIt                             )
723     {
724         const ::rtl::OUString& rItem = *pIt;
725         OUStringList::iterator pItem = lList.find(rItem);
726         if (pItem != lList.end())
727             lList.erase(pItem);
728     }
729 
730     OUStringList::iterator pItem = lList.find(rPath.sWritePath);
731     if (pItem != lList.end())
732         lList.erase(pItem);
733 }
734 
735 //-----------------------------------------------------------------------------
impl_rebuildPropertyDescriptor()736 void PathSettings::impl_rebuildPropertyDescriptor()
737 {
738     // SAFE ->
739     WriteGuard aWriteLock(m_aLock);
740 
741     sal_Int32 c = (sal_Int32)m_lPaths.size();
742     sal_Int32 i = 0;
743     m_lPropDesc.realloc(c*IDGROUP_COUNT);
744 
745     PathHash::const_iterator pIt;
746     for (  pIt  = m_lPaths.begin();
747            pIt != m_lPaths.end()  ;
748          ++pIt                     )
749     {
750         const PathSettings::PathInfo& rPath = pIt->second;
751               css::beans::Property*   pProp = 0;
752 
753         pProp             = &(m_lPropDesc[i]);
754         pProp->Name       = rPath.sPathName;
755         pProp->Handle     = i;
756         pProp->Type       = ::getCppuType((::rtl::OUString*)0);
757         pProp->Attributes = css::beans::PropertyAttribute::BOUND;
758         if (rPath.bIsReadonly)
759             pProp->Attributes |= css::beans::PropertyAttribute::READONLY;
760         ++i;
761 
762         pProp             = &(m_lPropDesc[i]);
763         pProp->Name       = rPath.sPathName+POSTFIX_INTERNAL_PATHES;
764         pProp->Handle     = i;
765         pProp->Type       = ::getCppuType((css::uno::Sequence< ::rtl::OUString >*)0);
766         pProp->Attributes = css::beans::PropertyAttribute::BOUND   |
767                             css::beans::PropertyAttribute::READONLY;
768         ++i;
769 
770         pProp             = &(m_lPropDesc[i]);
771         pProp->Name       = rPath.sPathName+POSTFIX_USER_PATHES;
772         pProp->Handle     = i;
773         pProp->Type       = ::getCppuType((css::uno::Sequence< ::rtl::OUString >*)0);
774         pProp->Attributes = css::beans::PropertyAttribute::BOUND;
775         if (rPath.bIsReadonly)
776             pProp->Attributes |= css::beans::PropertyAttribute::READONLY;
777         ++i;
778 
779         pProp             = &(m_lPropDesc[i]);
780         pProp->Name       = rPath.sPathName+POSTFIX_WRITE_PATH;
781         pProp->Handle     = i;
782         pProp->Type       = ::getCppuType((::rtl::OUString*)0);
783         pProp->Attributes = css::beans::PropertyAttribute::BOUND;
784         if (rPath.bIsReadonly)
785             pProp->Attributes |= css::beans::PropertyAttribute::READONLY;
786         ++i;
787     }
788 
789     if (m_pPropHelp)
790        delete m_pPropHelp;
791     m_pPropHelp = new ::cppu::OPropertyArrayHelper(m_lPropDesc, sal_False); // false => not sorted ... must be done inside helper
792 
793     aWriteLock.unlock();
794     // <- SAFE
795 }
796 
797 //-----------------------------------------------------------------------------
impl_getPathValue(sal_Int32 nID) const798 css::uno::Any PathSettings::impl_getPathValue(sal_Int32 nID) const
799 {
800     const PathSettings::PathInfo* pPath = impl_getPathAccessConst(nID);
801     if (! pPath)
802         throw css::container::NoSuchElementException();
803 
804     css::uno::Any aVal;
805     switch(impl_getPropGroup(nID))
806     {
807         case IDGROUP_OLDSTYLE :
808              {
809                 ::rtl::OUString sVal = impl_convertPath2OldStyle(*pPath);
810                 aVal <<= sVal;
811              }
812              break;
813 
814         case IDGROUP_INTERNAL_PATHES :
815              {
816                 aVal <<= pPath->lInternalPaths.getAsConstList();
817              }
818              break;
819 
820         case IDGROUP_USER_PATHES :
821              {
822                 aVal <<= pPath->lUserPaths.getAsConstList();
823              }
824              break;
825 
826         case IDGROUP_WRITE_PATH :
827              {
828                 aVal <<= pPath->sWritePath;
829              }
830              break;
831     }
832 
833     return aVal;
834 }
835 
836 //-----------------------------------------------------------------------------
impl_setPathValue(sal_Int32 nID,const css::uno::Any & aVal)837 void PathSettings::impl_setPathValue(      sal_Int32      nID ,
838                                      const css::uno::Any& aVal)
839 {
840     PathSettings::PathInfo* pOrgPath = impl_getPathAccess(nID);
841     if (! pOrgPath)
842         throw css::container::NoSuchElementException();
843 
844     // We work on a copied path ... so we can be sure that errors during this operation
845     // does not make our internal cache invalid .-)
846     PathSettings::PathInfo aChangePath(*pOrgPath);
847 
848     switch(impl_getPropGroup(nID))
849     {
850         case IDGROUP_OLDSTYLE :
851              {
852                 ::rtl::OUString sVal;
853                 aVal >>= sVal;
854                 OUStringList lList = impl_convertOldStyle2Path(sVal);
855                 impl_subst(lList, fa_getSubstitution(), sal_False);
856                 impl_purgeKnownPaths(aChangePath, lList);
857                 if (! impl_isValidPath(lList))
858                     throw css::lang::IllegalArgumentException();
859 
860                 if (aChangePath.bIsSinglePath)
861                 {
862                     LOG_ASSERT2(lList.size()>1, "PathSettings::impl_setPathValue()", "You try to set more then path value for a defined SINGLE_PATH!")
863                     if ( !lList.empty() )
864                         aChangePath.sWritePath = *(lList.begin());
865                     else
866                         aChangePath.sWritePath = ::rtl::OUString();
867                 }
868                 else
869                 {
870                     OUStringList::const_iterator pIt;
871                     for (  pIt  = lList.begin();
872                            pIt != lList.end()  ;
873                          ++pIt                 )
874                     {
875                         aChangePath.lUserPaths.push_back(*pIt);
876                     }
877                 }
878              }
879              break;
880 
881         case IDGROUP_INTERNAL_PATHES :
882              {
883                 if (aChangePath.bIsSinglePath)
884                 {
885                     ::rtl::OUStringBuffer sMsg(256);
886                     sMsg.appendAscii("The path '"    );
887                     sMsg.append     (aChangePath.sPathName);
888                     sMsg.appendAscii("' is defined as SINGLE_PATH. It's sub set of internal paths can't be set.");
889                     throw css::uno::Exception(sMsg.makeStringAndClear(),
890                                               static_cast< ::cppu::OWeakObject* >(this));
891                 }
892 
893                 OUStringList lList;
894                 lList << aVal;
895                 if (! impl_isValidPath(lList))
896                     throw css::lang::IllegalArgumentException();
897                 aChangePath.lInternalPaths = lList;
898              }
899              break;
900 
901         case IDGROUP_USER_PATHES :
902              {
903                 if (aChangePath.bIsSinglePath)
904                 {
905                     ::rtl::OUStringBuffer sMsg(256);
906                     sMsg.appendAscii("The path '"    );
907                     sMsg.append     (aChangePath.sPathName);
908                     sMsg.appendAscii("' is defined as SINGLE_PATH. It's sub set of internal paths can't be set.");
909                     throw css::uno::Exception(sMsg.makeStringAndClear(),
910                                               static_cast< ::cppu::OWeakObject* >(this));
911                 }
912 
913                 OUStringList lList;
914                 lList << aVal;
915                 if (! impl_isValidPath(lList))
916                     throw css::lang::IllegalArgumentException();
917                 aChangePath.lUserPaths = lList;
918              }
919              break;
920 
921         case IDGROUP_WRITE_PATH :
922              {
923                 ::rtl::OUString sVal;
924                 aVal >>= sVal;
925                 if (! impl_isValidPath(sVal))
926                     throw css::lang::IllegalArgumentException();
927                 aChangePath.sWritePath = sVal;
928              }
929              break;
930     }
931 
932     // TODO check if path has at least one path value set
933     // At least it depends from the feature using this path, if an empty path list is allowed.
934     /*
935     if (impl_isPathEmpty(aChangePath))
936     {
937         ::rtl::OUStringBuffer sMsg(256);
938         sMsg.appendAscii("The path '"    );
939         sMsg.append     (aChangePath.sPathName);
940         sMsg.appendAscii("' is empty now ... Not a real good idea.");
941         throw css::uno::Exception(sMsg.makeStringAndClear(),
942                                   static_cast< ::cppu::OWeakObject* >(this));
943     }
944     */
945 
946     // first we should try to store the changed (copied!) path ...
947     // In case an error occurs on saving time an exception is thrown ...
948     // If no exception occurs we can update our internal cache (means
949     // we can overwrite pOrgPath !
950     impl_storePath(aChangePath);
951     pOrgPath->takeOver(aChangePath);
952 }
953 
954 //-----------------------------------------------------------------------------
impl_isValidPath(const OUStringList & lPath) const955 sal_Bool PathSettings::impl_isValidPath(const OUStringList& lPath) const
956 {
957     OUStringList::const_iterator pIt;
958     for (  pIt  = lPath.begin();
959            pIt != lPath.end()  ;
960          ++pIt                 )
961     {
962         const ::rtl::OUString& rVal = *pIt;
963         if (! impl_isValidPath(rVal))
964             return sal_False;
965     }
966 
967     return sal_True;
968 }
969 
970 //-----------------------------------------------------------------------------
impl_isValidPath(const::rtl::OUString & sPath) const971 sal_Bool PathSettings::impl_isValidPath(const ::rtl::OUString& sPath) const
972 {
973     // allow empty path to reset a path.
974 // idea by LLA to support empty paths
975 //  if (sPath.getLength() == 0)
976 //  {
977 //      return sal_True;
978 //  }
979 
980     return (! INetURLObject(sPath).HasError());
981 }
982 
983 //-----------------------------------------------------------------------------
impl_extractBaseFromPropName(const::rtl::OUString & sPropName)984 ::rtl::OUString impl_extractBaseFromPropName(const ::rtl::OUString& sPropName)
985 {
986     sal_Int32 i = -1;
987 
988     i = sPropName.indexOf(POSTFIX_INTERNAL_PATHES);
989     if (i > -1)
990         return sPropName.copy(0, i);
991     i = sPropName.indexOf(POSTFIX_USER_PATHES);
992     if (i > -1)
993         return sPropName.copy(0, i);
994     i = sPropName.indexOf(POSTFIX_WRITE_PATH);
995     if (i > -1)
996         return sPropName.copy(0, i);
997 
998     return sPropName;
999 }
1000 
1001 //-----------------------------------------------------------------------------
impl_getPathAccess(sal_Int32 nHandle)1002 PathSettings::PathInfo* PathSettings::impl_getPathAccess(sal_Int32 nHandle)
1003 {
1004     // SAFE ->
1005     ReadGuard aReadLock(m_aLock);
1006 
1007     if (nHandle > (m_lPropDesc.getLength()-1))
1008         return 0;
1009 
1010     const css::beans::Property&            rProp = m_lPropDesc[nHandle];
1011           ::rtl::OUString                  sProp = impl_extractBaseFromPropName(rProp.Name);
1012           PathSettings::PathHash::iterator rPath = m_lPaths.find(sProp);
1013 
1014     if (rPath != m_lPaths.end())
1015        return &(rPath->second);
1016 
1017     return 0;
1018     // <- SAFE
1019 }
1020 
1021 //-----------------------------------------------------------------------------
impl_getPathAccessConst(sal_Int32 nHandle) const1022 const PathSettings::PathInfo* PathSettings::impl_getPathAccessConst(sal_Int32 nHandle) const
1023 {
1024     // SAFE ->
1025     ReadGuard aReadLock(m_aLock);
1026 
1027     if (nHandle > (m_lPropDesc.getLength()-1))
1028         return 0;
1029 
1030     const css::beans::Property&                  rProp = m_lPropDesc[nHandle];
1031           ::rtl::OUString                        sProp = impl_extractBaseFromPropName(rProp.Name);
1032           PathSettings::PathHash::const_iterator rPath = m_lPaths.find(sProp);
1033 
1034     if (rPath != m_lPaths.end())
1035        return &(rPath->second);
1036 
1037     return 0;
1038     // <- SAFE
1039 }
1040 
1041 //-----------------------------------------------------------------------------
convertFastPropertyValue(css::uno::Any & aConvertedValue,css::uno::Any & aOldValue,sal_Int32 nHandle,const css::uno::Any & aValue)1042 sal_Bool SAL_CALL PathSettings::convertFastPropertyValue(      css::uno::Any& aConvertedValue,
1043                                                                css::uno::Any& aOldValue      ,
1044                                                                sal_Int32      nHandle        ,
1045                                                          const css::uno::Any& aValue         )
1046 {
1047     // throws NoSuchElementException !
1048     css::uno::Any aCurrentVal = impl_getPathValue(nHandle);
1049 
1050     return PropHelper::willPropertyBeChanged(
1051                 aCurrentVal,
1052                 aValue,
1053                 aOldValue,
1054                 aConvertedValue);
1055 }
1056 
1057 //-----------------------------------------------------------------------------
setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any & aValue)1058 void SAL_CALL PathSettings::setFastPropertyValue_NoBroadcast(      sal_Int32      nHandle,
1059                                                              const css::uno::Any& aValue )
1060 {
1061     // throws NoSuchElement- and IllegalArgumentException !
1062     impl_setPathValue(nHandle, aValue);
1063 }
1064 
1065 //-----------------------------------------------------------------------------
getFastPropertyValue(css::uno::Any & aValue,sal_Int32 nHandle) const1066 void SAL_CALL PathSettings::getFastPropertyValue(css::uno::Any& aValue ,
1067                                                  sal_Int32      nHandle) const
1068 {
1069     aValue = impl_getPathValue(nHandle);
1070 }
1071 
1072 //-----------------------------------------------------------------------------
getInfoHelper()1073 ::cppu::IPropertyArrayHelper& SAL_CALL PathSettings::getInfoHelper()
1074 {
1075     return *m_pPropHelp;
1076 }
1077 
1078 //-----------------------------------------------------------------------------
getPropertySetInfo()1079 css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL PathSettings::getPropertySetInfo()
1080 {
1081     return css::uno::Reference< css::beans::XPropertySetInfo >(createPropertySetInfo(getInfoHelper()));
1082 }
1083 
1084 //-----------------------------------------------------------------------------
fa_getSubstitution()1085 css::uno::Reference< css::util::XStringSubstitution > PathSettings::fa_getSubstitution()
1086 {
1087     // SAFE ->
1088     ReadGuard aReadLock(m_aLock);
1089     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR  = m_xSMGR;
1090     css::uno::Reference< css::util::XStringSubstitution >  xSubst = m_xSubstitution;
1091     aReadLock.unlock();
1092     // <- SAFE
1093 
1094     if (! xSubst.is())
1095     {
1096         // create the needed substitution service.
1097         // We must replace all used variables inside read path values.
1098         // In case we can't do so ... the whole office can't work really.
1099         // That's why it seems to be OK to throw a RuntimeException then.
1100         xSubst = css::uno::Reference< css::util::XStringSubstitution >(
1101                                 xSMGR->createInstance(SERVICENAME_SUBSTITUTEPATHVARIABLES),
1102                                 css::uno::UNO_QUERY_THROW);
1103 
1104         // SAFE ->
1105         WriteGuard aWriteLock(m_aLock);
1106         m_xSubstitution = xSubst;
1107         aWriteLock.unlock();
1108     }
1109 
1110     return xSubst;
1111 }
1112 
1113 //-----------------------------------------------------------------------------
fa_getCfgOld()1114 css::uno::Reference< css::container::XNameAccess > PathSettings::fa_getCfgOld()
1115 {
1116     const static ::rtl::OUString CFG_NODE_OLD = ::rtl::OUString::createFromAscii("org.openoffice.Office.Common/Path/Current");
1117 
1118     // SAFE ->
1119     ReadGuard aReadLock(m_aLock);
1120     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
1121     css::uno::Reference< css::container::XNameAccess >     xCfg  = m_xCfgOld;
1122     aReadLock.unlock();
1123     // <- SAFE
1124 
1125     if (! xCfg.is())
1126     {
1127         xCfg = css::uno::Reference< css::container::XNameAccess >(
1128                    ::comphelper::ConfigurationHelper::openConfig(
1129                         xSMGR,
1130                         CFG_NODE_OLD,
1131                         ::comphelper::ConfigurationHelper::E_STANDARD), // not readonly! Sometimes we need write access there !!!
1132                    css::uno::UNO_QUERY_THROW);
1133 
1134         // SAFE ->
1135         WriteGuard aWriteLock(m_aLock);
1136         m_xCfgOld = xCfg;
1137         aWriteLock.unlock();
1138     }
1139 
1140     return xCfg;
1141 }
1142 
1143 //-----------------------------------------------------------------------------
fa_getCfgNew()1144 css::uno::Reference< css::container::XNameAccess > PathSettings::fa_getCfgNew()
1145 {
1146     const static ::rtl::OUString CFG_NODE_NEW = ::rtl::OUString::createFromAscii("org.openoffice.Office.Paths/Paths");
1147 
1148     // SAFE ->
1149     ReadGuard aReadLock(m_aLock);
1150     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
1151     css::uno::Reference< css::container::XNameAccess >     xCfg  = m_xCfgNew;
1152     aReadLock.unlock();
1153     // <- SAFE
1154 
1155     if (! xCfg.is())
1156     {
1157         xCfg = css::uno::Reference< css::container::XNameAccess >(
1158                    ::comphelper::ConfigurationHelper::openConfig(
1159                         xSMGR,
1160                         CFG_NODE_NEW,
1161                         ::comphelper::ConfigurationHelper::E_STANDARD),
1162                    css::uno::UNO_QUERY_THROW);
1163 
1164         // SAFE ->
1165         WriteGuard aWriteLock(m_aLock);
1166         m_xCfgNew = xCfg;
1167         aWriteLock.unlock();
1168 
1169         css::uno::Reference< css::util::XChangesNotifier > xBroadcaster(xCfg, css::uno::UNO_QUERY_THROW);
1170         xBroadcaster->addChangesListener(static_cast< css::util::XChangesListener* >(this));
1171     }
1172 
1173     return xCfg;
1174 }
1175 
1176 } // namespace framework
1177 
1178 /* vim: set noet sw=4 ts=4: */
1179