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