Coverage Report

Created: 2026-04-09 11:41

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