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