1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_framework.hxx"
26 #include <accelerators/presethandler.hxx>
27 
28 //_______________________________________________
29 // own includes
30 #include <classes/fwkresid.hxx>
31 
32 #include "classes/resource.hrc"
33 #include <threadhelp/readguard.hxx>
34 #include <threadhelp/writeguard.hxx>
35 #include <services.h>
36 
37 //_______________________________________________
38 // interface includes
39 
40 #ifndef __COM_SUN_STAR_CONFIGURATION_CORRUPTEDUICONFIGURATIONEXCEPTION_HPP_
41 #include <com/sun/star/configuration/CorruptedUIConfigurationException.hpp>
42 #endif
43 
44 #ifndef __COM_SUN_STAR_CONTAINER_NOSUCHELEMENTEXCEPTION_HPP_
45 #include <com/sun/star/container/NoSuchElementException.hpp>
46 #endif
47 
48 #ifndef __COM_SUN_STAR_CONTAINER_XNAMEACCESS_HPP_
49 #include <com/sun/star/container/XNameAccess.hpp>
50 #endif
51 
52 #ifndef __COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
53 #include <com/sun/star/beans/XPropertySet.hpp>
54 #endif
55 
56 #ifndef __COM_SUN_STAR_EMBED_ELEMENTMODES_HPP_
57 #include <com/sun/star/embed/ElementModes.hpp>
58 #endif
59 
60 #ifndef __COM_SUN_STAR_EMBED_XTRANSACTEDOBJECT_HPP_
61 #include <com/sun/star/embed/XTransactedObject.hpp>
62 #endif
63 
64 #ifndef __COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_
65 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
66 #endif
67 
68 //_______________________________________________
69 // other includes
70 #include <vcl/svapp.hxx>
71 
72 #ifndef _RTL_USTRBUF_HXX
73 #include <rtl/ustrbuf.hxx>
74 #endif
75 
76 //_______________________________________________
77 // const
78 
79 #define SUBSTORAGE_GLOBAL       DECLARE_ASCII("global" )
80 #define SUBSTORAGE_MODULES      DECLARE_ASCII("modules")
81 
82 #define BASEPATH_SHARE_LAYER    DECLARE_ASCII("UIConfig"  )
83 #define BASEPATH_USER_LAYER     DECLARE_ASCII("UserConfig")
84 
85 #define RELPATH_SHARE_LAYER     DECLARE_ASCII("soffice.cfg")
86 #define RELPATH_USER_LAYER      DECLARE_ASCII("soffice.cfg")
87 // #define RELPATH_SHARE_LAYER     DECLARE_ASCII("soffice.cfg/uiconfig.zip")
88 // #define RELPATH_USER_LAYER      DECLARE_ASCII("soffice.cfg/uiconfig.zip")
89 
90 #define FILE_EXTENSION          DECLARE_ASCII(".xml")
91 
92 #define PATH_SEPERATOR          DECLARE_ASCII("/")
93 
94 static const ::sal_Int32 ID_CORRUPT_UICONFIG_SHARE   = 1;
95 static const ::sal_Int32 ID_CORRUPT_UICONFIG_USER    = 2;
96 static const ::sal_Int32 ID_CORRUPT_UICONFIG_GENERAL = 3;
97 
98 //_______________________________________________
99 // namespace
100 
101 namespace framework
102 {
103 
104 //-----------------------------------------------
PRESET_DEFAULT()105 ::rtl::OUString PresetHandler::PRESET_DEFAULT()
106 {
107     static ::rtl::OUString RSTYPE = DECLARE_ASCII("default");
108     return RSTYPE;
109 }
110 
111 //-----------------------------------------------
TARGET_CURRENT()112 ::rtl::OUString PresetHandler::TARGET_CURRENT()
113 {
114     static ::rtl::OUString RSTYPE = DECLARE_ASCII("current");
115     return RSTYPE;
116 }
117 
118 //-----------------------------------------------
RESOURCETYPE_MENUBAR()119 ::rtl::OUString PresetHandler::RESOURCETYPE_MENUBAR()
120 {
121     static ::rtl::OUString RSTYPE = DECLARE_ASCII("menubar");
122     return RSTYPE;
123 }
124 
125 //-----------------------------------------------
RESOURCETYPE_TOOLBAR()126 ::rtl::OUString PresetHandler::RESOURCETYPE_TOOLBAR()
127 {
128     static ::rtl::OUString RSTYPE = DECLARE_ASCII("toolbar");
129     return RSTYPE;
130 }
131 
132 //-----------------------------------------------
RESOURCETYPE_ACCELERATOR()133 ::rtl::OUString PresetHandler::RESOURCETYPE_ACCELERATOR()
134 {
135     static ::rtl::OUString RSTYPE = DECLARE_ASCII("accelerator");
136     return RSTYPE;
137 }
138 
139 //-----------------------------------------------
RESOURCETYPE_STATUSBAR()140 ::rtl::OUString PresetHandler::RESOURCETYPE_STATUSBAR()
141 {
142     static ::rtl::OUString RSTYPE = DECLARE_ASCII("statusbar");
143     return RSTYPE;
144 }
145 
146 //-----------------------------------------------
PresetHandler(const css::uno::Reference<css::lang::XMultiServiceFactory> & xSMGR)147 PresetHandler::PresetHandler(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR)
148     : ThreadHelpBase     (&Application::GetSolarMutex()        )
149     , m_xSMGR            (xSMGR                                )
150     , m_aSharedStorages  (                                     )
151     , m_lDocumentStorages(xSMGR                                )
152     , m_aLocale          (::comphelper::Locale::X_NOTRANSLATE())
153 {
154 }
155 
156 //-----------------------------------------------
PresetHandler(const PresetHandler & rCopy)157 PresetHandler::PresetHandler(const PresetHandler& rCopy)
158     : ThreadHelpBase     (&Application::GetSolarMutex()        )
159 {
160     m_xSMGR                 = rCopy.m_xSMGR;
161     m_eConfigType           = rCopy.m_eConfigType;
162     m_sResourceType         = rCopy.m_sResourceType;
163     m_sModule               = rCopy.m_sModule;
164     m_aSharedStorages       = rCopy.m_aSharedStorages;
165     m_xWorkingStorageShare  = rCopy.m_xWorkingStorageShare;
166     m_xWorkingStorageNoLang = rCopy.m_xWorkingStorageNoLang;
167     m_xWorkingStorageUser   = rCopy.m_xWorkingStorageUser;
168     m_lPresets              = rCopy.m_lPresets;
169     m_lTargets              = rCopy.m_lTargets;
170     m_aLocale               = rCopy.m_aLocale;
171     m_lDocumentStorages     = rCopy.m_lDocumentStorages;
172     m_sRelPathShare         = rCopy.m_sRelPathShare;
173     m_sRelPathNoLang        = rCopy.m_sRelPathNoLang;
174     m_sRelPathUser          = rCopy.m_sRelPathUser;
175 }
176 
177 //-----------------------------------------------
~PresetHandler()178 PresetHandler::~PresetHandler()
179 {
180     m_xWorkingStorageShare.clear();
181     m_xWorkingStorageNoLang.clear();
182     m_xWorkingStorageUser.clear();
183 
184     /* #i46497#
185         Don't call forgetCachedStorages() here for shared storages.
186         Because we opened different sub storages by using openPath().
187         And every already open path was reused and referenced (means it's
188         ref count was increased!)
189         So now we have to release our ref counts to these shared storages
190         only... and not to free all used storages.
191         Otherwise we will disconnect all other open configuration access
192         objects which base on these storages.
193      */
194     m_aSharedStorages->m_lStoragesShare.closePath(m_sRelPathShare);
195     m_aSharedStorages->m_lStoragesUser.closePath (m_sRelPathUser );
196 
197     /* On the other side closePath() is not needed for our special handled
198        document storage. Because it's not shared with others... so we can
199        free it.
200      */
201     m_lDocumentStorages.forgetCachedStorages();
202 }
203 
204 //-----------------------------------------------
forgetCachedStorages()205 void PresetHandler::forgetCachedStorages()
206 {
207     // SAFE -> ----------------------------------
208     WriteGuard aWriteLock(m_aLock);
209 
210     if (m_eConfigType == E_DOCUMENT)
211     {
212         m_xWorkingStorageShare.clear();
213         m_xWorkingStorageNoLang.clear();
214         m_xWorkingStorageUser.clear();
215     }
216 
217     m_lDocumentStorages.forgetCachedStorages();
218 
219     aWriteLock.unlock();
220     // <- SAFE ----------------------------------
221 }
222 
223 //-----------------------------------------------
lcl_getLocalizedMessage(::sal_Int32 nID)224 ::rtl::OUString lcl_getLocalizedMessage(::sal_Int32 nID)
225 {
226     ::rtl::OUString sMessage = ::rtl::OUString::createFromAscii("Unknown error.");
227 
228     switch(nID)
229     {
230         case ID_CORRUPT_UICONFIG_SHARE :
231                 sMessage = ::rtl::OUString( String( FwkResId( STR_CORRUPT_UICFG_SHARE )));
232                 break;
233 
234         case ID_CORRUPT_UICONFIG_USER :
235                 sMessage = ::rtl::OUString( String( FwkResId( STR_CORRUPT_UICFG_USER )));
236                 break;
237 
238         case ID_CORRUPT_UICONFIG_GENERAL :
239                 sMessage = ::rtl::OUString( String( FwkResId( STR_CORRUPT_UICFG_GENERAL )));
240                 break;
241     }
242 
243     return sMessage;
244 }
245 
246 //-----------------------------------------------
getOrCreateRootStorageShare()247 css::uno::Reference< css::embed::XStorage > PresetHandler::getOrCreateRootStorageShare()
248 {
249     css::uno::Reference< css::embed::XStorage > xRoot = m_aSharedStorages->m_lStoragesShare.getRootStorage();
250     if (xRoot.is())
251         return xRoot;
252 
253     // SAFE -> ----------------------------------
254     ReadGuard aReadLock(m_aLock);
255     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
256     aReadLock.unlock();
257     // <- SAFE ----------------------------------
258 
259     css::uno::Reference< css::beans::XPropertySet > xPathSettings(
260         xSMGR->createInstance(SERVICENAME_PATHSETTINGS),
261         css::uno::UNO_QUERY_THROW);
262 
263     ::rtl::OUString sShareLayer;
264     xPathSettings->getPropertyValue(BASEPATH_SHARE_LAYER) >>= sShareLayer;
265 
266     // "UIConfig" is a "multi path" ... use first part only here!
267     sal_Int32 nPos = sShareLayer.indexOf(';');
268     if (nPos > 0)
269         sShareLayer = sShareLayer.copy(0, nPos);
270 
271     // Note: Maybe a user uses URLs without a final slash! Check it ...
272     nPos = sShareLayer.lastIndexOf('/');
273     if (nPos != sShareLayer.getLength()-1)
274         sShareLayer += ::rtl::OUString::createFromAscii("/");
275 
276     sShareLayer += RELPATH_SHARE_LAYER; // folder
277     /*
278     // TODO remove me!
279     // Attention: This is temp. workaround ... We create a temp. storage file
280     // based of a system directory. This must be used so, till the storage implementation
281     // can work on directories too.
282     */
283     css::uno::Sequence< css::uno::Any > lArgs(2);
284     lArgs[0] <<= sShareLayer;
285     lArgs[1] <<= css::embed::ElementModes::READ | css::embed::ElementModes::NOCREATE;
286 
287     css::uno::Reference< css::lang::XSingleServiceFactory > xStorageFactory(xSMGR->createInstance(SERVICENAME_FILESYSTEMSTORAGEFACTORY)  , css::uno::UNO_QUERY_THROW);
288     css::uno::Reference< css::embed::XStorage >             xStorage;
289 
290     try
291     {
292         xStorage = css::uno::Reference< css::embed::XStorage >(xStorageFactory->createInstanceWithArguments(lArgs), css::uno::UNO_QUERY_THROW);
293     }
294     catch(const css::uno::Exception& ex)
295     {
296         throw css::configuration::CorruptedUIConfigurationException(
297             lcl_getLocalizedMessage(ID_CORRUPT_UICONFIG_SHARE),
298             css::uno::Reference< css::uno::XInterface >(),
299             ex.Message);
300     }
301 
302     m_aSharedStorages->m_lStoragesShare.setRootStorage(xStorage);
303 
304     return xStorage;
305 }
306 
307 //-----------------------------------------------
getOrCreateRootStorageUser()308 css::uno::Reference< css::embed::XStorage > PresetHandler::getOrCreateRootStorageUser()
309 {
310     css::uno::Reference< css::embed::XStorage > xRoot = m_aSharedStorages->m_lStoragesUser.getRootStorage();
311     if (xRoot.is())
312         return xRoot;
313 
314     // SAFE -> ----------------------------------
315     ReadGuard aReadLock(m_aLock);
316     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
317     aReadLock.unlock();
318     // <- SAFE ----------------------------------
319 
320     css::uno::Reference< css::beans::XPropertySet > xPathSettings(
321         xSMGR->createInstance(SERVICENAME_PATHSETTINGS),
322         css::uno::UNO_QUERY_THROW);
323 
324     ::rtl::OUString sUserLayer;
325     xPathSettings->getPropertyValue(BASEPATH_USER_LAYER) >>= sUserLayer ;
326 
327     // Note: Maybe a user uses URLs without a final slash! Check it ...
328     sal_Int32 nPos = sUserLayer.lastIndexOf('/');
329     if (nPos != sUserLayer.getLength()-1)
330         sUserLayer += ::rtl::OUString::createFromAscii("/");
331 
332     sUserLayer  += RELPATH_USER_LAYER; // storage file
333 
334     css::uno::Sequence< css::uno::Any > lArgs(2);
335     lArgs[0] <<= sUserLayer;
336     lArgs[1] <<= css::embed::ElementModes::READWRITE;
337 
338     css::uno::Reference< css::lang::XSingleServiceFactory > xStorageFactory(xSMGR->createInstance(SERVICENAME_FILESYSTEMSTORAGEFACTORY)  , css::uno::UNO_QUERY_THROW);
339     css::uno::Reference< css::embed::XStorage >             xStorage;
340 
341     try
342     {
343         xStorage = css::uno::Reference< css::embed::XStorage >(xStorageFactory->createInstanceWithArguments(lArgs), css::uno::UNO_QUERY_THROW);
344     }
345     catch(const css::uno::Exception& ex)
346     {
347         throw css::configuration::CorruptedUIConfigurationException(
348             lcl_getLocalizedMessage(ID_CORRUPT_UICONFIG_USER),
349             css::uno::Reference< css::uno::XInterface >(),
350             ex.Message);
351     }
352 
353     m_aSharedStorages->m_lStoragesUser.setRootStorage(xStorage);
354 
355     return xStorage;
356 }
357 
358 //-----------------------------------------------
getWorkingStorageShare()359 css::uno::Reference< css::embed::XStorage > PresetHandler::getWorkingStorageShare()
360 {
361     // SAFE -> ----------------------------------
362     ReadGuard aReadLock(m_aLock);
363     return m_xWorkingStorageShare;
364     // <- SAFE ----------------------------------
365 }
366 
367 //-----------------------------------------------
getWorkingStorageUser()368 css::uno::Reference< css::embed::XStorage > PresetHandler::getWorkingStorageUser()
369 {
370     // SAFE -> ----------------------------------
371     ReadGuard aReadLock(m_aLock);
372     return m_xWorkingStorageUser;
373     // <- SAFE ----------------------------------
374 }
375 
376 //-----------------------------------------------
getParentStorageShare(const css::uno::Reference<css::embed::XStorage> &)377 css::uno::Reference< css::embed::XStorage > PresetHandler::getParentStorageShare(const css::uno::Reference< css::embed::XStorage >& /*xChild*/)
378 {
379     // SAFE -> ----------------------------------
380     ReadGuard aReadLock(m_aLock);
381     css::uno::Reference< css::embed::XStorage > xWorking = m_xWorkingStorageShare;
382     aReadLock.unlock();
383     // <- SAFE ----------------------------------
384 
385     return m_aSharedStorages->m_lStoragesShare.getParentStorage(xWorking);
386 }
387 
388 //-----------------------------------------------
getParentStorageUser(const css::uno::Reference<css::embed::XStorage> &)389 css::uno::Reference< css::embed::XStorage > PresetHandler::getParentStorageUser(const css::uno::Reference< css::embed::XStorage >& /*xChild*/)
390 {
391     // SAFE -> ----------------------------------
392     ReadGuard aReadLock(m_aLock);
393     css::uno::Reference< css::embed::XStorage > xWorking = m_xWorkingStorageUser;
394     aReadLock.unlock();
395     // <- SAFE ----------------------------------
396 
397     return m_aSharedStorages->m_lStoragesUser.getParentStorage(xWorking);
398 }
399 
400 //-----------------------------------------------
connectToResource(PresetHandler::EConfigType eConfigType,const::rtl::OUString & sResource,const::rtl::OUString & sModule,const css::uno::Reference<css::embed::XStorage> & xDocumentRoot,const::comphelper::Locale & aLocale)401 void PresetHandler::connectToResource(      PresetHandler::EConfigType                   eConfigType  ,
402                                       const ::rtl::OUString&                             sResource    ,
403                                       const ::rtl::OUString&                             sModule      ,
404                                       const css::uno::Reference< css::embed::XStorage >& xDocumentRoot,
405                                       const ::comphelper::Locale&                        aLocale      )
406 {
407     // TODO free all current open storages!
408 
409     // SAFE -> ----------------------------------
410     WriteGuard aWriteLock(m_aLock);
411 
412     m_eConfigType   = eConfigType  ;
413     m_sResourceType = sResource    ;
414     m_sModule       = sModule      ;
415     m_aLocale       = aLocale      ;
416 
417     aWriteLock.unlock();
418     // <- SAFE ----------------------------------
419 
420     css::uno::Reference< css::embed::XStorage > xShare;
421     css::uno::Reference< css::embed::XStorage > xNoLang;
422     css::uno::Reference< css::embed::XStorage > xUser;
423 
424     // special case for documents
425     // use outside root storage, if we run in E_DOCUMENT mode!
426     if (eConfigType == E_DOCUMENT)
427     {
428         if (!xDocumentRoot.is())
429             throw css::uno::RuntimeException(
430                     ::rtl::OUString::createFromAscii("There is valid root storage, where the UI configuration can work on."),
431                     css::uno::Reference< css::uno::XInterface >());
432         m_lDocumentStorages.setRootStorage(xDocumentRoot);
433         xShare = xDocumentRoot;
434         xUser  = xDocumentRoot;
435     }
436     else
437     {
438         xShare = getOrCreateRootStorageShare();
439         xUser  = getOrCreateRootStorageUser();
440     }
441 
442     // #...#
443     try
444     {
445 
446     // a) inside share layer we should not create any new structures ... We have to use
447     //    existing ones only!
448     // b) inside user layer we can (SOFT mode!) but sometimes we shouldn't (HARD mode!)
449     //    create new empty structures. We should prefer using of any existing structure.
450     sal_Int32 eShareMode = (css::embed::ElementModes::READ      | css::embed::ElementModes::NOCREATE);
451     sal_Int32 eUserMode  = (css::embed::ElementModes::READWRITE                                     );
452 
453     ::rtl::OUStringBuffer sRelPathBuf(1024);
454     ::rtl::OUString       sRelPathShare;
455     ::rtl::OUString       sRelPathNoLang;
456     ::rtl::OUString       sRelPathUser;
457     switch(eConfigType)
458     {
459         case E_GLOBAL :
460         {
461             sRelPathBuf.append(SUBSTORAGE_GLOBAL);
462             sRelPathBuf.append(PATH_SEPERATOR   );
463             sRelPathBuf.append(sResource        );
464             sRelPathShare = sRelPathBuf.makeStringAndClear();
465             sRelPathUser  = sRelPathShare;
466 
467             xShare = impl_openPathIgnoringErrors(sRelPathShare, eShareMode, sal_True );
468             xUser  = impl_openPathIgnoringErrors(sRelPathUser , eUserMode , sal_False);
469         }
470         break;
471 
472         case E_MODULES :
473         {
474             sRelPathBuf.append(SUBSTORAGE_MODULES);
475             sRelPathBuf.append(PATH_SEPERATOR    );
476             sRelPathBuf.append(sModule           );
477             sRelPathBuf.append(PATH_SEPERATOR    );
478             sRelPathBuf.append(sResource         );
479             sRelPathShare = sRelPathBuf.makeStringAndClear();
480             sRelPathUser  = sRelPathShare;
481 
482             xShare = impl_openPathIgnoringErrors(sRelPathShare, eShareMode, sal_True );
483             xUser  = impl_openPathIgnoringErrors(sRelPathUser , eUserMode , sal_False);
484         }
485         break;
486 
487         case E_DOCUMENT :
488         {
489             // A document does not have a share layer in real.
490             // It has one layer only, and this one should be opened READ_WRITE.
491             // So we open the user layer here only and set the share layer equals to it .-)
492 
493             sRelPathBuf.append(sResource);
494             sRelPathUser  = sRelPathBuf.makeStringAndClear();
495             sRelPathShare = sRelPathUser;
496 
497             try
498             {
499                 xUser  = m_lDocumentStorages.openPath(sRelPathUser , eUserMode );
500                 xShare = xUser;
501             }
502             catch(const css::uno::RuntimeException& exRun)
503                 { throw exRun; }
504             catch(const css::uno::Exception&)
505                 { xShare.clear(); xUser.clear(); }
506         }
507         break;
508     }
509 
510     // Non-localized global share
511     xNoLang = xShare;
512     sRelPathNoLang = sRelPathShare;
513 
514     if (
515         (aLocale     != ::comphelper::Locale::X_NOTRANSLATE()) && // localized level?
516         (eConfigType != E_DOCUMENT                           )    // no localization in document mode!
517        )
518     {
519         // First try to find the right localized set inside share layer.
520         // Fallbacks are allowed there.
521         ::comphelper::Locale aShareLocale       = aLocale      ;
522         ::rtl::OUString      sLocalizedSharePath(sRelPathShare);
523         sal_Bool             bAllowFallbacks    = sal_True     ;
524         xShare = impl_openLocalizedPathIgnoringErrors(sLocalizedSharePath, eShareMode, sal_True , aShareLocale, bAllowFallbacks);
525 
526         // The try to locate the right sub dir inside user layer ... without using fallbacks!
527         // Normally the corresponding sub dir should be created matching the specified locale.
528         // Because we allow creation of storages inside user layer by default.
529         ::comphelper::Locale aUserLocale        = aLocale    ;
530         ::rtl::OUString      sLocalizedUserPath(sRelPathUser);
531                              bAllowFallbacks    = sal_False  ;
532         xUser = impl_openLocalizedPathIgnoringErrors(sLocalizedUserPath, eUserMode , sal_False, aUserLocale, bAllowFallbacks);
533 
534         sRelPathShare = sLocalizedSharePath;
535         sRelPathUser  = sLocalizedUserPath ;
536     }
537 
538     // read content of level 3 (presets, targets)
539           css::uno::Reference< css::container::XNameAccess > xAccess ;
540           css::uno::Sequence< ::rtl::OUString >              lNames  ;
541     const ::rtl::OUString*                                   pNames  ;
542           sal_Int32                                          c       ;
543           sal_Int32                                          i       ;
544           OUStringList                                       lPresets;
545           OUStringList                                       lTargets;
546 
547     // read preset names of share layer
548     xAccess = css::uno::Reference< css::container::XNameAccess >(xShare, css::uno::UNO_QUERY);
549     if (xAccess.is())
550     {
551         lNames  = xAccess->getElementNames();
552         pNames  = lNames.getConstArray();
553         c       = lNames.getLength();
554 
555         for (i=0; i<c; ++i)
556         {
557             ::rtl::OUString sTemp = pNames[i];
558             sal_Int32       nPos  = sTemp.indexOf(FILE_EXTENSION);
559             if (nPos > -1)
560                 sTemp = sTemp.copy(0,nPos);
561             lPresets.push_back(sTemp);
562         }
563     }
564 
565     // read preset names of user layer
566     xAccess = css::uno::Reference< css::container::XNameAccess >(xUser, css::uno::UNO_QUERY);
567     if (xAccess.is())
568     {
569         lNames  = xAccess->getElementNames();
570         pNames  = lNames.getConstArray();
571         c       = lNames.getLength();
572 
573         for (i=0; i<c; ++i)
574         {
575             ::rtl::OUString sTemp = pNames[i];
576             sal_Int32       nPos  = sTemp.indexOf(FILE_EXTENSION);
577             if (nPos > -1)
578                 sTemp = sTemp.copy(0,nPos);
579             lTargets.push_back(sTemp);
580         }
581     }
582 
583     // SAFE -> ----------------------------------
584     aWriteLock.lock();
585 
586     m_xWorkingStorageShare = xShare  ;
587     m_xWorkingStorageNoLang= xNoLang;
588     m_xWorkingStorageUser  = xUser   ;
589     m_lPresets             = lPresets;
590     m_lTargets             = lTargets;
591     m_sRelPathShare        = sRelPathShare;
592     m_sRelPathNoLang       = sRelPathNoLang;
593     m_sRelPathUser         = sRelPathUser;
594 
595     aWriteLock.unlock();
596     // <- SAFE ----------------------------------
597 
598     }
599     catch(const css::uno::Exception& ex)
600     {
601         throw css::configuration::CorruptedUIConfigurationException(
602             lcl_getLocalizedMessage(ID_CORRUPT_UICONFIG_GENERAL),
603             css::uno::Reference< css::uno::XInterface >(),
604             ex.Message);
605     }
606 }
607 
608 //-----------------------------------------------
copyPresetToTarget(const::rtl::OUString & sPreset,const::rtl::OUString & sTarget)609 void PresetHandler::copyPresetToTarget(const ::rtl::OUString& sPreset,
610                                        const ::rtl::OUString& sTarget)
611 {
612     // don't check our preset list, if element exists
613     // We try to open it and forward all errors to the user!
614 
615     // SAFE -> ----------------------------------
616     ReadGuard aReadLock(m_aLock);
617     css::uno::Reference< css::embed::XStorage > xWorkingShare = m_xWorkingStorageShare;
618     css::uno::Reference< css::embed::XStorage > xWorkingNoLang= m_xWorkingStorageNoLang;
619     css::uno::Reference< css::embed::XStorage > xWorkingUser  = m_xWorkingStorageUser ;
620     aReadLock.unlock();
621     // <- SAFE ----------------------------------
622 
623     // e.g. module without any config data ?!
624     if (
625         (!xWorkingShare.is()) ||
626         (!xWorkingUser.is() )
627        )
628     {
629        return;
630     }
631 
632     ::rtl::OUString sPresetFile(sPreset);
633     sPresetFile += FILE_EXTENSION;
634 
635     ::rtl::OUString sTargetFile(sTarget);
636     sTargetFile += FILE_EXTENSION;
637 
638     // remove existing elements before you try to copy the preset to that location ...
639     // Otherwise w will get an ElementExistException inside copyElementTo()!
640     css::uno::Reference< css::container::XNameAccess > xCheckingUser(xWorkingUser, css::uno::UNO_QUERY_THROW);
641     if (xCheckingUser->hasByName(sTargetFile))
642         xWorkingUser->removeElement(sTargetFile);
643 
644     xWorkingShare->copyElementTo(sPresetFile, xWorkingUser, sTargetFile);
645 
646     // If our storages work in transacted mode, we have
647     // to commit all changes from bottom to top!
648     commitUserChanges();
649 }
650 
651 //-----------------------------------------------
openPreset(const::rtl::OUString & sPreset,sal_Bool bUseNoLangGlobal)652 css::uno::Reference< css::io::XStream > PresetHandler::openPreset(const ::rtl::OUString& sPreset,
653                                                                   sal_Bool bUseNoLangGlobal)
654 {
655     // SAFE -> ----------------------------------
656     ReadGuard aReadLock(m_aLock);
657     css::uno::Reference< css::embed::XStorage > xFolder = bUseNoLangGlobal? m_xWorkingStorageNoLang: m_xWorkingStorageShare;
658     aReadLock.unlock();
659     // <- SAFE ----------------------------------
660 
661     // e.g. module without any config data ?!
662     if (!xFolder.is())
663        return css::uno::Reference< css::io::XStream >();
664 
665     ::rtl::OUString sFile(sPreset);
666     sFile += FILE_EXTENSION;
667 
668     // inform user about errors (use original exceptions!)
669     css::uno::Reference< css::io::XStream > xStream = xFolder->openStreamElement(sFile, css::embed::ElementModes::READ);
670     return xStream;
671 }
672 
673 //-----------------------------------------------
openTarget(const::rtl::OUString & sTarget,sal_Bool bCreateIfMissing)674 css::uno::Reference< css::io::XStream > PresetHandler::openTarget(const ::rtl::OUString& sTarget         ,
675                                                                         sal_Bool         bCreateIfMissing)
676 {
677     // SAFE -> ----------------------------------
678     ReadGuard aReadLock(m_aLock);
679     css::uno::Reference< css::embed::XStorage > xFolder = m_xWorkingStorageUser;
680     aReadLock.unlock();
681     // <- SAFE ----------------------------------
682 
683     // e.g. module without any config data ?!
684     if (!xFolder.is())
685        return css::uno::Reference< css::io::XStream >();
686 
687     ::rtl::OUString sFile(sTarget);
688     sFile += FILE_EXTENSION;
689 
690     sal_Int32 nOpenMode = css::embed::ElementModes::READWRITE;
691     if (!bCreateIfMissing)
692         nOpenMode |= css::embed::ElementModes::NOCREATE;
693 
694     // try it in read/write mode first and ignore errors.
695     css::uno::Reference< css::io::XStream > xStream;
696     try
697     {
698         xStream = xFolder->openStreamElement(sFile, nOpenMode);
699         return xStream;
700     }
701     catch(const css::uno::RuntimeException&)
702         { throw; }
703     catch(const css::uno::Exception&)
704         { xStream.clear(); }
705 
706     // try it readonly if it failed before.
707     // inform user about errors (use original exceptions!)
708     nOpenMode &= ~css::embed::ElementModes::WRITE;
709     xStream    = xFolder->openStreamElement(sFile, nOpenMode);
710 
711     return xStream;
712 }
713 
714 //-----------------------------------------------
commitUserChanges()715 void PresetHandler::commitUserChanges()
716 {
717     // SAFE -> ----------------------------------
718     ReadGuard aReadLock(m_aLock);
719     css::uno::Reference< css::embed::XStorage > xWorking = m_xWorkingStorageUser;
720     EConfigType                                 eCfgType = m_eConfigType;
721     aReadLock.unlock();
722     // <- SAFE ----------------------------------
723 
724     // e.g. module without any config data ?!
725     if (!xWorking.is())
726        return;
727 
728     ::rtl::OUString sPath;
729 
730     switch(eCfgType)
731     {
732         case E_GLOBAL :
733         case E_MODULES :
734         {
735             sPath = m_aSharedStorages->m_lStoragesUser.getPathOfStorage(xWorking);
736             m_aSharedStorages->m_lStoragesUser.commitPath(sPath);
737             m_aSharedStorages->m_lStoragesUser.notifyPath(sPath);
738         }
739         break;
740 
741         case E_DOCUMENT :
742         {
743             sPath = m_lDocumentStorages.getPathOfStorage(xWorking);
744             m_lDocumentStorages.commitPath(sPath);
745             m_lDocumentStorages.notifyPath(sPath);
746         }
747         break;
748     }
749 }
750 
751 //-----------------------------------------------
addStorageListener(IStorageListener * pListener)752 void PresetHandler::addStorageListener(IStorageListener* pListener)
753 {
754     // SAFE -> ----------------------------------
755     ReadGuard aReadLock(m_aLock);
756     ::rtl::OUString sRelPath = m_sRelPathUser; // use user path ... because we don't work directly on the share layer!
757     EConfigType     eCfgType = m_eConfigType;
758     aReadLock.unlock();
759     // <- SAFE ----------------------------------
760 
761     if (!sRelPath.getLength())
762         return;
763 
764     switch(eCfgType)
765     {
766         case E_GLOBAL :
767         case E_MODULES :
768         {
769             m_aSharedStorages->m_lStoragesUser.addStorageListener(pListener, sRelPath);
770         }
771         break;
772 
773         case E_DOCUMENT :
774         {
775             m_lDocumentStorages.addStorageListener(pListener, sRelPath);
776         }
777         break;
778     }
779 }
780 
781 //-----------------------------------------------
removeStorageListener(IStorageListener * pListener)782 void PresetHandler::removeStorageListener(IStorageListener* pListener)
783 {
784     // SAFE -> ----------------------------------
785     ReadGuard aReadLock(m_aLock);
786     ::rtl::OUString sRelPath = m_sRelPathUser; // use user path ... because we don't work directly on the share layer!
787     EConfigType     eCfgType = m_eConfigType;
788     aReadLock.unlock();
789     // <- SAFE ----------------------------------
790 
791     if (!sRelPath.getLength())
792         return;
793 
794     switch(eCfgType)
795     {
796         case E_GLOBAL :
797         case E_MODULES :
798         {
799             m_aSharedStorages->m_lStoragesUser.removeStorageListener(pListener, sRelPath);
800         }
801         break;
802 
803         case E_DOCUMENT :
804         {
805             m_lDocumentStorages.removeStorageListener(pListener, sRelPath);
806         }
807         break;
808     }
809 }
810 
811 //-----------------------------------------------
impl_openPathIgnoringErrors(const::rtl::OUString & sPath,sal_Int32 eMode,sal_Bool bShare)812 css::uno::Reference< css::embed::XStorage > PresetHandler::impl_openPathIgnoringErrors(const ::rtl::OUString& sPath ,
813                                                                                              sal_Int32        eMode ,
814                                                                                              sal_Bool         bShare)
815 {
816     css::uno::Reference< css::embed::XStorage > xPath;
817     try
818     {
819         if (bShare)
820             xPath = m_aSharedStorages->m_lStoragesShare.openPath(sPath, eMode);
821         else
822             xPath = m_aSharedStorages->m_lStoragesUser.openPath(sPath, eMode);
823     }
824     catch(const css::uno::RuntimeException& exRun)
825         { throw exRun; }
826     catch(const css::uno::Exception&)
827         { xPath.clear(); }
828     return xPath;
829 }
830 
831 //-----------------------------------------------
impl_findMatchingLocalizedValue(const::std::vector<::rtl::OUString> & lLocalizedValues,::comphelper::Locale & aLocale,sal_Bool bAllowFallbacks)832 ::std::vector< ::rtl::OUString >::const_iterator PresetHandler::impl_findMatchingLocalizedValue(const ::std::vector< ::rtl::OUString >& lLocalizedValues,
833                                                                                                       ::comphelper::Locale&             aLocale         ,
834                                                                                                       sal_Bool                          bAllowFallbacks )
835 {
836     ::std::vector< ::rtl::OUString >::const_iterator pFound = lLocalizedValues.end();
837     if (bAllowFallbacks)
838     {
839         pFound = ::comphelper::Locale::getFallback(lLocalizedValues, aLocale.toISO());
840     }
841     else
842     {
843         for (  pFound  = lLocalizedValues.begin();
844                pFound != lLocalizedValues.end()  ;
845              ++pFound                            )
846         {
847             const ::rtl::OUString&     sCheckISO   = *pFound;
848                   ::comphelper::Locale aCheckLocale(sCheckISO);
849             if (aCheckLocale.equals(aLocale))
850                 break;
851         }
852     }
853 
854     // if we found a valid locale ... take it over to our in/out parameter aLocale
855     if (pFound != lLocalizedValues.end())
856     {
857         const ::rtl::OUString& sISOLocale = *pFound;
858         aLocale.fromISO(sISOLocale);
859     }
860 
861     return pFound;
862 }
863 
864 //-----------------------------------------------
impl_openLocalizedPathIgnoringErrors(::rtl::OUString & sPath,sal_Int32 eMode,sal_Bool bShare,::comphelper::Locale & aLocale,sal_Bool bAllowFallback)865 css::uno::Reference< css::embed::XStorage > PresetHandler::impl_openLocalizedPathIgnoringErrors(::rtl::OUString&      sPath         ,
866                                                                                                 sal_Int32             eMode         ,
867                                                                                                 sal_Bool              bShare        ,
868                                                                                                 ::comphelper::Locale& aLocale       ,
869                                                                                                 sal_Bool              bAllowFallback)
870 {
871     css::uno::Reference< css::embed::XStorage >      xPath         = impl_openPathIgnoringErrors(sPath, eMode, bShare);
872     ::std::vector< ::rtl::OUString >                 lSubFolders   = impl_getSubFolderNames(xPath);
873     ::std::vector< ::rtl::OUString >::const_iterator pLocaleFolder = impl_findMatchingLocalizedValue(lSubFolders, aLocale, bAllowFallback);
874 
875     // no fallback ... creation not allowed => no storage
876     if (
877         (pLocaleFolder == lSubFolders.end()                                                ) &&
878         ((eMode & css::embed::ElementModes::NOCREATE) == css::embed::ElementModes::NOCREATE)
879        )
880         return css::uno::Reference< css::embed::XStorage >();
881 
882     // it doesn't matter, if there is a locale fallback or not
883     // If creation of storages is allowed, we do it anyway.
884     // Otherwise we have no acc config at all, which can make other trouble.
885     ::rtl::OUString sLocalizedPath;
886     sLocalizedPath  = sPath;
887     sLocalizedPath += PATH_SEPERATOR;
888     if (pLocaleFolder != lSubFolders.end())
889         sLocalizedPath += *pLocaleFolder;
890     else
891         sLocalizedPath += aLocale.toISO();
892 
893     css::uno::Reference< css::embed::XStorage > xLocalePath = impl_openPathIgnoringErrors(sLocalizedPath, eMode, bShare);
894 
895     if (xLocalePath.is())
896         sPath = sLocalizedPath;
897     else
898         sPath = ::rtl::OUString();
899 
900     return xLocalePath;
901 }
902 
903 //-----------------------------------------------
impl_getSubFolderNames(const css::uno::Reference<css::embed::XStorage> & xFolder)904 ::std::vector< ::rtl::OUString > PresetHandler::impl_getSubFolderNames(const css::uno::Reference< css::embed::XStorage >& xFolder)
905 {
906     css::uno::Reference< css::container::XNameAccess > xAccess(xFolder, css::uno::UNO_QUERY);
907     if (!xAccess.is())
908         return ::std::vector< ::rtl::OUString >();
909 
910           ::std::vector< ::rtl::OUString >      lSubFolders;
911     const css::uno::Sequence< ::rtl::OUString > lNames = xAccess->getElementNames();
912     const ::rtl::OUString*                      pNames = lNames.getConstArray();
913           sal_Int32                             c      = lNames.getLength();
914           sal_Int32                             i      = 0;
915 
916     for (i=0; i<c; ++i)
917     {
918         try
919         {
920             if (xFolder->isStorageElement(pNames[i]))
921                 lSubFolders.push_back(pNames[i]);
922         }
923         catch(const css::uno::RuntimeException& exRun)
924             { throw exRun; }
925         catch(const css::uno::Exception&)
926             {}
927     }
928 
929     return lSubFolders;
930 }
931 
932 //-----------------------------------------------
933 } // namespace framework
934