/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include "itemholder1.hxx" #include #include #include #include #include #include #include using namespace ::std; using namespace ::utl; using namespace ::osl; using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::beans; namespace { static const ::sal_Int32 s_nOffsetURL = 0; static const ::sal_Int32 s_nOffsetFilter = 1; static const ::sal_Int32 s_nOffsetTitle = 2; static const ::sal_Int32 s_nOffsetPassword = 3; static const ::sal_Int32 s_nOffsetThumbnail = 4; const char s_sItemList[] = "ItemList"; const char s_sOrderList[] = "OrderList"; const char s_sHistoryItemRef[] = "HistoryItemRef"; const char s_sFilter[] = "Filter"; const char s_sTitle[] = "Title"; const char s_sPassword[] = "Password"; const char s_sThumbnail[] = "Thumbnail"; class theHistoryOptionsMutex : public rtl::Static{}; } /// Internal implementation of the SvtHistoryOptions. class SvtHistoryOptions_Impl { public: SvtHistoryOptions_Impl(); /// Returns the maximum size of the internal lists, ie. the capacity not the size. sal_uInt32 GetCapacity(EHistoryType eHistory) const; /// Clear the specified history list. void Clear(EHistoryType eHistory); /// Get a sequence list from the items. Sequence< Sequence > GetList(EHistoryType eHistory); void AppendItem(EHistoryType eHistory, const OUString& sURL, const OUString& sFilter, const OUString& sTitle, const boost::optional& sThumbnail); void DeleteItem(EHistoryType eHistory, const OUString& sURL); private: /// Return the appropriate list of recent documents (based on eHistory). uno::Reference GetListAccess(EHistoryType eHistory) const; void impl_truncateList(EHistoryType eHistory, sal_uInt32 nSize); private: uno::Reference m_xCfg; uno::Reference m_xCommonXCU; }; SvtHistoryOptions_Impl::SvtHistoryOptions_Impl() { try { m_xCfg.set( ::comphelper::ConfigurationHelper::openConfig( ::comphelper::getProcessComponentContext(), "org.openoffice.Office.Histories/Histories", ::comphelper::EConfigurationModes::Standard), uno::UNO_QUERY); m_xCommonXCU.set( ::comphelper::ConfigurationHelper::openConfig( ::comphelper::getProcessComponentContext(), "org.openoffice.Office.Common/History", ::comphelper::EConfigurationModes::Standard), uno::UNO_QUERY); } catch(const uno::Exception&) { DBG_UNHANDLED_EXCEPTION("unotools.config"); m_xCfg.clear(); m_xCommonXCU.clear(); } } sal_uInt32 SvtHistoryOptions_Impl::GetCapacity(EHistoryType eHistory) const { uno::Reference xListAccess(m_xCommonXCU, uno::UNO_QUERY); if (!xListAccess.is()) return 0; sal_uInt32 nSize = 0; try { switch (eHistory) { case ePICKLIST: xListAccess->getPropertyValue("PickListSize") >>= nSize; break; case eHELPBOOKMARKS: xListAccess->getPropertyValue("HelpBookmarkSize") >>= nSize; break; default: break; } } catch (const uno::Exception&) { DBG_UNHANDLED_EXCEPTION("unotools.config"); } return nSize; } uno::Reference SvtHistoryOptions_Impl::GetListAccess(EHistoryType eHistory) const { uno::Reference xListAccess; try { switch (eHistory) { case ePICKLIST: m_xCfg->getByName("PickList") >>= xListAccess; break; case eHELPBOOKMARKS: m_xCfg->getByName("HelpBookmarks") >>= xListAccess; break; default: break; } } catch (const uno::Exception&) { DBG_UNHANDLED_EXCEPTION("unotools.config"); } return xListAccess; } void SvtHistoryOptions_Impl::impl_truncateList(EHistoryType eHistory, sal_uInt32 nSize) { uno::Reference xList(GetListAccess(eHistory)); if (!xList.is()) return; uno::Reference xItemList; uno::Reference xOrderList; uno::Reference xSet; try { xList->getByName(s_sOrderList) >>= xOrderList; xList->getByName(s_sItemList) >>= xItemList; const sal_uInt32 nLength = xOrderList->getElementNames().getLength(); if (nSize < nLength) { for (sal_uInt32 i=nLength-1; i>=nSize; --i) { OUString sTmp; const OUString sRemove = OUString::number(i); xOrderList->getByName(sRemove) >>= xSet; xSet->getPropertyValue(s_sHistoryItemRef) >>= sTmp; xItemList->removeByName(sTmp); xOrderList->removeByName(sRemove); } ::comphelper::ConfigurationHelper::flush(m_xCfg); } } catch(const uno::Exception&) { DBG_UNHANDLED_EXCEPTION("unotools.config"); } } void SvtHistoryOptions_Impl::Clear( EHistoryType eHistory ) { uno::Reference xListAccess(GetListAccess(eHistory)); if (!xListAccess.is()) return; uno::Reference xNode; try { // clear ItemList xListAccess->getByName(s_sItemList) >>= xNode; Sequence aStrings(xNode->getElementNames()); const sal_Int32 nLength = aStrings.getLength(); for (sal_Int32 i = 0; i < nLength; ++i) xNode->removeByName(aStrings[i]); // clear OrderList xListAccess->getByName(s_sOrderList) >>= xNode; aStrings = xNode->getElementNames(); for (sal_Int32 j = 0; j < nLength; ++j) xNode->removeByName(aStrings[j]); ::comphelper::ConfigurationHelper::flush(m_xCfg); } catch(const uno::Exception&) { DBG_UNHANDLED_EXCEPTION("unotools.config"); } } Sequence< Sequence > SvtHistoryOptions_Impl::GetList(EHistoryType eHistory) { uno::Reference xListAccess(GetListAccess(eHistory)); if (!xListAccess.is()) return Sequence< Sequence >(); impl_truncateList(eHistory, GetCapacity(eHistory)); Sequence seqProperties(5); seqProperties[s_nOffsetURL ].Name = HISTORY_PROPERTYNAME_URL; seqProperties[s_nOffsetFilter ].Name = HISTORY_PROPERTYNAME_FILTER; seqProperties[s_nOffsetTitle ].Name = HISTORY_PROPERTYNAME_TITLE; seqProperties[s_nOffsetPassword ].Name = HISTORY_PROPERTYNAME_PASSWORD; seqProperties[s_nOffsetThumbnail ].Name = HISTORY_PROPERTYNAME_THUMBNAIL; uno::Reference xItemList; uno::Reference xOrderList; try { xListAccess->getByName(s_sItemList) >>= xItemList; xListAccess->getByName(s_sOrderList) >>= xOrderList; } catch(const uno::Exception&) { DBG_UNHANDLED_EXCEPTION("unotools.config"); } const sal_Int32 nLength = xOrderList->getElementNames().getLength(); Sequence< Sequence > aRet(nLength); sal_Int32 nCount = 0; for (sal_Int32 nItem = 0; nItem < nLength; ++nItem) { try { OUString sUrl; uno::Reference xSet; xOrderList->getByName(OUString::number(nItem)) >>= xSet; xSet->getPropertyValue(s_sHistoryItemRef) >>= sUrl; xItemList->getByName(sUrl) >>= xSet; seqProperties[s_nOffsetURL ].Value <<= sUrl; seqProperties[s_nOffsetFilter ].Value = xSet->getPropertyValue(s_sFilter); seqProperties[s_nOffsetTitle ].Value = xSet->getPropertyValue(s_sTitle); seqProperties[s_nOffsetPassword ].Value = xSet->getPropertyValue(s_sPassword); seqProperties[s_nOffsetThumbnail].Value = xSet->getPropertyValue(s_sThumbnail); aRet[nCount++] = seqProperties; } catch(const uno::Exception&) { // // "FILEOPEN: No Recent Documents..." discusses a problem // with corrupted /org.openoffice.Office/Histories/Histories // configuration items; to work around that problem, simply // ignore such corrupted individual items here, so that at // least newly added items are successfully reported back // from this function: DBG_UNHANDLED_EXCEPTION("unotools.config"); } } assert(nCount <= nLength); aRet.realloc(nCount); return aRet; } void SvtHistoryOptions_Impl::AppendItem(EHistoryType eHistory, const OUString& sURL, const OUString& sFilter, const OUString& sTitle, const boost::optional& sThumbnail) { uno::Reference xListAccess(GetListAccess(eHistory)); if (!xListAccess.is()) return; impl_truncateList(eHistory, GetCapacity(eHistory)); sal_Int32 nMaxSize = GetCapacity(eHistory); if (nMaxSize == 0) return; uno::Reference xItemList; uno::Reference xOrderList; uno::Reference xSet; try { xListAccess->getByName(s_sItemList) >>= xItemList; xListAccess->getByName(s_sOrderList) >>= xOrderList; sal_Int32 nLength = xOrderList->getElementNames().getLength(); // The item to be appended already exists if (xItemList->hasByName(sURL)) { if (sThumbnail) { // update the thumbnail xItemList->getByName(sURL) >>= xSet; xSet->setPropertyValue(s_sThumbnail, uno::makeAny(*sThumbnail)); } for (sal_Int32 i=0; igetByName(OUString::number(i)) >>= xSet; xSet->getPropertyValue(s_sHistoryItemRef) >>= aItem; if (aItem == sURL) { for (sal_Int32 j = i - 1; j >= 0; --j) { uno::Reference xPrevSet; uno::Reference xNextSet; xOrderList->getByName(OUString::number(j+1)) >>= xPrevSet; xOrderList->getByName(OUString::number(j)) >>= xNextSet; OUString sTemp; xNextSet->getPropertyValue(s_sHistoryItemRef) >>= sTemp; xPrevSet->setPropertyValue(s_sHistoryItemRef, uno::makeAny(sTemp)); } xOrderList->getByName(OUString::number(0)) >>= xSet; xSet->setPropertyValue(s_sHistoryItemRef, uno::makeAny(aItem)); break; } } ::comphelper::ConfigurationHelper::flush(m_xCfg); } else // The item to be appended does not exist yet { uno::Reference xFac; uno::Reference xInst; uno::Reference xPrevSet; uno::Reference xNextSet; // Append new item to OrderList. if ( nLength == nMaxSize ) { OUString sRemove; xOrderList->getByName(OUString::number(nLength-1)) >>= xSet; xSet->getPropertyValue(s_sHistoryItemRef) >>= sRemove; try { xItemList->removeByName(sRemove); } catch (container::NoSuchElementException &) { // // "FILEOPEN: No Recent Documents..." discusses a problem // with corrupted /org.openoffice.Office/Histories/Histories // configuration items; to work around that problem, simply // ignore such corrupted individual items here, so that at // least newly added items are successfully added: if (!sRemove.isEmpty()) { throw; } } } if (nLength != nMaxSize) { xFac.set(xOrderList, uno::UNO_QUERY); xInst = xFac->createInstance(); OUString sPush = OUString::number(nLength++); xOrderList->insertByName(sPush, uno::makeAny(xInst)); } for (sal_Int32 j=nLength-1; j>0; --j) { xOrderList->getByName( OUString::number(j) ) >>= xPrevSet; xOrderList->getByName( OUString::number(j-1) ) >>= xNextSet; OUString sTemp; xNextSet->getPropertyValue(s_sHistoryItemRef) >>= sTemp; xPrevSet->setPropertyValue(s_sHistoryItemRef, uno::makeAny(sTemp)); } xOrderList->getByName( OUString::number(0) ) >>= xSet; xSet->setPropertyValue(s_sHistoryItemRef, uno::makeAny(sURL)); // Append the item to ItemList. xFac.set(xItemList, uno::UNO_QUERY); xInst = xFac->createInstance(); xItemList->insertByName(sURL, uno::makeAny(xInst)); xSet.set(xInst, uno::UNO_QUERY); xSet->setPropertyValue(s_sFilter, uno::makeAny(sFilter)); xSet->setPropertyValue(s_sTitle, uno::makeAny(sTitle)); xSet->setPropertyValue(s_sPassword, uno::makeAny(OUString())); xSet->setPropertyValue(s_sThumbnail, uno::makeAny(sThumbnail.get_value_or(OUString()))); ::comphelper::ConfigurationHelper::flush(m_xCfg); } } catch(const uno::Exception&) { DBG_UNHANDLED_EXCEPTION("unotools.config"); } } void SvtHistoryOptions_Impl::DeleteItem(EHistoryType eHistory, const OUString& sURL) { uno::Reference xListAccess(GetListAccess(eHistory)); if (!xListAccess.is()) return; uno::Reference xItemList; uno::Reference xOrderList; uno::Reference xSet; try { xListAccess->getByName(s_sItemList) >>= xItemList; xListAccess->getByName(s_sOrderList) >>= xOrderList; sal_Int32 nLength = xOrderList->getElementNames().getLength(); // if it does not exist, nothing to do if (!xItemList->hasByName(sURL)) return; // it's the last one, just clear the lists if (nLength == 1) { Clear(eHistory); return; } // find it in the OrderList sal_Int32 nFromWhere = 0; for (; nFromWhere < nLength - 1; ++nFromWhere) { OUString aItem; xOrderList->getByName(OUString::number(nFromWhere)) >>= xSet; xSet->getPropertyValue(s_sHistoryItemRef) >>= aItem; if (aItem == sURL) break; } // and shift the rest of the items in OrderList accordingly for (sal_Int32 i = nFromWhere; i < nLength - 1; ++i) { uno::Reference xPrevSet; uno::Reference xNextSet; xOrderList->getByName(OUString::number(i)) >>= xPrevSet; xOrderList->getByName(OUString::number(i + 1)) >>= xNextSet; OUString sTemp; xNextSet->getPropertyValue(s_sHistoryItemRef) >>= sTemp; xPrevSet->setPropertyValue(s_sHistoryItemRef, uno::makeAny(sTemp)); } xOrderList->removeByName(OUString::number(nLength - 1)); // and finally remove it from the ItemList xItemList->removeByName(sURL); ::comphelper::ConfigurationHelper::flush(m_xCfg); } catch (const uno::Exception&) { DBG_UNHANDLED_EXCEPTION("unotools.config"); } } namespace { std::weak_ptr g_pHistoryOptions; } SvtHistoryOptions::SvtHistoryOptions() { MutexGuard aGuard(theHistoryOptionsMutex::get()); m_pImpl = g_pHistoryOptions.lock(); if( !m_pImpl ) { m_pImpl = std::make_shared(); g_pHistoryOptions = m_pImpl; ItemHolder1::holdConfigItem(EItem::HistoryOptions); } } SvtHistoryOptions::~SvtHistoryOptions() { MutexGuard aGuard(theHistoryOptionsMutex::get()); m_pImpl.reset(); } void SvtHistoryOptions::Clear( EHistoryType eHistory ) { MutexGuard aGuard(theHistoryOptionsMutex::get()); m_pImpl->Clear( eHistory ); } Sequence< Sequence< PropertyValue > > SvtHistoryOptions::GetList( EHistoryType eHistory ) const { MutexGuard aGuard(theHistoryOptionsMutex::get()); return m_pImpl->GetList( eHistory ); } void SvtHistoryOptions::AppendItem(EHistoryType eHistory, const OUString& sURL, const OUString& sFilter, const OUString& sTitle, const boost::optional& sThumbnail) { MutexGuard aGuard(theHistoryOptionsMutex::get()); m_pImpl->AppendItem(eHistory, sURL, sFilter, sTitle, sThumbnail); } void SvtHistoryOptions::DeleteItem(EHistoryType eHistory, const OUString& sURL) { MutexGuard aGuard(theHistoryOptionsMutex::get()); m_pImpl->DeleteItem(eHistory, sURL); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */