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