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