Coverage Report

Created: 2026-08-14 10:22

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