merge the formfield patch from ooo-build
[ooovba.git] / framework / source / accelerators / storageholder.cxx
blobdd4bf12e05cb74d4259b88bea20cfd9aeebc14b9
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: storageholder.cxx,v $
10 * $Revision: 1.8.82.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_framework.hxx"
33 #include <accelerators/storageholder.hxx>
35 //===============================================
36 // own includes
37 #include <threadhelp/readguard.hxx>
38 #include <threadhelp/writeguard.hxx>
39 #include <services.h>
41 //===============================================
42 // interface includes
44 #ifndef __COM_SUN_STAR_CONTAINER_NOSUCHELEMENTEXCEPTION_HPP_
45 #include <com/sun/star/container/NoSuchElementException.hpp>
46 #endif
48 #ifndef __COM_SUN_STAR_CONTAINER_XNAMEACCESS_HPP_
49 #include <com/sun/star/container/XNameAccess.hpp>
50 #endif
52 #ifndef __COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
53 #include <com/sun/star/beans/XPropertySet.hpp>
54 #endif
56 #ifndef __COM_SUN_STAR_EMBED_ELEMENTMODES_HPP_
57 #include <com/sun/star/embed/ElementModes.hpp>
58 #endif
60 #ifndef __COM_SUN_STAR_EMBED_XTRANSACTEDOBJECT_HPP_
61 #include <com/sun/star/embed/XTransactedObject.hpp>
62 #endif
64 #ifndef __COM_SUN_STAR_EMBED_XPACKAGESTRUCTURECREATOR_HPP_
65 #include <com/sun/star/embed/XPackageStructureCreator.hpp>
66 #endif
68 #ifndef __COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_
69 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
70 #endif
72 #ifndef __COM_SUN_STAR_IO_XSEEKABLE_HPP_
73 #include <com/sun/star/io/XSeekable.hpp>
74 #endif
76 //===============================================
77 // other includes
78 #include <comphelper/processfactory.hxx>
80 //===============================================
81 // const
83 #define PATH_SEPERATOR_ASCII "/"
84 #define PATH_SEPERATOR_UNICODE ((sal_Unicode)'/')
85 #define PATH_SEPERATOR ::rtl::OUString::createFromAscii(PATH_SEPERATOR_ASCII)
87 //===============================================
88 // namespace
90 namespace framework
93 namespace css = ::com::sun::star;
95 //-----------------------------------------------
96 StorageHolder::StorageHolder()
97 : ThreadHelpBase( )
98 , m_xSMGR (::comphelper::getProcessServiceFactory())
102 //-----------------------------------------------
103 StorageHolder::StorageHolder(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR)
104 : ThreadHelpBase( )
105 , m_xSMGR (xSMGR)
109 //-----------------------------------------------
110 StorageHolder::~StorageHolder()
112 // TODO implement me
113 // dispose/clear etcpp.
116 //-----------------------------------------------
117 void StorageHolder::forgetCachedStorages()
119 // SAFE -> ----------------------------------
120 WriteGuard aWriteLock(m_aLock);
122 TPath2StorageInfo::iterator pIt;
123 for ( pIt = m_lStorages.begin();
124 pIt != m_lStorages.end() ;
125 ++pIt )
127 TStorageInfo& rInfo = pIt->second;
128 // TODO think about listener !
129 rInfo.Storage.clear();
131 m_lStorages.clear();
133 aWriteLock.unlock();
134 // <- SAFE ----------------------------------
137 //-----------------------------------------------
138 void StorageHolder::setRootStorage(const css::uno::Reference< css::embed::XStorage >& xRoot)
140 // SAFE -> ----------------------------------
141 WriteGuard aWriteLock(m_aLock);
142 m_xRoot = xRoot;
143 aWriteLock.unlock();
144 // <- SAFE ----------------------------------
147 //-----------------------------------------------
148 css::uno::Reference< css::embed::XStorage > StorageHolder::getRootStorage() const
150 // SAFE -> ----------------------------------
151 ReadGuard aReadLock(m_aLock);
152 return m_xRoot;
153 // <- SAFE ----------------------------------
156 //-----------------------------------------------
157 css::uno::Reference< css::embed::XStorage > StorageHolder::openPath(const ::rtl::OUString& sPath ,
158 sal_Int32 nOpenMode)
160 ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
161 OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath);
163 // SAFE -> ----------------------------------
164 ReadGuard aReadLock(m_aLock);
165 css::uno::Reference< css::embed::XStorage > xParent = m_xRoot;
166 aReadLock.unlock();
167 // <- SAFE ----------------------------------
169 css::uno::Reference< css::embed::XStorage > xChild ;
170 ::rtl::OUString sRelPath;
171 OUStringList::const_iterator pIt ;
173 for ( pIt = lFolders.begin();
174 pIt != lFolders.end() ;
175 ++pIt )
177 const ::rtl::OUString& sChild = *pIt;
178 ::rtl::OUString sCheckPath (sRelPath);
179 sCheckPath += sChild;
180 sCheckPath += PATH_SEPERATOR;
182 // SAFE -> ------------------------------
183 aReadLock.lock();
185 // If we found an already open storage ... we must increase
186 // its use count. Otherwhise it will may be closed to early :-)
187 TPath2StorageInfo::iterator pCheck = m_lStorages.find(sCheckPath);
188 TStorageInfo* pInfo = 0;
189 if (pCheck != m_lStorages.end())
191 pInfo = &(pCheck->second);
192 ++(pInfo->UseCount);
193 xChild = pInfo->Storage;
195 else
197 aReadLock.unlock();
198 // <- SAFE ------------------------------
202 xChild = StorageHolder::openSubStorageWithFallback(xParent, sChild, nOpenMode, sal_True); // TODO think about delegating fallback decision to our own calli!
204 catch(const css::uno::RuntimeException& exRun)
205 { throw exRun; }
206 catch(const css::uno::Exception& exAny)
208 /* TODO URGENT!
209 in case we found some "already existing storages" on the path before and increased its UseCount ...
210 and now we will get an exception on creating a new sub storage ...
211 we must decrease all UseCounts, which was touched before. Otherwise these storages cant be closed!
213 Idea: Using of another structure member "PossibleUseCount" as vector of unique numbers.
214 Every thread use another unique number to identify all "owned candidates".
215 A flush method with the same unique number force increasing of the "UseCount" variable then
216 inside a synchronized block ...
218 throw exAny;
221 // SAFE -> ------------------------------
222 WriteGuard aWriteLock(m_aLock);
223 pInfo = &(m_lStorages[sCheckPath]);
224 pInfo->Storage = xChild;
225 pInfo->UseCount = 1;
226 aWriteLock.unlock();
227 // <- SAFE ------------------------------
230 xParent = xChild;
231 sRelPath += sChild;
232 sRelPath += PATH_SEPERATOR;
235 // TODO think about return last storage as working storage ... but dont caching it inside this holder!
236 // => otherwhise the same storage is may be commit more then once.
238 return xChild;
241 //-----------------------------------------------
242 StorageHolder::TStorageList StorageHolder::getAllPathStorages(const ::rtl::OUString& sPath)
244 ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
245 OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath);
247 StorageHolder::TStorageList lStoragesOfPath;
248 ::rtl::OUString sRelPath ;
249 OUStringList::const_iterator pIt ;
251 // SAFE -> ----------------------------------
252 ReadGuard aReadLock(m_aLock);
254 for ( pIt = lFolders.begin();
255 pIt != lFolders.end() ;
256 ++pIt )
258 const ::rtl::OUString& sChild = *pIt;
259 ::rtl::OUString sCheckPath (sRelPath);
260 sCheckPath += sChild;
261 sCheckPath += PATH_SEPERATOR;
263 TPath2StorageInfo::iterator pCheck = m_lStorages.find(sCheckPath);
264 if (pCheck == m_lStorages.end())
266 // at least one path element was not found
267 // Seems that this path isnt open ...
268 lStoragesOfPath.clear();
269 return lStoragesOfPath;
272 TStorageInfo& rInfo = pCheck->second;
273 lStoragesOfPath.push_back(rInfo.Storage);
275 sRelPath += sChild;
276 sRelPath += PATH_SEPERATOR;
279 aReadLock.unlock();
280 // <- SAFE ----------------------------------
282 return lStoragesOfPath;
285 //-----------------------------------------------
286 void StorageHolder::commitPath(const ::rtl::OUString& sPath)
288 StorageHolder::TStorageList lStorages = getAllPathStorages(sPath);
290 css::uno::Reference< css::embed::XTransactedObject > xCommit;
291 StorageHolder::TStorageList::reverse_iterator pIt;
292 for ( pIt = lStorages.rbegin(); // order of commit is important ... otherwhise changes are not recognized!
293 pIt != lStorages.rend() ;
294 ++pIt )
296 xCommit = css::uno::Reference< css::embed::XTransactedObject >(*pIt, css::uno::UNO_QUERY);
297 if (!xCommit.is())
298 continue;
299 xCommit->commit();
302 // SAFE -> ------------------------------
303 ReadGuard aReadLock(m_aLock);
304 xCommit = css::uno::Reference< css::embed::XTransactedObject >(m_xRoot, css::uno::UNO_QUERY);
305 aReadLock.unlock();
306 // <- SAFE ------------------------------
308 if (xCommit.is())
309 xCommit->commit();
312 //-----------------------------------------------
313 void StorageHolder::closePath(const ::rtl::OUString& rPath)
315 ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(rPath);
316 OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath);
318 /* convert list of pathes in the following way:
319 [0] = "path_1" => "path_1
320 [1] = "path_2" => "path_1/path_2"
321 [2] = "path_3" => "path_1/path_2/path_3"
323 OUStringList::iterator pIt1 ;
324 ::rtl::OUString sParentPath;
325 for ( pIt1 = lFolders.begin();
326 pIt1 != lFolders.end() ;
327 ++pIt1 )
329 ::rtl::OUString sCurrentRelPath = sParentPath;
330 sCurrentRelPath += *pIt1;
331 sCurrentRelPath += PATH_SEPERATOR;
332 *pIt1 = sCurrentRelPath;
333 sParentPath = sCurrentRelPath;
336 // SAFE -> ------------------------------
337 ReadGuard aReadLock(m_aLock);
339 OUStringList::reverse_iterator pIt2;
340 for ( pIt2 = lFolders.rbegin();
341 pIt2 != lFolders.rend() ;
342 ++pIt2 )
344 ::rtl::OUString sPath = *pIt2;
345 TPath2StorageInfo::iterator pPath = m_lStorages.find(sPath);
346 if (pPath == m_lStorages.end())
347 continue; // ???
349 TStorageInfo& rInfo = pPath->second;
350 --rInfo.UseCount;
351 if (rInfo.UseCount < 1)
353 rInfo.Storage.clear();
354 m_lStorages.erase(pPath);
358 aReadLock.unlock();
359 // <- SAFE ------------------------------
362 //-----------------------------------------------
363 void StorageHolder::notifyPath(const ::rtl::OUString& sPath)
365 ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
367 // SAFE -> ------------------------------
368 ReadGuard aReadLock(m_aLock);
370 TPath2StorageInfo::iterator pIt1 = m_lStorages.find(sNormedPath);
371 if (pIt1 == m_lStorages.end())
372 return;
374 TStorageInfo& rInfo = pIt1->second;
375 TStorageListenerList::iterator pIt2;
376 for ( pIt2 = rInfo.Listener.begin();
377 pIt2 != rInfo.Listener.end() ;
378 ++pIt2 )
380 IStorageListener* pListener = *pIt2;
381 if (pListener)
382 pListener->changesOccured(sNormedPath);
385 aReadLock.unlock();
386 // <- SAFE ------------------------------
389 //-----------------------------------------------
390 void StorageHolder::addStorageListener( IStorageListener* pListener,
391 const ::rtl::OUString& sPath )
393 ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
395 // SAFE -> ------------------------------
396 ReadGuard aReadLock(m_aLock);
398 TPath2StorageInfo::iterator pIt1 = m_lStorages.find(sNormedPath);
399 if (pIt1 == m_lStorages.end())
400 return;
402 TStorageInfo& rInfo = pIt1->second;
403 TStorageListenerList::iterator pIt2 = ::std::find(rInfo.Listener.begin(), rInfo.Listener.end(), pListener);
404 if (pIt2 == rInfo.Listener.end())
405 rInfo.Listener.push_back(pListener);
407 aReadLock.unlock();
408 // <- SAFE ------------------------------
411 //-----------------------------------------------
412 void StorageHolder::removeStorageListener( IStorageListener* pListener,
413 const ::rtl::OUString& sPath )
415 ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
417 // SAFE -> ------------------------------
418 ReadGuard aReadLock(m_aLock);
420 TPath2StorageInfo::iterator pIt1 = m_lStorages.find(sNormedPath);
421 if (pIt1 == m_lStorages.end())
422 return;
424 TStorageInfo& rInfo = pIt1->second;
425 TStorageListenerList::iterator pIt2 = ::std::find(rInfo.Listener.begin(), rInfo.Listener.end(), pListener);
426 if (pIt2 != rInfo.Listener.end())
427 rInfo.Listener.erase(pIt2);
429 aReadLock.unlock();
430 // <- SAFE ------------------------------
433 //-----------------------------------------------
434 ::rtl::OUString StorageHolder::getPathOfStorage(const css::uno::Reference< css::embed::XStorage >& xStorage)
436 // SAFE -> ------------------------------
437 ReadGuard aReadLock(m_aLock);
439 TPath2StorageInfo::const_iterator pIt;
440 for ( pIt = m_lStorages.begin();
441 pIt != m_lStorages.end() ;
442 ++pIt )
444 const TStorageInfo& rInfo = pIt->second;
445 if (rInfo.Storage == xStorage)
446 break;
449 if (pIt == m_lStorages.end())
450 return ::rtl::OUString();
452 return pIt->first;
454 // <- SAFE ------------------------------
457 //-----------------------------------------------
458 css::uno::Reference< css::embed::XStorage > StorageHolder::getParentStorage(const css::uno::Reference< css::embed::XStorage >& xChild)
460 ::rtl::OUString sChildPath = getPathOfStorage(xChild);
461 return getParentStorage(sChildPath);
464 //-----------------------------------------------
465 css::uno::Reference< css::embed::XStorage > StorageHolder::getParentStorage(const ::rtl::OUString& sChildPath)
467 // normed path = "a/b/c/" ... we search for "a/b/"
468 ::rtl::OUString sNormedPath = StorageHolder::impl_st_normPath(sChildPath);
469 OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath);
470 sal_Int32 c = lFolders.size();
472 // a) "" => - => no parent
473 // b) "a/b/c/" => "a/b/" => return storage "a/b/"
474 // c) "a/" => "" => return root !
476 // a)
477 if (c < 1)
478 return css::uno::Reference< css::embed::XStorage >();
480 // SAFE -> ----------------------------------
481 ReadGuard aReadLock(m_aLock);
483 // b)
484 if (c < 2)
485 return m_xRoot;
487 // c)
488 ::rtl::OUString sParentPath;
489 sal_Int32 i = 0;
490 for (i=0; i<c-1; ++i)
492 sParentPath += lFolders[i];
493 sParentPath += PATH_SEPERATOR;
496 TPath2StorageInfo::const_iterator pParent = m_lStorages.find(sParentPath);
497 if (pParent != m_lStorages.end())
498 return pParent->second.Storage;
500 aReadLock.unlock();
501 // <- SAFE ----------------------------------
503 // ?
504 LOG_WARNING("StorageHolder::getParentStorage()", "Unexpected situation. Cached storage item seems to be wrong.")
505 return css::uno::Reference< css::embed::XStorage >();
508 //-----------------------------------------------
509 void StorageHolder::operator=(const StorageHolder& rCopy)
511 // SAFE -> ----------------------------------
512 WriteGuard aWriteLock(m_aLock);
514 m_xSMGR = rCopy.m_xSMGR; // ???
515 m_xRoot = rCopy.m_xRoot;
516 m_lStorages = rCopy.m_lStorages;
518 aWriteLock.unlock();
519 // <- SAFE ----------------------------------
522 //-----------------------------------------------
523 css::uno::Reference< css::embed::XStorage > StorageHolder::openSubStorageWithFallback(const css::uno::Reference< css::embed::XStorage >& xBaseStorage ,
524 const ::rtl::OUString& sSubStorage ,
525 sal_Int32 eOpenMode ,
526 sal_Bool bAllowFallback)
528 // a) try it first with user specified open mode
529 // ignore errors ... but save it for later use!
530 css::uno::Exception exResult;
533 css::uno::Reference< css::embed::XStorage > xSubStorage = xBaseStorage->openStorageElement(sSubStorage, eOpenMode);
534 if (xSubStorage.is())
535 return xSubStorage;
537 catch(const css::uno::RuntimeException&)
538 { throw; }
539 catch(const css::uno::Exception& ex)
540 { exResult = ex; }
542 // b) readonly already tried? => forward last error!
543 if (
544 (!bAllowFallback ) || // fallback allowed ?
545 ((eOpenMode & css::embed::ElementModes::WRITE) != css::embed::ElementModes::WRITE) // fallback possible ?
547 throw exResult;
549 // c) try it readonly
550 // dont catch exception here! Outside code whish to know, if operation failed or not.
551 // Otherwhise they work on NULL references ...
552 sal_Int32 eNewMode = (eOpenMode & ~css::embed::ElementModes::WRITE);
553 css::uno::Reference< css::embed::XStorage > xSubStorage = xBaseStorage->openStorageElement(sSubStorage, eNewMode);
554 if (xSubStorage.is())
555 return xSubStorage;
557 // d) no chance!
558 LOG_WARNING("openSubStorageWithFallback()", "Unexpected situation! Got no exception for missing storage ...")
559 return css::uno::Reference< css::embed::XStorage >();
562 //-----------------------------------------------
563 css::uno::Reference< css::io::XStream > StorageHolder::openSubStreamWithFallback(const css::uno::Reference< css::embed::XStorage >& xBaseStorage ,
564 const ::rtl::OUString& sSubStream ,
565 sal_Int32 eOpenMode ,
566 sal_Bool bAllowFallback)
568 // a) try it first with user specified open mode
569 // ignore errors ... but save it for later use!
570 css::uno::Exception exResult;
573 css::uno::Reference< css::io::XStream > xSubStream = xBaseStorage->openStreamElement(sSubStream, eOpenMode);
574 if (xSubStream.is())
575 return xSubStream;
577 catch(const css::uno::RuntimeException&)
578 { throw; }
579 catch(const css::uno::Exception& ex)
580 { exResult = ex; }
582 // b) readonly already tried? => forward last error!
583 if (
584 (!bAllowFallback ) || // fallback allowed ?
585 ((eOpenMode & css::embed::ElementModes::WRITE) != css::embed::ElementModes::WRITE) // fallback possible ?
587 throw exResult;
589 // c) try it readonly
590 // dont catch exception here! Outside code whish to know, if operation failed or not.
591 // Otherwhise they work on NULL references ...
592 sal_Int32 eNewMode = (eOpenMode & ~css::embed::ElementModes::WRITE);
593 css::uno::Reference< css::io::XStream > xSubStream = xBaseStorage->openStreamElement(sSubStream, eNewMode);
594 if (xSubStream.is())
595 return xSubStream;
597 // d) no chance!
598 LOG_WARNING("openSubStreamWithFallbacks()", "Unexpected situation! Got no exception for missing stream ...")
599 return css::uno::Reference< css::io::XStream >();
602 //-----------------------------------------------
603 ::rtl::OUString StorageHolder::impl_st_normPath(const ::rtl::OUString& sPath)
605 // path must start without "/" but end with "/"!
607 ::rtl::OUString sNormedPath = sPath;
609 // "/bla" => "bla" && "/" => "" (!)
610 if (sNormedPath.indexOf(PATH_SEPERATOR) == 0)
611 sNormedPath += sNormedPath.copy(1);
613 // "/" => "" || "" => "" ?
614 if (sNormedPath.getLength() < 1)
615 return ::rtl::OUString();
617 // "bla" => "bla/"
618 if (sNormedPath.lastIndexOf(PATH_SEPERATOR) != (sNormedPath.getLength()-1))
619 sNormedPath += PATH_SEPERATOR;
621 return sNormedPath;
624 //-----------------------------------------------
625 OUStringList StorageHolder::impl_st_parsePath(const ::rtl::OUString& sPath)
627 OUStringList lToken;
628 sal_Int32 i = 0;
629 while (sal_True)
631 ::rtl::OUString sToken = sPath.getToken(0, PATH_SEPERATOR_UNICODE, i);
632 if (i < 0)
633 break;
634 lToken.push_back(sToken);
636 return lToken;
639 //===============================================
640 } // namespace framework