Bump version to 4.3-4
[LibreOffice.git] / unotools / source / config / historyoptions.cxx
blobb4195691a6d661d171870e837d4aecda2b7f7442
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 <osl/file.hxx>
21 #include <unotools/historyoptions.hxx>
22 #include <unotools/configmgr.hxx>
23 #include <unotools/configitem.hxx>
24 #include <com/sun/star/uno/Any.hxx>
25 #include <com/sun/star/uno/Sequence.hxx>
27 #include <cassert>
28 #include <deque>
29 #include <algorithm>
31 #include "itemholder1.hxx"
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/container/XNameAccess.hpp>
35 #include <com/sun/star/container/XNameContainer.hpp>
36 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
37 #include <comphelper/configurationhelper.hxx>
38 #include <comphelper/processfactory.hxx>
40 using namespace ::std;
41 using namespace ::utl;
42 using namespace ::osl;
43 using namespace ::com::sun::star;
44 using namespace ::com::sun::star::uno;
45 using namespace ::com::sun::star::beans;
47 namespace {
48 static const ::sal_Int32 s_nOffsetURL = 0;
49 static const ::sal_Int32 s_nOffsetFilter = 1;
50 static const ::sal_Int32 s_nOffsetTitle = 2;
51 static const ::sal_Int32 s_nOffsetPassword = 3;
52 static const ::sal_Int32 s_nOffsetThumbnail = 4;
54 const char s_sCommonHistory[] = "org.openoffice.Office.Common/History";
55 const char s_sHistories[] = "org.openoffice.Office.Histories/Histories";
56 const char s_sPickListSize[] = "PickListSize";
57 const char s_sHelpBookmarksSize[] = "HelpBookmarkSize";
58 const char s_sPickList[] = "PickList";
59 const char s_sHelpBookmarks[] = "HelpBookmarks";
60 const char s_sItemList[] = "ItemList";
61 const char s_sOrderList[] = "OrderList";
62 const char s_sHistoryItemRef[] = "HistoryItemRef";
63 const char s_sFilter[] = "Filter";
64 const char s_sTitle[] = "Title";
65 const char s_sPassword[] = "Password";
66 const char s_sThumbnail[] = "Thumbnail";
68 class theHistoryOptionsMutex : public rtl::Static<osl::Mutex, theHistoryOptionsMutex>{};
71 /// Internal implementation of the SvtHistoryOptions.
72 class SvtHistoryOptions_Impl
74 public:
75 SvtHistoryOptions_Impl();
76 ~SvtHistoryOptions_Impl();
78 /// Returns the maximum size of the internal lists, ie. the capacity not the size.
79 sal_uInt32 GetCapacity(EHistoryType eHistory);
81 /// Clear the specified history list.
82 void Clear(EHistoryType eHistory);
84 /// Get a sequence list from the items.
85 Sequence< Sequence<PropertyValue> > GetList(EHistoryType eHistory);
87 void AppendItem(EHistoryType eHistory,
88 const OUString& sURL, const OUString& sFilter, const OUString& sTitle,
89 const OUString& sPassword, const OUString& sThumbnail);
91 void DeleteItem(EHistoryType eHistory, const OUString& sURL);
93 private:
94 /// Return the appropriate list of recent documents (based on eHistory).
95 uno::Reference<container::XNameAccess> GetListAccess(EHistoryType eHistory) const;
97 void impl_truncateList(EHistoryType eHistory, sal_uInt32 nSize);
99 private:
100 uno::Reference<container::XNameAccess> m_xCfg;
101 uno::Reference<container::XNameAccess> m_xCommonXCU;
104 SvtHistoryOptions_Impl::SvtHistoryOptions_Impl()
108 m_xCfg = Reference<container::XNameAccess> (
109 ::comphelper::ConfigurationHelper::openConfig(
110 ::comphelper::getProcessComponentContext(),
111 s_sHistories,
112 ::comphelper::ConfigurationHelper::E_STANDARD),
113 uno::UNO_QUERY);
115 m_xCommonXCU = Reference<container::XNameAccess> (
116 ::comphelper::ConfigurationHelper::openConfig(
117 ::comphelper::getProcessComponentContext(),
118 s_sCommonHistory,
119 ::comphelper::ConfigurationHelper::E_STANDARD),
120 uno::UNO_QUERY);
122 catch(const uno::Exception& ex)
124 m_xCfg.clear();
125 m_xCommonXCU.clear();
127 SAL_WARN("unotools.config", "Caught unexpected: " << ex.Message);
131 SvtHistoryOptions_Impl::~SvtHistoryOptions_Impl()
135 sal_uInt32 SvtHistoryOptions_Impl::GetCapacity(EHistoryType eHistory)
137 uno::Reference<beans::XPropertySet> xListAccess(m_xCommonXCU, uno::UNO_QUERY);
139 if (!xListAccess.is())
140 return 0;
142 sal_uInt32 nSize = 0;
146 switch (eHistory)
148 case ePICKLIST:
149 xListAccess->getPropertyValue(s_sPickListSize) >>= nSize;
150 break;
152 case eHELPBOOKMARKS:
153 xListAccess->getPropertyValue(s_sHelpBookmarksSize) >>= nSize;
154 break;
156 default:
157 break;
160 catch (const uno::Exception& ex)
162 SAL_WARN("unotools.config", "Caught unexpected: " << ex.Message);
165 return nSize;
168 uno::Reference<container::XNameAccess> SvtHistoryOptions_Impl::GetListAccess(EHistoryType eHistory) const
170 uno::Reference<container::XNameAccess> xListAccess;
174 switch (eHistory)
176 case ePICKLIST:
177 m_xCfg->getByName(s_sPickList) >>= xListAccess;
178 break;
180 case eHELPBOOKMARKS:
181 m_xCfg->getByName(s_sHelpBookmarks) >>= xListAccess;
182 break;
184 default:
185 break;
188 catch (const uno::Exception& ex)
190 SAL_WARN("unotools.config", "Caught unexpected: " << ex.Message);
193 return xListAccess;
196 void SvtHistoryOptions_Impl::impl_truncateList(EHistoryType eHistory, sal_uInt32 nSize)
198 uno::Reference<container::XNameAccess> xList(GetListAccess(eHistory));
199 if (!xList.is())
200 return;
202 uno::Reference<container::XNameContainer> xItemList;
203 uno::Reference<container::XNameContainer> xOrderList;
204 uno::Reference<beans::XPropertySet> xSet;
208 xList->getByName(s_sOrderList) >>= xOrderList;
209 xList->getByName(s_sItemList) >>= xItemList;
211 const sal_uInt32 nLength = xOrderList->getElementNames().getLength();
212 if (nSize < nLength)
214 for (sal_uInt32 i=nLength-1; i>=nSize; --i)
216 OUString sTmp;
217 const OUString sRemove = OUString::number(i);
218 xOrderList->getByName(sRemove) >>= xSet;
219 xSet->getPropertyValue(s_sHistoryItemRef) >>= sTmp;
220 xItemList->removeByName(sTmp);
221 xOrderList->removeByName(sRemove);
224 ::comphelper::ConfigurationHelper::flush(m_xCfg);
227 catch(const uno::Exception& ex)
229 SAL_WARN("unotools.config", "Caught unexpected: " << ex.Message);
233 void SvtHistoryOptions_Impl::Clear( EHistoryType eHistory )
235 uno::Reference<container::XNameAccess> xListAccess(GetListAccess(eHistory));
236 if (!xListAccess.is())
237 return;
239 uno::Reference<container::XNameContainer> xNode;
243 // clear ItemList
244 xListAccess->getByName(s_sItemList) >>= xNode;
245 Sequence<OUString> aStrings(xNode->getElementNames());
247 const sal_Int32 nLength = aStrings.getLength();
248 for (sal_Int32 i = 0; i < nLength; ++i)
249 xNode->removeByName(aStrings[i]);
251 // clear OrderList
252 xListAccess->getByName(s_sOrderList) >>= xNode;
253 aStrings = xNode->getElementNames();
255 for (sal_Int32 j = 0; j < nLength; ++j)
256 xNode->removeByName(aStrings[j]);
258 ::comphelper::ConfigurationHelper::flush(m_xCfg);
260 catch(const uno::Exception& ex)
262 SAL_WARN("unotools.config", "Caught unexpected: " << ex.Message);
266 static bool lcl_fileOpenable(const OUString &rURL)
268 osl::File aRecentFile(rURL);
269 if(!aRecentFile.open(osl_File_OpenFlag_Read))
271 aRecentFile.close();
272 return true;
274 else
275 return false;
278 Sequence< Sequence<PropertyValue> > SvtHistoryOptions_Impl::GetList(EHistoryType eHistory)
280 uno::Reference<container::XNameAccess> xListAccess(GetListAccess(eHistory));
281 if (!xListAccess.is())
282 return Sequence< Sequence<PropertyValue> >();
284 impl_truncateList(eHistory, GetCapacity(eHistory));
286 Sequence<PropertyValue> seqProperties(5);
287 seqProperties[s_nOffsetURL ].Name = HISTORY_PROPERTYNAME_URL;
288 seqProperties[s_nOffsetFilter ].Name = HISTORY_PROPERTYNAME_FILTER;
289 seqProperties[s_nOffsetTitle ].Name = HISTORY_PROPERTYNAME_TITLE;
290 seqProperties[s_nOffsetPassword ].Name = HISTORY_PROPERTYNAME_PASSWORD;
291 seqProperties[s_nOffsetThumbnail ].Name = HISTORY_PROPERTYNAME_THUMBNAIL;
293 uno::Reference<container::XNameAccess> xItemList;
294 uno::Reference<container::XNameAccess> xOrderList;
297 xListAccess->getByName(s_sItemList) >>= xItemList;
298 xListAccess->getByName(s_sOrderList) >>= xOrderList;
300 catch(const uno::Exception& ex)
302 SAL_WARN("unotools.config", "Caught unexpected: " << ex.Message);
305 const sal_Int32 nLength = xOrderList->getElementNames().getLength();
306 Sequence< Sequence<PropertyValue> > aRet(nLength);
307 sal_Int32 nCount = 0;
309 for (sal_Int32 nItem = 0; nItem < nLength; ++nItem)
313 OUString sUrl;
314 uno::Reference<beans::XPropertySet> xSet;
315 xOrderList->getByName(OUString::number(nItem)) >>= xSet;
316 xSet->getPropertyValue(s_sHistoryItemRef) >>= sUrl;
318 if (!sUrl.startsWith("file://") || lcl_fileOpenable(sUrl))
320 xItemList->getByName(sUrl) >>= xSet;
321 seqProperties[s_nOffsetURL ].Value <<= sUrl;
323 xSet->getPropertyValue(s_sFilter) >>= seqProperties[s_nOffsetFilter ].Value;
324 xSet->getPropertyValue(s_sTitle) >>= seqProperties[s_nOffsetTitle ].Value;
325 xSet->getPropertyValue(s_sPassword) >>= seqProperties[s_nOffsetPassword ].Value;
326 xSet->getPropertyValue(s_sThumbnail)>>= seqProperties[s_nOffsetThumbnail].Value;
327 aRet[nCount++] = seqProperties;
330 catch(const uno::Exception& ex)
332 // <https://bugs.libreoffice.org/show_bug.cgi?id=46074>
333 // "FILEOPEN: No Recent Documents..." discusses a problem
334 // with corrupted /org.openoffice.Office/Histories/Histories
335 // configuration items; to work around that problem, simply
336 // ignore such corrupted individual items here, so that at
337 // least newly added items are successfully reported back
338 // from this function:
339 SAL_WARN("unotools.config", "Caught unexpected: " << ex.Message);
342 assert(nCount <= nLength);
343 aRet.realloc(nCount);
344 return aRet;
347 void SvtHistoryOptions_Impl::AppendItem(EHistoryType eHistory,
348 const OUString& sURL, const OUString& sFilter, const OUString& sTitle,
349 const OUString& sPassword, const OUString& sThumbnail)
351 uno::Reference<container::XNameAccess> xListAccess(GetListAccess(eHistory));
352 if (!xListAccess.is())
353 return;
355 impl_truncateList(eHistory, GetCapacity(eHistory));
357 sal_Int32 nMaxSize = GetCapacity(eHistory);
358 if (nMaxSize == 0)
359 return;
361 uno::Reference<container::XNameContainer> xItemList;
362 uno::Reference<container::XNameContainer> xOrderList;
363 uno::Reference<beans::XPropertySet> xSet;
367 xListAccess->getByName(s_sItemList) >>= xItemList;
368 xListAccess->getByName(s_sOrderList) >>= xOrderList;
369 sal_Int32 nLength = xOrderList->getElementNames().getLength();
371 // The item to be appended already exists
372 if (xItemList->hasByName(sURL))
374 if (!sThumbnail.isEmpty())
376 // update the thumbnail
377 xItemList->getByName(sURL) >>= xSet;
378 xSet->setPropertyValue(s_sThumbnail, uno::makeAny(sThumbnail));
381 for (sal_Int32 i=0; i<nLength; ++i)
383 OUString aItem;
384 xOrderList->getByName(OUString::number(i)) >>= xSet;
385 xSet->getPropertyValue(s_sHistoryItemRef) >>= aItem;
387 if (aItem == sURL)
389 for (sal_Int32 j = i - 1; j >= 0; --j)
391 uno::Reference<beans::XPropertySet> xPrevSet;
392 uno::Reference<beans::XPropertySet> xNextSet;
393 xOrderList->getByName(OUString::number(j+1)) >>= xPrevSet;
394 xOrderList->getByName(OUString::number(j)) >>= xNextSet;
396 OUString sTemp;
397 xNextSet->getPropertyValue(s_sHistoryItemRef) >>= sTemp;
398 xPrevSet->setPropertyValue(s_sHistoryItemRef, uno::makeAny(sTemp));
400 xOrderList->getByName(OUString::number(0)) >>= xSet;
401 xSet->setPropertyValue(s_sHistoryItemRef, uno::makeAny(aItem));
402 break;
406 ::comphelper::ConfigurationHelper::flush(m_xCfg);
408 else // The item to be appended does not exist yet
410 uno::Reference<lang::XSingleServiceFactory> xFac;
411 uno::Reference<uno::XInterface> xInst;
412 uno::Reference<beans::XPropertySet> xPrevSet;
413 uno::Reference<beans::XPropertySet> xNextSet;
415 // Append new item to OrderList.
416 if ( nLength == nMaxSize )
418 OUString sRemove;
419 xOrderList->getByName(OUString::number(nLength-1)) >>= xSet;
420 xSet->getPropertyValue(s_sHistoryItemRef) >>= sRemove;
423 xItemList->removeByName(sRemove);
425 catch (container::NoSuchElementException &)
427 // <https://bugs.libreoffice.org/show_bug.cgi?id=46074>
428 // "FILEOPEN: No Recent Documents..." discusses a problem
429 // with corrupted /org.openoffice.Office/Histories/Histories
430 // configuration items; to work around that problem, simply
431 // ignore such corrupted individual items here, so that at
432 // least newly added items are successfully added:
433 if (!sRemove.isEmpty())
435 throw;
439 if (nLength != nMaxSize)
441 xFac = uno::Reference<lang::XSingleServiceFactory>(xOrderList, uno::UNO_QUERY);
442 xInst = xFac->createInstance();
443 OUString sPush = OUString::number(nLength++);
444 xOrderList->insertByName(sPush, uno::makeAny(xInst));
446 for (sal_Int32 j=nLength-1; j>0; --j)
448 xOrderList->getByName( OUString::number(j) ) >>= xPrevSet;
449 xOrderList->getByName( OUString::number(j-1) ) >>= xNextSet;
450 OUString sTemp;
451 xNextSet->getPropertyValue(s_sHistoryItemRef) >>= sTemp;
452 xPrevSet->setPropertyValue(s_sHistoryItemRef, uno::makeAny(sTemp));
454 xOrderList->getByName( OUString::number(0) ) >>= xSet;
455 xSet->setPropertyValue(s_sHistoryItemRef, uno::makeAny(sURL));
457 // Append the item to ItemList.
458 xFac = uno::Reference<lang::XSingleServiceFactory>(xItemList, uno::UNO_QUERY);
459 xInst = xFac->createInstance();
460 xItemList->insertByName(sURL, uno::makeAny(xInst));
462 xSet = uno::Reference<beans::XPropertySet>(xInst, uno::UNO_QUERY);
463 xSet->setPropertyValue(s_sFilter, uno::makeAny(sFilter));
464 xSet->setPropertyValue(s_sTitle, uno::makeAny(sTitle));
465 xSet->setPropertyValue(s_sPassword, uno::makeAny(sPassword));
466 xSet->setPropertyValue(s_sThumbnail, uno::makeAny(sThumbnail));
468 ::comphelper::ConfigurationHelper::flush(m_xCfg);
471 catch(const uno::Exception& ex)
473 SAL_WARN("unotools.config", "Caught unexpected: " << ex.Message);
477 void SvtHistoryOptions_Impl::DeleteItem(EHistoryType eHistory, const OUString& sURL)
479 uno::Reference<container::XNameAccess> xListAccess(GetListAccess(eHistory));
480 if (!xListAccess.is())
481 return;
483 uno::Reference<container::XNameContainer> xItemList;
484 uno::Reference<container::XNameContainer> xOrderList;
485 uno::Reference<beans::XPropertySet> xSet;
489 xListAccess->getByName(s_sItemList) >>= xItemList;
490 xListAccess->getByName(s_sOrderList) >>= xOrderList;
491 sal_Int32 nLength = xOrderList->getElementNames().getLength();
493 // if it does not exist, nothing to do
494 if (!xItemList->hasByName(sURL))
495 return;
497 // it's the last one, just clear the lists
498 if (nLength == 1)
500 Clear(eHistory);
501 return;
504 // find it in the OrderList
505 sal_Int32 nFromWhere = 0;
506 for (; nFromWhere < nLength - 1; ++nFromWhere)
508 OUString aItem;
509 xOrderList->getByName(OUString::number(nFromWhere)) >>= xSet;
510 xSet->getPropertyValue(s_sHistoryItemRef) >>= aItem;
512 if (aItem == sURL)
513 break;
516 // and shift the rest of the items in OrderList accordingly
517 for (sal_Int32 i = nFromWhere; i < nLength - 1; ++i)
519 uno::Reference<beans::XPropertySet> xPrevSet;
520 uno::Reference<beans::XPropertySet> xNextSet;
521 xOrderList->getByName(OUString::number(i)) >>= xPrevSet;
522 xOrderList->getByName(OUString::number(i + 1)) >>= xNextSet;
524 OUString sTemp;
525 xNextSet->getPropertyValue(s_sHistoryItemRef) >>= sTemp;
526 xPrevSet->setPropertyValue(s_sHistoryItemRef, uno::makeAny(sTemp));
528 xOrderList->removeByName(OUString::number(nLength - 1));
530 // and finally remove it from the ItemList
531 xItemList->removeByName(sURL);
533 ::comphelper::ConfigurationHelper::flush(m_xCfg);
535 catch (const uno::Exception& ex)
537 SAL_WARN("unotools.config", "Caught unexpected: " << ex.Message);
541 // initialize static member
542 // DON'T DO IT IN YOUR HEADER!
543 // see definition for further information
545 SvtHistoryOptions_Impl* SvtHistoryOptions::m_pDataContainer = NULL;
546 sal_Int32 SvtHistoryOptions::m_nRefCount = 0;
548 // constructor
550 SvtHistoryOptions::SvtHistoryOptions()
552 MutexGuard aGuard(theHistoryOptionsMutex::get());
554 // Increase our refcount ...
555 ++m_nRefCount;
556 // ... and initialize our data container only if it not already exist!
557 if( m_pDataContainer == NULL )
559 m_pDataContainer = new SvtHistoryOptions_Impl;
561 ItemHolder1::holdConfigItem(E_HISTORYOPTIONS);
565 // destructor
567 SvtHistoryOptions::~SvtHistoryOptions()
569 MutexGuard aGuard(theHistoryOptionsMutex::get());
571 // Decrease our refcount.
572 --m_nRefCount;
573 // If last instance was deleted ...
574 // we must destroy our static data container!
575 if( m_nRefCount <= 0 )
577 delete m_pDataContainer;
578 m_pDataContainer = NULL;
582 sal_uInt32 SvtHistoryOptions::GetSize( EHistoryType eHistory ) const
584 MutexGuard aGuard(theHistoryOptionsMutex::get());
586 return m_pDataContainer->GetCapacity(eHistory);
589 void SvtHistoryOptions::Clear( EHistoryType eHistory )
591 MutexGuard aGuard(theHistoryOptionsMutex::get());
593 m_pDataContainer->Clear( eHistory );
596 Sequence< Sequence< PropertyValue > > SvtHistoryOptions::GetList( EHistoryType eHistory ) const
598 MutexGuard aGuard(theHistoryOptionsMutex::get());
600 return m_pDataContainer->GetList( eHistory );
603 void SvtHistoryOptions::AppendItem(EHistoryType eHistory,
604 const OUString& sURL, const OUString& sFilter, const OUString& sTitle,
605 const OUString& sPassword, const OUString& sThumbnail)
607 MutexGuard aGuard(theHistoryOptionsMutex::get());
609 m_pDataContainer->AppendItem(eHistory, sURL, sFilter, sTitle, sPassword, sThumbnail);
612 void SvtHistoryOptions::DeleteItem(EHistoryType eHistory, const OUString& sURL)
614 MutexGuard aGuard(theHistoryOptionsMutex::get());
616 m_pDataContainer->DeleteItem(eHistory, sURL);
619 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */