1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include <sal/config.h>
21
22 #include <string_view>
23 #include <utility>
24 #include <unordered_map>
25
26 #include <properties.h>
27 #include <helper/mischelper.hxx>
28
29 #include <com/sun/star/beans/Property.hpp>
30 #include <com/sun/star/beans/XProperty.hpp>
31 #include <com/sun/star/beans/PropertyAttribute.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/util/XChangesNotifier.hpp>
34 #include <com/sun/star/util/PathSubstitution.hpp>
35 #include <com/sun/star/container/XNameAccess.hpp>
36 #include <com/sun/star/lang/XServiceInfo.hpp>
37 #include <com/sun/star/util/XStringSubstitution.hpp>
38 #include <com/sun/star/util/XChangesListener.hpp>
39 #include <com/sun/star/util/XPathSettings.hpp>
40
41 #include <tools/urlobj.hxx>
42 #include <rtl/ustrbuf.hxx>
43 #include <rtl/ref.hxx>
44 #include <sal/log.hxx>
45
46 #include <cppuhelper/basemutex.hxx>
47 #include <cppuhelper/propshlp.hxx>
48 #include <cppuhelper/compbase.hxx>
49 #include <cppuhelper/supportsservice.hxx>
50 #include <comphelper/sequence.hxx>
51 #include <comphelper/configurationhelper.hxx>
52 #include <unotools/configpaths.hxx>
53
54 using namespace framework;
55
56 #define CFGPROP_USERPATHS "UserPaths"
57 #define CFGPROP_WRITEPATH "WritePath"
58
59 /*
60 0 : old style "Template" string using ";" as separator
61 1 : internal paths "Template_internal" string list
62 2 : user paths "Template_user" string list
63 3 : write path "Template_write" string
64 */
65
66 #define POSTFIX_INTERNAL_PATHS "_internal"
67 #define POSTFIX_USER_PATHS "_user"
68 #define POSTFIX_WRITE_PATH "_writable"
69
70 namespace {
71
72 const sal_Int32 IDGROUP_OLDSTYLE = 0;
73 const sal_Int32 IDGROUP_INTERNAL_PATHS = 1;
74 const sal_Int32 IDGROUP_USER_PATHS = 2;
75 const sal_Int32 IDGROUP_WRITE_PATH = 3;
76
77 const sal_Int32 IDGROUP_COUNT = 4;
78
impl_getPropGroup(sal_Int32 nID)79 sal_Int32 impl_getPropGroup(sal_Int32 nID)
80 {
81 return (nID % IDGROUP_COUNT);
82 }
83
84 /* enable it if you wish to migrate old user settings (using the old cfg schema) on demand...
85 disable it in case only the new schema must be used.
86 */
87
88 typedef ::cppu::WeakComponentImplHelper<
89 css::lang::XServiceInfo,
90 css::util::XChangesListener, // => XEventListener
91 css::util::XPathSettings> // => XPropertySet
92 PathSettings_BASE;
93
94 class PathSettings : private cppu::BaseMutex
95 , public PathSettings_BASE
96 , public ::cppu::OPropertySetHelper
97 {
98 struct PathInfo
99 {
100 public:
101
PathInfo__anon002abc1c0111::PathSettings::PathInfo102 PathInfo()
103 : sPathName ()
104 , lInternalPaths()
105 , lUserPaths ()
106 , sWritePath ()
107 , bIsSinglePath (false)
108 , bIsReadonly (false)
109 {}
110
111 /// an internal name describing this path
112 OUString sPathName;
113
114 /// contains all paths, which are used internally - but are not visible for the user.
115 std::vector<OUString> lInternalPaths;
116
117 /// contains all paths configured by the user
118 std::vector<OUString> lUserPaths;
119
120 /// this special path is used to generate feature depending content there
121 OUString sWritePath;
122
123 /// indicates real single paths, which uses WritePath property only
124 bool bIsSinglePath;
125
126 /// simple handling of finalized/mandatory states ... => we know one state READONLY only .-)
127 bool bIsReadonly;
128 };
129
130 typedef std::unordered_map<OUString, PathSettings::PathInfo> PathHash;
131
132 enum EChangeOp
133 {
134 E_UNDEFINED,
135 E_ADDED,
136 E_CHANGED,
137 E_REMOVED
138 };
139
140 private:
141
142 /** reference to factory, which has create this instance. */
143 css::uno::Reference< css::uno::XComponentContext > m_xContext;
144
145 /** list of all path variables and her corresponding values. */
146 PathSettings::PathHash m_lPaths;
147
148 /** describes all properties available on our interface.
149 Will be generated on demand based on our path list m_lPaths. */
150 css::uno::Sequence< css::beans::Property > m_lPropDesc;
151
152 /** helper needed to (re-)substitute all internal save path values. */
153 css::uno::Reference< css::util::XStringSubstitution > m_xSubstitution;
154
155 /** provides access to the old configuration schema (which will be migrated on demand). */
156 css::uno::Reference< css::container::XNameAccess > m_xCfgOld;
157
158 /** provides access to the new configuration schema. */
159 css::uno::Reference< css::container::XNameAccess > m_xCfgNew;
160
161 /** helper to listen for configuration changes without ownership cycle problems */
162 css::uno::Reference< css::util::XChangesListener > m_xCfgNewListener;
163
164 std::unique_ptr<::cppu::OPropertyArrayHelper> m_pPropHelp;
165
166 public:
167
168 /** initialize a new instance of this class.
169 Attention: It's necessary for right function of this class, that the order of base
170 classes is the right one. Because we transfer information from one base to another
171 during this ctor runs! */
172 explicit PathSettings(const css::uno::Reference< css::uno::XComponentContext >& xContext);
173
174 /** free all used resources ... if it was not already done. */
175 virtual ~PathSettings() override;
176
getImplementationName()177 virtual OUString SAL_CALL getImplementationName() override
178 {
179 return "com.sun.star.comp.framework.PathSettings";
180 }
181
supportsService(OUString const & ServiceName)182 virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
183 {
184 return cppu::supportsService(this, ServiceName);
185 }
186
getSupportedServiceNames()187 virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
188 {
189 return {"com.sun.star.util.PathSettings"};
190 }
191
192 // XInterface
193 virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& type) override;
acquire()194 virtual void SAL_CALL acquire() noexcept override
195 { OWeakObject::acquire(); }
release()196 virtual void SAL_CALL release() noexcept override
197 { OWeakObject::release(); }
198
199 // XTypeProvider
200 virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
201
202 // css::util::XChangesListener
203 virtual void SAL_CALL changesOccurred(const css::util::ChangesEvent& aEvent) override;
204
205 // css::lang::XEventListener
206 virtual void SAL_CALL disposing(const css::lang::EventObject& aSource) override;
207
208 /**
209 * XPathSettings attribute methods
210 */
getAddin()211 virtual OUString SAL_CALL getAddin() override
212 { return getStringProperty("Addin"); }
setAddin(const OUString & p1)213 virtual void SAL_CALL setAddin(const OUString& p1) override
214 { setStringProperty("Addin", p1); }
getAutoCorrect()215 virtual OUString SAL_CALL getAutoCorrect() override
216 { return getStringProperty("AutoCorrect"); }
setAutoCorrect(const OUString & p1)217 virtual void SAL_CALL setAutoCorrect(const OUString& p1) override
218 { setStringProperty("AutoCorrect", p1); }
getAutoText()219 virtual OUString SAL_CALL getAutoText() override
220 { return getStringProperty("AutoText"); }
setAutoText(const OUString & p1)221 virtual void SAL_CALL setAutoText(const OUString& p1) override
222 { setStringProperty("AutoText", p1); }
getBackup()223 virtual OUString SAL_CALL getBackup() override
224 { return getStringProperty("Backup"); }
setBackup(const OUString & p1)225 virtual void SAL_CALL setBackup(const OUString& p1) override
226 { setStringProperty("Backup", p1); }
getBasic()227 virtual OUString SAL_CALL getBasic() override
228 { return getStringProperty("Basic"); }
setBasic(const OUString & p1)229 virtual void SAL_CALL setBasic(const OUString& p1) override
230 { setStringProperty("Basic", p1); }
getBitmap()231 virtual OUString SAL_CALL getBitmap() override
232 { return getStringProperty("Bitmap"); }
setBitmap(const OUString & p1)233 virtual void SAL_CALL setBitmap(const OUString& p1) override
234 { setStringProperty("Bitmap", p1); }
getConfig()235 virtual OUString SAL_CALL getConfig() override
236 { return getStringProperty("Config"); }
setConfig(const OUString & p1)237 virtual void SAL_CALL setConfig(const OUString& p1) override
238 { setStringProperty("Config", p1); }
getDictionary()239 virtual OUString SAL_CALL getDictionary() override
240 { return getStringProperty("Dictionary"); }
setDictionary(const OUString & p1)241 virtual void SAL_CALL setDictionary(const OUString& p1) override
242 { setStringProperty("Dictionary", p1); }
getFavorite()243 virtual OUString SAL_CALL getFavorite() override
244 { return getStringProperty("Favorite"); }
setFavorite(const OUString & p1)245 virtual void SAL_CALL setFavorite(const OUString& p1) override
246 { setStringProperty("Favorite", p1); }
getFilter()247 virtual OUString SAL_CALL getFilter() override
248 { return getStringProperty("Filter"); }
setFilter(const OUString & p1)249 virtual void SAL_CALL setFilter(const OUString& p1) override
250 { setStringProperty("Filter", p1); }
getGallery()251 virtual OUString SAL_CALL getGallery() override
252 { return getStringProperty("Gallery"); }
setGallery(const OUString & p1)253 virtual void SAL_CALL setGallery(const OUString& p1) override
254 { setStringProperty("Gallery", p1); }
getGraphic()255 virtual OUString SAL_CALL getGraphic() override
256 { return getStringProperty("Graphic"); }
setGraphic(const OUString & p1)257 virtual void SAL_CALL setGraphic(const OUString& p1) override
258 { setStringProperty("Graphic", p1); }
getHelp()259 virtual OUString SAL_CALL getHelp() override
260 { return getStringProperty("Help"); }
setHelp(const OUString & p1)261 virtual void SAL_CALL setHelp(const OUString& p1) override
262 { setStringProperty("Help", p1); }
getLinguistic()263 virtual OUString SAL_CALL getLinguistic() override
264 { return getStringProperty("Linguistic"); }
setLinguistic(const OUString & p1)265 virtual void SAL_CALL setLinguistic(const OUString& p1) override
266 { setStringProperty("Linguistic", p1); }
getModule()267 virtual OUString SAL_CALL getModule() override
268 { return getStringProperty("Module"); }
setModule(const OUString & p1)269 virtual void SAL_CALL setModule(const OUString& p1) override
270 { setStringProperty("Module", p1); }
getPalette()271 virtual OUString SAL_CALL getPalette() override
272 { return getStringProperty("Palette"); }
setPalette(const OUString & p1)273 virtual void SAL_CALL setPalette(const OUString& p1) override
274 { setStringProperty("Palette", p1); }
getPlugin()275 virtual OUString SAL_CALL getPlugin() override
276 { return getStringProperty("Plugin"); }
setPlugin(const OUString & p1)277 virtual void SAL_CALL setPlugin(const OUString& p1) override
278 { setStringProperty("Plugin", p1); }
getStorage()279 virtual OUString SAL_CALL getStorage() override
280 { return getStringProperty("Storage"); }
setStorage(const OUString & p1)281 virtual void SAL_CALL setStorage(const OUString& p1) override
282 { setStringProperty("Storage", p1); }
getTemp()283 virtual OUString SAL_CALL getTemp() override
284 { return getStringProperty("Temp"); }
setTemp(const OUString & p1)285 virtual void SAL_CALL setTemp(const OUString& p1) override
286 { setStringProperty("Temp", p1); }
getTemplate()287 virtual OUString SAL_CALL getTemplate() override
288 { return getStringProperty("Template"); }
setTemplate(const OUString & p1)289 virtual void SAL_CALL setTemplate(const OUString& p1) override
290 { setStringProperty("Template", p1); }
getUIConfig()291 virtual OUString SAL_CALL getUIConfig() override
292 { return getStringProperty("UIConfig"); }
setUIConfig(const OUString & p1)293 virtual void SAL_CALL setUIConfig(const OUString& p1) override
294 { setStringProperty("UIConfig", p1); }
getUserConfig()295 virtual OUString SAL_CALL getUserConfig() override
296 { return getStringProperty("UserConfig"); }
setUserConfig(const OUString & p1)297 virtual void SAL_CALL setUserConfig(const OUString& p1) override
298 { setStringProperty("UserConfig", p1); }
getUserDictionary()299 virtual OUString SAL_CALL getUserDictionary() override
300 { return getStringProperty("UserDictionary"); }
setUserDictionary(const OUString & p1)301 virtual void SAL_CALL setUserDictionary(const OUString& p1) override
302 { setStringProperty("UserDictionary", p1); }
getWork()303 virtual OUString SAL_CALL getWork() override
304 { return getStringProperty("Work"); }
setWork(const OUString & p1)305 virtual void SAL_CALL setWork(const OUString& p1) override
306 { setStringProperty("Work", p1); }
getBasePathShareLayer()307 virtual OUString SAL_CALL getBasePathShareLayer() override
308 { return getStringProperty("UIConfig"); }
setBasePathShareLayer(const OUString & p1)309 virtual void SAL_CALL setBasePathShareLayer(const OUString& p1) override
310 { setStringProperty("UIConfig", p1); }
getBasePathUserLayer()311 virtual OUString SAL_CALL getBasePathUserLayer() override
312 { return getStringProperty("UserConfig"); }
setBasePathUserLayer(const OUString & p1)313 virtual void SAL_CALL setBasePathUserLayer(const OUString& p1) override
314 { setStringProperty("UserConfig", p1); }
315
316 /**
317 * overrides to resolve inheritance ambiguity
318 */
setPropertyValue(const OUString & p1,const css::uno::Any & p2)319 virtual void SAL_CALL setPropertyValue(const OUString& p1, const css::uno::Any& p2) override
320 { ::cppu::OPropertySetHelper::setPropertyValue(p1, p2); }
getPropertyValue(const OUString & p1)321 virtual css::uno::Any SAL_CALL getPropertyValue(const OUString& p1) override
322 { return ::cppu::OPropertySetHelper::getPropertyValue(p1); }
addPropertyChangeListener(const OUString & p1,const css::uno::Reference<css::beans::XPropertyChangeListener> & p2)323 virtual void SAL_CALL addPropertyChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XPropertyChangeListener>& p2) override
324 { ::cppu::OPropertySetHelper::addPropertyChangeListener(p1, p2); }
removePropertyChangeListener(const OUString & p1,const css::uno::Reference<css::beans::XPropertyChangeListener> & p2)325 virtual void SAL_CALL removePropertyChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XPropertyChangeListener>& p2) override
326 { ::cppu::OPropertySetHelper::removePropertyChangeListener(p1, p2); }
addVetoableChangeListener(const OUString & p1,const css::uno::Reference<css::beans::XVetoableChangeListener> & p2)327 virtual void SAL_CALL addVetoableChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XVetoableChangeListener>& p2) override
328 { ::cppu::OPropertySetHelper::addVetoableChangeListener(p1, p2); }
removeVetoableChangeListener(const OUString & p1,const css::uno::Reference<css::beans::XVetoableChangeListener> & p2)329 virtual void SAL_CALL removeVetoableChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XVetoableChangeListener>& p2) override
330 { ::cppu::OPropertySetHelper::removeVetoableChangeListener(p1, p2); }
331 /** read all configured paths and create all needed internal structures. */
332 void impl_readAll();
333
334 private:
335 virtual void SAL_CALL disposing() final override;
336
337 /// @throws css::uno::RuntimeException
338 OUString getStringProperty(const OUString& p1);
339
340 /// @throws css::uno::RuntimeException
341 void setStringProperty(const OUString& p1, const OUString& p2);
342
343 /** read a path info using the old cfg schema.
344 This is needed for "migration on demand" reasons only.
345 Can be removed for next major release .-) */
346 std::vector<OUString> impl_readOldFormat(const OUString& sPath);
347
348 /** read a path info using the new cfg schema. */
349 PathSettings::PathInfo impl_readNewFormat(const OUString& sPath);
350
351 /** filter "real user defined paths" from the old configuration schema
352 and set it as UserPaths on the new schema.
353 Can be removed with new major release ... */
354
355 void impl_mergeOldUserPaths( PathSettings::PathInfo& rPath,
356 const std::vector<OUString>& lOld );
357
358 /** reload one path directly from the new configuration schema (because
359 it was updated by any external code) */
360 PathSettings::EChangeOp impl_updatePath(const OUString& sPath ,
361 bool bNotifyListener);
362
363 /** replace all might existing placeholder variables inside the given path ...
364 or check if the given path value uses paths, which can be replaced with predefined
365 placeholder variables ...
366 */
367 void impl_subst(std::vector<OUString>& lVals ,
368 const css::uno::Reference< css::util::XStringSubstitution >& xSubst ,
369 bool bReSubst);
370
371 void impl_subst(PathSettings::PathInfo& aPath ,
372 bool bReSubst);
373
374 /** converts our new string list schema to the old ";" separated schema ... */
375 OUString impl_convertPath2OldStyle(const PathSettings::PathInfo& rPath ) const;
376 std::vector<OUString> impl_convertOldStyle2Path(const OUString& sOldStylePath) const;
377
378 /** remove still known paths from the given lList argument.
379 So real user defined paths can be extracted from the list of
380 fix internal paths !
381 */
382 void impl_purgeKnownPaths(PathSettings::PathInfo& rPath,
383 std::vector<OUString>& lList);
384
385 /** rebuild the member m_lPropDesc using the path list m_lPaths. */
386 void impl_rebuildPropertyDescriptor();
387
388 /** provides direct access to the list of path values
389 using its internal property id.
390 */
391 css::uno::Any impl_getPathValue( sal_Int32 nID ) const;
392 void impl_setPathValue( sal_Int32 nID ,
393 const css::uno::Any& aVal);
394
395 /** check the given handle and return the corresponding PathInfo reference.
396 These reference can be used then directly to manipulate these path. */
397 PathSettings::PathInfo* impl_getPathAccess (sal_Int32 nHandle);
398 const PathSettings::PathInfo* impl_getPathAccessConst(sal_Int32 nHandle) const;
399
400 /** it checks, if the given path value seems to be a valid URL or system path. */
401 bool impl_isValidPath(const OUString& sPath) const;
402 bool impl_isValidPath(const std::vector<OUString>& lPath) const;
403
404 void impl_storePath(const PathSettings::PathInfo& aPath);
405
406 css::uno::Sequence< sal_Int32 > impl_mapPathName2IDList(std::u16string_view sPath);
407
408 void impl_notifyPropListener( std::u16string_view sPath ,
409 const PathSettings::PathInfo* pPathOld,
410 const PathSettings::PathInfo* pPathNew);
411
412 // OPropertySetHelper
413 virtual sal_Bool SAL_CALL convertFastPropertyValue( css::uno::Any& aConvertedValue,
414 css::uno::Any& aOldValue,
415 sal_Int32 nHandle,
416 const css::uno::Any& aValue ) override;
417 virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle,
418 const css::uno::Any& aValue ) override;
419 virtual void SAL_CALL getFastPropertyValue( css::uno::Any& aValue,
420 sal_Int32 nHandle ) const override;
421 // Avoid:
422 // warning: 'virtual css::uno::Any cppu::OPropertySetHelper::getFastPropertyValue(sal_Int32)' was hidden [-Woverloaded-virtual]
423 // warning: by ‘virtual void {anonymous}::PathSettings::getFastPropertyValue(css::uno::Any&, sal_Int32) const’ [-Woverloaded-virtual]
424 using cppu::OPropertySetHelper::getFastPropertyValue;
425 virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
426 virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
427
428 /** factory methods to guarantee right (but on demand) initialized members ... */
429 css::uno::Reference< css::util::XStringSubstitution > fa_getSubstitution();
430 css::uno::Reference< css::container::XNameAccess > fa_getCfgOld();
431 css::uno::Reference< css::container::XNameAccess > fa_getCfgNew();
432 };
433
PathSettings(const css::uno::Reference<css::uno::XComponentContext> & xContext)434 PathSettings::PathSettings( const css::uno::Reference< css::uno::XComponentContext >& xContext )
435 : PathSettings_BASE(m_aMutex)
436 , ::cppu::OPropertySetHelper(cppu::WeakComponentImplHelperBase::rBHelper)
437 , m_xContext (xContext)
438 {
439 }
440
~PathSettings()441 PathSettings::~PathSettings()
442 {
443 disposing();
444 }
445
disposing()446 void SAL_CALL PathSettings::disposing()
447 {
448 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
449
450 css::uno::Reference< css::util::XChangesNotifier >
451 xBroadcaster(m_xCfgNew, css::uno::UNO_QUERY);
452 if (xBroadcaster.is())
453 xBroadcaster->removeChangesListener(m_xCfgNewListener);
454
455 m_xSubstitution.clear();
456 m_xCfgOld.clear();
457 m_xCfgNew.clear();
458 m_xCfgNewListener.clear();
459
460 m_pPropHelp.reset();
461 }
462
queryInterface(const css::uno::Type & _rType)463 css::uno::Any SAL_CALL PathSettings::queryInterface( const css::uno::Type& _rType )
464 {
465 css::uno::Any aRet = PathSettings_BASE::queryInterface( _rType );
466 if ( !aRet.hasValue() )
467 aRet = ::cppu::OPropertySetHelper::queryInterface( _rType );
468 return aRet;
469 }
470
getTypes()471 css::uno::Sequence< css::uno::Type > SAL_CALL PathSettings::getTypes( )
472 {
473 return comphelper::concatSequences(
474 PathSettings_BASE::getTypes(),
475 ::cppu::OPropertySetHelper::getTypes()
476 );
477 }
478
changesOccurred(const css::util::ChangesEvent & aEvent)479 void SAL_CALL PathSettings::changesOccurred(const css::util::ChangesEvent& aEvent)
480 {
481 sal_Int32 c = aEvent.Changes.getLength();
482 sal_Int32 i = 0;
483 bool bUpdateDescriptor = false;
484
485 for (i=0; i<c; ++i)
486 {
487 const css::util::ElementChange& aChange = aEvent.Changes[i];
488
489 OUString sChanged;
490 aChange.Accessor >>= sChanged;
491
492 OUString sPath = ::utl::extractFirstFromConfigurationPath(sChanged);
493 if (!sPath.isEmpty())
494 {
495 PathSettings::EChangeOp eOp = impl_updatePath(sPath, true);
496 if (
497 (eOp == PathSettings::E_ADDED ) ||
498 (eOp == PathSettings::E_REMOVED)
499 )
500 bUpdateDescriptor = true;
501 }
502 }
503
504 if (bUpdateDescriptor)
505 impl_rebuildPropertyDescriptor();
506 }
507
disposing(const css::lang::EventObject & aSource)508 void SAL_CALL PathSettings::disposing(const css::lang::EventObject& aSource)
509 {
510 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
511
512 if (aSource.Source == m_xCfgNew)
513 m_xCfgNew.clear();
514 }
515
getStringProperty(const OUString & p1)516 OUString PathSettings::getStringProperty(const OUString& p1)
517 {
518 css::uno::Any a = ::cppu::OPropertySetHelper::getPropertyValue(p1);
519 OUString s;
520 a >>= s;
521 return s;
522 }
523
setStringProperty(const OUString & p1,const OUString & p2)524 void PathSettings::setStringProperty(const OUString& p1, const OUString& p2)
525 {
526 ::cppu::OPropertySetHelper::setPropertyValue(p1, css::uno::Any(p2));
527 }
528
impl_readAll()529 void PathSettings::impl_readAll()
530 {
531 try
532 {
533 // TODO think about me
534 css::uno::Reference< css::container::XNameAccess > xCfg = fa_getCfgNew();
535 css::uno::Sequence< OUString > lPaths = xCfg->getElementNames();
536
537 sal_Int32 c = lPaths.getLength();
538 for (sal_Int32 i = 0; i < c; ++i)
539 {
540 const OUString& sPath = lPaths[i];
541 impl_updatePath(sPath, false);
542 }
543 }
544 catch(const css::uno::RuntimeException& )
545 {
546 }
547
548 impl_rebuildPropertyDescriptor();
549 }
550
551 // NO substitution here ! It's done outside ...
impl_readOldFormat(const OUString & sPath)552 std::vector<OUString> PathSettings::impl_readOldFormat(const OUString& sPath)
553 {
554 css::uno::Reference< css::container::XNameAccess > xCfg( fa_getCfgOld() );
555 std::vector<OUString> aPathVal;
556
557 if( xCfg->hasByName(sPath) )
558 {
559 css::uno::Any aVal( xCfg->getByName(sPath) );
560
561 OUString sStringVal;
562 css::uno::Sequence< OUString > lStringListVal;
563
564 if (aVal >>= sStringVal)
565 {
566 aPathVal.push_back(sStringVal);
567 }
568 else if (aVal >>= lStringListVal)
569 {
570 aPathVal = comphelper::sequenceToContainer<std::vector<OUString>>(lStringListVal);
571 }
572 }
573
574 return aPathVal;
575 }
576
577 // NO substitution here ! It's done outside ...
impl_readNewFormat(const OUString & sPath)578 PathSettings::PathInfo PathSettings::impl_readNewFormat(const OUString& sPath)
579 {
580 css::uno::Reference< css::container::XNameAccess > xCfg = fa_getCfgNew();
581
582 // get access to the "queried" path
583 css::uno::Reference< css::container::XNameAccess > xPath;
584 xCfg->getByName(sPath) >>= xPath;
585
586 PathSettings::PathInfo aPathVal;
587
588 // read internal path list
589 css::uno::Reference< css::container::XNameAccess > xIPath;
590 xPath->getByName("InternalPaths") >>= xIPath;
591 aPathVal.lInternalPaths = comphelper::sequenceToContainer<std::vector<OUString>>(xIPath->getElementNames());
592
593 // read user defined path list
594 css::uno::Sequence<OUString> vTmpUserPathsSeq;
595 xPath->getByName(CFGPROP_USERPATHS) >>= vTmpUserPathsSeq;
596 aPathVal.lUserPaths = comphelper::sequenceToContainer<std::vector<OUString>>(vTmpUserPathsSeq);
597
598 // read the writeable path
599 xPath->getByName(CFGPROP_WRITEPATH) >>= aPathVal.sWritePath;
600
601 // avoid duplicates, by removing the writeable path from
602 // the user defined path list if it happens to be there too
603 std::vector<OUString>::iterator aI = std::find(aPathVal.lUserPaths.begin(), aPathVal.lUserPaths.end(), aPathVal.sWritePath);
604 if (aI != aPathVal.lUserPaths.end())
605 aPathVal.lUserPaths.erase(aI);
606
607 // read state props
608 xPath->getByName("IsSinglePath") >>= aPathVal.bIsSinglePath;
609
610 // analyze finalized/mandatory states
611 aPathVal.bIsReadonly = false;
612 css::uno::Reference< css::beans::XProperty > xInfo(xPath, css::uno::UNO_QUERY);
613 if (xInfo.is())
614 {
615 css::beans::Property aInfo = xInfo->getAsProperty();
616 bool bFinalized = ((aInfo.Attributes & css::beans::PropertyAttribute::READONLY ) == css::beans::PropertyAttribute::READONLY );
617
618 // Note: 'till we support finalized/mandatory on our API more in detail we handle
619 // all states simple as READONLY! But because all really needed paths are "mandatory" by default
620 // we have to handle "finalized" as the real "readonly" indicator.
621 aPathVal.bIsReadonly = bFinalized;
622 }
623
624 return aPathVal;
625 }
626
impl_storePath(const PathSettings::PathInfo & aPath)627 void PathSettings::impl_storePath(const PathSettings::PathInfo& aPath)
628 {
629 css::uno::Reference< css::container::XNameAccess > xCfgNew = fa_getCfgNew();
630 css::uno::Reference< css::container::XNameAccess > xCfgOld = fa_getCfgOld();
631
632 // try to replace path-parts with well known and supported variables.
633 // So an office can be moved easily to another location without losing
634 // its related paths.
635 PathInfo aResubstPath(aPath);
636 impl_subst(aResubstPath, true);
637
638 // update new configuration
639 if (! aResubstPath.bIsSinglePath)
640 {
641 ::comphelper::ConfigurationHelper::writeRelativeKey(xCfgNew,
642 aResubstPath.sPathName,
643 CFGPROP_USERPATHS,
644 css::uno::makeAny(comphelper::containerToSequence(aResubstPath.lUserPaths)));
645 }
646
647 ::comphelper::ConfigurationHelper::writeRelativeKey(xCfgNew,
648 aResubstPath.sPathName,
649 CFGPROP_WRITEPATH,
650 css::uno::makeAny(aResubstPath.sWritePath));
651
652 ::comphelper::ConfigurationHelper::flush(xCfgNew);
653
654 // remove the whole path from the old configuration!
655 // Otherwise we can't make sure that the diff between new and old configuration
656 // on loading time really represents a user setting!!!
657
658 // Check if the given path exists inside the old configuration.
659 // Because our new configuration knows more than the list of old paths ... !
660 if (xCfgOld->hasByName(aResubstPath.sPathName))
661 {
662 css::uno::Reference< css::beans::XPropertySet > xProps(xCfgOld, css::uno::UNO_QUERY_THROW);
663 xProps->setPropertyValue(aResubstPath.sPathName, css::uno::Any());
664 ::comphelper::ConfigurationHelper::flush(xCfgOld);
665 }
666 }
667
impl_mergeOldUserPaths(PathSettings::PathInfo & rPath,const std::vector<OUString> & lOld)668 void PathSettings::impl_mergeOldUserPaths( PathSettings::PathInfo& rPath,
669 const std::vector<OUString>& lOld )
670 {
671 for (auto const& old : lOld)
672 {
673 if (rPath.bIsSinglePath)
674 {
675 SAL_WARN_IF(lOld.size()>1, "fwk", "PathSettings::impl_mergeOldUserPaths(): Single path has more than one path value inside old configuration (Common.xcu)!");
676 if ( rPath.sWritePath != old )
677 rPath.sWritePath = old;
678 }
679 else
680 {
681 if (
682 ( std::find(rPath.lInternalPaths.begin(), rPath.lInternalPaths.end(), old) == rPath.lInternalPaths.end()) &&
683 ( std::find(rPath.lUserPaths.begin(), rPath.lUserPaths.end(), old) == rPath.lUserPaths.end() ) &&
684 ( rPath.sWritePath != old )
685 )
686 rPath.lUserPaths.push_back(old);
687 }
688 }
689 }
690
impl_updatePath(const OUString & sPath,bool bNotifyListener)691 PathSettings::EChangeOp PathSettings::impl_updatePath(const OUString& sPath ,
692 bool bNotifyListener)
693 {
694 // SAFE ->
695 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
696
697 PathSettings::PathInfo* pPathOld = nullptr;
698 PathSettings::PathInfo* pPathNew = nullptr;
699 PathSettings::EChangeOp eOp = PathSettings::E_UNDEFINED;
700 PathSettings::PathInfo aPath;
701
702 try
703 {
704 aPath = impl_readNewFormat(sPath);
705 aPath.sPathName = sPath;
706 // replace all might existing variables with real values
707 // Do it before these old paths will be compared against the
708 // new path configuration. Otherwise some strings uses different variables ... but substitution
709 // will produce strings with same content (because some variables are redundant!)
710 impl_subst(aPath, false);
711 }
712 catch(const css::uno::RuntimeException&)
713 { throw; }
714 catch(const css::container::NoSuchElementException&)
715 { eOp = PathSettings::E_REMOVED; }
716 catch(const css::uno::Exception&)
717 { throw; }
718
719 try
720 {
721 // migration of old user defined values on demand
722 // can be disabled for a new major
723 std::vector<OUString> lOldVals = impl_readOldFormat(sPath);
724 // replace all might existing variables with real values
725 // Do it before these old paths will be compared against the
726 // new path configuration. Otherwise some strings uses different variables ... but substitution
727 // will produce strings with same content (because some variables are redundant!)
728 impl_subst(lOldVals, fa_getSubstitution(), false);
729 impl_mergeOldUserPaths(aPath, lOldVals);
730 }
731 catch(const css::uno::RuntimeException&)
732 { throw; }
733 // Normal(!) exceptions can be ignored!
734 // E.g. in case an addon installs a new path, which was not well known for an OOo 1.x installation
735 // we can't find a value for it inside the "old" configuration. So a NoSuchElementException
736 // will be normal .-)
737 catch(const css::uno::Exception&)
738 {}
739
740 PathSettings::PathHash::iterator pPath = m_lPaths.find(sPath);
741 if (eOp == PathSettings::E_UNDEFINED)
742 {
743 if (pPath != m_lPaths.end())
744 eOp = PathSettings::E_CHANGED;
745 else
746 eOp = PathSettings::E_ADDED;
747 }
748
749 switch(eOp)
750 {
751 case PathSettings::E_ADDED :
752 {
753 if (bNotifyListener)
754 {
755 pPathOld = nullptr;
756 pPathNew = &aPath;
757 impl_notifyPropListener(sPath, pPathOld, pPathNew);
758 }
759 m_lPaths[sPath] = aPath;
760 }
761 break;
762
763 case PathSettings::E_CHANGED :
764 {
765 if (bNotifyListener)
766 {
767 pPathOld = &(pPath->second);
768 pPathNew = &aPath;
769 impl_notifyPropListener(sPath, pPathOld, pPathNew);
770 }
771 m_lPaths[sPath] = aPath;
772 }
773 break;
774
775 case PathSettings::E_REMOVED :
776 {
777 if (pPath != m_lPaths.end())
778 {
779 if (bNotifyListener)
780 {
781 pPathOld = &(pPath->second);
782 pPathNew = nullptr;
783 impl_notifyPropListener(sPath, pPathOld, pPathNew);
784 }
785 m_lPaths.erase(pPath);
786 }
787 }
788 break;
789
790 default: // to let compiler be happy
791 break;
792 }
793
794 return eOp;
795 }
796
impl_mapPathName2IDList(std::u16string_view sPath)797 css::uno::Sequence< sal_Int32 > PathSettings::impl_mapPathName2IDList(std::u16string_view sPath)
798 {
799 OUString sInternalProp = OUString::Concat(sPath)+POSTFIX_INTERNAL_PATHS;
800 OUString sUserProp = OUString::Concat(sPath)+POSTFIX_USER_PATHS;
801 OUString sWriteProp = OUString::Concat(sPath)+POSTFIX_WRITE_PATH;
802
803 // Attention: The default set of IDs is fix and must follow these schema.
804 // Otherwise the outside code ant work for new added properties.
805 // Why?
806 // The outside code must fire N events for every changed property.
807 // And the knowing about packaging of variables of the structure PathInfo
808 // follow these group IDs! But if such ID is not in the range of [0..IDGROUP_COUNT]
809 // the outside can't determine the right group ... and can not fire the right events .-)
810
811 css::uno::Sequence< sal_Int32 > lIDs(IDGROUP_COUNT);
812 lIDs[0] = IDGROUP_OLDSTYLE;
813 lIDs[1] = IDGROUP_INTERNAL_PATHS;
814 lIDs[2] = IDGROUP_USER_PATHS;
815 lIDs[3] = IDGROUP_WRITE_PATH;
816
817 sal_Int32 c = m_lPropDesc.getLength();
818 sal_Int32 i = 0;
819 for (i=0; i<c; ++i)
820 {
821 const css::beans::Property& rProp = m_lPropDesc[i];
822
823 if (rProp.Name == sPath)
824 lIDs[IDGROUP_OLDSTYLE] = rProp.Handle;
825 else
826 if (rProp.Name == sInternalProp)
827 lIDs[IDGROUP_INTERNAL_PATHS] = rProp.Handle;
828 else
829 if (rProp.Name == sUserProp)
830 lIDs[IDGROUP_USER_PATHS] = rProp.Handle;
831 else
832 if (rProp.Name == sWriteProp)
833 lIDs[IDGROUP_WRITE_PATH] = rProp.Handle;
834 }
835
836 return lIDs;
837 }
838
impl_notifyPropListener(std::u16string_view sPath,const PathSettings::PathInfo * pPathOld,const PathSettings::PathInfo * pPathNew)839 void PathSettings::impl_notifyPropListener( std::u16string_view sPath,
840 const PathSettings::PathInfo* pPathOld,
841 const PathSettings::PathInfo* pPathNew)
842 {
843 css::uno::Sequence< sal_Int32 > lHandles(1);
844 css::uno::Sequence< css::uno::Any > lOldVals(1);
845 css::uno::Sequence< css::uno::Any > lNewVals(1);
846
847 css::uno::Sequence< sal_Int32 > lIDs = impl_mapPathName2IDList(sPath);
848 sal_Int32 c = lIDs.getLength();
849 sal_Int32 i = 0;
850 sal_Int32 nMaxID = m_lPropDesc.getLength()-1;
851 for (i=0; i<c; ++i)
852 {
853 sal_Int32 nID = lIDs[i];
854
855 if (
856 (nID < 0 ) ||
857 (nID > nMaxID)
858 )
859 continue;
860
861 lHandles[0] = nID;
862 switch(impl_getPropGroup(nID))
863 {
864 case IDGROUP_OLDSTYLE :
865 {
866 if (pPathOld)
867 {
868 OUString sVal = impl_convertPath2OldStyle(*pPathOld);
869 lOldVals[0] <<= sVal;
870 }
871 if (pPathNew)
872 {
873 OUString sVal = impl_convertPath2OldStyle(*pPathNew);
874 lNewVals[0] <<= sVal;
875 }
876 }
877 break;
878
879 case IDGROUP_INTERNAL_PATHS :
880 {
881 if (pPathOld)
882 lOldVals[0] <<= comphelper::containerToSequence(pPathOld->lInternalPaths);
883 if (pPathNew)
884 lNewVals[0] <<= comphelper::containerToSequence(pPathNew->lInternalPaths);
885 }
886 break;
887
888 case IDGROUP_USER_PATHS :
889 {
890 if (pPathOld)
891 lOldVals[0] <<= comphelper::containerToSequence(pPathOld->lUserPaths);
892 if (pPathNew)
893 lNewVals[0] <<= comphelper::containerToSequence(pPathNew->lUserPaths);
894 }
895 break;
896
897 case IDGROUP_WRITE_PATH :
898 {
899 if (pPathOld)
900 lOldVals[0] <<= pPathOld->sWritePath;
901 if (pPathNew)
902 lNewVals[0] <<= pPathNew->sWritePath;
903 }
904 break;
905 }
906
907 fire(lHandles.getArray(),
908 lNewVals.getArray(),
909 lOldVals.getArray(),
910 1,
911 false);
912 }
913 }
914
impl_subst(std::vector<OUString> & lVals,const css::uno::Reference<css::util::XStringSubstitution> & xSubst,bool bReSubst)915 void PathSettings::impl_subst(std::vector<OUString>& lVals ,
916 const css::uno::Reference< css::util::XStringSubstitution >& xSubst ,
917 bool bReSubst)
918 {
919 for (auto & old : lVals)
920 {
921 OUString sNew;
922 if (bReSubst)
923 sNew = xSubst->reSubstituteVariables(old);
924 else
925 sNew = xSubst->substituteVariables(old, false);
926
927 old = sNew;
928 }
929 }
930
impl_subst(PathSettings::PathInfo & aPath,bool bReSubst)931 void PathSettings::impl_subst(PathSettings::PathInfo& aPath ,
932 bool bReSubst)
933 {
934 css::uno::Reference< css::util::XStringSubstitution > xSubst = fa_getSubstitution();
935
936 impl_subst(aPath.lInternalPaths, xSubst, bReSubst);
937 impl_subst(aPath.lUserPaths , xSubst, bReSubst);
938 if (bReSubst)
939 aPath.sWritePath = xSubst->reSubstituteVariables(aPath.sWritePath);
940 else
941 aPath.sWritePath = xSubst->substituteVariables(aPath.sWritePath, false);
942 }
943
impl_convertPath2OldStyle(const PathSettings::PathInfo & rPath) const944 OUString PathSettings::impl_convertPath2OldStyle(const PathSettings::PathInfo& rPath) const
945 {
946 std::vector<OUString> lTemp;
947 lTemp.reserve(rPath.lInternalPaths.size() + rPath.lUserPaths.size() + 1);
948
949 for (auto const& internalPath : rPath.lInternalPaths)
950 {
951 lTemp.push_back(internalPath);
952 }
953 for (auto const& userPath : rPath.lUserPaths)
954 {
955 lTemp.push_back(userPath);
956 }
957
958 if (!rPath.sWritePath.isEmpty())
959 lTemp.push_back(rPath.sWritePath);
960
961 OUStringBuffer sPathVal(256);
962 for ( auto pIt = lTemp.begin();
963 pIt != lTemp.end();
964 )
965 {
966 sPathVal.append(*pIt);
967 ++pIt;
968 if (pIt != lTemp.end())
969 sPathVal.append(";");
970 }
971
972 return sPathVal.makeStringAndClear();
973 }
974
impl_convertOldStyle2Path(const OUString & sOldStylePath) const975 std::vector<OUString> PathSettings::impl_convertOldStyle2Path(const OUString& sOldStylePath) const
976 {
977 std::vector<OUString> lList;
978 sal_Int32 nToken = 0;
979 do
980 {
981 OUString sToken = sOldStylePath.getToken(0, ';', nToken);
982 if (!sToken.isEmpty())
983 lList.push_back(sToken);
984 }
985 while(nToken >= 0);
986
987 return lList;
988 }
989
impl_purgeKnownPaths(PathSettings::PathInfo & rPath,std::vector<OUString> & lList)990 void PathSettings::impl_purgeKnownPaths(PathSettings::PathInfo& rPath,
991 std::vector<OUString>& lList)
992 {
993 // Erase items in the internal path list from lList.
994 // Also erase items in the internal path list from the user path list.
995 for (auto const& internalPath : rPath.lInternalPaths)
996 {
997 std::vector<OUString>::iterator pItem = std::find(lList.begin(), lList.end(), internalPath);
998 if (pItem != lList.end())
999 lList.erase(pItem);
1000 pItem = std::find(rPath.lUserPaths.begin(), rPath.lUserPaths.end(), internalPath);
1001 if (pItem != rPath.lUserPaths.end())
1002 rPath.lUserPaths.erase(pItem);
1003 }
1004
1005 // Erase items not in lList from the user path list.
1006 rPath.lUserPaths.erase(std::remove_if(rPath.lUserPaths.begin(), rPath.lUserPaths.end(),
1007 [&lList](const OUString& rItem) {
1008 return std::find(lList.begin(), lList.end(), rItem) == lList.end();
1009 }),
1010 rPath.lUserPaths.end());
1011
1012 // Erase items in the user path list from lList.
1013 for (auto const& userPath : rPath.lUserPaths)
1014 {
1015 std::vector<OUString>::iterator pItem = std::find(lList.begin(), lList.end(), userPath);
1016 if (pItem != lList.end())
1017 lList.erase(pItem);
1018 }
1019
1020 // Erase the write path from lList
1021 std::vector<OUString>::iterator pItem = std::find(lList.begin(), lList.end(), rPath.sWritePath);
1022 if (pItem != lList.end())
1023 lList.erase(pItem);
1024 }
1025
impl_rebuildPropertyDescriptor()1026 void PathSettings::impl_rebuildPropertyDescriptor()
1027 {
1028 // SAFE ->
1029 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
1030
1031 sal_Int32 c = static_cast<sal_Int32>(m_lPaths.size());
1032 sal_Int32 i = 0;
1033 m_lPropDesc.realloc(c*IDGROUP_COUNT);
1034
1035 for (auto const& path : m_lPaths)
1036 {
1037 const PathSettings::PathInfo& rPath = path.second;
1038 css::beans::Property* pProp = nullptr;
1039
1040 pProp = &(m_lPropDesc[i]);
1041 pProp->Name = rPath.sPathName;
1042 pProp->Handle = i;
1043 pProp->Type = cppu::UnoType<OUString>::get();
1044 pProp->Attributes = css::beans::PropertyAttribute::BOUND;
1045 if (rPath.bIsReadonly)
1046 pProp->Attributes |= css::beans::PropertyAttribute::READONLY;
1047 ++i;
1048
1049 pProp = &(m_lPropDesc[i]);
1050 pProp->Name = rPath.sPathName+POSTFIX_INTERNAL_PATHS;
1051 pProp->Handle = i;
1052 pProp->Type = cppu::UnoType<css::uno::Sequence< OUString >>::get();
1053 pProp->Attributes = css::beans::PropertyAttribute::BOUND |
1054 css::beans::PropertyAttribute::READONLY;
1055 ++i;
1056
1057 pProp = &(m_lPropDesc[i]);
1058 pProp->Name = rPath.sPathName+POSTFIX_USER_PATHS;
1059 pProp->Handle = i;
1060 pProp->Type = cppu::UnoType<css::uno::Sequence< OUString >>::get();
1061 pProp->Attributes = css::beans::PropertyAttribute::BOUND;
1062 if (rPath.bIsReadonly)
1063 pProp->Attributes |= css::beans::PropertyAttribute::READONLY;
1064 ++i;
1065
1066 pProp = &(m_lPropDesc[i]);
1067 pProp->Name = rPath.sPathName+POSTFIX_WRITE_PATH;
1068 pProp->Handle = i;
1069 pProp->Type = cppu::UnoType<OUString>::get();
1070 pProp->Attributes = css::beans::PropertyAttribute::BOUND;
1071 if (rPath.bIsReadonly)
1072 pProp->Attributes |= css::beans::PropertyAttribute::READONLY;
1073 ++i;
1074 }
1075
1076 m_pPropHelp.reset(new ::cppu::OPropertyArrayHelper(m_lPropDesc, false)); // false => not sorted ... must be done inside helper
1077
1078 // <- SAFE
1079 }
1080
impl_getPathValue(sal_Int32 nID) const1081 css::uno::Any PathSettings::impl_getPathValue(sal_Int32 nID) const
1082 {
1083 const PathSettings::PathInfo* pPath = impl_getPathAccessConst(nID);
1084 if (! pPath)
1085 throw css::lang::IllegalArgumentException();
1086
1087 css::uno::Any aVal;
1088 switch(impl_getPropGroup(nID))
1089 {
1090 case IDGROUP_OLDSTYLE :
1091 {
1092 OUString sVal = impl_convertPath2OldStyle(*pPath);
1093 aVal <<= sVal;
1094 }
1095 break;
1096
1097 case IDGROUP_INTERNAL_PATHS :
1098 {
1099 aVal <<= comphelper::containerToSequence(pPath->lInternalPaths);
1100 }
1101 break;
1102
1103 case IDGROUP_USER_PATHS :
1104 {
1105 aVal <<= comphelper::containerToSequence(pPath->lUserPaths);
1106 }
1107 break;
1108
1109 case IDGROUP_WRITE_PATH :
1110 {
1111 aVal <<= pPath->sWritePath;
1112 }
1113 break;
1114 }
1115
1116 return aVal;
1117 }
1118
impl_setPathValue(sal_Int32 nID,const css::uno::Any & aVal)1119 void PathSettings::impl_setPathValue( sal_Int32 nID ,
1120 const css::uno::Any& aVal)
1121 {
1122 PathSettings::PathInfo* pOrgPath = impl_getPathAccess(nID);
1123 if (! pOrgPath)
1124 throw css::container::NoSuchElementException();
1125
1126 // We work on a copied path ... so we can be sure that errors during this operation
1127 // does not make our internal cache invalid .-)
1128 PathSettings::PathInfo aChangePath(*pOrgPath);
1129
1130 switch(impl_getPropGroup(nID))
1131 {
1132 case IDGROUP_OLDSTYLE :
1133 {
1134 OUString sVal;
1135 aVal >>= sVal;
1136 std::vector<OUString> lList = impl_convertOldStyle2Path(sVal);
1137 impl_subst(lList, fa_getSubstitution(), false);
1138 impl_purgeKnownPaths(aChangePath, lList);
1139 if (! impl_isValidPath(lList))
1140 throw css::lang::IllegalArgumentException();
1141
1142 if (aChangePath.bIsSinglePath)
1143 {
1144 SAL_WARN_IF(lList.size()>1, "fwk", "PathSettings::impl_setPathValue(): You try to set more than path value for a defined SINGLE_PATH!");
1145 if ( !lList.empty() )
1146 aChangePath.sWritePath = *(lList.begin());
1147 else
1148 aChangePath.sWritePath.clear();
1149 }
1150 else
1151 {
1152 for (auto const& elem : lList)
1153 {
1154 aChangePath.lUserPaths.push_back(elem);
1155 }
1156 }
1157 }
1158 break;
1159
1160 case IDGROUP_INTERNAL_PATHS :
1161 {
1162 if (aChangePath.bIsSinglePath)
1163 {
1164 throw css::uno::Exception(
1165 "The path '" + aChangePath.sPathName
1166 + "' is defined as SINGLE_PATH. It's sub set of internal paths can't be set.",
1167 static_cast< ::cppu::OWeakObject* >(this));
1168 }
1169
1170 css::uno::Sequence<OUString> lTmpList;
1171 aVal >>= lTmpList;
1172 std::vector<OUString> lList = comphelper::sequenceToContainer<std::vector<OUString>>(lTmpList);
1173 if (! impl_isValidPath(lList))
1174 throw css::lang::IllegalArgumentException();
1175 aChangePath.lInternalPaths = lList;
1176 }
1177 break;
1178
1179 case IDGROUP_USER_PATHS :
1180 {
1181 if (aChangePath.bIsSinglePath)
1182 {
1183 throw css::uno::Exception(
1184 "The path '" + aChangePath.sPathName
1185 + "' is defined as SINGLE_PATH. It's sub set of internal paths can't be set.",
1186 static_cast< ::cppu::OWeakObject* >(this));
1187 }
1188
1189 css::uno::Sequence<OUString> lTmpList;
1190 aVal >>= lTmpList;
1191 std::vector<OUString> lList = comphelper::sequenceToContainer<std::vector<OUString>>(lTmpList);
1192 if (! impl_isValidPath(lList))
1193 throw css::lang::IllegalArgumentException();
1194 aChangePath.lUserPaths = lList;
1195 }
1196 break;
1197
1198 case IDGROUP_WRITE_PATH :
1199 {
1200 OUString sVal;
1201 aVal >>= sVal;
1202 if (! impl_isValidPath(sVal))
1203 throw css::lang::IllegalArgumentException();
1204 aChangePath.sWritePath = sVal;
1205 }
1206 break;
1207 }
1208
1209 // TODO check if path has at least one path value set
1210 // At least it depends from the feature using this path, if an empty path list is allowed.
1211
1212 // first we should try to store the changed (copied!) path ...
1213 // In case an error occurs on saving time an exception is thrown ...
1214 // If no exception occurs we can update our internal cache (means
1215 // we can overwrite pOrgPath !
1216 impl_storePath(aChangePath);
1217 *pOrgPath = std::move(aChangePath);
1218 }
1219
impl_isValidPath(const std::vector<OUString> & lPath) const1220 bool PathSettings::impl_isValidPath(const std::vector<OUString>& lPath) const
1221 {
1222 for (auto const& path : lPath)
1223 {
1224 if (! impl_isValidPath(path))
1225 return false;
1226 }
1227
1228 return true;
1229 }
1230
impl_isValidPath(const OUString & sPath) const1231 bool PathSettings::impl_isValidPath(const OUString& sPath) const
1232 {
1233 // allow empty path to reset a path.
1234 // idea by LLA to support empty paths
1235 // if (sPath.getLength() == 0)
1236 // {
1237 // return sal_True;
1238 // }
1239
1240 return (! INetURLObject(sPath).HasError());
1241 }
1242
impl_extractBaseFromPropName(const OUString & sPropName)1243 OUString impl_extractBaseFromPropName(const OUString& sPropName)
1244 {
1245 sal_Int32 i = sPropName.indexOf(POSTFIX_INTERNAL_PATHS);
1246 if (i > -1)
1247 return sPropName.copy(0, i);
1248 i = sPropName.indexOf(POSTFIX_USER_PATHS);
1249 if (i > -1)
1250 return sPropName.copy(0, i);
1251 i = sPropName.indexOf(POSTFIX_WRITE_PATH);
1252 if (i > -1)
1253 return sPropName.copy(0, i);
1254
1255 return sPropName;
1256 }
1257
impl_getPathAccess(sal_Int32 nHandle)1258 PathSettings::PathInfo* PathSettings::impl_getPathAccess(sal_Int32 nHandle)
1259 {
1260 // SAFE ->
1261 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
1262
1263 if (nHandle > (m_lPropDesc.getLength()-1))
1264 return nullptr;
1265
1266 const css::beans::Property& rProp = m_lPropDesc[nHandle];
1267 OUString sProp = impl_extractBaseFromPropName(rProp.Name);
1268 PathSettings::PathHash::iterator rPath = m_lPaths.find(sProp);
1269
1270 if (rPath != m_lPaths.end())
1271 return &(rPath->second);
1272
1273 return nullptr;
1274 // <- SAFE
1275 }
1276
impl_getPathAccessConst(sal_Int32 nHandle) const1277 const PathSettings::PathInfo* PathSettings::impl_getPathAccessConst(sal_Int32 nHandle) const
1278 {
1279 // SAFE ->
1280 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
1281
1282 if (nHandle > (m_lPropDesc.getLength()-1))
1283 return nullptr;
1284
1285 const css::beans::Property& rProp = m_lPropDesc[nHandle];
1286 OUString sProp = impl_extractBaseFromPropName(rProp.Name);
1287 PathSettings::PathHash::const_iterator rPath = m_lPaths.find(sProp);
1288
1289 if (rPath != m_lPaths.end())
1290 return &(rPath->second);
1291
1292 return nullptr;
1293 // <- SAFE
1294 }
1295
convertFastPropertyValue(css::uno::Any & aConvertedValue,css::uno::Any & aOldValue,sal_Int32 nHandle,const css::uno::Any & aValue)1296 sal_Bool SAL_CALL PathSettings::convertFastPropertyValue( css::uno::Any& aConvertedValue,
1297 css::uno::Any& aOldValue ,
1298 sal_Int32 nHandle ,
1299 const css::uno::Any& aValue )
1300 {
1301 // throws NoSuchElementException !
1302 css::uno::Any aCurrentVal = impl_getPathValue(nHandle);
1303
1304 return PropHelper::willPropertyBeChanged(
1305 aCurrentVal,
1306 aValue,
1307 aOldValue,
1308 aConvertedValue);
1309 }
1310
setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any & aValue)1311 void SAL_CALL PathSettings::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle,
1312 const css::uno::Any& aValue )
1313 {
1314 // throws NoSuchElement- and IllegalArgumentException !
1315 impl_setPathValue(nHandle, aValue);
1316 }
1317
getFastPropertyValue(css::uno::Any & aValue,sal_Int32 nHandle) const1318 void SAL_CALL PathSettings::getFastPropertyValue(css::uno::Any& aValue ,
1319 sal_Int32 nHandle) const
1320 {
1321 aValue = impl_getPathValue(nHandle);
1322 }
1323
getInfoHelper()1324 ::cppu::IPropertyArrayHelper& SAL_CALL PathSettings::getInfoHelper()
1325 {
1326 return *m_pPropHelp;
1327 }
1328
getPropertySetInfo()1329 css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL PathSettings::getPropertySetInfo()
1330 {
1331 return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
1332 }
1333
fa_getSubstitution()1334 css::uno::Reference< css::util::XStringSubstitution > PathSettings::fa_getSubstitution()
1335 {
1336 css::uno::Reference< css::util::XStringSubstitution > xSubst;
1337 { // SAFE ->
1338 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
1339 xSubst = m_xSubstitution;
1340 }
1341
1342 if (! xSubst.is())
1343 {
1344 // create the needed substitution service.
1345 // We must replace all used variables inside read path values.
1346 // In case we can't do so... the whole office can't work really.
1347 // That's why it seems to be OK to throw a RuntimeException then.
1348 xSubst = css::util::PathSubstitution::create(m_xContext);
1349
1350 { // SAFE ->
1351 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
1352 m_xSubstitution = xSubst;
1353 }
1354 }
1355
1356 return xSubst;
1357 }
1358
fa_getCfgOld()1359 css::uno::Reference< css::container::XNameAccess > PathSettings::fa_getCfgOld()
1360 {
1361 css::uno::Reference< css::container::XNameAccess > xCfg;
1362 { // SAFE ->
1363 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
1364 xCfg = m_xCfgOld;
1365 } // <- SAFE
1366
1367 if (! xCfg.is())
1368 {
1369 xCfg.set( ::comphelper::ConfigurationHelper::openConfig(
1370 m_xContext,
1371 "org.openoffice.Office.Common/Path/Current",
1372 ::comphelper::EConfigurationModes::Standard), // not readonly! Sometimes we need write access there !!!
1373 css::uno::UNO_QUERY_THROW);
1374
1375 { // SAFE ->
1376 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
1377 m_xCfgOld = xCfg;
1378 }
1379 }
1380
1381 return xCfg;
1382 }
1383
fa_getCfgNew()1384 css::uno::Reference< css::container::XNameAccess > PathSettings::fa_getCfgNew()
1385 {
1386 css::uno::Reference< css::container::XNameAccess > xCfg;
1387 { // SAFE ->
1388 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
1389 xCfg = m_xCfgNew;
1390 } // <- SAFE
1391
1392 if (! xCfg.is())
1393 {
1394 xCfg.set( ::comphelper::ConfigurationHelper::openConfig(
1395 m_xContext,
1396 "org.openoffice.Office.Paths/Paths",
1397 ::comphelper::EConfigurationModes::Standard),
1398 css::uno::UNO_QUERY_THROW);
1399
1400 { // SAFE ->
1401 osl::MutexGuard g(cppu::WeakComponentImplHelperBase::rBHelper.rMutex);
1402 m_xCfgNew = xCfg;
1403 m_xCfgNewListener = new WeakChangesListener(this);
1404 }
1405
1406 css::uno::Reference< css::util::XChangesNotifier > xBroadcaster(xCfg, css::uno::UNO_QUERY_THROW);
1407 xBroadcaster->addChangesListener(m_xCfgNewListener);
1408 }
1409
1410 return xCfg;
1411 }
1412
1413 }
1414
1415 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
com_sun_star_comp_framework_PathSettings_get_implementation(css::uno::XComponentContext * context,css::uno::Sequence<css::uno::Any> const &)1416 com_sun_star_comp_framework_PathSettings_get_implementation(
1417 css::uno::XComponentContext *context,
1418 css::uno::Sequence<css::uno::Any> const &)
1419 {
1420 rtl::Reference<PathSettings> xPathSettings = new PathSettings(context);
1421 // fill cache
1422 xPathSettings->impl_readAll();
1423
1424 return cppu::acquire(xPathSettings.get());
1425 }
1426
1427 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1428