update dev300-m57
[ooovba.git] / framework / source / services / pathsettings.cxx
blob0f19580d167173acd2ff1e94c0d9816304f97739
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: pathsettings.cxx,v $
10 * $Revision: 1.12 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_framework.hxx"
33 // ______________________________________________
34 // my own includes
36 /** Attention: stl headers must(!) be included at first. Otherwhise it can make trouble
37 with solaris headers ...
39 #include <vector>
40 #include <services/pathsettings.hxx>
41 #include <threadhelp/readguard.hxx>
42 #include <threadhelp/writeguard.hxx>
43 #include <services.h>
45 // ______________________________________________
46 // interface includes
47 #include <com/sun/star/beans/Property.hpp>
48 #include <com/sun/star/beans/XProperty.hpp>
49 #include <com/sun/star/beans/PropertyAttribute.hpp>
50 #include <com/sun/star/container/XContainer.hpp>
51 #include <com/sun/star/beans/XPropertySet.hpp>
52 #include <com/sun/star/util/XChangesNotifier.hpp>
54 // ______________________________________________
55 // includes of other projects
56 #include <tools/urlobj.hxx>
57 #include <rtl/ustrbuf.hxx>
58 #include <rtl/logfile.hxx>
60 #include <comphelper/configurationhelper.hxx>
61 #include <unotools/configpathes.hxx>
63 // ______________________________________________
64 // non exported const
66 #define CFG_READONLY_DEFAULT sal_False
68 const ::rtl::OUString CFGPROP_INTERNALPATHES = ::rtl::OUString::createFromAscii("InternalPaths");
69 const ::rtl::OUString CFGPROP_USERPATHES = ::rtl::OUString::createFromAscii("UserPaths" );
70 const ::rtl::OUString CFGPROP_WRITEPATH = ::rtl::OUString::createFromAscii("WritePath" );
71 const ::rtl::OUString CFGPROP_ISSINGLEPATH = ::rtl::OUString::createFromAscii("IsSinglePath" );
74 0 : old style "Template" string using ";" as seperator
75 1 : internal paths "Template_internal" string list
76 2 : user paths "Template_user" string list
77 3 : write path "Template_write" string
80 const ::rtl::OUString POSTFIX_INTERNAL_PATHES = ::rtl::OUString::createFromAscii("_internal");
81 const ::rtl::OUString POSTFIX_USER_PATHES = ::rtl::OUString::createFromAscii("_user" );
82 const ::rtl::OUString POSTFIX_WRITE_PATH = ::rtl::OUString::createFromAscii("_writable");
84 const sal_Int32 IDGROUP_OLDSTYLE = 0;
85 const sal_Int32 IDGROUP_INTERNAL_PATHES = 1;
86 const sal_Int32 IDGROUP_USER_PATHES = 2;
87 const sal_Int32 IDGROUP_WRITE_PATH = 3;
89 const sal_Int32 IDGROUP_COUNT = 4;
91 sal_Int32 impl_getPropGroup(sal_Int32 nID)
93 return (nID % IDGROUP_COUNT);
96 // ______________________________________________
97 // namespace
99 namespace framework
102 //-----------------------------------------------------------------------------
103 // XInterface, XTypeProvider, XServiceInfo
105 DEFINE_XINTERFACE_7 ( PathSettings ,
106 OWeakObject ,
107 DIRECT_INTERFACE ( css::lang::XTypeProvider ),
108 DIRECT_INTERFACE ( css::lang::XServiceInfo ),
109 DERIVED_INTERFACE( css::lang::XEventListener, css::util::XChangesListener),
110 DIRECT_INTERFACE ( css::util::XChangesListener ),
111 DIRECT_INTERFACE ( css::beans::XPropertySet ),
112 DIRECT_INTERFACE ( css::beans::XFastPropertySet ),
113 DIRECT_INTERFACE ( css::beans::XMultiPropertySet )
116 DEFINE_XTYPEPROVIDER_7 ( PathSettings ,
117 css::lang::XTypeProvider ,
118 css::lang::XServiceInfo ,
119 css::lang::XEventListener ,
120 css::util::XChangesListener ,
121 css::beans::XPropertySet ,
122 css::beans::XFastPropertySet ,
123 css::beans::XMultiPropertySet
126 DEFINE_XSERVICEINFO_ONEINSTANCESERVICE ( PathSettings ,
127 ::cppu::OWeakObject ,
128 SERVICENAME_PATHSETTINGS ,
129 IMPLEMENTATIONNAME_PATHSETTINGS
132 DEFINE_INIT_SERVICE ( PathSettings,
134 /*Attention
135 I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
136 to create a new instance of this class by our own supported service factory.
137 see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations!
140 // fill cache
141 impl_readAll();
145 //-----------------------------------------------------------------------------
146 PathSettings::PathSettings( const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR )
147 // Init baseclasses first
148 // Attention: Don't change order of initialization!
149 // ThreadHelpBase is a struct with a lock as member. We can't use a lock as direct member!
150 // We must garant right initialization and a valid value of this to initialize other baseclasses!
151 : ThreadHelpBase()
152 , ::cppu::OBroadcastHelperVar< ::cppu::OMultiTypeInterfaceContainerHelper, ::cppu::OMultiTypeInterfaceContainerHelper::keyType >(m_aLock.getShareableOslMutex())
153 , ::cppu::OPropertySetHelper(*(static_cast< ::cppu::OBroadcastHelper* >(this)))
154 , ::cppu::OWeakObject()
155 // Init member
156 , m_xSMGR (xSMGR)
157 , m_pPropHelp(0 )
158 , m_bIgnoreEvents(sal_False)
162 //-----------------------------------------------------------------------------
163 PathSettings::~PathSettings()
165 if (m_pPropHelp)
166 delete m_pPropHelp;
169 //-----------------------------------------------------------------------------
170 void SAL_CALL PathSettings::changesOccurred(const css::util::ChangesEvent& aEvent)
171 throw (css::uno::RuntimeException)
174 if (m_bIgnoreEvents)
175 return;
178 sal_Int32 c = aEvent.Changes.getLength();
179 sal_Int32 i = 0;
180 sal_Bool bUpdateDescriptor = sal_False;
182 for (i=0; i<c; ++i)
184 const css::util::ElementChange& aChange = aEvent.Changes[i];
186 ::rtl::OUString sChanged;
187 aChange.Accessor >>= sChanged;
189 ::rtl::OUString sPath = ::utl::extractFirstFromConfigurationPath(sChanged);
190 if (sPath.getLength())
192 PathSettings::EChangeOp eOp = impl_updatePath(sPath, sal_True);
193 if (
194 (eOp == PathSettings::E_ADDED ) ||
195 (eOp == PathSettings::E_REMOVED)
197 bUpdateDescriptor = sal_True;
201 if (bUpdateDescriptor)
202 impl_rebuildPropertyDescriptor();
205 //-----------------------------------------------------------------------------
206 void SAL_CALL PathSettings::disposing(const css::lang::EventObject& aSource)
207 throw(css::uno::RuntimeException)
209 // SAFE ->
210 WriteGuard aWriteLock(m_aLock);
212 if (aSource.Source == m_xCfgNew)
213 m_xCfgNew.clear();
215 aWriteLock.unlock();
216 // <- SAFE
219 //-----------------------------------------------------------------------------
220 void PathSettings::impl_readAll()
222 RTL_LOGFILE_CONTEXT(aLog, "framework (as96863) ::PathSettings::load config (all)");
224 // TODO think about me
225 css::uno::Reference< css::container::XNameAccess > xCfg = fa_getCfgNew();
226 css::uno::Sequence< ::rtl::OUString > lPaths = xCfg->getElementNames();
228 sal_Int32 c = lPaths.getLength();
229 sal_Int32 i = 0;
231 for (i=0; i<c; ++i)
233 const ::rtl::OUString& sPath = lPaths[i];
234 impl_updatePath(sPath, sal_False);
237 impl_rebuildPropertyDescriptor();
240 //-----------------------------------------------------------------------------
241 // NO substitution here ! It's done outside ...
242 OUStringList PathSettings::impl_readOldFormat(const ::rtl::OUString& sPath)
244 css::uno::Reference< css::container::XNameAccess > xCfg = fa_getCfgOld();
245 css::uno::Any aVal = xCfg->getByName(sPath);
247 ::rtl::OUString sStringVal;
248 css::uno::Sequence< ::rtl::OUString > lStringListVal;
249 OUStringList aPathVal;
251 if (aVal >>= sStringVal)
253 aPathVal.push_back(sStringVal);
255 else
256 if (aVal >>= lStringListVal)
258 aPathVal << lStringListVal;
261 return aPathVal;
264 //-----------------------------------------------------------------------------
265 // NO substitution here ! It's done outside ...
266 PathSettings::PathInfo PathSettings::impl_readNewFormat(const ::rtl::OUString& sPath)
268 css::uno::Reference< css::container::XNameAccess > xCfg = fa_getCfgNew();
270 // get access to the "queried" path
271 css::uno::Reference< css::container::XNameAccess > xPath;
272 xCfg->getByName(sPath) >>= xPath;
274 PathSettings::PathInfo aPathVal;
276 // read internal path list
277 css::uno::Reference< css::container::XNameAccess > xIPath;
278 xPath->getByName(CFGPROP_INTERNALPATHES) >>= xIPath;
279 aPathVal.lInternalPaths << xIPath->getElementNames();
281 // read user defined path list
282 aPathVal.lUserPaths << xPath->getByName(CFGPROP_USERPATHES);
284 // read the writeable path
285 xPath->getByName(CFGPROP_WRITEPATH) >>= aPathVal.sWritePath;
287 // read state props
288 xPath->getByName(CFGPROP_ISSINGLEPATH) >>= aPathVal.bIsSinglePath;
290 // analyze finalized/mandatory states
291 aPathVal.bIsReadonly = sal_False;
292 css::uno::Reference< css::beans::XProperty > xInfo(xPath, css::uno::UNO_QUERY);
293 if (xInfo.is())
295 css::beans::Property aInfo = xInfo->getAsProperty();
296 sal_Bool bFinalized = ((aInfo.Attributes & css::beans::PropertyAttribute::READONLY ) == css::beans::PropertyAttribute::READONLY );
297 //sal_Bool bMandatory = ((aInfo.Attributes & css::beans::PropertyAttribute::REMOVEABLE) != css::beans::PropertyAttribute::REMOVEABLE);
299 // Note: Till we support finalized / mandatory on our API more in detail we handle
300 // all states simple as READONLY ! But because all realy needed pathes are "mandatory" by default
301 // we have to handle "finalized" as the real "readonly" indicator .
302 aPathVal.bIsReadonly = bFinalized;
305 return aPathVal;
308 //-----------------------------------------------------------------------------
309 void PathSettings::impl_storePath(const PathSettings::PathInfo& aPath)
311 m_bIgnoreEvents = sal_True;
313 css::uno::Reference< css::container::XNameAccess > xCfgNew = fa_getCfgNew();
314 css::uno::Reference< css::container::XNameAccess > xCfgOld = fa_getCfgOld();
316 // try to replace path-parts with well known and uspported variables.
317 // So an office can be moved easialy to another location without loosing
318 // it's related pathes.
319 PathInfo aResubstPath(aPath);
320 impl_subst(aResubstPath, sal_True);
322 // update new configuration
323 if (! aResubstPath.bIsSinglePath)
325 ::comphelper::ConfigurationHelper::writeRelativeKey(xCfgNew,
326 aResubstPath.sPathName,
327 CFGPROP_USERPATHES,
328 css::uno::makeAny(aResubstPath.lUserPaths.getAsConstList()));
331 ::comphelper::ConfigurationHelper::writeRelativeKey(xCfgNew,
332 aResubstPath.sPathName,
333 CFGPROP_WRITEPATH,
334 css::uno::makeAny(aResubstPath.sWritePath));
336 ::comphelper::ConfigurationHelper::flush(xCfgNew);
338 // remove the whole path from the old configuration !
339 // Otherwise we cant make sure that the diff between new and old configuration
340 // on loading time realy represent an user setting !!!
342 // Check if the given path exists inside the old configuration.
343 // Because our new configuration knows more then the list of old pathes ... !
344 if (xCfgOld->hasByName(aResubstPath.sPathName))
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);
351 m_bIgnoreEvents = sal_False;
354 //-----------------------------------------------------------------------------
355 #ifdef MIGRATE_OLD_USER_PATHES
356 void PathSettings::impl_mergeOldUserPaths( PathSettings::PathInfo& rPath,
357 const OUStringList& lOld )
359 OUStringList::const_iterator pIt;
360 for ( pIt = lOld.begin();
361 pIt != lOld.end() ;
362 ++pIt )
364 const ::rtl::OUString& sOld = *pIt;
366 if (rPath.bIsSinglePath)
368 LOG_ASSERT2(lOld.size()>1, "PathSettings::impl_mergeOldUserPaths()", "Single path has more then one path value inside old configuration (Common.xcu)!")
369 if (! rPath.sWritePath.equals(sOld))
370 rPath.sWritePath = sOld;
372 else
374 if (
375 ( rPath.lInternalPaths.findConst(sOld) == rPath.lInternalPaths.end()) &&
376 ( rPath.lUserPaths.findConst(sOld) == rPath.lUserPaths.end() ) &&
377 (! rPath.sWritePath.equals(sOld) )
379 rPath.lUserPaths.push_back(sOld);
383 #endif // MIGRATE_OLD_USER_PATHES
385 //-----------------------------------------------------------------------------
386 PathSettings::EChangeOp PathSettings::impl_updatePath(const ::rtl::OUString& sPath ,
387 sal_Bool bNotifyListener)
389 // SAFE ->
390 WriteGuard aWriteLock(m_aLock);
392 PathSettings::PathInfo* pPathOld = 0;
393 PathSettings::PathInfo* pPathNew = 0;
394 PathSettings::EChangeOp eOp = PathSettings::E_UNDEFINED;
395 PathSettings::PathInfo aPath;
399 aPath = impl_readNewFormat(sPath);
400 aPath.sPathName = sPath;
401 // replace all might existing variables with real values
402 // Do it before these old pathes will be compared against the
403 // new path configuration. Otherwise some striungs uses different variables ... but substitution
404 // will produce strings with same content (because some variables are redundant!)
405 impl_subst(aPath, sal_False);
407 catch(const css::uno::RuntimeException& exRun)
408 { throw exRun; }
409 catch(const css::container::NoSuchElementException&)
410 { eOp = PathSettings::E_REMOVED; }
411 catch(const css::uno::Exception& exAny)
412 { throw exAny; }
414 #ifdef MIGRATE_OLD_USER_PATHES
417 // migration of old user defined values on demand
418 // can be disabled for a new major
419 OUStringList lOldVals = impl_readOldFormat(sPath);
420 // replace all might existing variables with real values
421 // Do it before these old pathes will be compared against the
422 // new path configuration. Otherwise some striungs uses different variables ... but substitution
423 // will produce strings with same content (because some variables are redundant!)
424 impl_subst(lOldVals, fa_getSubstitution(), sal_False);
425 impl_mergeOldUserPaths(aPath, lOldVals);
427 catch(const css::uno::RuntimeException& exRun)
428 { throw exRun; }
429 // Normal(!) exceptions can be ignored!
430 // E.g. in case an addon installs a new path, which was not well known for an OOo 1.x installation
431 // we cant find a value for it inside the "old" configuration. So a NoSuchElementException
432 // will be normal .-)
433 catch(const css::uno::Exception&)
435 #endif // MIGRATE_OLD_USER_PATHES
437 PathSettings::PathHash::iterator pPath = m_lPaths.find(sPath);
438 if (eOp == PathSettings::E_UNDEFINED)
440 if (pPath != m_lPaths.end())
441 eOp = PathSettings::E_CHANGED;
442 else
443 eOp = PathSettings::E_ADDED;
446 switch(eOp)
448 case PathSettings::E_ADDED :
450 if (bNotifyListener)
452 pPathOld = 0;
453 pPathNew = &aPath;
454 impl_notifyPropListener(eOp, sPath, pPathOld, pPathNew);
456 m_lPaths[sPath] = aPath;
458 break;
460 case PathSettings::E_CHANGED :
462 if (bNotifyListener)
464 pPathOld = &(pPath->second);
465 pPathNew = &aPath;
466 impl_notifyPropListener(eOp, sPath, pPathOld, pPathNew);
468 m_lPaths[sPath] = aPath;
470 break;
472 case PathSettings::E_REMOVED :
474 if (pPath != m_lPaths.end())
476 if (bNotifyListener)
478 pPathOld = &(pPath->second);
479 pPathNew = 0;
480 impl_notifyPropListener(eOp, sPath, pPathOld, pPathNew);
482 m_lPaths.erase(pPath);
485 break;
487 default: // to let compiler be happy
488 break;
491 return eOp;
494 //-----------------------------------------------------------------------------
495 css::uno::Sequence< sal_Int32 > PathSettings::impl_mapPathName2IDList(const ::rtl::OUString& sPath)
497 ::rtl::OUString sOldStyleProp = sPath;
498 ::rtl::OUString sInternalProp = sPath+POSTFIX_INTERNAL_PATHES;
499 ::rtl::OUString sUserProp = sPath+POSTFIX_USER_PATHES;
500 ::rtl::OUString sWriteProp = sPath+POSTFIX_WRITE_PATH;
502 // Attention: The default set of IDs is fix and must follow these schema.
503 // Otherwhise the outside code ant work for new added properties.
504 // Why ?
505 // The outside code must fire N events for every changed property.
506 // And the knowing about packaging of variables of the structure PathInfo
507 // follow these group IDs ! But if such ID isnt in the range of [0..IDGROUP_COUNT]
508 // the outside cant determine the right group ... and cant fire the right events .-)
510 css::uno::Sequence< sal_Int32 > lIDs(IDGROUP_COUNT);
511 lIDs[0] = IDGROUP_OLDSTYLE ;
512 lIDs[1] = IDGROUP_INTERNAL_PATHES;
513 lIDs[2] = IDGROUP_USER_PATHES ;
514 lIDs[3] = IDGROUP_WRITE_PATH ;
516 sal_Int32 c = m_lPropDesc.getLength();
517 sal_Int32 i = 0;
518 for (i=0; i<c; ++i)
520 const css::beans::Property& rProp = m_lPropDesc[i];
522 if (rProp.Name.equals(sOldStyleProp))
523 lIDs[IDGROUP_OLDSTYLE] = rProp.Handle;
524 else
525 if (rProp.Name.equals(sInternalProp))
526 lIDs[IDGROUP_INTERNAL_PATHES] = rProp.Handle;
527 else
528 if (rProp.Name.equals(sUserProp))
529 lIDs[IDGROUP_USER_PATHES] = rProp.Handle;
530 else
531 if (rProp.Name.equals(sWriteProp))
532 lIDs[IDGROUP_WRITE_PATH] = rProp.Handle;
535 return lIDs;
538 //-----------------------------------------------------------------------------
539 void PathSettings::impl_notifyPropListener( PathSettings::EChangeOp /*eOp*/ ,
540 const ::rtl::OUString& sPath ,
541 const PathSettings::PathInfo* pPathOld,
542 const PathSettings::PathInfo* pPathNew)
544 css::uno::Sequence< sal_Int32 > lHandles(1);
545 css::uno::Sequence< css::uno::Any > lOldVals(1);
546 css::uno::Sequence< css::uno::Any > lNewVals(1);
548 css::uno::Sequence< sal_Int32 > lIDs = impl_mapPathName2IDList(sPath);
549 sal_Int32 c = lIDs.getLength();
550 sal_Int32 i = 0;
551 sal_Int32 nMaxID = m_lPropDesc.getLength()-1;
552 for (i=0; i<c; ++i)
554 sal_Int32 nID = lIDs[i];
556 if (
557 (nID < 0 ) ||
558 (nID > nMaxID)
560 continue;
562 lHandles[0] = nID;
563 switch(impl_getPropGroup(nID))
565 case IDGROUP_OLDSTYLE :
567 if (pPathOld)
569 ::rtl::OUString sVal = impl_convertPath2OldStyle(*pPathOld);
570 lOldVals[0] <<= sVal;
572 if (pPathNew)
574 ::rtl::OUString sVal = impl_convertPath2OldStyle(*pPathNew);
575 lNewVals[0] <<= sVal;
578 break;
580 case IDGROUP_INTERNAL_PATHES :
582 if (pPathOld)
583 lOldVals[0] <<= pPathOld->lInternalPaths.getAsConstList();
584 if (pPathNew)
585 lNewVals[0] <<= pPathNew->lInternalPaths.getAsConstList();
587 break;
589 case IDGROUP_USER_PATHES :
591 if (pPathOld)
592 lOldVals[0] <<= pPathOld->lUserPaths.getAsConstList();
593 if (pPathNew)
594 lNewVals[0] <<= pPathNew->lUserPaths.getAsConstList();
596 break;
598 case IDGROUP_WRITE_PATH :
600 if (pPathOld)
601 lOldVals[0] <<= pPathOld->sWritePath;
602 if (pPathNew)
603 lNewVals[0] <<= pPathNew->sWritePath;
605 break;
608 fire(lHandles.getArray(),
609 lNewVals.getArray(),
610 lOldVals.getArray(),
612 sal_False);
616 //-----------------------------------------------------------------------------
617 void PathSettings::impl_subst( OUStringList& lVals ,
618 const css::uno::Reference< css::util::XStringSubstitution >& xSubst ,
619 sal_Bool bReSubst)
621 OUStringList::iterator pIt;
623 for ( pIt = lVals.begin();
624 pIt != lVals.end() ;
625 ++pIt )
627 const ::rtl::OUString& sOld = *pIt;
628 ::rtl::OUString sNew ;
629 if (bReSubst)
630 sNew = xSubst->reSubstituteVariables(sOld);
631 else
632 sNew = xSubst->substituteVariables(sOld, sal_False);
634 *pIt = sNew;
638 //-----------------------------------------------------------------------------
639 void PathSettings::impl_subst(PathSettings::PathInfo& aPath ,
640 sal_Bool bReSubst)
642 css::uno::Reference< css::util::XStringSubstitution > xSubst = fa_getSubstitution();
644 impl_subst(aPath.lInternalPaths, xSubst, bReSubst);
645 impl_subst(aPath.lUserPaths , xSubst, bReSubst);
646 if (bReSubst)
647 aPath.sWritePath = xSubst->reSubstituteVariables(aPath.sWritePath);
648 else
649 aPath.sWritePath = xSubst->substituteVariables(aPath.sWritePath, sal_False);
652 //-----------------------------------------------------------------------------
653 ::rtl::OUString PathSettings::impl_convertPath2OldStyle(const PathSettings::PathInfo& rPath) const
655 OUStringList::const_iterator pIt;
656 OUStringList lTemp;
658 for ( pIt = rPath.lInternalPaths.begin();
659 pIt != rPath.lInternalPaths.end() ;
660 ++pIt )
662 lTemp.push_back(*pIt);
664 for ( pIt = rPath.lUserPaths.begin();
665 pIt != rPath.lUserPaths.end() ;
666 ++pIt )
668 lTemp.push_back(*pIt);
671 if (rPath.sWritePath.getLength() > 0)
672 lTemp.push_back(rPath.sWritePath);
674 ::rtl::OUStringBuffer sPathVal(256);
675 for ( pIt = lTemp.begin();
676 pIt != lTemp.end() ;
679 sPathVal.append(*pIt);
680 ++pIt;
681 if (pIt != lTemp.end())
682 sPathVal.appendAscii(";");
685 return sPathVal.makeStringAndClear();
688 //-----------------------------------------------------------------------------
689 OUStringList PathSettings::impl_convertOldStyle2Path(const ::rtl::OUString& sOldStylePath) const
691 OUStringList lList;
692 sal_Int32 nToken = 0;
695 ::rtl::OUString sToken = sOldStylePath.getToken(0, ';', nToken);
696 if (sToken.getLength())
697 lList.push_back(sToken);
699 while(nToken >= 0);
701 return lList;
704 //-----------------------------------------------------------------------------
705 void PathSettings::impl_purgeKnownPaths(const PathSettings::PathInfo& rPath,
706 OUStringList& lList)
708 OUStringList::const_iterator pIt;
709 for ( pIt = rPath.lInternalPaths.begin();
710 pIt != rPath.lInternalPaths.end() ;
711 ++pIt )
713 const ::rtl::OUString& rItem = *pIt;
714 OUStringList::iterator pItem = lList.find(rItem);
715 if (pItem != lList.end())
716 lList.erase(pItem);
718 for ( pIt = rPath.lUserPaths.begin();
719 pIt != rPath.lUserPaths.end() ;
720 ++pIt )
722 const ::rtl::OUString& rItem = *pIt;
723 OUStringList::iterator pItem = lList.find(rItem);
724 if (pItem != lList.end())
725 lList.erase(pItem);
728 OUStringList::iterator pItem = lList.find(rPath.sWritePath);
729 if (pItem != lList.end())
730 lList.erase(pItem);
733 //-----------------------------------------------------------------------------
734 void PathSettings::impl_rebuildPropertyDescriptor()
736 // SAFE ->
737 WriteGuard aWriteLock(m_aLock);
739 sal_Int32 c = (sal_Int32)m_lPaths.size();
740 sal_Int32 i = 0;
741 m_lPropDesc.realloc(c*IDGROUP_COUNT);
743 PathHash::const_iterator pIt;
744 for ( pIt = m_lPaths.begin();
745 pIt != m_lPaths.end() ;
746 ++pIt )
748 const PathSettings::PathInfo& rPath = pIt->second;
749 css::beans::Property* pProp = 0;
751 pProp = &(m_lPropDesc[i]);
752 pProp->Name = rPath.sPathName;
753 pProp->Handle = i;
754 pProp->Type = ::getCppuType((::rtl::OUString*)0);
755 pProp->Attributes = css::beans::PropertyAttribute::BOUND;
756 if (rPath.bIsReadonly)
757 pProp->Attributes |= css::beans::PropertyAttribute::READONLY;
758 ++i;
760 pProp = &(m_lPropDesc[i]);
761 pProp->Name = rPath.sPathName+POSTFIX_INTERNAL_PATHES;
762 pProp->Handle = i;
763 pProp->Type = ::getCppuType((css::uno::Sequence< ::rtl::OUString >*)0);
764 pProp->Attributes = css::beans::PropertyAttribute::BOUND |
765 css::beans::PropertyAttribute::READONLY;
766 ++i;
768 pProp = &(m_lPropDesc[i]);
769 pProp->Name = rPath.sPathName+POSTFIX_USER_PATHES;
770 pProp->Handle = i;
771 pProp->Type = ::getCppuType((css::uno::Sequence< ::rtl::OUString >*)0);
772 pProp->Attributes = css::beans::PropertyAttribute::BOUND;
773 if (rPath.bIsReadonly)
774 pProp->Attributes |= css::beans::PropertyAttribute::READONLY;
775 ++i;
777 pProp = &(m_lPropDesc[i]);
778 pProp->Name = rPath.sPathName+POSTFIX_WRITE_PATH;
779 pProp->Handle = i;
780 pProp->Type = ::getCppuType((::rtl::OUString*)0);
781 pProp->Attributes = css::beans::PropertyAttribute::BOUND;
782 if (rPath.bIsReadonly)
783 pProp->Attributes |= css::beans::PropertyAttribute::READONLY;
784 ++i;
787 if (m_pPropHelp)
788 delete m_pPropHelp;
789 m_pPropHelp = new ::cppu::OPropertyArrayHelper(m_lPropDesc, sal_False); // false => not sorted ... must be done inside helper
791 aWriteLock.unlock();
792 // <- SAFE
795 //-----------------------------------------------------------------------------
796 css::uno::Any PathSettings::impl_getPathValue(sal_Int32 nID) const
798 const PathSettings::PathInfo* pPath = impl_getPathAccessConst(nID);
799 if (! pPath)
800 throw css::container::NoSuchElementException();
802 css::uno::Any aVal;
803 switch(impl_getPropGroup(nID))
805 case IDGROUP_OLDSTYLE :
807 ::rtl::OUString sVal = impl_convertPath2OldStyle(*pPath);
808 aVal <<= sVal;
810 break;
812 case IDGROUP_INTERNAL_PATHES :
814 aVal <<= pPath->lInternalPaths.getAsConstList();
816 break;
818 case IDGROUP_USER_PATHES :
820 aVal <<= pPath->lUserPaths.getAsConstList();
822 break;
824 case IDGROUP_WRITE_PATH :
826 aVal <<= pPath->sWritePath;
828 break;
831 return aVal;
834 //-----------------------------------------------------------------------------
835 void PathSettings::impl_setPathValue( sal_Int32 nID ,
836 const css::uno::Any& aVal)
838 PathSettings::PathInfo* pOrgPath = impl_getPathAccess(nID);
839 if (! pOrgPath)
840 throw css::container::NoSuchElementException();
842 // We work on a copied path ... so we can be sure that errors during this operation
843 // does not make our internal cache invalid .-)
844 PathSettings::PathInfo aChangePath(*pOrgPath);
846 switch(impl_getPropGroup(nID))
848 case IDGROUP_OLDSTYLE :
850 ::rtl::OUString sVal;
851 aVal >>= sVal;
852 OUStringList lList = impl_convertOldStyle2Path(sVal);
853 impl_purgeKnownPaths(aChangePath, lList);
854 if (! impl_isValidPath(lList))
855 throw css::lang::IllegalArgumentException();
857 if (aChangePath.bIsSinglePath)
859 LOG_ASSERT2(lList.size()>1, "PathSettings::impl_setPathValue()", "You try to set more then path value for a defined SINGLE_PATH!")
860 if (lList.size()>0)
861 aChangePath.sWritePath = *(lList.begin());
862 else
863 aChangePath.sWritePath = ::rtl::OUString();
865 else
867 OUStringList::const_iterator pIt;
868 for ( pIt = lList.begin();
869 pIt != lList.end() ;
870 ++pIt )
872 aChangePath.lUserPaths.push_back(*pIt);
876 break;
878 case IDGROUP_INTERNAL_PATHES :
880 if (aChangePath.bIsSinglePath)
882 ::rtl::OUStringBuffer sMsg(256);
883 sMsg.appendAscii("The path '" );
884 sMsg.append (aChangePath.sPathName);
885 sMsg.appendAscii("' is defined as SINGLE_PATH. It's sub set of internal pathes cant be set.");
886 throw css::uno::Exception(sMsg.makeStringAndClear(),
887 static_cast< ::cppu::OWeakObject* >(this));
890 OUStringList lList;
891 lList << aVal;
892 if (! impl_isValidPath(lList))
893 throw css::lang::IllegalArgumentException();
894 aChangePath.lInternalPaths = lList;
896 break;
898 case IDGROUP_USER_PATHES :
900 if (aChangePath.bIsSinglePath)
902 ::rtl::OUStringBuffer sMsg(256);
903 sMsg.appendAscii("The path '" );
904 sMsg.append (aChangePath.sPathName);
905 sMsg.appendAscii("' is defined as SINGLE_PATH. It's sub set of internal pathes cant be set.");
906 throw css::uno::Exception(sMsg.makeStringAndClear(),
907 static_cast< ::cppu::OWeakObject* >(this));
910 OUStringList lList;
911 lList << aVal;
912 if (! impl_isValidPath(lList))
913 throw css::lang::IllegalArgumentException();
914 aChangePath.lUserPaths = lList;
916 break;
918 case IDGROUP_WRITE_PATH :
920 ::rtl::OUString sVal;
921 aVal >>= sVal;
922 if (! impl_isValidPath(sVal))
923 throw css::lang::IllegalArgumentException();
924 aChangePath.sWritePath = sVal;
926 break;
929 // TODO check if path has at least one path value set
930 // At least it depends from the feature using this path, if an empty path list is allowed.
932 if (impl_isPathEmpty(aChangePath))
934 ::rtl::OUStringBuffer sMsg(256);
935 sMsg.appendAscii("The path '" );
936 sMsg.append (aChangePath.sPathName);
937 sMsg.appendAscii("' is empty now ... Not a real good idea.");
938 throw css::uno::Exception(sMsg.makeStringAndClear(),
939 static_cast< ::cppu::OWeakObject* >(this));
943 // first we should try to store the changed (copied!) path ...
944 // In case an error occure on saving time an exception is thrown ...
945 // If no exception occures we can update our internal cache (means
946 // we can overwrite pOrgPath !
947 impl_storePath(aChangePath);
948 pOrgPath->takeOver(aChangePath);
951 //-----------------------------------------------------------------------------
952 sal_Bool PathSettings::impl_isValidPath(const OUStringList& lPath) const
954 OUStringList::const_iterator pIt;
955 for ( pIt = lPath.begin();
956 pIt != lPath.end() ;
957 ++pIt )
959 const ::rtl::OUString& rVal = *pIt;
960 if (! impl_isValidPath(rVal))
961 return sal_False;
964 return sal_True;
967 //-----------------------------------------------------------------------------
968 sal_Bool PathSettings::impl_isValidPath(const ::rtl::OUString& sPath) const
970 return (! INetURLObject(sPath).HasError());
973 //-----------------------------------------------------------------------------
974 ::rtl::OUString impl_extractBaseFromPropName(const ::rtl::OUString& sPropName)
976 sal_Int32 i = -1;
978 i = sPropName.indexOf(POSTFIX_INTERNAL_PATHES);
979 if (i > -1)
980 return sPropName.copy(0, i);
981 i = sPropName.indexOf(POSTFIX_USER_PATHES);
982 if (i > -1)
983 return sPropName.copy(0, i);
984 i = sPropName.indexOf(POSTFIX_WRITE_PATH);
985 if (i > -1)
986 return sPropName.copy(0, i);
988 return sPropName;
991 //-----------------------------------------------------------------------------
992 PathSettings::PathInfo* PathSettings::impl_getPathAccess(sal_Int32 nHandle)
994 // SAFE ->
995 ReadGuard aReadLock(m_aLock);
997 if (nHandle > (m_lPropDesc.getLength()-1))
998 return 0;
1000 const css::beans::Property& rProp = m_lPropDesc[nHandle];
1001 ::rtl::OUString sProp = impl_extractBaseFromPropName(rProp.Name);
1002 PathSettings::PathHash::iterator rPath = m_lPaths.find(sProp);
1004 if (rPath != m_lPaths.end())
1005 return &(rPath->second);
1007 return 0;
1008 // <- SAFE
1011 //-----------------------------------------------------------------------------
1012 const PathSettings::PathInfo* PathSettings::impl_getPathAccessConst(sal_Int32 nHandle) const
1014 // SAFE ->
1015 ReadGuard aReadLock(m_aLock);
1017 if (nHandle > (m_lPropDesc.getLength()-1))
1018 return 0;
1020 const css::beans::Property& rProp = m_lPropDesc[nHandle];
1021 ::rtl::OUString sProp = impl_extractBaseFromPropName(rProp.Name);
1022 PathSettings::PathHash::const_iterator rPath = m_lPaths.find(sProp);
1024 if (rPath != m_lPaths.end())
1025 return &(rPath->second);
1027 return 0;
1028 // <- SAFE
1031 //-----------------------------------------------------------------------------
1032 sal_Bool SAL_CALL PathSettings::convertFastPropertyValue( css::uno::Any& aConvertedValue,
1033 css::uno::Any& aOldValue ,
1034 sal_Int32 nHandle ,
1035 const css::uno::Any& aValue )
1036 throw(css::lang::IllegalArgumentException)
1038 // throws NoSuchElementException !
1039 css::uno::Any aCurrentVal = impl_getPathValue(nHandle);
1041 return PropHelper::willPropertyBeChanged(
1042 aCurrentVal,
1043 aValue,
1044 aOldValue,
1045 aConvertedValue);
1048 //-----------------------------------------------------------------------------
1049 void SAL_CALL PathSettings::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle,
1050 const css::uno::Any& aValue )
1051 throw(css::uno::Exception)
1053 // throws NoSuchElement- and IllegalArgumentException !
1054 impl_setPathValue(nHandle, aValue);
1057 //-----------------------------------------------------------------------------
1058 void SAL_CALL PathSettings::getFastPropertyValue(css::uno::Any& aValue ,
1059 sal_Int32 nHandle) const
1061 aValue = impl_getPathValue(nHandle);
1064 //-----------------------------------------------------------------------------
1065 ::cppu::IPropertyArrayHelper& SAL_CALL PathSettings::getInfoHelper()
1067 return *m_pPropHelp;
1070 //-----------------------------------------------------------------------------
1071 css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL PathSettings::getPropertySetInfo()
1072 throw(css::uno::RuntimeException)
1074 return css::uno::Reference< css::beans::XPropertySetInfo >(createPropertySetInfo(getInfoHelper()));
1077 //-----------------------------------------------------------------------------
1078 css::uno::Reference< css::util::XStringSubstitution > PathSettings::fa_getSubstitution()
1080 // SAFE ->
1081 ReadGuard aReadLock(m_aLock);
1082 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
1083 css::uno::Reference< css::util::XStringSubstitution > xSubst = m_xSubstitution;
1084 aReadLock.unlock();
1085 // <- SAFE
1087 if (! xSubst.is())
1089 // create the needed substitution service.
1090 // We must replace all used variables inside readed path values.
1091 // In case we can't do so ... the whole office can't work realy.
1092 // That's why it seams to be OK to throw a RuntimeException then.
1093 xSubst = css::uno::Reference< css::util::XStringSubstitution >(
1094 xSMGR->createInstance(SERVICENAME_SUBSTITUTEPATHVARIABLES),
1095 css::uno::UNO_QUERY_THROW);
1097 // SAFE ->
1098 WriteGuard aWriteLock(m_aLock);
1099 m_xSubstitution = xSubst;
1100 aWriteLock.unlock();
1103 return xSubst;
1106 //-----------------------------------------------------------------------------
1107 css::uno::Reference< css::container::XNameAccess > PathSettings::fa_getCfgOld()
1109 const static ::rtl::OUString CFG_NODE_OLD = ::rtl::OUString::createFromAscii("org.openoffice.Office.Common/Path/Current");
1111 // SAFE ->
1112 ReadGuard aReadLock(m_aLock);
1113 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
1114 css::uno::Reference< css::container::XNameAccess > xCfg = m_xCfgOld;
1115 aReadLock.unlock();
1116 // <- SAFE
1118 if (! xCfg.is())
1120 xCfg = css::uno::Reference< css::container::XNameAccess >(
1121 ::comphelper::ConfigurationHelper::openConfig(
1122 xSMGR,
1123 CFG_NODE_OLD,
1124 ::comphelper::ConfigurationHelper::E_STANDARD), // not readonly! Somtimes we need write access there !!!
1125 css::uno::UNO_QUERY_THROW);
1127 // SAFE ->
1128 WriteGuard aWriteLock(m_aLock);
1129 m_xCfgOld = xCfg;
1130 aWriteLock.unlock();
1133 return xCfg;
1136 //-----------------------------------------------------------------------------
1137 css::uno::Reference< css::container::XNameAccess > PathSettings::fa_getCfgNew()
1139 const static ::rtl::OUString CFG_NODE_NEW = ::rtl::OUString::createFromAscii("org.openoffice.Office.Paths/Paths");
1141 // SAFE ->
1142 ReadGuard aReadLock(m_aLock);
1143 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
1144 css::uno::Reference< css::container::XNameAccess > xCfg = m_xCfgNew;
1145 aReadLock.unlock();
1146 // <- SAFE
1148 if (! xCfg.is())
1150 xCfg = css::uno::Reference< css::container::XNameAccess >(
1151 ::comphelper::ConfigurationHelper::openConfig(
1152 xSMGR,
1153 CFG_NODE_NEW,
1154 ::comphelper::ConfigurationHelper::E_STANDARD),
1155 css::uno::UNO_QUERY_THROW);
1157 // SAFE ->
1158 WriteGuard aWriteLock(m_aLock);
1159 m_xCfgNew = xCfg;
1160 aWriteLock.unlock();
1162 css::uno::Reference< css::util::XChangesNotifier > xBroadcaster(xCfg, css::uno::UNO_QUERY_THROW);
1163 xBroadcaster->addChangesListener(static_cast< css::util::XChangesListener* >(this));
1166 return xCfg;
1169 } // namespace framework