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