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