Updated core
[LibreOffice.git] / unotools / source / config / historyoptions.cxx
blob9c66fbfefb29519bec9ed65f4afc5398cce00fd8
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 .
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 <rtl/logfile.hxx>
32 #include "itemholder1.hxx"
34 #include <com/sun/star/beans/XPropertySet.hpp>
35 #include <com/sun/star/container/XNameAccess.hpp>
36 #include <com/sun/star/container/XNameContainer.hpp>
37 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
38 #include <comphelper/configurationhelper.hxx>
39 #include <comphelper/processfactory.hxx>
41 using namespace ::std ;
42 using namespace ::utl ;
43 using namespace ::rtl ;
44 using namespace ::osl ;
45 using namespace ::com::sun::star::uno ;
46 using namespace ::com::sun::star::beans ;
48 namespace {
49 static const ::sal_Int32 s_nOffsetURL = 0;
50 static const ::sal_Int32 s_nOffsetFilter = 1;
51 static const ::sal_Int32 s_nOffsetTitle = 2;
52 static const ::sal_Int32 s_nOffsetPassword = 3;
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_sURLHistorySize[] = "Size";
58 const char s_sHelpBookmarksSize[] = "HelpBookmarkSize";
59 const char s_sPickList[] = "PickList";
60 const char s_sURLHistory[] = "URLHistory";
61 const char s_sHelpBookmarks[] = "HelpBookmarks";
62 const char s_sItemList[] = "ItemList";
63 const char s_sOrderList[] = "OrderList";
64 const char s_sHistoryItemRef[] = "HistoryItemRef";
65 const char s_sFilter[] = "Filter";
66 const char s_sTitle[] = "Title";
67 const char s_sPassword[] = "Password";
70 struct IMPL_THistoryItem
72 IMPL_THistoryItem()
76 IMPL_THistoryItem( const OUString& sNewURL ,
77 const OUString& sNewFilter ,
78 const OUString& sNewTitle ,
79 const OUString& sNewPassword )
81 sURL = sNewURL ;
82 sFilter = sNewFilter ;
83 sTitle = sNewTitle ;
84 sPassword = sNewPassword ;
87 sal_Bool operator==( const OUString& sSearchedURL ) const
89 return( sURL == sSearchedURL );
92 OUString sURL ;
93 OUString sFilter ;
94 OUString sTitle ;
95 OUString sPassword ;
98 //*****************************************************************************************************************
99 // class SvtHistoryOptions_Impl
100 // redesigned
101 //*****************************************************************************************************************
102 class SvtHistoryOptions_Impl
104 public:
105 SvtHistoryOptions_Impl();
106 ~SvtHistoryOptions_Impl();
108 sal_uInt32 GetSize( EHistoryType eHistory );
109 void Clear( EHistoryType eHistory );
110 Sequence< Sequence< PropertyValue > > GetList( EHistoryType eHistory );
111 void AppendItem( EHistoryType eHistory ,
112 const OUString& sURL ,
113 const OUString& sFilter ,
114 const OUString& sTitle ,
115 const OUString& sPassword );
117 private:
118 void impl_truncateList (EHistoryType eHistory, sal_uInt32 nSize);
120 private:
121 css::uno::Reference< css::container::XNameAccess > m_xCfg;
122 css::uno::Reference< css::container::XNameAccess > m_xCommonXCU;
125 //*****************************************************************************************************************
126 // constructor
127 //*****************************************************************************************************************
128 SvtHistoryOptions_Impl::SvtHistoryOptions_Impl()
132 m_xCfg = Reference< css::container::XNameAccess > (
133 ::comphelper::ConfigurationHelper::openConfig(
134 ::comphelper::getProcessComponentContext(),
135 OUString(s_sHistories),
136 ::comphelper::ConfigurationHelper::E_STANDARD),
137 css::uno::UNO_QUERY );
139 m_xCommonXCU = Reference< css::container::XNameAccess > (
140 ::comphelper::ConfigurationHelper::openConfig(
141 ::comphelper::getProcessComponentContext(),
142 OUString(s_sCommonHistory),
143 ::comphelper::ConfigurationHelper::E_STANDARD),
144 css::uno::UNO_QUERY );
146 catch(const css::uno::Exception& ex)
148 m_xCfg.clear();
149 m_xCommonXCU.clear();
151 SAL_WARN("unotools.config", "Caught unexpected: " << ex.Message);
155 //*****************************************************************************************************************
156 // destructor
157 //*****************************************************************************************************************
158 SvtHistoryOptions_Impl::~SvtHistoryOptions_Impl()
162 //*****************************************************************************************************************
163 // public method
164 // Attention: We return the max. size of our internal lists - That is the capacity not the size!
165 //*****************************************************************************************************************
166 sal_uInt32 SvtHistoryOptions_Impl::GetSize( EHistoryType eHistory )
168 css::uno::Reference< css::beans::XPropertySet > xListAccess(m_xCommonXCU, css::uno::UNO_QUERY);
170 if (!xListAccess.is())
171 return 0;
173 sal_uInt32 nSize = 0 ;
177 switch( eHistory )
179 case ePICKLIST:
180 xListAccess->getPropertyValue(OUString(s_sPickListSize)) >>= nSize;
181 break;
183 case eHISTORY:
184 xListAccess->getPropertyValue(OUString(s_sURLHistorySize)) >>= nSize;
185 break;
187 case eHELPBOOKMARKS:
188 xListAccess->getPropertyValue(OUString(s_sHelpBookmarksSize)) >>= nSize;
189 break;
191 default:
192 break;
195 catch(const css::uno::Exception& ex)
197 SAL_WARN("unotools.config", "Caught unexpected: " << ex.Message);
200 return nSize;
203 //*****************************************************************************************************************
204 void SvtHistoryOptions_Impl::impl_truncateList ( EHistoryType eHistory, sal_uInt32 nSize )
206 css::uno::Reference< css::container::XNameAccess > xList;
207 css::uno::Reference< css::container::XNameContainer > xItemList;
208 css::uno::Reference< css::container::XNameContainer > xOrderList;
209 css::uno::Reference< css::beans::XPropertySet > xSet;
213 switch( eHistory )
215 case ePICKLIST:
216 m_xCfg->getByName(OUString(s_sPickList)) >>= xList;
217 break;
219 case eHISTORY:
220 m_xCfg->getByName(OUString(s_sURLHistory)) >>= xList;
221 break;
223 case eHELPBOOKMARKS:
224 m_xCfg->getByName(OUString(s_sHelpBookmarks)) >>= xList;
225 break;
227 default:
228 break;
231 // If too much items in current list ...
232 // truncate the oldest items BEFORE you set the new one.
233 if ( ! xList.is())
234 return;
236 xList->getByName(OUString(s_sOrderList)) >>= xOrderList;
237 xList->getByName(OUString(s_sItemList)) >>= xItemList;
239 const sal_uInt32 nLength = xOrderList->getElementNames().getLength();
240 if (nSize < nLength)
242 for (sal_uInt32 i=nLength-1; i>=nSize; --i)
244 OUString sTmp;
245 const OUString sRemove = OUString::valueOf((sal_Int32)i);
246 xOrderList->getByName(sRemove) >>= xSet;
247 xSet->getPropertyValue(OUString(s_sHistoryItemRef)) >>= sTmp;
248 xItemList->removeByName(sTmp);
249 xOrderList->removeByName(sRemove);
252 ::comphelper::ConfigurationHelper::flush(m_xCfg);
255 catch(const css::uno::Exception& ex)
257 SAL_WARN("unotools.config", "Caught unexpected: " << ex.Message);
261 //*****************************************************************************************************************
262 // public method
263 // Clear specified history list
264 //*****************************************************************************************************************
265 void SvtHistoryOptions_Impl::Clear( EHistoryType eHistory )
267 css::uno::Reference< css::container::XNameAccess > xListAccess;
268 css::uno::Reference< css::container::XNameContainer > xNode;
269 Sequence< OUString > lOrders;
273 switch( eHistory )
275 case ePICKLIST:
277 m_xCfg->getByName(OUString(s_sPickList)) >>= xListAccess;
278 break;
281 case eHISTORY:
283 m_xCfg->getByName(OUString(s_sURLHistory)) >>= xListAccess;
284 break;
287 case eHELPBOOKMARKS:
289 m_xCfg->getByName(OUString(s_sHelpBookmarks)) >>= xListAccess;
290 break;
293 default:
294 break;
297 if (xListAccess.is())
299 // clear ItemList
300 xListAccess->getByName(OUString(s_sItemList)) >>= xNode ;
301 lOrders = xNode->getElementNames();
302 const sal_Int32 nLength = lOrders.getLength();
303 for(sal_Int32 i=0; i<nLength; ++i)
304 xNode->removeByName(lOrders[i]);
306 // clear OrderList
307 xListAccess->getByName(OUString(s_sOrderList)) >>= xNode ;
308 lOrders = xNode->getElementNames();
309 for(sal_Int32 j=0; j<nLength; ++j)
310 xNode->removeByName(lOrders[j]);
312 ::comphelper::ConfigurationHelper::flush(m_xCfg);
315 catch(const css::uno::Exception& ex)
317 SAL_WARN("unotools.config", "Caught unexpected: " << ex.Message);
321 //*****************************************************************************************************************
322 // public method
323 // get a sequence list from the items
324 //*****************************************************************************************************************
325 Sequence< Sequence< PropertyValue > > SvtHistoryOptions_Impl::GetList( EHistoryType eHistory )
327 impl_truncateList (eHistory, GetSize (eHistory));
329 Sequence< Sequence< PropertyValue > > seqReturn; // Set default return value.
330 Sequence< PropertyValue > seqProperties( 4 );
331 Sequence< OUString > lOrders;
333 css::uno::Reference< css::container::XNameAccess > xListAccess;
334 css::uno::Reference< css::container::XNameAccess > xItemList;
335 css::uno::Reference< css::container::XNameAccess > xOrderList;
336 css::uno::Reference< css::beans::XPropertySet > xSet;
338 seqProperties[s_nOffsetURL ].Name = HISTORY_PROPERTYNAME_URL;
339 seqProperties[s_nOffsetFilter ].Name = HISTORY_PROPERTYNAME_FILTER;
340 seqProperties[s_nOffsetTitle ].Name = HISTORY_PROPERTYNAME_TITLE;
341 seqProperties[s_nOffsetPassword ].Name = HISTORY_PROPERTYNAME_PASSWORD;
345 switch( eHistory )
347 case ePICKLIST:
349 m_xCfg->getByName(OUString(s_sPickList)) >>= xListAccess;
350 break;
353 case eHISTORY:
355 m_xCfg->getByName(OUString(s_sURLHistory)) >>= xListAccess;
356 break;
359 case eHELPBOOKMARKS:
361 m_xCfg->getByName(OUString(s_sHelpBookmarks)) >>= xListAccess;
362 break;
365 default:
366 break;
369 if (xListAccess.is())
371 xListAccess->getByName(OUString(s_sItemList)) >>= xItemList;
372 xListAccess->getByName(OUString(s_sOrderList)) >>= xOrderList;
374 const sal_Int32 nLength = xOrderList->getElementNames().getLength();
375 Sequence< Sequence< PropertyValue > > aRet(nLength);
376 sal_Int32 nCount = 0;
378 for(sal_Int32 nItem=0; nItem<nLength; ++nItem)
382 OUString sUrl;
383 xOrderList->getByName(OUString::valueOf(nItem)) >>= xSet;
384 xSet->getPropertyValue(OUString(s_sHistoryItemRef)) >>= sUrl;
386 xItemList->getByName(sUrl) >>= xSet;
387 seqProperties[s_nOffsetURL ].Value <<= sUrl;
388 xSet->getPropertyValue(OUString(s_sFilter)) >>= seqProperties[s_nOffsetFilter ].Value;
389 xSet->getPropertyValue(OUString(s_sTitle)) >>= seqProperties[s_nOffsetTitle ].Value;
390 xSet->getPropertyValue(OUString(s_sPassword)) >>= seqProperties[s_nOffsetPassword ].Value;
391 aRet[nCount++] = seqProperties;
393 catch(const css::uno::Exception& ex)
395 // <https://bugs.freedesktop.org/show_bug.cgi?id=46074>
396 // "FILEOPEN: No Recent Documents..." discusses a problem
397 // with corrupted /org.openoffice.Office/Histories/Histories
398 // configuration items; to work around that problem, simply
399 // ignore such corrupted individual items here, so that at
400 // least newly added items are successfully reported back
401 // from this function:
402 SAL_WARN("unotools.config", "Caught unexpected: " << ex.Message);
405 assert(nCount <= nLength);
406 aRet.realloc(nCount);
407 seqReturn = aRet;
410 catch(const css::uno::Exception& ex)
412 SAL_WARN("unotools.config", "Caught unexpected: " << ex.Message);
415 return seqReturn;
418 //*****************************************************************************************************************
419 // public method
420 // implements a deque in XML
421 //*****************************************************************************************************************
422 void SvtHistoryOptions_Impl::AppendItem( EHistoryType eHistory ,
423 const OUString& sURL ,
424 const OUString& sFilter ,
425 const OUString& sTitle ,
426 const OUString& sPassword )
428 impl_truncateList (eHistory, GetSize (eHistory));
430 css::uno::Reference< css::container::XNameAccess > xListAccess;
431 sal_Int32 nMaxSize = 0;
433 switch(eHistory)
435 case ePICKLIST:
437 m_xCfg->getByName(OUString(s_sPickList)) >>= xListAccess;
438 nMaxSize = GetSize(ePICKLIST);
440 break;
441 case eHISTORY:
443 m_xCfg->getByName(OUString(s_sURLHistory)) >>= xListAccess;
444 nMaxSize = GetSize(eHISTORY);
446 break;
447 case eHELPBOOKMARKS:
449 m_xCfg->getByName(OUString(s_sHelpBookmarks)) >>= xListAccess;
450 nMaxSize = GetSize(eHELPBOOKMARKS);
452 break;
453 default:
454 break;
457 if (nMaxSize==0)
458 return;
460 css::uno::Reference< css::container::XNameContainer > xItemList;
461 css::uno::Reference< css::container::XNameContainer > xOrderList;
462 css::uno::Reference< css::beans::XPropertySet > xSet;
466 xListAccess->getByName(OUString(s_sItemList)) >>= xItemList;
467 xListAccess->getByName(OUString(s_sOrderList)) >>= xOrderList;
468 sal_Int32 nLength = xOrderList->getElementNames().getLength();
470 OUString sHistoryItemRef(s_sHistoryItemRef);
471 // The item to be appended is already existing!
472 if (xItemList->hasByName(sURL))
474 for (sal_Int32 i=0; i<nLength; ++i)
476 OUString sTmp;
477 xOrderList->getByName(OUString::valueOf(i)) >>= xSet;
478 xSet->getPropertyValue(sHistoryItemRef) >>= sTmp;
480 if(sURL == sTmp)
482 OUString sFind;
483 xOrderList->getByName( OUString::valueOf(i) ) >>= xSet;
484 xSet->getPropertyValue(sHistoryItemRef) >>= sFind;
485 for (sal_Int32 j=i-1; j>=0; --j)
487 css::uno::Reference< css::beans::XPropertySet > xPrevSet;
488 css::uno::Reference< css::beans::XPropertySet > xNextSet;
489 xOrderList->getByName( OUString::valueOf(j+1) ) >>= xPrevSet;
490 xOrderList->getByName( OUString::valueOf(j) ) >>= xNextSet;
492 OUString sTemp;
493 xNextSet->getPropertyValue(sHistoryItemRef) >>= sTemp;
494 xPrevSet->setPropertyValue(sHistoryItemRef, css::uno::makeAny(sTemp));
496 xOrderList->getByName( OUString::valueOf((sal_Int32)0) ) >>= xSet;
497 xSet->setPropertyValue(sHistoryItemRef, css::uno::makeAny(sFind));
499 ::comphelper::ConfigurationHelper::flush(m_xCfg);
500 break;
505 // The item to be appended is not existing!
506 else
508 css::uno::Reference< css::lang::XSingleServiceFactory > xFac;
509 css::uno::Reference< css::uno::XInterface > xInst;
510 css::uno::Reference< css::beans::XPropertySet > xPrevSet;
511 css::uno::Reference< css::beans::XPropertySet > xNextSet;
513 // Append new item to OrderList.
514 if ( nLength == nMaxSize )
516 OUString sRemove;
517 xOrderList->getByName(OUString::valueOf(nLength-1)) >>= xSet;
518 xSet->getPropertyValue(sHistoryItemRef) >>= sRemove;
521 xItemList->removeByName(sRemove);
523 catch (css::container::NoSuchElementException &)
525 // <https://bugs.freedesktop.org/show_bug.cgi?id=46074>
526 // "FILEOPEN: No Recent Documents..." discusses a problem
527 // with corrupted /org.openoffice.Office/Histories/Histories
528 // configuration items; to work around that problem, simply
529 // ignore such corrupted individual items here, so that at
530 // least newly added items are successfully added:
531 if (!sRemove.isEmpty())
533 throw;
537 if ( nLength != nMaxSize )
539 xFac = css::uno::Reference< css::lang::XSingleServiceFactory >(xOrderList, css::uno::UNO_QUERY);
540 xInst = xFac->createInstance();
541 OUString sPush = OUString::valueOf(nLength++);
542 xOrderList->insertByName(sPush, css::uno::makeAny(xInst));
544 for (sal_Int32 j=nLength-1; j>0; --j)
546 xOrderList->getByName( OUString::valueOf(j) ) >>= xPrevSet;
547 xOrderList->getByName( OUString::valueOf(j-1) ) >>= xNextSet;
548 OUString sTemp;
549 xNextSet->getPropertyValue(sHistoryItemRef) >>= sTemp;
550 xPrevSet->setPropertyValue(sHistoryItemRef, css::uno::makeAny(sTemp));
552 xOrderList->getByName( OUString::valueOf((sal_Int32)0) ) >>= xSet;
553 xSet->setPropertyValue(sHistoryItemRef, css::uno::makeAny(sURL));
555 // Append the item to ItemList.
556 xFac = css::uno::Reference< css::lang::XSingleServiceFactory >(xItemList, css::uno::UNO_QUERY);
557 xInst = xFac->createInstance();
558 xItemList->insertByName(sURL, css::uno::makeAny(xInst));
559 xSet = css::uno::Reference< css::beans::XPropertySet >(xInst, css::uno::UNO_QUERY);
560 xSet->setPropertyValue(OUString(s_sFilter), css::uno::makeAny(sFilter));
561 xSet->setPropertyValue(OUString(s_sTitle), css::uno::makeAny(sTitle));
562 xSet->setPropertyValue(OUString(s_sPassword), css::uno::makeAny(sPassword));
564 ::comphelper::ConfigurationHelper::flush(m_xCfg);
567 catch(const css::uno::Exception& ex)
569 SAL_WARN("unotools.config", "Caught unexpected: " << ex.Message);
573 //*****************************************************************************************************************
574 // initialize static member
575 // DON'T DO IT IN YOUR HEADER!
576 // see definition for further information
577 //*****************************************************************************************************************
578 SvtHistoryOptions_Impl* SvtHistoryOptions::m_pDataContainer = NULL ;
579 sal_Int32 SvtHistoryOptions::m_nRefCount = 0 ;
581 //*****************************************************************************************************************
582 // constructor
583 //*****************************************************************************************************************
584 SvtHistoryOptions::SvtHistoryOptions()
586 // Global access, must be guarded (multithreading!).
587 MutexGuard aGuard( GetOwnStaticMutex() );
588 // Increase ouer refcount ...
589 ++m_nRefCount;
590 // ... and initialize ouer data container only if it not already exist!
591 if( m_pDataContainer == NULL )
593 RTL_LOGFILE_CONTEXT(aLog, "unotools ( ??? ) ::SvtHistoryOptions_Impl::ctor()");
594 m_pDataContainer = new SvtHistoryOptions_Impl;
596 ItemHolder1::holdConfigItem(E_HISTORYOPTIONS);
600 //*****************************************************************************************************************
601 // destructor
602 //*****************************************************************************************************************
603 SvtHistoryOptions::~SvtHistoryOptions()
605 // Global access, must be guarded (multithreading!)
606 MutexGuard aGuard( GetOwnStaticMutex() );
607 // Decrease ouer refcount.
608 --m_nRefCount;
609 // If last instance was deleted ...
610 // we must destroy ouer static data container!
611 if( m_nRefCount <= 0 )
613 delete m_pDataContainer;
614 m_pDataContainer = NULL;
618 //*****************************************************************************************************************
619 // public method
620 //*****************************************************************************************************************
621 sal_uInt32 SvtHistoryOptions::GetSize( EHistoryType eHistory ) const
623 MutexGuard aGuard( GetOwnStaticMutex() );
624 return m_pDataContainer->GetSize( eHistory );
627 //*****************************************************************************************************************
628 // public method
629 //*****************************************************************************************************************
630 void SvtHistoryOptions::Clear( EHistoryType eHistory )
632 MutexGuard aGuard( GetOwnStaticMutex() );
633 m_pDataContainer->Clear( eHistory );
636 //*****************************************************************************************************************
637 // public method
638 //*****************************************************************************************************************
639 Sequence< Sequence< PropertyValue > > SvtHistoryOptions::GetList( EHistoryType eHistory ) const
641 MutexGuard aGuard( GetOwnStaticMutex() );
642 return m_pDataContainer->GetList( eHistory );
645 //*****************************************************************************************************************
646 // public method
647 //*****************************************************************************************************************
648 void SvtHistoryOptions::AppendItem( EHistoryType eHistory ,
649 const OUString& sURL ,
650 const OUString& sFilter ,
651 const OUString& sTitle ,
652 const OUString& sPassword )
654 MutexGuard aGuard( GetOwnStaticMutex() );
655 m_pDataContainer->AppendItem( eHistory, sURL, sFilter, sTitle, sPassword );
658 namespace
660 class theHistoryOptionsMutex : public rtl::Static<osl::Mutex, theHistoryOptionsMutex>{};
663 //*****************************************************************************************************************
664 // private method
665 //*****************************************************************************************************************
666 Mutex& SvtHistoryOptions::GetOwnStaticMutex()
668 return theHistoryOptionsMutex::get();
671 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */