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