fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / framework / source / accelerators / storageholder.cxx
blob2dc27318d2228725a0b654d16e748dacc9c8ace8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <accelerators/storageholder.hxx>
22 #include <services.h>
24 #include <com/sun/star/container/NoSuchElementException.hpp>
26 #include <com/sun/star/container/XNameAccess.hpp>
28 #include <com/sun/star/beans/XPropertySet.hpp>
30 #include <com/sun/star/embed/ElementModes.hpp>
32 #include <com/sun/star/embed/XTransactedObject.hpp>
34 #include <com/sun/star/embed/XPackageStructureCreator.hpp>
36 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
38 #include <com/sun/star/io/XSeekable.hpp>
40 #include <algorithm>
42 #define PATH_SEPARATOR_ASCII "/"
43 #define PATH_SEPARATOR_UNICODE ((sal_Unicode)'/')
44 #define PATH_SEPARATOR OUString(PATH_SEPARATOR_ASCII)
46 namespace framework
49 StorageHolder::StorageHolder()
53 StorageHolder::~StorageHolder()
55 // TODO implement me
56 // dispose/clear etcpp.
59 void StorageHolder::forgetCachedStorages()
61 osl::MutexGuard g(m_mutex);
62 TPath2StorageInfo::iterator pIt;
63 for ( pIt = m_lStorages.begin();
64 pIt != m_lStorages.end();
65 ++pIt )
67 TStorageInfo& rInfo = pIt->second;
68 // TODO think about listener !
69 rInfo.Storage.clear();
71 m_lStorages.clear();
74 void StorageHolder::setRootStorage(const css::uno::Reference< css::embed::XStorage >& xRoot)
76 osl::MutexGuard g(m_mutex);
77 m_xRoot = xRoot;
80 css::uno::Reference< css::embed::XStorage > StorageHolder::getRootStorage() const
82 osl::MutexGuard g(m_mutex);
83 return m_xRoot;
86 css::uno::Reference< css::embed::XStorage > StorageHolder::openPath(const OUString& sPath ,
87 sal_Int32 nOpenMode)
89 OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
90 OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath);
92 // SAFE -> ----------------------------------
93 osl::ResettableMutexGuard aReadLock(m_mutex);
94 css::uno::Reference< css::embed::XStorage > xParent = m_xRoot;
95 aReadLock.clear();
96 // <- SAFE ----------------------------------
98 css::uno::Reference< css::embed::XStorage > xChild;
99 OUString sRelPath;
100 OUStringList::const_iterator pIt;
102 for ( pIt = lFolders.begin();
103 pIt != lFolders.end();
104 ++pIt )
106 const OUString& sChild = *pIt;
107 OUString sCheckPath (sRelPath);
108 sCheckPath += sChild;
109 sCheckPath += PATH_SEPARATOR;
111 // SAFE -> ------------------------------
112 aReadLock.reset();
114 // If we found an already open storage ... we must increase
115 // its use count. Otherwhise it will may be closed to early :-)
116 TPath2StorageInfo::iterator pCheck = m_lStorages.find(sCheckPath);
117 TStorageInfo* pInfo = 0;
118 if (pCheck != m_lStorages.end())
120 pInfo = &(pCheck->second);
121 ++(pInfo->UseCount);
122 xChild = pInfo->Storage;
124 aReadLock.clear();
125 // <- SAFE ------------------------------
127 else
129 aReadLock.clear();
130 // <- SAFE ------------------------------
134 xChild = StorageHolder::openSubStorageWithFallback(xParent, sChild, nOpenMode, true); // TODO think about delegating fallback decision to our own calli!
136 catch(const css::uno::RuntimeException&)
137 { throw; }
138 catch(const css::uno::Exception&)
140 /* TODO URGENT!
141 in case we found some "already existing storages" on the path before and increased its UseCount ...
142 and now we will get an exception on creating a new sub storage ...
143 we must decrease all UseCounts, which was touched before. Otherwise these storages can't be closed!
145 Idea: Using of another structure member "PossibleUseCount" as vector of unique numbers.
146 Every thread use another unique number to identify all "owned candidates".
147 A flush method with the same unique number force increasing of the "UseCount" variable then
148 inside a synchronized block ...
150 throw;
153 osl::MutexGuard g(m_mutex);
154 pInfo = &(m_lStorages[sCheckPath]);
155 pInfo->Storage = xChild;
156 pInfo->UseCount = 1;
159 xParent = xChild;
160 sRelPath += sChild;
161 sRelPath += PATH_SEPARATOR;
164 // TODO think about return last storage as working storage ... but dont caching it inside this holder!
165 // => otherwise the same storage is may be commit more than once.
167 return xChild;
170 StorageHolder::TStorageList StorageHolder::getAllPathStorages(const OUString& sPath)
172 OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
173 OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath);
175 StorageHolder::TStorageList lStoragesOfPath;
176 OUString sRelPath;
177 OUStringList::const_iterator pIt;
179 osl::MutexGuard g(m_mutex);
181 for ( pIt = lFolders.begin();
182 pIt != lFolders.end();
183 ++pIt )
185 const OUString& sChild = *pIt;
186 OUString sCheckPath (sRelPath);
187 sCheckPath += sChild;
188 sCheckPath += PATH_SEPARATOR;
190 TPath2StorageInfo::iterator pCheck = m_lStorages.find(sCheckPath);
191 if (pCheck == m_lStorages.end())
193 // at least one path element was not found
194 // Seems that this path isn't open ...
195 lStoragesOfPath.clear();
196 return lStoragesOfPath;
199 TStorageInfo& rInfo = pCheck->second;
200 lStoragesOfPath.push_back(rInfo.Storage);
202 sRelPath += sChild;
203 sRelPath += PATH_SEPARATOR;
206 return lStoragesOfPath;
209 void StorageHolder::commitPath(const OUString& sPath)
211 StorageHolder::TStorageList lStorages = getAllPathStorages(sPath);
213 css::uno::Reference< css::embed::XTransactedObject > xCommit;
214 StorageHolder::TStorageList::reverse_iterator pIt;
215 for ( pIt = lStorages.rbegin(); // order of commit is important ... otherwise changes are not recognized!
216 pIt != lStorages.rend();
217 ++pIt )
219 xCommit = css::uno::Reference< css::embed::XTransactedObject >(*pIt, css::uno::UNO_QUERY);
220 if (!xCommit.is())
221 continue;
222 xCommit->commit();
225 // SAFE -> ------------------------------
226 osl::ClearableMutexGuard aReadLock(m_mutex);
227 xCommit = css::uno::Reference< css::embed::XTransactedObject >(m_xRoot, css::uno::UNO_QUERY);
228 aReadLock.clear();
229 // <- SAFE ------------------------------
231 if (xCommit.is())
232 xCommit->commit();
235 void StorageHolder::closePath(const OUString& rPath)
237 OUString sNormedPath = StorageHolder::impl_st_normPath(rPath);
238 OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath);
240 /* convert list of paths in the following way:
241 [0] = "path_1" => "path_1
242 [1] = "path_2" => "path_1/path_2"
243 [2] = "path_3" => "path_1/path_2/path_3"
245 OUStringList::iterator pIt1;
246 OUString sParentPath;
247 for ( pIt1 = lFolders.begin();
248 pIt1 != lFolders.end();
249 ++pIt1 )
251 OUString sCurrentRelPath = sParentPath;
252 sCurrentRelPath += *pIt1;
253 sCurrentRelPath += PATH_SEPARATOR;
254 *pIt1 = sCurrentRelPath;
255 sParentPath = sCurrentRelPath;
258 osl::MutexGuard g(m_mutex);
260 OUStringList::reverse_iterator pIt2;
261 for ( pIt2 = lFolders.rbegin();
262 pIt2 != lFolders.rend();
263 ++pIt2 )
265 OUString sPath = *pIt2;
266 TPath2StorageInfo::iterator pPath = m_lStorages.find(sPath);
267 if (pPath == m_lStorages.end())
268 continue; // ???
270 TStorageInfo& rInfo = pPath->second;
271 --rInfo.UseCount;
272 if (rInfo.UseCount < 1)
274 rInfo.Storage.clear();
275 m_lStorages.erase(pPath);
280 void StorageHolder::notifyPath(const OUString& sPath)
282 OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
284 osl::MutexGuard g(m_mutex);
286 TPath2StorageInfo::iterator pIt1 = m_lStorages.find(sNormedPath);
287 if (pIt1 == m_lStorages.end())
288 return;
290 TStorageInfo& rInfo = pIt1->second;
291 TStorageListenerList::iterator pIt2;
292 for ( pIt2 = rInfo.Listener.begin();
293 pIt2 != rInfo.Listener.end();
294 ++pIt2 )
296 IStorageListener* pListener = *pIt2;
297 if (pListener)
298 pListener->changesOccurred(sNormedPath);
302 void StorageHolder::addStorageListener( IStorageListener* pListener,
303 const OUString& sPath )
305 OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
307 osl::MutexGuard g(m_mutex);
309 TPath2StorageInfo::iterator pIt1 = m_lStorages.find(sNormedPath);
310 if (pIt1 == m_lStorages.end())
311 return;
313 TStorageInfo& rInfo = pIt1->second;
314 TStorageListenerList::iterator pIt2 = ::std::find(rInfo.Listener.begin(), rInfo.Listener.end(), pListener);
315 if (pIt2 == rInfo.Listener.end())
316 rInfo.Listener.push_back(pListener);
319 void StorageHolder::removeStorageListener( IStorageListener* pListener,
320 const OUString& sPath )
322 OUString sNormedPath = StorageHolder::impl_st_normPath(sPath);
324 osl::MutexGuard g(m_mutex);
326 TPath2StorageInfo::iterator pIt1 = m_lStorages.find(sNormedPath);
327 if (pIt1 == m_lStorages.end())
328 return;
330 TStorageInfo& rInfo = pIt1->second;
331 TStorageListenerList::iterator pIt2 = ::std::find(rInfo.Listener.begin(), rInfo.Listener.end(), pListener);
332 if (pIt2 != rInfo.Listener.end())
333 rInfo.Listener.erase(pIt2);
336 OUString StorageHolder::getPathOfStorage(const css::uno::Reference< css::embed::XStorage >& xStorage)
338 osl::MutexGuard g(m_mutex);
340 TPath2StorageInfo::const_iterator pIt;
341 for ( pIt = m_lStorages.begin();
342 pIt != m_lStorages.end();
343 ++pIt )
345 const TStorageInfo& rInfo = pIt->second;
346 if (rInfo.Storage == xStorage)
347 break;
350 if (pIt == m_lStorages.end())
351 return OUString();
353 return pIt->first;
356 css::uno::Reference< css::embed::XStorage > StorageHolder::getParentStorage(const css::uno::Reference< css::embed::XStorage >& xChild)
358 OUString sChildPath = getPathOfStorage(xChild);
359 return getParentStorage(sChildPath);
362 css::uno::Reference< css::embed::XStorage > StorageHolder::getParentStorage(const OUString& sChildPath)
364 // normed path = "a/b/c/" ... we search for "a/b/"
365 OUString sNormedPath = StorageHolder::impl_st_normPath(sChildPath);
366 OUStringList lFolders = StorageHolder::impl_st_parsePath(sNormedPath);
367 sal_Int32 c = lFolders.size();
369 // a) "" => - => no parent
370 // b) "a/b/c/" => "a/b/" => return storage "a/b/"
371 // c) "a/" => "" => return root !
373 // a)
374 if (c < 1)
375 return css::uno::Reference< css::embed::XStorage >();
377 // SAFE -> ----------------------------------
378 osl::ClearableMutexGuard aReadLock(m_mutex);
380 // b)
381 if (c < 2)
382 return m_xRoot;
384 // c)
385 OUString sParentPath;
386 sal_Int32 i = 0;
387 for (i=0; i<c-1; ++i)
389 sParentPath += lFolders[i];
390 sParentPath += PATH_SEPARATOR;
393 TPath2StorageInfo::const_iterator pParent = m_lStorages.find(sParentPath);
394 if (pParent != m_lStorages.end())
395 return pParent->second.Storage;
397 aReadLock.clear();
398 // <- SAFE ----------------------------------
400 // ?
401 SAL_INFO("fwk", "StorageHolder::getParentStorage(): Unexpected situation. Cached storage item seems to be wrong.");
402 return css::uno::Reference< css::embed::XStorage >();
405 void StorageHolder::operator=(const StorageHolder& rCopy)
407 osl::MutexGuard g(m_mutex);
408 m_xRoot = rCopy.m_xRoot;
409 m_lStorages = rCopy.m_lStorages;
412 css::uno::Reference< css::embed::XStorage > StorageHolder::openSubStorageWithFallback(const css::uno::Reference< css::embed::XStorage >& xBaseStorage ,
413 const OUString& sSubStorage ,
414 sal_Int32 eOpenMode ,
415 bool bAllowFallback)
417 // a) try it first with user specified open mode
418 // ignore errors ... but save it for later use!
419 css::uno::Exception exResult;
422 css::uno::Reference< css::embed::XStorage > xSubStorage = xBaseStorage->openStorageElement(sSubStorage, eOpenMode);
423 if (xSubStorage.is())
424 return xSubStorage;
426 catch(const css::uno::RuntimeException&)
427 { throw; }
428 catch(const css::uno::Exception& ex)
429 { exResult = ex; }
431 // b) readonly already tried? => forward last error!
432 if (
433 (!bAllowFallback ) || // fallback allowed ?
434 ((eOpenMode & css::embed::ElementModes::WRITE) != css::embed::ElementModes::WRITE) // fallback possible ?
436 throw exResult;
438 // c) try it readonly
439 // dont catch exception here! Outside code wish to know, if operation failed or not.
440 // Otherwhise they work on NULL references ...
441 sal_Int32 eNewMode = (eOpenMode & ~css::embed::ElementModes::WRITE);
442 css::uno::Reference< css::embed::XStorage > xSubStorage = xBaseStorage->openStorageElement(sSubStorage, eNewMode);
443 if (xSubStorage.is())
444 return xSubStorage;
446 // d) no chance!
447 SAL_INFO("fwk", "openSubStorageWithFallback(): Unexpected situation! Got no exception for missing storage ...");
448 return css::uno::Reference< css::embed::XStorage >();
451 css::uno::Reference< css::io::XStream > StorageHolder::openSubStreamWithFallback(const css::uno::Reference< css::embed::XStorage >& xBaseStorage ,
452 const OUString& sSubStream ,
453 sal_Int32 eOpenMode ,
454 bool bAllowFallback)
456 // a) try it first with user specified open mode
457 // ignore errors ... but save it for later use!
458 css::uno::Exception exResult;
461 css::uno::Reference< css::io::XStream > xSubStream = xBaseStorage->openStreamElement(sSubStream, eOpenMode);
462 if (xSubStream.is())
463 return xSubStream;
465 catch(const css::uno::RuntimeException&)
466 { throw; }
467 catch(const css::uno::Exception& ex)
468 { exResult = ex; }
470 // b) readonly already tried? => forward last error!
471 if (
472 (!bAllowFallback ) || // fallback allowed ?
473 ((eOpenMode & css::embed::ElementModes::WRITE) != css::embed::ElementModes::WRITE) // fallback possible ?
475 throw exResult;
477 // c) try it readonly
478 // dont catch exception here! Outside code wish to know, if operation failed or not.
479 // Otherwhise they work on NULL references ...
480 sal_Int32 eNewMode = (eOpenMode & ~css::embed::ElementModes::WRITE);
481 css::uno::Reference< css::io::XStream > xSubStream = xBaseStorage->openStreamElement(sSubStream, eNewMode);
482 if (xSubStream.is())
483 return xSubStream;
485 // d) no chance!
486 SAL_INFO("fwk", "openSubStreamWithFallbacks(): Unexpected situation! Got no exception for missing stream ...");
487 return css::uno::Reference< css::io::XStream >();
490 OUString StorageHolder::impl_st_normPath(const OUString& sPath)
492 // path must start without "/" but end with "/"!
494 OUString sNormedPath = sPath;
496 // "/bla" => "bla" && "/" => "" (!)
497 if (sNormedPath.startsWith(PATH_SEPARATOR))
498 sNormedPath += sNormedPath.copy(1);
500 // "/" => "" || "" => "" ?
501 if (sNormedPath.isEmpty())
502 return OUString();
504 // "bla" => "bla/"
505 if (sNormedPath.lastIndexOf(PATH_SEPARATOR) != (sNormedPath.getLength()-1))
506 sNormedPath += PATH_SEPARATOR;
508 return sNormedPath;
511 OUStringList StorageHolder::impl_st_parsePath(const OUString& sPath)
513 OUStringList lToken;
514 sal_Int32 i = 0;
515 while (true)
517 OUString sToken = sPath.getToken(0, PATH_SEPARATOR_UNICODE, i);
518 if (i < 0)
519 break;
520 lToken.push_back(sToken);
522 return lToken;
525 } // namespace framework
527 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */