Coverage Report

Created: 2026-10-14 09:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/framework/source/accelerators/presethandler.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 <accelerators/presethandler.hxx>
21
22
#include <classes/fwkresid.hxx>
23
24
#include <strings.hrc>
25
26
#include <com/sun/star/configuration/CorruptedUIConfigurationException.hpp>
27
#include <com/sun/star/container/XNameAccess.hpp>
28
#include <com/sun/star/embed/ElementModes.hpp>
29
#include <com/sun/star/embed/FileSystemStorageFactory.hpp>
30
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
31
#include <com/sun/star/util/thePathSettings.hpp>
32
33
#include <utility>
34
#include <vcl/svapp.hxx>
35
#include <cppuhelper/exc_hlp.hxx>
36
#include <rtl/ustrbuf.hxx>
37
#include <osl/diagnose.h>
38
#include <i18nlangtag/languagetag.hxx>
39
40
const ::sal_Int32 ID_CORRUPT_UICONFIG_SHARE   = 1;
41
const ::sal_Int32 ID_CORRUPT_UICONFIG_USER    = 2;
42
const ::sal_Int32 ID_CORRUPT_UICONFIG_GENERAL = 3;
43
44
namespace framework
45
{
46
47
namespace {
48
49
/** @short  because a concurrent access to the same storage from different implementations
50
            isn't supported, we have to share it with others.
51
52
    @descr  This struct is allegedly shared and must be used within a
53
            synchronized section. But it isn't.
54
 */
55
struct TSharedStorages final
56
{
57
        StorageHolder m_lStoragesShare;
58
        StorageHolder m_lStoragesUser;
59
60
        TSharedStorages()
61
0
        {};
62
};
63
64
/** @short  provides access to the:
65
            a) shared root storages
66
            b) shared "inbetween" storages
67
            of the share and user layer. */
68
TSharedStorages& SharedStorages()
69
0
{
70
0
    static TSharedStorages theStorages;
71
0
    return theStorages;
72
0
}
73
74
}
75
76
PresetHandler::PresetHandler(css::uno::Reference< css::uno::XComponentContext > xContext)
77
0
    : m_xContext(std::move(xContext))
78
0
    , m_eConfigType(E_GLOBAL)
79
0
    , m_bShouldReopenRWOnStore(false)
80
0
{
81
0
}
82
83
PresetHandler::PresetHandler(const PresetHandler& rCopy)
84
0
{
85
0
    m_xContext               = rCopy.m_xContext;
86
0
    m_eConfigType            = rCopy.m_eConfigType;
87
0
    m_xWorkingStorageShare   = rCopy.m_xWorkingStorageShare;
88
0
    m_xWorkingStorageNoLang  = rCopy.m_xWorkingStorageNoLang;
89
0
    m_xWorkingStorageUser    = rCopy.m_xWorkingStorageUser;
90
0
    m_lDocumentStorages      = rCopy.m_lDocumentStorages;
91
0
    m_sRelPathShare          = rCopy.m_sRelPathShare;
92
0
    m_sRelPathUser           = rCopy.m_sRelPathUser;
93
0
    m_bShouldReopenRWOnStore = rCopy.m_bShouldReopenRWOnStore;
94
0
}
95
96
PresetHandler::~PresetHandler()
97
0
{
98
0
    m_xWorkingStorageShare.clear();
99
0
    m_xWorkingStorageNoLang.clear();
100
0
    m_xWorkingStorageUser.clear();
101
102
    /* #i46497#
103
        Don't call forgetCachedStorages() here for shared storages.
104
        Because we opened different sub storages by using openPath().
105
        And every already open path was reused and referenced (means it's
106
        ref count was increased!)
107
        So now we have to release our ref counts to these shared storages
108
        only ... and not to free all used storages.
109
        Otherwise we will disconnect all other open configuration access
110
        objects which base on these storages.
111
     */
112
0
    auto & sharedStorages = SharedStorages();
113
0
    sharedStorages.m_lStoragesShare.closePath(m_sRelPathShare);
114
0
    sharedStorages.m_lStoragesUser.closePath (m_sRelPathUser );
115
116
    /* On the other side closePath() is not needed for our special handled
117
       document storage. Because it's not shared with others ... so we can
118
       free it.
119
     */
120
0
    m_lDocumentStorages.forgetCachedStorages();
121
0
}
122
123
void PresetHandler::forgetCachedStorages()
124
0
{
125
0
    SolarMutexGuard g;
126
127
0
    if (m_eConfigType == E_DOCUMENT)
128
0
    {
129
0
        m_xWorkingStorageShare.clear();
130
0
        m_xWorkingStorageNoLang.clear();
131
0
        m_xWorkingStorageUser.clear();
132
0
    }
133
134
0
    m_lDocumentStorages.forgetCachedStorages();
135
0
}
136
137
namespace {
138
139
OUString lcl_getLocalizedMessage(::sal_Int32 nID)
140
0
{
141
0
    OUString sMessage(u"Unknown error."_ustr);
142
143
0
    switch(nID)
144
0
    {
145
0
        case ID_CORRUPT_UICONFIG_SHARE :
146
0
                sMessage = FwkResId(STR_CORRUPT_UICFG_SHARE);
147
148
0
                break;
149
150
0
        case ID_CORRUPT_UICONFIG_USER :
151
0
                sMessage = FwkResId(STR_CORRUPT_UICFG_USER);
152
0
                break;
153
154
0
        case ID_CORRUPT_UICONFIG_GENERAL :
155
0
                sMessage = FwkResId(STR_CORRUPT_UICFG_GENERAL);
156
0
                break;
157
0
    }
158
159
0
    return sMessage;
160
0
}
161
162
void lcl_throwCorruptedUIConfigurationException(
163
    css::uno::Any const & exception, sal_Int32 id)
164
0
{
165
0
    css::uno::Exception e;
166
0
    bool ok = (exception >>= e);
167
0
    OSL_ASSERT(ok);
168
0
    throw css::configuration::CorruptedUIConfigurationException(
169
0
        lcl_getLocalizedMessage(id),
170
0
        css::uno::Reference< css::uno::XInterface >(),
171
0
        exception.getValueTypeName() + ": \"" + e.Message + "\"");
172
0
}
173
174
}
175
176
css::uno::Reference< css::embed::XStorage > PresetHandler::getOrCreateRootStorageShare()
177
0
{
178
0
    auto & sharedStorages = SharedStorages();
179
0
    css::uno::Reference< css::embed::XStorage > xRoot = sharedStorages.m_lStoragesShare.getRootStorage();
180
0
    if (xRoot.is())
181
0
        return xRoot;
182
183
0
    css::uno::Reference< css::uno::XComponentContext > xContext;
184
0
    {
185
0
        SolarMutexGuard g;
186
0
        xContext = m_xContext;
187
0
    }
188
189
0
    css::uno::Reference< css::util::XPathSettings > xPathSettings =
190
0
        css::util::thePathSettings::get( xContext );
191
192
0
    OUString sShareLayer = xPathSettings->getBasePathShareLayer();
193
194
    // "UIConfig" is a "multi path" ... use first part only here!
195
0
    sal_Int32 nPos = sShareLayer.indexOf(';');
196
0
    if (nPos > 0)
197
0
        sShareLayer = sShareLayer.copy(0, nPos);
198
199
    // Note: May be an user uses URLs without a final slash! Check it ...
200
0
    nPos = sShareLayer.lastIndexOf('/');
201
0
    if (nPos != sShareLayer.getLength()-1)
202
0
        sShareLayer += "/";
203
204
0
    sShareLayer += "soffice.cfg";
205
    /*
206
    // TODO remove me!
207
    // Attention: This is temp. workaround ... We create a temp. storage file
208
    // based of a system directory. This must be used so, till the storage implementation
209
    // can work on directories too.
210
    */
211
0
    css::uno::Sequence< css::uno::Any > lArgs{
212
0
        css::uno::Any(sShareLayer),
213
0
        css::uno::Any(css::embed::ElementModes::READ | css::embed::ElementModes::NOCREATE)
214
0
    };
215
216
0
    css::uno::Reference< css::lang::XSingleServiceFactory > xStorageFactory = css::embed::FileSystemStorageFactory::create( xContext );
217
0
    css::uno::Reference< css::embed::XStorage >             xStorage;
218
219
0
    try
220
0
    {
221
0
        xStorage.set(xStorageFactory->createInstanceWithArguments(lArgs), css::uno::UNO_QUERY_THROW);
222
0
    }
223
0
    catch(const css::uno::Exception&)
224
0
    {
225
0
        css::uno::Any ex(cppu::getCaughtException());
226
0
        lcl_throwCorruptedUIConfigurationException(
227
0
            ex, ID_CORRUPT_UICONFIG_SHARE);
228
0
    }
229
230
0
    sharedStorages.m_lStoragesShare.setRootStorage(xStorage);
231
232
0
    return xStorage;
233
0
}
234
235
css::uno::Reference< css::embed::XStorage > PresetHandler::getOrCreateRootStorageUser()
236
0
{
237
0
    auto & sharedStorages = SharedStorages();
238
0
    css::uno::Reference< css::embed::XStorage > xRoot = sharedStorages.m_lStoragesUser.getRootStorage();
239
0
    if (xRoot.is())
240
0
        return xRoot;
241
242
0
    css::uno::Reference< css::uno::XComponentContext > xContext;
243
0
    {
244
0
        SolarMutexGuard g;
245
0
        xContext = m_xContext;
246
0
    }
247
248
0
    css::uno::Reference< css::util::XPathSettings > xPathSettings =
249
0
        css::util::thePathSettings::get( xContext );
250
251
0
    OUString sUserLayer = xPathSettings->getBasePathUserLayer();
252
253
    // Note: May be an user uses URLs without a final slash! Check it ...
254
0
    sal_Int32 nPos = sUserLayer.lastIndexOf('/');
255
0
    if (nPos != sUserLayer.getLength()-1)
256
0
        sUserLayer += "/";
257
258
0
    sUserLayer  += "soffice.cfg"; // storage file
259
260
0
    css::uno::Sequence< css::uno::Any > lArgs{ css::uno::Any(sUserLayer),
261
0
                                               css::uno::Any(css::embed::ElementModes::READWRITE) };
262
263
0
    css::uno::Reference< css::lang::XSingleServiceFactory > xStorageFactory = css::embed::FileSystemStorageFactory::create( xContext );
264
0
    css::uno::Reference< css::embed::XStorage >             xStorage;
265
266
0
    try
267
0
    {
268
0
        xStorage.set(xStorageFactory->createInstanceWithArguments(lArgs), css::uno::UNO_QUERY_THROW);
269
0
    }
270
0
    catch(const css::uno::Exception&)
271
0
    {
272
0
        css::uno::Any ex(cppu::getCaughtException());
273
0
        lcl_throwCorruptedUIConfigurationException(
274
0
            ex, ID_CORRUPT_UICONFIG_USER);
275
0
    }
276
277
0
    sharedStorages.m_lStoragesUser.setRootStorage(xStorage);
278
279
0
    return xStorage;
280
0
}
281
282
css::uno::Reference< css::embed::XStorage > PresetHandler::getWorkingStorageUser() const
283
0
{
284
0
    SolarMutexGuard g;
285
0
    return m_xWorkingStorageUser;
286
0
}
287
288
css::uno::Reference< css::embed::XStorage > PresetHandler::getParentStorageShare()
289
0
{
290
0
    css::uno::Reference< css::embed::XStorage > xWorking;
291
0
    {
292
0
        SolarMutexGuard g;
293
0
        xWorking = m_xWorkingStorageShare;
294
0
    }
295
296
0
    return SharedStorages().m_lStoragesShare.getParentStorage(xWorking);
297
0
}
298
299
css::uno::Reference< css::embed::XStorage > PresetHandler::getParentStorageUser()
300
0
{
301
0
    css::uno::Reference< css::embed::XStorage > xWorking;
302
0
    {
303
0
        SolarMutexGuard g;
304
0
        xWorking = m_xWorkingStorageUser;
305
0
    }
306
307
0
    return SharedStorages().m_lStoragesUser.getParentStorage(xWorking);
308
0
}
309
310
void PresetHandler::connectToResource(      PresetHandler::EConfigType                   eConfigType  ,
311
                                      std::u16string_view                             sResource    ,
312
                                      std::u16string_view                             sModule      ,
313
                                      const css::uno::Reference< css::embed::XStorage >& xDocumentRoot,
314
                                      const LanguageTag&                                 rLanguageTag )
315
0
{
316
    // TODO free all current open storages!
317
318
0
    {
319
0
        SolarMutexGuard g;
320
0
        m_eConfigType   = eConfigType;
321
0
    }
322
323
0
    css::uno::Reference< css::embed::XStorage > xShare;
324
0
    css::uno::Reference< css::embed::XStorage > xNoLang;
325
0
    css::uno::Reference< css::embed::XStorage > xUser;
326
327
    // special case for documents
328
    // use outside root storage, if we run in E_DOCUMENT mode!
329
0
    if (eConfigType == E_DOCUMENT)
330
0
    {
331
0
        if (!xDocumentRoot.is())
332
0
            throw css::uno::RuntimeException(
333
0
                    u"There is valid root storage, where the UI configuration can work on."_ustr);
334
0
        m_lDocumentStorages.setRootStorage(xDocumentRoot);
335
0
        xShare = xDocumentRoot;
336
0
        xUser  = xDocumentRoot;
337
0
    }
338
0
    else
339
0
    {
340
0
        xShare = getOrCreateRootStorageShare();
341
0
        xUser  = getOrCreateRootStorageUser();
342
0
    }
343
344
    // #...#
345
0
    try
346
0
    {
347
348
    // a) inside share layer we should not create any new structures... We have to use
349
    //    existing ones only!
350
    // b) inside user layer we can (SOFT mode!) but sometimes we should not (HARD mode!)
351
    //    create new empty structures. We should prefer using of any existing structure.
352
    // c) in document mode we first open the storage as readonly and later reopen it as
353
    //    readwrite if we need to store to it
354
0
    sal_Int32 eShareMode = css::embed::ElementModes::READ;
355
0
    sal_Int32 eUserMode  = css::embed::ElementModes::READWRITE;
356
0
    sal_Int32 eDocMode = css::embed::ElementModes::READ;
357
358
0
    OUStringBuffer sRelPathBuf(1024);
359
0
    OUString       sRelPathShare;
360
0
    OUString       sRelPathUser;
361
0
    switch(eConfigType)
362
0
    {
363
0
        case E_GLOBAL :
364
0
        {
365
0
            sRelPathShare = OUString::Concat("global/") + sResource;
366
0
            sRelPathUser  = sRelPathShare;
367
368
0
            xShare = impl_openPathIgnoringErrors(sRelPathShare, eShareMode, true );
369
0
            xUser  = impl_openPathIgnoringErrors(sRelPathUser , eUserMode , false);
370
0
        }
371
0
        break;
372
373
0
        case E_MODULES :
374
0
        {
375
0
            sRelPathShare = OUString::Concat("modules/") + sModule + "/" + sResource;
376
0
            sRelPathUser  = sRelPathShare;
377
378
0
            xShare = impl_openPathIgnoringErrors(sRelPathShare, eShareMode, true );
379
0
            xUser  = impl_openPathIgnoringErrors(sRelPathUser , eUserMode , false);
380
0
        }
381
0
        break;
382
383
0
        case E_DOCUMENT :
384
0
        {
385
            // A document does not have a share layer in real.
386
            // It has one layer only, and this one should be opened READ_WRITE.
387
            // So we open the user layer here only and set the share layer equals to it .-)
388
389
            // We initially open the layer as readonly to avoid creating the subdirectory
390
            // for files that don't need it. We will reopen it as readwrite if needed.
391
392
0
            sRelPathBuf.append(sResource);
393
0
            sRelPathUser  = sRelPathBuf.makeStringAndClear();
394
0
            sRelPathShare = sRelPathUser;
395
396
0
            {
397
0
                SolarMutexGuard g;
398
399
0
                css::uno::Reference< css::beans::XPropertySet > xPropSet( xDocumentRoot, css::uno::UNO_QUERY );
400
0
                if ( xPropSet.is() )
401
0
                {
402
0
                    tools::Long nOpenMode = 0;
403
0
                    if ( xPropSet->getPropertyValue(u"OpenMode"_ustr) >>= nOpenMode )
404
0
                        m_bShouldReopenRWOnStore = nOpenMode & css::embed::ElementModes::WRITE;
405
0
                }
406
0
            }
407
408
0
            try
409
0
            {
410
0
                xUser  = m_lDocumentStorages.openPath(sRelPathUser , eDocMode );
411
0
                xShare = xUser;
412
413
0
            }
414
0
            catch(const css::uno::RuntimeException&)
415
0
                { throw; }
416
0
            catch(const css::uno::Exception&)
417
0
                { xShare.clear(); xUser.clear(); }
418
0
        }
419
0
        break;
420
0
    }
421
422
    // Non-localized global share
423
0
    xNoLang = xShare;
424
425
0
    if (
426
0
        (rLanguageTag != LanguageTag(LANGUAGE_USER_PRIV_NOTRANSLATE)) && // localized level?
427
0
        (eConfigType != E_DOCUMENT                           )    // no localization in document mode!
428
0
       )
429
0
    {
430
        // First try to find the right localized set inside share layer.
431
        // Fallbacks are allowed there.
432
0
        OUString         aShareLocale( rLanguageTag.getBcp47());
433
0
        OUString         sLocalizedSharePath(sRelPathShare);
434
0
        bool             bAllowFallbacks    = true;
435
0
        xShare = impl_openLocalizedPathIgnoringErrors(sLocalizedSharePath, eShareMode, true , aShareLocale, bAllowFallbacks);
436
437
        // The try to locate the right sub dir inside user layer ... without using fallbacks!
438
        // Normally the corresponding sub dir should be created matching the specified locale.
439
        // Because we allow creation of storages inside user layer by default.
440
0
        OUString      aUserLocale( rLanguageTag.getBcp47());
441
0
        OUString      sLocalizedUserPath(sRelPathUser);
442
0
        bAllowFallbacks    = false;
443
0
        xUser = impl_openLocalizedPathIgnoringErrors(sLocalizedUserPath, eUserMode, false, aUserLocale, bAllowFallbacks);
444
445
0
        sRelPathShare = sLocalizedSharePath;
446
0
        sRelPathUser  = sLocalizedUserPath;
447
0
    }
448
449
0
    {
450
0
        SolarMutexGuard g;
451
0
        m_xWorkingStorageShare = std::move(xShare);
452
0
        m_xWorkingStorageNoLang= std::move(xNoLang);
453
0
        m_xWorkingStorageUser  = std::move(xUser);
454
0
        m_sRelPathShare        = sRelPathShare;
455
0
        m_sRelPathUser         = sRelPathUser;
456
0
    }
457
458
0
    }
459
0
    catch(const css::uno::Exception&)
460
0
    {
461
0
        css::uno::Any ex(cppu::getCaughtException());
462
0
        lcl_throwCorruptedUIConfigurationException(
463
0
            ex, ID_CORRUPT_UICONFIG_GENERAL);
464
0
    }
465
0
}
466
467
void PresetHandler::copyPresetToTarget(std::u16string_view sPreset,
468
                                       std::u16string_view sTarget)
469
0
{
470
    // don't check our preset list, if element exists
471
    // We try to open it and forward all errors to the user!
472
473
0
    maybeReopenStorageAsReadWrite();
474
475
0
    css::uno::Reference< css::embed::XStorage > xWorkingShare;
476
0
    css::uno::Reference< css::embed::XStorage > xWorkingNoLang;
477
0
    css::uno::Reference< css::embed::XStorage > xWorkingUser;
478
479
0
    {
480
0
        SolarMutexGuard g;
481
0
        xWorkingShare = m_xWorkingStorageShare;
482
0
        xWorkingNoLang= m_xWorkingStorageNoLang;
483
0
        xWorkingUser  = m_xWorkingStorageUser;
484
0
    }
485
486
    // e.g. module without any config data ?!
487
0
    if (
488
0
        (!xWorkingShare.is()) ||
489
0
        (!xWorkingUser.is() )
490
0
       )
491
0
    {
492
0
       return;
493
0
    }
494
495
0
    OUString sPresetFile = OUString::Concat(sPreset) + ".xml";
496
0
    OUString sTargetFile = OUString::Concat(sTarget) + ".xml";
497
498
    // remove existing elements before you try to copy the preset to that location ...
499
    // Otherwise w will get an ElementExistException inside copyElementTo()!
500
0
    css::uno::Reference< css::container::XNameAccess > xCheckingUser(xWorkingUser, css::uno::UNO_QUERY_THROW);
501
0
    if (xCheckingUser->hasByName(sTargetFile))
502
0
        xWorkingUser->removeElement(sTargetFile);
503
504
0
    xWorkingShare->copyElementTo(sPresetFile, xWorkingUser, sTargetFile);
505
506
    // If our storages work in transacted mode, we have
507
    // to commit all changes from bottom to top!
508
0
    commitUserChanges();
509
0
}
510
511
css::uno::Reference< css::io::XStream > PresetHandler::openPreset(std::u16string_view sPreset)
512
0
{
513
0
    css::uno::Reference< css::embed::XStorage > xFolder;
514
0
    {
515
0
        SolarMutexGuard g;
516
0
        xFolder = m_xWorkingStorageNoLang;
517
0
    }
518
519
    // e.g. module without any config data ?!
520
0
    if (!xFolder.is())
521
0
       return css::uno::Reference< css::io::XStream >();
522
523
0
    OUString sFile = OUString::Concat(sPreset) + ".xml";
524
525
    // inform user about errors (use original exceptions!)
526
0
    css::uno::Reference< css::io::XStream > xStream = xFolder->openStreamElement(sFile, css::embed::ElementModes::READ);
527
0
    return xStream;
528
0
}
529
530
css::uno::Reference< css::io::XStream > PresetHandler::openTarget(
531
        std::u16string_view sTarget, sal_Int32 const nMode)
532
0
{
533
0
    if (nMode & css::embed::ElementModes::WRITE) {
534
0
        maybeReopenStorageAsReadWrite();
535
0
    }
536
537
0
    css::uno::Reference< css::embed::XStorage > xFolder;
538
0
    {
539
0
        SolarMutexGuard g;
540
0
        xFolder = m_xWorkingStorageUser;
541
0
    }
542
543
    // e.g. module without any config data ?!
544
0
    if (!xFolder.is())
545
0
       return css::uno::Reference< css::io::XStream >();
546
547
0
    OUString const sFile(OUString::Concat(sTarget) + ".xml");
548
549
0
    return xFolder->openStreamElement(sFile, nMode);
550
0
}
551
552
void PresetHandler::commitUserChanges()
553
0
{
554
0
    css::uno::Reference< css::embed::XStorage > xWorking;
555
0
    EConfigType                                 eCfgType;
556
0
    {
557
0
        SolarMutexGuard g;
558
0
        xWorking = m_xWorkingStorageUser;
559
0
        eCfgType = m_eConfigType;
560
0
    }
561
562
    // e.g. module without any config data ?!
563
0
    if (!xWorking.is())
564
0
       return;
565
566
0
    OUString sPath;
567
568
0
    switch(eCfgType)
569
0
    {
570
0
        case E_GLOBAL :
571
0
        case E_MODULES :
572
0
        {
573
0
            auto & sharedStorages = SharedStorages();
574
0
            sPath = sharedStorages.m_lStoragesUser.getPathOfStorage(xWorking);
575
0
            sharedStorages.m_lStoragesUser.commitPath(sPath);
576
0
            sharedStorages.m_lStoragesUser.notifyPath(sPath);
577
0
        }
578
0
        break;
579
580
0
        case E_DOCUMENT :
581
0
        {
582
0
            sPath = m_lDocumentStorages.getPathOfStorage(xWorking);
583
0
            m_lDocumentStorages.commitPath(sPath);
584
0
            m_lDocumentStorages.notifyPath(sPath);
585
0
        }
586
0
        break;
587
0
    }
588
0
}
589
590
void PresetHandler::addStorageListener(XMLBasedAcceleratorConfiguration* pListener)
591
0
{
592
0
    OUString sRelPath;
593
0
    EConfigType eCfgType;
594
0
    {
595
0
        SolarMutexGuard g;
596
0
        sRelPath = m_sRelPathUser; // use user path ... because we don't work directly on the share layer!
597
0
        eCfgType = m_eConfigType;
598
0
    }
599
600
0
    if (sRelPath.isEmpty())
601
0
        return;
602
603
0
    switch(eCfgType)
604
0
    {
605
0
        case E_GLOBAL :
606
0
        case E_MODULES :
607
0
        {
608
0
            SharedStorages().m_lStoragesUser.addStorageListener(pListener, sRelPath);
609
0
        }
610
0
        break;
611
612
0
        case E_DOCUMENT :
613
0
        {
614
0
            m_lDocumentStorages.addStorageListener(pListener, sRelPath);
615
0
        }
616
0
        break;
617
0
    }
618
0
}
619
620
void PresetHandler::removeStorageListener(XMLBasedAcceleratorConfiguration* pListener)
621
0
{
622
0
    OUString sRelPath;
623
0
    EConfigType eCfgType;
624
0
    {
625
0
        SolarMutexGuard g;
626
0
        sRelPath = m_sRelPathUser; // use user path ... because we don't work directly on the share layer!
627
0
        eCfgType = m_eConfigType;
628
0
    }
629
630
0
    if (sRelPath.isEmpty())
631
0
        return;
632
633
0
    switch(eCfgType)
634
0
    {
635
0
        case E_GLOBAL :
636
0
        case E_MODULES :
637
0
        {
638
0
            SharedStorages().m_lStoragesUser.removeStorageListener(pListener, sRelPath);
639
0
        }
640
0
        break;
641
642
0
        case E_DOCUMENT :
643
0
        {
644
0
            m_lDocumentStorages.removeStorageListener(pListener, sRelPath);
645
0
        }
646
0
        break;
647
0
    }
648
0
}
649
650
0
bool PresetHandler::isReadOnly() {
651
0
    SolarMutexGuard g;
652
653
0
    if (m_eConfigType == E_DOCUMENT)
654
0
    {
655
0
        if ( css::uno::Reference<css::embed::XStorage> xDocumentRoot = m_lDocumentStorages.getRootStorage(); xDocumentRoot.is() )
656
0
        {
657
0
            css::uno::Reference< css::beans::XPropertySet > xPropSet( xDocumentRoot, css::uno::UNO_QUERY );
658
0
            if ( xPropSet.is() )
659
0
            {
660
0
                tools::Long nOpenMode = 0;
661
0
                if ( xPropSet->getPropertyValue(u"OpenMode"_ustr) >>= nOpenMode )
662
0
                    return !( nOpenMode & css::embed::ElementModes::WRITE );
663
0
            }
664
0
        }
665
0
    }
666
0
    else
667
0
    {
668
0
        if ( m_xWorkingStorageUser.is() )
669
0
        {
670
0
            css::uno::Reference< css::beans::XPropertySet > xPropSet( m_xWorkingStorageUser, css::uno::UNO_QUERY );
671
0
            if ( xPropSet.is() )
672
0
            {
673
0
                tools::Long nOpenMode = 0;
674
0
                if ( xPropSet->getPropertyValue(u"OpenMode"_ustr) >>= nOpenMode )
675
0
                    return !( nOpenMode & css::embed::ElementModes::WRITE );
676
0
            }
677
0
        }
678
0
    }
679
680
0
    return true;
681
0
}
682
683
0
void PresetHandler::maybeReopenStorageAsReadWrite() {
684
0
    SolarMutexGuard g;
685
686
0
    if ((m_eConfigType == E_DOCUMENT) && m_bShouldReopenRWOnStore)
687
0
    {
688
0
        m_bShouldReopenRWOnStore = false;
689
0
        try
690
0
        {
691
0
            forgetCachedStorages();
692
693
0
            sal_Int32 eUserMode = css::embed::ElementModes::READWRITE;
694
0
            m_xWorkingStorageUser = m_lDocumentStorages.openPath( m_sRelPathUser, eUserMode );
695
0
            m_xWorkingStorageShare = m_xWorkingStorageUser;
696
0
            m_xWorkingStorageNoLang = m_xWorkingStorageUser;
697
698
0
        }
699
0
        catch(const css::uno::RuntimeException&)
700
0
            { throw; }
701
0
        catch(const css::uno::Exception&)
702
0
            { forgetCachedStorages(); }
703
0
    }
704
0
}
705
706
707
// static
708
css::uno::Reference< css::embed::XStorage > PresetHandler::impl_openPathIgnoringErrors(const OUString& sPath ,
709
                                                                                             sal_Int32        eMode ,
710
                                                                                             bool         bShare)
711
0
{
712
0
    css::uno::Reference< css::embed::XStorage > xPath;
713
0
    try
714
0
    {
715
0
        if (bShare)
716
0
            xPath = SharedStorages().m_lStoragesShare.openPath(sPath, eMode);
717
0
        else
718
0
            xPath = SharedStorages().m_lStoragesUser.openPath(sPath, eMode);
719
0
    }
720
0
    catch(const css::uno::RuntimeException&)
721
0
        { throw; }
722
0
    catch(const css::uno::Exception&)
723
0
        { xPath.clear(); }
724
0
    return xPath;
725
0
}
726
727
// static
728
::std::vector< OUString >::const_iterator PresetHandler::impl_findMatchingLocalizedValue(
729
        const ::std::vector< OUString >& lLocalizedValues,
730
        OUString& rLanguageTag,
731
        bool bAllowFallbacks )
732
0
{
733
0
    ::std::vector< OUString >::const_iterator pFound = lLocalizedValues.end();
734
0
    if (bAllowFallbacks)
735
0
    {
736
0
        pFound = LanguageTag::getFallback(lLocalizedValues, rLanguageTag);
737
        // if we found a valid locale ... take it over to our in/out parameter
738
        // rLanguageTag
739
0
        if (pFound != lLocalizedValues.end())
740
0
        {
741
0
            rLanguageTag = *pFound;
742
0
        }
743
0
    }
744
0
    else
745
0
    {
746
0
        pFound = std::find(lLocalizedValues.begin(), lLocalizedValues.end(), rLanguageTag);
747
0
    }
748
749
0
    return pFound;
750
0
}
751
752
// static
753
css::uno::Reference< css::embed::XStorage > PresetHandler::impl_openLocalizedPathIgnoringErrors(
754
        OUString&      sPath         ,
755
        sal_Int32             eMode         ,
756
        bool              bShare        ,
757
        OUString&             rLanguageTag  ,
758
        bool              bAllowFallback)
759
0
{
760
0
    css::uno::Reference< css::embed::XStorage >      xPath         = impl_openPathIgnoringErrors(sPath, eMode, bShare);
761
0
    ::std::vector< OUString >                 lSubFolders   = impl_getSubFolderNames(xPath);
762
0
    ::std::vector< OUString >::const_iterator pLocaleFolder = impl_findMatchingLocalizedValue(lSubFolders, rLanguageTag, bAllowFallback);
763
764
    // no fallback ... creation not allowed => no storage
765
0
    if (
766
0
        (pLocaleFolder == lSubFolders.end()                                                ) &&
767
0
        ((eMode & css::embed::ElementModes::NOCREATE) == css::embed::ElementModes::NOCREATE)
768
0
       )
769
0
        return css::uno::Reference< css::embed::XStorage >();
770
771
    // it doesn't matter, if there is a locale fallback or not
772
    // If creation of storages is allowed, we do it anyway.
773
    // Otherwise we have no acc config at all, which can make other trouble.
774
0
    OUString sLocalizedPath = sPath + "/";
775
0
    if (pLocaleFolder != lSubFolders.end())
776
0
        sLocalizedPath += *pLocaleFolder;
777
0
    else
778
0
        sLocalizedPath += rLanguageTag;
779
780
0
    css::uno::Reference< css::embed::XStorage > xLocalePath = impl_openPathIgnoringErrors(sLocalizedPath, eMode, bShare);
781
782
0
    if (xLocalePath.is())
783
0
        sPath = sLocalizedPath;
784
0
    else
785
0
        sPath.clear();
786
787
0
    return xLocalePath;
788
0
}
789
790
// static
791
::std::vector< OUString > PresetHandler::impl_getSubFolderNames(const css::uno::Reference< css::embed::XStorage >& xFolder)
792
0
{
793
0
    if (!xFolder.is())
794
0
        return ::std::vector< OUString >();
795
796
0
    ::std::vector< OUString >      lSubFolders;
797
798
0
    for (const OUString& rName : xFolder->getElementNames())
799
0
    {
800
0
        try
801
0
        {
802
0
            if (xFolder->isStorageElement(rName))
803
0
                lSubFolders.push_back(rName);
804
0
        }
805
0
        catch(const css::uno::RuntimeException&)
806
0
            { throw; }
807
0
        catch(const css::uno::Exception&)
808
0
            {}
809
0
    }
810
811
0
    return lSubFolders;
812
0
}
813
814
} // namespace framework
815
816
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */