diff options
Diffstat (limited to 'sc/source/ui/unoobj/linkuno.cxx')
-rw-r--r-- | sc/source/ui/unoobj/linkuno.cxx | 1688 |
1 files changed, 1688 insertions, 0 deletions
diff --git a/sc/source/ui/unoobj/linkuno.cxx b/sc/source/ui/unoobj/linkuno.cxx new file mode 100644 index 0000000000..b8c6a9c7e3 --- /dev/null +++ b/sc/source/ui/unoobj/linkuno.cxx @@ -0,0 +1,1688 @@ +/* -*- 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 <sal/config.h> + +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <comphelper/sequence.hxx> +#include <formula/token.hxx> +#include <svl/hint.hxx> +#include <sfx2/linkmgr.hxx> +#include <utility> +#include <vcl/svapp.hxx> +#include <svl/sharedstringpool.hxx> + +#include <linkuno.hxx> +#include <miscuno.hxx> +#include <convuno.hxx> +#include <docsh.hxx> +#include <docfunc.hxx> +#include <tablink.hxx> +#include <arealink.hxx> +#include <hints.hxx> +#include <unonames.hxx> +#include <rangeseq.hxx> +#include <scmatrix.hxx> +#include <documentlinkmgr.hxx> + +#include <string_view> +#include <vector> + +using namespace com::sun::star; +using namespace formula; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::lang::IllegalArgumentException; +using ::com::sun::star::uno::RuntimeException; +using ::std::vector; + +// used for sheet- and area link: +static std::span<const SfxItemPropertyMapEntry> lcl_GetSheetLinkMap() +{ + static const SfxItemPropertyMapEntry aSheetLinkMap_Impl[] = + { + { SC_UNONAME_FILTER, 0, cppu::UnoType<OUString>::get(), 0, 0 }, + { SC_UNONAME_FILTOPT, 0, cppu::UnoType<OUString>::get(), 0, 0 }, + { SC_UNONAME_LINKURL, 0, cppu::UnoType<OUString>::get(), 0, 0 }, + { SC_UNONAME_REFDELAY, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 }, + { SC_UNONAME_REFPERIOD, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 }, + }; + return aSheetLinkMap_Impl; +} + +SC_SIMPLE_SERVICE_INFO( ScAreaLinkObj, "ScAreaLinkObj", "com.sun.star.sheet.CellAreaLink" ) +SC_SIMPLE_SERVICE_INFO( ScAreaLinksObj, "ScAreaLinksObj", "com.sun.star.sheet.CellAreaLinks" ) +SC_SIMPLE_SERVICE_INFO( ScDDELinkObj, "ScDDELinkObj", "com.sun.star.sheet.DDELink" ) +SC_SIMPLE_SERVICE_INFO( ScDDELinksObj, "ScDDELinksObj", "com.sun.star.sheet.DDELinks" ) +SC_SIMPLE_SERVICE_INFO( ScSheetLinkObj, "ScSheetLinkObj", "com.sun.star.sheet.SheetLink" ) +SC_SIMPLE_SERVICE_INFO( ScSheetLinksObj, "ScSheetLinksObj", "com.sun.star.sheet.SheetLinks" ) + +ScSheetLinkObj::ScSheetLinkObj(ScDocShell* pDocSh, OUString aName) : + aPropSet( lcl_GetSheetLinkMap() ), + pDocShell( pDocSh ), + aFileName(std::move( aName )) +{ + pDocShell->GetDocument().AddUnoObject(*this); +} + +ScSheetLinkObj::~ScSheetLinkObj() +{ + SolarMutexGuard g; + + if (pDocShell) + pDocShell->GetDocument().RemoveUnoObject(*this); +} + +void ScSheetLinkObj::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + //! notify if links in document are changed + // UpdateRef is not needed here + + if ( auto pRefreshHint = dynamic_cast<const ScLinkRefreshedHint*>(&rHint) ) + { + if ( pRefreshHint->GetLinkType() == ScLinkRefType::SHEET && pRefreshHint->GetUrl() == aFileName ) + Refreshed_Impl(); + } + else + { + if ( rHint.GetId() == SfxHintId::Dying ) + pDocShell = nullptr; // pointer is invalid + } +} + +ScTableLink* ScSheetLinkObj::GetLink_Impl() const +{ + if (pDocShell) + { + sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager(); + size_t nCount = pLinkManager->GetLinks().size(); + for (size_t i=0; i<nCount; i++) + { + ::sfx2::SvBaseLink* pBase = pLinkManager->GetLinks()[i].get(); + if (auto pTabLink = dynamic_cast<ScTableLink*>( pBase)) + { + if ( pTabLink->GetFileName() == aFileName ) + return pTabLink; + } + } + } + return nullptr; // not found +} + +// XNamed + +OUString SAL_CALL ScSheetLinkObj::getName() +{ + SolarMutexGuard aGuard; + return getFileName(); // Name is the same as filename (URL) +} + +void SAL_CALL ScSheetLinkObj::setName( const OUString& aName ) +{ + SolarMutexGuard aGuard; + setFileName(aName); // Name is the same as filename (URL) +} + +// XRefreshable + +void SAL_CALL ScSheetLinkObj::refresh() +{ + SolarMutexGuard aGuard; + ScTableLink* pLink = GetLink_Impl(); + if (pLink) + pLink->Refresh( pLink->GetFileName(), pLink->GetFilterName(), nullptr, pLink->GetRefreshDelaySeconds() ); +} + +void SAL_CALL ScSheetLinkObj::addRefreshListener( + const uno::Reference<util::XRefreshListener >& xListener ) +{ + SolarMutexGuard aGuard; + aRefreshListeners.push_back( xListener ); + + // hold one additional ref to keep this object alive as long as there are listeners + if ( aRefreshListeners.size() == 1 ) + acquire(); +} + +void SAL_CALL ScSheetLinkObj::removeRefreshListener( + const uno::Reference<util::XRefreshListener >& xListener ) +{ + SolarMutexGuard aGuard; + size_t nCount = aRefreshListeners.size(); + for ( size_t n=nCount; n--; ) + { + uno::Reference<util::XRefreshListener>& rObj = aRefreshListeners[n]; + if ( rObj == xListener ) + { + aRefreshListeners.erase( aRefreshListeners.begin() + n ); + if ( aRefreshListeners.empty() ) + release(); // release ref for listeners + break; + } + } +} + +void ScSheetLinkObj::Refreshed_Impl() +{ + lang::EventObject aEvent; + aEvent.Source.set(getXWeak()); + for (uno::Reference<util::XRefreshListener> & xRefreshListener : aRefreshListeners) + xRefreshListener->refreshed( aEvent ); +} + +void ScSheetLinkObj::ModifyRefreshDelay_Impl( sal_Int32 nRefresh ) +{ + ScTableLink* pLink = GetLink_Impl(); + if( pLink ) + pLink->SetRefreshDelay( static_cast<sal_uLong>(nRefresh) ); +} + +// XPropertySet + +uno::Reference<beans::XPropertySetInfo> SAL_CALL ScSheetLinkObj::getPropertySetInfo() +{ + SolarMutexGuard aGuard; + static uno::Reference<beans::XPropertySetInfo> aRef( + new SfxItemPropertySetInfo( aPropSet.getPropertyMap() )); + return aRef; +} + +void SAL_CALL ScSheetLinkObj::setPropertyValue( + const OUString& aPropertyName, const uno::Any& aValue ) +{ + SolarMutexGuard aGuard; + OUString aValStr; + if ( aPropertyName == SC_UNONAME_LINKURL ) + { + if ( aValue >>= aValStr ) + setFileName( aValStr ); + } + else if ( aPropertyName == SC_UNONAME_FILTER ) + { + if ( aValue >>= aValStr ) + setFilter( aValStr ); + } + else if ( aPropertyName == SC_UNONAME_FILTOPT ) + { + if ( aValue >>= aValStr ) + setFilterOptions( aValStr ); + } + else if ( aPropertyName == SC_UNONAME_REFPERIOD ) + { + sal_Int32 nRefresh = 0; + if ( aValue >>= nRefresh ) + setRefreshDelay( nRefresh ); + } + else if ( aPropertyName == SC_UNONAME_REFDELAY ) + { + sal_Int32 nRefresh = 0; + if ( aValue >>= nRefresh ) + setRefreshDelay( nRefresh ); + } +} + +uno::Any SAL_CALL ScSheetLinkObj::getPropertyValue( const OUString& aPropertyName ) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + if ( aPropertyName == SC_UNONAME_LINKURL ) + aRet <<= getFileName(); + else if ( aPropertyName == SC_UNONAME_FILTER ) + aRet <<= getFilter(); + else if ( aPropertyName == SC_UNONAME_FILTOPT ) + aRet <<= getFilterOptions(); + else if ( aPropertyName == SC_UNONAME_REFPERIOD ) + aRet <<= getRefreshDelay(); + else if ( aPropertyName == SC_UNONAME_REFDELAY ) + aRet <<= getRefreshDelay(); + return aRet; +} + +SC_IMPL_DUMMY_PROPERTY_LISTENER( ScSheetLinkObj ) + +// internal: + +OUString ScSheetLinkObj::getFileName() const +{ + SolarMutexGuard aGuard; + return aFileName; +} + +void ScSheetLinkObj::setFileName(const OUString& rNewName) +{ + SolarMutexGuard aGuard; + ScTableLink* pLink = GetLink_Impl(); + if (!pLink) + return; + + // pLink->Refresh with a new file name confuses sfx2::LinkManager + // therefore we transplant the sheets manually and create new links with UpdateLinks + + OUString aNewStr(ScGlobal::GetAbsDocName( rNewName, pDocShell )); + + // first transplant the sheets + + ScDocument& rDoc = pDocShell->GetDocument(); + SCTAB nTabCount = rDoc.GetTableCount(); + for (SCTAB nTab=0; nTab<nTabCount; nTab++) + if ( rDoc.IsLinked(nTab) && rDoc.GetLinkDoc(nTab) == aFileName ) // old file + rDoc.SetLink( nTab, rDoc.GetLinkMode(nTab), aNewStr, + rDoc.GetLinkFlt(nTab), rDoc.GetLinkOpt(nTab), + rDoc.GetLinkTab(nTab), + rDoc.GetLinkRefreshDelay(nTab) ); // only change the file + + // update links + //! Undo !!! + + pDocShell->UpdateLinks(); // remove old links, possibly set up new ones + + // copy data + + aFileName = aNewStr; + pLink = GetLink_Impl(); // new link with new name + if (pLink) + pLink->Update(); // incl. paint & undo for data +} + +OUString ScSheetLinkObj::getFilter() const +{ + SolarMutexGuard aGuard; + OUString aRet; + ScTableLink* pLink = GetLink_Impl(); + if (pLink) + aRet = pLink->GetFilterName(); + return aRet; +} + +void ScSheetLinkObj::setFilter(const OUString& rFilter) +{ + SolarMutexGuard aGuard; + ScTableLink* pLink = GetLink_Impl(); + if (pLink) + { + pLink->Refresh( aFileName, rFilter, nullptr, pLink->GetRefreshDelaySeconds() ); + } +} + +OUString ScSheetLinkObj::getFilterOptions() const +{ + SolarMutexGuard aGuard; + OUString aRet; + ScTableLink* pLink = GetLink_Impl(); + if (pLink) + aRet = pLink->GetOptions(); + return aRet; +} + +void ScSheetLinkObj::setFilterOptions(const OUString& FilterOptions) +{ + SolarMutexGuard aGuard; + ScTableLink* pLink = GetLink_Impl(); + if (pLink) + { + OUString aOptStr(FilterOptions); + pLink->Refresh( aFileName, pLink->GetFilterName(), &aOptStr, pLink->GetRefreshDelaySeconds() ); + } +} + +sal_Int32 ScSheetLinkObj::getRefreshDelay() const +{ + SolarMutexGuard aGuard; + sal_Int32 nRet = 0; + ScTableLink* pLink = GetLink_Impl(); + if (pLink) + nRet = pLink->GetRefreshDelaySeconds(); + return nRet; +} + +void ScSheetLinkObj::setRefreshDelay(sal_Int32 nRefreshDelay) +{ + SolarMutexGuard aGuard; + ModifyRefreshDelay_Impl( nRefreshDelay ); +} + +ScSheetLinksObj::ScSheetLinksObj(ScDocShell* pDocSh) : + pDocShell( pDocSh ) +{ + pDocShell->GetDocument().AddUnoObject(*this); +} + +ScSheetLinksObj::~ScSheetLinksObj() +{ + SolarMutexGuard g; + + if (pDocShell) + pDocShell->GetDocument().RemoveUnoObject(*this); +} + +void ScSheetLinksObj::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + // we don't care about update of references here + + if ( rHint.GetId() == SfxHintId::Dying ) + { + pDocShell = nullptr; // became invalid + } +} + +// XSheetLinks + +rtl::Reference<ScSheetLinkObj> ScSheetLinksObj::GetObjectByIndex_Impl(sal_Int32 nIndex) +{ + if (!pDocShell) + return nullptr; + + typedef std::unordered_set<OUString> StrSetType; + StrSetType aNames; + ScDocument& rDoc = pDocShell->GetDocument(); + SCTAB nTabCount = rDoc.GetTableCount(); + sal_Int32 nCount = 0; + for (SCTAB nTab = 0; nTab < nTabCount; ++nTab) + { + if (!rDoc.IsLinked(nTab)) + continue; + + OUString aLinkDoc = rDoc.GetLinkDoc(nTab); + if (aNames.insert(aLinkDoc).second) + { + // unique document name. + if (nCount == nIndex) + return new ScSheetLinkObj( pDocShell, aLinkDoc ); + ++nCount; + } + } + + return nullptr; // no document or index too large +} + +rtl::Reference<ScSheetLinkObj> ScSheetLinksObj::GetObjectByName_Impl(const OUString& aName) +{ + // Name is the same as file name + + if (pDocShell) + { + ScDocument& rDoc = pDocShell->GetDocument(); + SCTAB nTabCount = rDoc.GetTableCount(); + for (SCTAB nTab=0; nTab<nTabCount; nTab++) + if (rDoc.IsLinked(nTab)) + { + //! case-insensitive ??? + OUString aLinkDoc = rDoc.GetLinkDoc( nTab ); + if ( aLinkDoc == aName ) + return new ScSheetLinkObj( pDocShell, aName ); + } + } + + return nullptr; +} + +// XEnumerationAccess +uno::Reference<container::XEnumeration> SAL_CALL ScSheetLinksObj::createEnumeration() +{ + SolarMutexGuard aGuard; + return new ScIndexEnumeration(this, "com.sun.star.sheet.SheetLinksEnumeration"); +} + +// XIndexAccess +sal_Int32 SAL_CALL ScSheetLinksObj::getCount() +{ + typedef std::unordered_set<OUString> StrSetType; + + SolarMutexGuard aGuard; + if (!pDocShell) + return 0; + + sal_Int32 nCount = 0; + + StrSetType aNames; + ScDocument& rDoc = pDocShell->GetDocument(); + SCTAB nTabCount = rDoc.GetTableCount(); + for (SCTAB nTab = 0; nTab < nTabCount; ++nTab) + { + if (!rDoc.IsLinked(nTab)) + continue; + + OUString aLinkDoc = rDoc.GetLinkDoc(nTab); + if (aNames.insert(aLinkDoc).second) + ++nCount; + } + return nCount; +} + +uno::Any SAL_CALL ScSheetLinksObj::getByIndex( sal_Int32 nIndex ) +{ + SolarMutexGuard aGuard; + uno::Reference<beans::XPropertySet> xLink(GetObjectByIndex_Impl(nIndex)); + if (!xLink.is()) + throw lang::IndexOutOfBoundsException(); + + return uno::Any(xLink); +} + +uno::Type SAL_CALL ScSheetLinksObj::getElementType() +{ + return cppu::UnoType<beans::XPropertySet>::get(); +} + +sal_Bool SAL_CALL ScSheetLinksObj::hasElements() +{ + SolarMutexGuard aGuard; + return ( getCount() != 0 ); +} + +uno::Any SAL_CALL ScSheetLinksObj::getByName( const OUString& aName ) +{ + SolarMutexGuard aGuard; + uno::Reference<beans::XPropertySet> xLink(GetObjectByName_Impl(aName)); + if (!xLink.is()) + throw container::NoSuchElementException(); + + return uno::Any(xLink); +} + +sal_Bool SAL_CALL ScSheetLinksObj::hasByName( const OUString& aName ) +{ + SolarMutexGuard aGuard; + // Name is the same as file name + + if (pDocShell) + { + ScDocument& rDoc = pDocShell->GetDocument(); + SCTAB nTabCount = rDoc.GetTableCount(); + for (SCTAB nTab=0; nTab<nTabCount; nTab++) + if (rDoc.IsLinked(nTab)) + { + //! case-insensitive ??? + OUString aLinkDoc(rDoc.GetLinkDoc( nTab )); + if ( aLinkDoc == aName ) + return true; + } + } + return false; +} + +uno::Sequence<OUString> SAL_CALL ScSheetLinksObj::getElementNames() +{ + typedef std::unordered_set<OUString> StrSetType; + + SolarMutexGuard aGuard; + // Name is the same as file name + + if (!pDocShell) + return uno::Sequence<OUString>(); + + StrSetType aNames; + ScDocument& rDoc = pDocShell->GetDocument(); + SCTAB nTabCount = rDoc.GetTableCount(); + + sal_Int32 nLinkCount = getCount(); + uno::Sequence<OUString> aSeq(nLinkCount); + OUString* pAry = aSeq.getArray(); + size_t nPos = 0; + for (SCTAB nTab = 0; nTab < nTabCount; ++nTab) + { + if (!rDoc.IsLinked(nTab)) + continue; + + OUString aLinkDoc = rDoc.GetLinkDoc(nTab); + if (aNames.insert(aLinkDoc).second) + pAry[nPos++] = aLinkDoc; + } + OSL_ENSURE( nPos==static_cast<size_t>(nLinkCount), "verzaehlt" ); + return aSeq; +} + +static ScAreaLink* lcl_GetAreaLink( ScDocShell* pDocShell, size_t nPos ) +{ + if (pDocShell) + { + sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager(); + size_t nTotalCount = pLinkManager->GetLinks().size(); + size_t nAreaCount = 0; + for (size_t i=0; i<nTotalCount; i++) + { + ::sfx2::SvBaseLink* pBase = pLinkManager->GetLinks()[i].get(); + if (auto pAreaLink = dynamic_cast<ScAreaLink*>( pBase)) + { + if ( nAreaCount == nPos ) + return pAreaLink; + ++nAreaCount; + } + } + } + return nullptr; // not found +} + +ScAreaLinkObj::ScAreaLinkObj(ScDocShell* pDocSh, size_t nP) : + aPropSet( lcl_GetSheetLinkMap() ), + pDocShell( pDocSh ), + nPos( nP ) +{ + pDocShell->GetDocument().AddUnoObject(*this); +} + +ScAreaLinkObj::~ScAreaLinkObj() +{ + SolarMutexGuard g; + + if (pDocShell) + pDocShell->GetDocument().RemoveUnoObject(*this); +} + +void ScAreaLinkObj::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + //! notify if links in document are changed + // UpdateRef is not needed here + + if ( auto pRefreshedHint = dynamic_cast<const ScLinkRefreshedHint*>(&rHint) ) + { + if ( pRefreshedHint->GetLinkType() == ScLinkRefType::AREA ) + { + // get this link to compare dest position + ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos); + if ( pLink && pLink->GetDestArea().aStart == pRefreshedHint->GetDestPos() ) + Refreshed_Impl(); + } + } + else + { + if ( rHint.GetId() == SfxHintId::Dying ) + pDocShell = nullptr; // pointer is invalid + } +} + +// XFileLink + +void ScAreaLinkObj::Modify_Impl( const OUString* pNewFile, const OUString* pNewFilter, + const OUString* pNewOptions, const OUString* pNewSource, + const table::CellRangeAddress* pNewDest ) +{ + ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos); + if (!pLink) + return; + + OUString aFile (pLink->GetFile()); + OUString aFilter (pLink->GetFilter()); + OUString aOptions (pLink->GetOptions()); + OUString aSource (pLink->GetSource()); + ScRange aDest (pLink->GetDestArea()); + sal_Int32 nRefreshDelaySeconds = pLink->GetRefreshDelaySeconds(); + + //! Undo delete + //! Undo merge + + sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager(); + pLinkManager->Remove( pLink ); + pLink = nullptr; // deleted along with remove + + bool bFitBlock = true; // move, if the size changes with update + if (pNewFile) + { + aFile = ScGlobal::GetAbsDocName( *pNewFile, pDocShell ); //! in InsertAreaLink? + } + if (pNewFilter) + aFilter = *pNewFilter; + if (pNewOptions) + aOptions = *pNewOptions; + if (pNewSource) + aSource = *pNewSource; + if (pNewDest) + { + ScUnoConversion::FillScRange( aDest, *pNewDest ); + bFitBlock = false; // new range was specified -> do not move the content + } + pDocShell->GetDocFunc().InsertAreaLink( aFile, aFilter, aOptions, aSource, + aDest, nRefreshDelaySeconds, bFitBlock, true ); +} + +void ScAreaLinkObj::ModifyRefreshDelay_Impl( sal_Int32 nRefreshDelaySeconds ) +{ + ScAreaLink* pLink = lcl_GetAreaLink( pDocShell, nPos ); + if( pLink ) + pLink->SetRefreshDelay( nRefreshDelaySeconds ); +} + +// XRefreshable + +void SAL_CALL ScAreaLinkObj::refresh() +{ + SolarMutexGuard aGuard; + ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos); + if (pLink) + pLink->Refresh( pLink->GetFile(), pLink->GetFilter(), pLink->GetSource(), pLink->GetRefreshDelaySeconds() ); +} + +void SAL_CALL ScAreaLinkObj::addRefreshListener( + const uno::Reference<util::XRefreshListener >& xListener ) +{ + SolarMutexGuard aGuard; + aRefreshListeners.push_back( xListener ); + + // hold one additional ref to keep this object alive as long as there are listeners + if ( aRefreshListeners.size() == 1 ) + acquire(); +} + +void SAL_CALL ScAreaLinkObj::removeRefreshListener( + const uno::Reference<util::XRefreshListener >& xListener ) +{ + SolarMutexGuard aGuard; + size_t nCount = aRefreshListeners.size(); + for ( size_t n=nCount; n--; ) + { + uno::Reference<util::XRefreshListener>& rObj = aRefreshListeners[n]; + if ( rObj == xListener ) + { + aRefreshListeners.erase( aRefreshListeners.begin() + n ); + if ( aRefreshListeners.empty() ) + release(); // release ref for listeners + break; + } + + if(n == 0) + break; + } +} + +void ScAreaLinkObj::Refreshed_Impl() +{ + lang::EventObject aEvent; + aEvent.Source.set(getXWeak()); + for (uno::Reference<util::XRefreshListener> & xRefreshListener : aRefreshListeners) + xRefreshListener->refreshed( aEvent ); +} + +// XPropertySet + +uno::Reference<beans::XPropertySetInfo> SAL_CALL ScAreaLinkObj::getPropertySetInfo() +{ + SolarMutexGuard aGuard; + static uno::Reference<beans::XPropertySetInfo> aRef( + new SfxItemPropertySetInfo( aPropSet.getPropertyMap() )); + return aRef; +} + +void SAL_CALL ScAreaLinkObj::setPropertyValue( + const OUString& aPropertyName, const uno::Any& aValue ) +{ + SolarMutexGuard aGuard; + OUString aValStr; + if ( aPropertyName == SC_UNONAME_LINKURL ) + { + if ( aValue >>= aValStr ) + setFileName( aValStr ); + } + else if ( aPropertyName == SC_UNONAME_FILTER ) + { + if ( aValue >>= aValStr ) + setFilter( aValStr ); + } + else if ( aPropertyName == SC_UNONAME_FILTOPT ) + { + if ( aValue >>= aValStr ) + setFilterOptions( aValStr ); + } + else if ( aPropertyName == SC_UNONAME_REFPERIOD ) + { + sal_Int32 nRefresh = 0; + if ( aValue >>= nRefresh ) + setRefreshDelay( nRefresh ); + } + else if ( aPropertyName == SC_UNONAME_REFDELAY ) + { + sal_Int32 nRefresh = 0; + if ( aValue >>= nRefresh ) + setRefreshDelay( nRefresh ); + } +} + +uno::Any SAL_CALL ScAreaLinkObj::getPropertyValue( const OUString& aPropertyName ) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + if ( aPropertyName == SC_UNONAME_LINKURL ) + aRet <<= getFileName(); + else if ( aPropertyName == SC_UNONAME_FILTER ) + aRet <<= getFilter(); + else if ( aPropertyName == SC_UNONAME_FILTOPT ) + aRet <<= getFilterOptions(); + else if ( aPropertyName == SC_UNONAME_REFPERIOD ) + aRet <<= getRefreshDelay(); + else if ( aPropertyName == SC_UNONAME_REFDELAY ) + aRet <<= getRefreshDelay(); + return aRet; +} + +SC_IMPL_DUMMY_PROPERTY_LISTENER( ScAreaLinkObj ) + +// internal: + +OUString ScAreaLinkObj::getFileName() const +{ + SolarMutexGuard aGuard; + OUString aRet; + ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos); + if (pLink) + aRet = pLink->GetFile(); + return aRet; +} + +void ScAreaLinkObj::setFileName(const OUString& rNewName) +{ + SolarMutexGuard aGuard; + Modify_Impl( &rNewName, nullptr, nullptr, nullptr, nullptr ); +} + +OUString ScAreaLinkObj::getFilter() const +{ + SolarMutexGuard aGuard; + OUString aRet; + ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos); + if (pLink) + aRet = pLink->GetFilter(); + return aRet; +} + +void ScAreaLinkObj::setFilter(const OUString& Filter) +{ + SolarMutexGuard aGuard; + Modify_Impl( nullptr, &Filter, nullptr, nullptr, nullptr ); +} + +OUString ScAreaLinkObj::getFilterOptions() const +{ + SolarMutexGuard aGuard; + OUString aRet; + ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos); + if (pLink) + aRet = pLink->GetOptions(); + return aRet; +} + +void ScAreaLinkObj::setFilterOptions(const OUString& FilterOptions) +{ + SolarMutexGuard aGuard; + Modify_Impl( nullptr, nullptr, &FilterOptions, nullptr, nullptr ); +} + +sal_Int32 ScAreaLinkObj::getRefreshDelay() const +{ + SolarMutexGuard aGuard; + sal_Int32 nRet = 0; + ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos); + if (pLink) + nRet = pLink->GetRefreshDelaySeconds(); + return nRet; +} + +void ScAreaLinkObj::setRefreshDelay(sal_Int32 nRefreshDelay) +{ + SolarMutexGuard aGuard; + ModifyRefreshDelay_Impl( nRefreshDelay ); +} + +// XAreaLink + +OUString SAL_CALL ScAreaLinkObj::getSourceArea() +{ + SolarMutexGuard aGuard; + OUString aRet; + ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos); + if (pLink) + aRet = pLink->GetSource(); + return aRet; +} + +void SAL_CALL ScAreaLinkObj::setSourceArea( const OUString& aSourceArea ) +{ + SolarMutexGuard aGuard; + Modify_Impl( nullptr, nullptr, nullptr, &aSourceArea, nullptr ); +} + +table::CellRangeAddress SAL_CALL ScAreaLinkObj::getDestArea() +{ + SolarMutexGuard aGuard; + table::CellRangeAddress aRet; + ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos); + if (pLink) + ScUnoConversion::FillApiRange( aRet, pLink->GetDestArea() ); + return aRet; +} + +void SAL_CALL ScAreaLinkObj::setDestArea( const table::CellRangeAddress& aDestArea ) +{ + SolarMutexGuard aGuard; + Modify_Impl( nullptr, nullptr, nullptr, nullptr, &aDestArea ); +} + +ScAreaLinksObj::ScAreaLinksObj(ScDocShell* pDocSh) : + pDocShell( pDocSh ) +{ + pDocShell->GetDocument().AddUnoObject(*this); +} + +ScAreaLinksObj::~ScAreaLinksObj() +{ + SolarMutexGuard g; + + if (pDocShell) + pDocShell->GetDocument().RemoveUnoObject(*this); +} + +void ScAreaLinksObj::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + // we don't care about update of references here + + if ( rHint.GetId() == SfxHintId::Dying ) + { + pDocShell = nullptr; // became invalid + } +} + +// XAreaLinks + +rtl::Reference<ScAreaLinkObj> ScAreaLinksObj::GetObjectByIndex_Impl(sal_Int32 nIndex) +{ + if ( pDocShell && nIndex >= 0 && nIndex < getCount() ) + return new ScAreaLinkObj( pDocShell, static_cast<size_t>(nIndex) ); + + return nullptr; // not found +} + +void SAL_CALL ScAreaLinksObj::insertAtPosition( const table::CellAddress& aDestPos, + const OUString& aFileName, + const OUString& aSourceArea, + const OUString& aFilter, + const OUString& aFilterOptions ) +{ + SolarMutexGuard aGuard; + if (pDocShell) + { + OUString aFileStr (aFileName); + ScAddress aDestAddr( static_cast<SCCOL>(aDestPos.Column), static_cast<SCROW>(aDestPos.Row), aDestPos.Sheet ); + + aFileStr = ScGlobal::GetAbsDocName( aFileStr, pDocShell ); //! in InsertAreaLink ??? + pDocShell->GetDocFunc().InsertAreaLink( aFileStr, aFilter, aFilterOptions, + aSourceArea, ScRange(aDestAddr), + /*nRefreshDelaySeconds*/0, false, true ); // don't move contents + } +} + +void SAL_CALL ScAreaLinksObj::removeByIndex( sal_Int32 nIndex ) +{ + SolarMutexGuard aGuard; + ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, static_cast<size_t>(nIndex)); + if (pLink) + { + //! SetAddUndo or what + + sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager(); + pLinkManager->Remove( pLink ); + } +} + +// XEnumerationAccess + +uno::Reference<container::XEnumeration> SAL_CALL ScAreaLinksObj::createEnumeration() +{ + SolarMutexGuard aGuard; + return new ScIndexEnumeration(this, "com.sun.star.sheet.CellAreaLinksEnumeration"); +} + +// XIndexAccess + +sal_Int32 SAL_CALL ScAreaLinksObj::getCount() +{ + SolarMutexGuard aGuard; + sal_Int32 nAreaCount = 0; + if (pDocShell) + { + sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager(); + size_t nTotalCount = pLinkManager->GetLinks().size(); + for (size_t i=0; i<nTotalCount; i++) + { + ::sfx2::SvBaseLink* pBase = pLinkManager->GetLinks()[i].get(); + if (dynamic_cast<const ScAreaLink*>( pBase) != nullptr) + ++nAreaCount; + } + } + return nAreaCount; +} + +uno::Any SAL_CALL ScAreaLinksObj::getByIndex( sal_Int32 nIndex ) +{ + SolarMutexGuard aGuard; + uno::Reference<sheet::XAreaLink> xLink(GetObjectByIndex_Impl(nIndex)); + if (!xLink.is()) + throw lang::IndexOutOfBoundsException(); + + return uno::Any(xLink); + +} + +uno::Type SAL_CALL ScAreaLinksObj::getElementType() +{ + return cppu::UnoType<sheet::XAreaLink>::get(); +} + +sal_Bool SAL_CALL ScAreaLinksObj::hasElements() +{ + SolarMutexGuard aGuard; + return ( getCount() != 0 ); +} + +ScDDELinkObj::ScDDELinkObj(ScDocShell* pDocSh, OUString aA, + OUString aT, OUString aI) : + pDocShell( pDocSh ), + aAppl(std::move( aA )), + aTopic(std::move( aT )), + aItem(std::move( aI )) +{ + pDocShell->GetDocument().AddUnoObject(*this); +} + +ScDDELinkObj::~ScDDELinkObj() +{ + SolarMutexGuard g; + + if (pDocShell) + pDocShell->GetDocument().RemoveUnoObject(*this); +} + +void ScDDELinkObj::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + //! notify if links in document are changed + // UpdateRef is not needed here + + if ( auto pRefreshedHint = dynamic_cast<const ScLinkRefreshedHint*>(&rHint) ) + { + if ( pRefreshedHint->GetLinkType() == ScLinkRefType::DDE && + pRefreshedHint->GetDdeAppl() == aAppl && + pRefreshedHint->GetDdeTopic() == aTopic && + pRefreshedHint->GetDdeItem() == aItem ) //! mode is ignored + Refreshed_Impl(); + } + else + { + if ( rHint.GetId() == SfxHintId::Dying ) + pDocShell = nullptr; // pointer is invalid + } +} + +// XNamed + +static OUString lcl_BuildDDEName( std::u16string_view rAppl, std::u16string_view rTopic, std::u16string_view rItem ) +{ + // Appl|Topic!Item (like Excel) + OUString aRet = OUString::Concat(rAppl) + "|" + rTopic + "!" + rItem; + return aRet; +} + +OUString SAL_CALL ScDDELinkObj::getName() +{ + SolarMutexGuard aGuard; + return lcl_BuildDDEName( aAppl, aTopic, aItem ); +} + +void SAL_CALL ScDDELinkObj::setName( const OUString& /* aName */ ) +{ + // name can't be changed (formulas wouldn't find the link) + throw uno::RuntimeException(); +} + +// XDDELink + +OUString SAL_CALL ScDDELinkObj::getApplication() +{ + //! Test if the link is still in the document? + + return aAppl; +} + +OUString SAL_CALL ScDDELinkObj::getTopic() +{ + //! Test if the link is still in the document? + + return aTopic; +} + +OUString SAL_CALL ScDDELinkObj::getItem() +{ + //! Test if the link is still in the document? + + return aItem; +} + +// XRefreshable + +void SAL_CALL ScDDELinkObj::refresh() +{ + SolarMutexGuard aGuard; + if (pDocShell) + { + sc::DocumentLinkManager& rMgr = pDocShell->GetDocument().GetDocLinkManager(); + rMgr.updateDdeLink(aAppl, aTopic, aItem); + } +} + +void SAL_CALL ScDDELinkObj::addRefreshListener( + const uno::Reference<util::XRefreshListener >& xListener ) +{ + SolarMutexGuard aGuard; + aRefreshListeners.push_back( xListener ); + + // hold one additional ref to keep this object alive as long as there are listeners + if ( aRefreshListeners.size() == 1 ) + acquire(); +} + +void SAL_CALL ScDDELinkObj::removeRefreshListener( + const uno::Reference<util::XRefreshListener >& xListener ) +{ + SolarMutexGuard aGuard; + size_t nCount = aRefreshListeners.size(); + for ( size_t n=nCount; n--; ) + { + uno::Reference<util::XRefreshListener>& rObj = aRefreshListeners[n]; + if ( rObj == xListener ) + { + aRefreshListeners.erase( aRefreshListeners.begin() + n ); + if ( aRefreshListeners.empty() ) + release(); // release ref for listeners + break; + } + } +} + +// XDDELinkResults + +uno::Sequence< uno::Sequence< uno::Any > > ScDDELinkObj::getResults( ) +{ + SolarMutexGuard aGuard; + uno::Sequence< uno::Sequence< uno::Any > > aReturn; + bool bSuccess = false; + + if ( pDocShell ) + { + ScDocument& rDoc = pDocShell->GetDocument(); + size_t nPos = 0; + if ( rDoc.FindDdeLink( aAppl, aTopic, aItem, SC_DDE_IGNOREMODE, nPos ) ) + { + const ScMatrix* pMatrix = rDoc.GetDdeLinkResultMatrix( nPos ); + if ( pMatrix ) + { + uno::Any aAny; + if ( ScRangeToSequence::FillMixedArray( aAny, pMatrix, true ) ) + { + aAny >>= aReturn; + } + } + bSuccess = true; + } + } + + if ( !bSuccess ) + { + throw uno::RuntimeException( + "ScDDELinkObj::getResults: failed to get results!" ); + } + + return aReturn; +} + +void ScDDELinkObj::setResults( const uno::Sequence< uno::Sequence< uno::Any > >& aResults ) +{ + SolarMutexGuard aGuard; + bool bSuccess = false; + + if ( pDocShell ) + { + ScDocument& rDoc = pDocShell->GetDocument(); + size_t nPos = 0; + if ( rDoc.FindDdeLink( aAppl, aTopic, aItem, SC_DDE_IGNOREMODE, nPos ) ) + { + ScMatrixRef xMatrix = ScSequenceToMatrix::CreateMixedMatrix( Any(aResults) ); + bSuccess = rDoc.SetDdeLinkResultMatrix( nPos, xMatrix ); + } + } + + if ( !bSuccess ) + { + throw uno::RuntimeException( + "ScDDELinkObj::setResults: failed to set results!" ); + } +} + +void ScDDELinkObj::Refreshed_Impl() +{ + lang::EventObject aEvent; + aEvent.Source.set(getXWeak()); + for (uno::Reference<util::XRefreshListener> & xRefreshListener : aRefreshListeners) + xRefreshListener->refreshed( aEvent ); +} + +ScDDELinksObj::ScDDELinksObj(ScDocShell* pDocSh) : + pDocShell( pDocSh ) +{ + pDocShell->GetDocument().AddUnoObject(*this); +} + +ScDDELinksObj::~ScDDELinksObj() +{ + SolarMutexGuard g; + + if (pDocShell) + pDocShell->GetDocument().RemoveUnoObject(*this); +} + +void ScDDELinksObj::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + // we don't care about update of references here + + if ( rHint.GetId() == SfxHintId::Dying ) + { + pDocShell = nullptr; // became invalid + } +} + +// XDDELinks + +rtl::Reference<ScDDELinkObj> ScDDELinksObj::GetObjectByIndex_Impl(sal_Int32 nIndex) +{ + if (pDocShell) + { + OUString aAppl, aTopic, aItem; + if ( pDocShell->GetDocument().GetDdeLinkData( static_cast<size_t>(nIndex), aAppl, aTopic, aItem ) ) + return new ScDDELinkObj( pDocShell, aAppl, aTopic, aItem ); + } + return nullptr; +} + +rtl::Reference<ScDDELinkObj> ScDDELinksObj::GetObjectByName_Impl(std::u16string_view aName) +{ + if (pDocShell) + { + OUString aAppl, aTopic, aItem; + + ScDocument& rDoc = pDocShell->GetDocument(); + size_t nCount = rDoc.GetDocLinkManager().getDdeLinkCount(); + for (size_t i=0; i<nCount; i++) + { + rDoc.GetDdeLinkData( i, aAppl, aTopic, aItem ); + if ( lcl_BuildDDEName(aAppl, aTopic, aItem) == aName ) + return new ScDDELinkObj( pDocShell, aAppl, aTopic, aItem ); + } + } + return nullptr; +} + +// XEnumerationAccess + +uno::Reference<container::XEnumeration> SAL_CALL ScDDELinksObj::createEnumeration() +{ + SolarMutexGuard aGuard; + return new ScIndexEnumeration(this, "com.sun.star.sheet.DDELinksEnumeration"); +} + +// XIndexAccess + +sal_Int32 SAL_CALL ScDDELinksObj::getCount() +{ + SolarMutexGuard aGuard; + sal_Int32 nAreaCount = 0; + if (pDocShell) + nAreaCount = pDocShell->GetDocument().GetDocLinkManager().getDdeLinkCount(); + return nAreaCount; +} + +uno::Any SAL_CALL ScDDELinksObj::getByIndex( sal_Int32 nIndex ) +{ + SolarMutexGuard aGuard; + uno::Reference<sheet::XDDELink> xLink(GetObjectByIndex_Impl(nIndex)); + if (!xLink.is()) + throw lang::IndexOutOfBoundsException(); + + return uno::Any(xLink); +} + +uno::Type SAL_CALL ScDDELinksObj::getElementType() +{ + return cppu::UnoType<sheet::XDDELink>::get(); +} + +sal_Bool SAL_CALL ScDDELinksObj::hasElements() +{ + SolarMutexGuard aGuard; + return ( getCount() != 0 ); +} + +uno::Any SAL_CALL ScDDELinksObj::getByName( const OUString& aName ) +{ + SolarMutexGuard aGuard; + uno::Reference<sheet::XDDELink> xLink(GetObjectByName_Impl(aName)); + if (!xLink.is()) + throw container::NoSuchElementException(); + + return uno::Any(xLink); +} + +uno::Sequence<OUString> SAL_CALL ScDDELinksObj::getElementNames() +{ + SolarMutexGuard aGuard; + if (pDocShell) + { + OUString aAppl, aTopic, aItem; + + ScDocument& rDoc = pDocShell->GetDocument(); + size_t nCount = pDocShell->GetDocument().GetDocLinkManager().getDdeLinkCount(); + uno::Sequence<OUString> aSeq(nCount); + OUString* pAry = aSeq.getArray(); + + for (size_t i=0; i<nCount; i++) + { + rDoc.GetDdeLinkData( i, aAppl, aTopic, aItem ); + pAry[i] = lcl_BuildDDEName(aAppl, aTopic, aItem); + } + return aSeq; + } + return uno::Sequence<OUString>(); +} + +sal_Bool SAL_CALL ScDDELinksObj::hasByName( const OUString& aName ) +{ + SolarMutexGuard aGuard; + if (pDocShell) + { + OUString aAppl, aTopic, aItem; + + ScDocument& rDoc = pDocShell->GetDocument(); + size_t nCount = pDocShell->GetDocument().GetDocLinkManager().getDdeLinkCount(); + for (size_t i=0; i<nCount; i++) + { + rDoc.GetDdeLinkData( i, aAppl, aTopic, aItem ); + if ( lcl_BuildDDEName(aAppl, aTopic, aItem) == aName ) + return true; + } + } + return false; +} + +// XDDELinks + +uno::Reference< sheet::XDDELink > ScDDELinksObj::addDDELink( + const OUString& aApplication, const OUString& aTopic, + const OUString& aItem, css::sheet::DDELinkMode nMode ) +{ + SolarMutexGuard aGuard; + uno::Reference< sheet::XDDELink > xLink; + + if ( pDocShell ) + { + ScDocument& rDoc = pDocShell->GetDocument(); + sal_uInt8 nMod = SC_DDE_DEFAULT; + switch ( nMode ) + { + case sheet::DDELinkMode_DEFAULT: + { + nMod = SC_DDE_DEFAULT; + } + break; + case sheet::DDELinkMode_ENGLISH: + { + nMod = SC_DDE_ENGLISH; + } + break; + case sheet::DDELinkMode_TEXT: + { + nMod = SC_DDE_TEXT; + } + break; + default: + { + } + break; + } + + if ( rDoc.CreateDdeLink( aApplication, aTopic, aItem, nMod, ScMatrixRef() ) ) + { + const OUString aName( lcl_BuildDDEName( aApplication, aTopic, aItem ) ); + xLink.set( GetObjectByName_Impl( aName ) ); + } + } + + if ( !xLink.is() ) + { + throw uno::RuntimeException( + "ScDDELinksObj::addDDELink: cannot add DDE link!" ); + } + + return xLink; +} + +ScExternalSheetCacheObj::ScExternalSheetCacheObj(ScDocShell* pDocShell, ScExternalRefCache::TableTypeRef pTable, size_t nIndex) : + mpDocShell(pDocShell), + mpTable(std::move(pTable)), + mnIndex(nIndex) +{ +} + +ScExternalSheetCacheObj::~ScExternalSheetCacheObj() +{ +} + +void SAL_CALL ScExternalSheetCacheObj::setCellValue(sal_Int32 nCol, sal_Int32 nRow, const Any& rValue) +{ + SolarMutexGuard aGuard; + if (nRow < 0 || nCol < 0) + throw IllegalArgumentException(); + + ScExternalRefCache::TokenRef pToken; + double fVal = 0.0; + OUString aVal; + if (rValue >>= fVal) + pToken.reset(new FormulaDoubleToken(fVal)); + else if (rValue >>= aVal) + { + svl::SharedStringPool& rPool = mpDocShell->GetDocument().GetSharedStringPool(); + svl::SharedString aSS = rPool.intern(aVal); + pToken.reset(new FormulaStringToken(std::move(aSS))); + } + else + // unidentified value type. + return; + + mpTable->setCell(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), pToken); +} + +Any SAL_CALL ScExternalSheetCacheObj::getCellValue(sal_Int32 nCol, sal_Int32 nRow) +{ + SolarMutexGuard aGuard; + if (nRow < 0 || nCol < 0) + throw IllegalArgumentException(); + + FormulaToken* pToken = mpTable->getCell(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow)).get(); + if (!pToken) + throw IllegalArgumentException(); + + Any aValue; + switch (pToken->GetType()) + { + case svDouble: + { + double fVal = pToken->GetDouble(); + aValue <<= fVal; + } + break; + case svString: + { + OUString aVal = pToken->GetString().getString(); + aValue <<= aVal; + } + break; + default: + throw IllegalArgumentException(); + } + return aValue; +} + +Sequence< sal_Int32 > SAL_CALL ScExternalSheetCacheObj::getAllRows() +{ + SolarMutexGuard aGuard; + vector<SCROW> aRows; + mpTable->getAllRows(aRows); + size_t nSize = aRows.size(); + Sequence<sal_Int32> aRowsSeq(nSize); + auto aRowsSeqRange = asNonConstRange(aRowsSeq); + for (size_t i = 0; i < nSize; ++i) + aRowsSeqRange[i] = aRows[i]; + + return aRowsSeq; +} + +Sequence< sal_Int32 > SAL_CALL ScExternalSheetCacheObj::getAllColumns(sal_Int32 nRow) +{ + SolarMutexGuard aGuard; + if (nRow < 0) + throw IllegalArgumentException(); + + vector<SCCOL> aCols; + mpTable->getAllCols(static_cast<SCROW>(nRow), aCols); + size_t nSize = aCols.size(); + Sequence<sal_Int32> aColsSeq(nSize); + auto aColsSeqRange = asNonConstRange(aColsSeq); + for (size_t i = 0; i < nSize; ++i) + aColsSeqRange[i] = aCols[i]; + + return aColsSeq; +} + +sal_Int32 SAL_CALL ScExternalSheetCacheObj::getTokenIndex() +{ + return static_cast< sal_Int32 >( mnIndex ); +} + +ScExternalDocLinkObj::ScExternalDocLinkObj(ScDocShell* pDocShell, ScExternalRefManager* pRefMgr, sal_uInt16 nFileId) : + mpDocShell(pDocShell), mpRefMgr(pRefMgr), mnFileId(nFileId) +{ +} + +ScExternalDocLinkObj::~ScExternalDocLinkObj() +{ +} + +uno::Reference< sheet::XExternalSheetCache > SAL_CALL ScExternalDocLinkObj::addSheetCache( + const OUString& aSheetName, sal_Bool bDynamicCache ) +{ + SolarMutexGuard aGuard; + size_t nIndex = 0; + ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aSheetName, true, &nIndex); + if (!bDynamicCache) + // Set the whole table cached to prevent access to the source document. + pTable->setWholeTableCached(); + + uno::Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(mpDocShell, pTable, nIndex)); + return aSheetCache; +} + +Any SAL_CALL ScExternalDocLinkObj::getByName(const OUString &aName) +{ + SolarMutexGuard aGuard; + size_t nIndex = 0; + ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aName, false, &nIndex); + if (!pTable) + throw container::NoSuchElementException(); + + uno::Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(mpDocShell, pTable, nIndex)); + + return Any(aSheetCache); +} + +Sequence< OUString > SAL_CALL ScExternalDocLinkObj::getElementNames() +{ + SolarMutexGuard aGuard; + vector<OUString> aTabNames; + mpRefMgr->getAllCachedTableNames(mnFileId, aTabNames); + + // #i116940# be consistent with getByName: include only table names which have a cache already + vector<OUString> aValidNames; + std::copy_if(aTabNames.begin(), aTabNames.end(), std::back_inserter(aValidNames), + [&](const OUString& rTabName) { return mpRefMgr->getCacheTable(mnFileId, rTabName, false); }); + + Sequence<OUString> aSeq(comphelper::containerToSequence(aValidNames)); + return aSeq; +} + +sal_Bool SAL_CALL ScExternalDocLinkObj::hasByName(const OUString &aName) +{ + SolarMutexGuard aGuard; + + // #i116940# be consistent with getByName: allow only table names which have a cache already + ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aName, false); + return bool(pTable); +} + +sal_Int32 SAL_CALL ScExternalDocLinkObj::getCount() +{ + SolarMutexGuard aGuard; + + // #i116940# be consistent with getByName: count only table names which have a cache already + return getElementNames().getLength(); +} + +Any SAL_CALL ScExternalDocLinkObj::getByIndex(sal_Int32 nApiIndex) +{ + SolarMutexGuard aGuard; + + // #i116940# Can't use nApiIndex as index for the ref manager, because the API counts only + // the entries which have a cache already. Quick solution: Use getElementNames. + Sequence< OUString > aNames( getElementNames() ); + if (nApiIndex < 0 || nApiIndex >= aNames.getLength()) + throw lang::IndexOutOfBoundsException(); + + size_t nIndex = 0; + ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aNames[nApiIndex], false, &nIndex); + if (!pTable) + throw lang::IndexOutOfBoundsException(); + + uno::Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(mpDocShell, pTable, nIndex)); + + return Any(aSheetCache); +} + +uno::Reference< container::XEnumeration > SAL_CALL ScExternalDocLinkObj::createEnumeration() +{ + SolarMutexGuard aGuard; + uno::Reference< container::XEnumeration > aRef( + new ScIndexEnumeration(this, "com.sun.star.sheet.ExternalDocLink")); + return aRef; +} + +uno::Type SAL_CALL ScExternalDocLinkObj::getElementType() +{ + return cppu::UnoType<sheet::XExternalDocLink>::get(); +} + +sal_Bool SAL_CALL ScExternalDocLinkObj::hasElements() +{ + SolarMutexGuard aGuard; + + // #i116940# be consistent with getByName: count only table names which have a cache already + return getElementNames().hasElements(); +} + +sal_Int32 SAL_CALL ScExternalDocLinkObj::getTokenIndex() +{ + return static_cast<sal_Int32>(mnFileId); +} + +ScExternalDocLinksObj::ScExternalDocLinksObj(ScDocShell* pDocShell) : + mpDocShell(pDocShell), + mpRefMgr(pDocShell->GetDocument().GetExternalRefManager()) +{ +} + +ScExternalDocLinksObj::~ScExternalDocLinksObj() +{ +} + +uno::Reference< sheet::XExternalDocLink > SAL_CALL ScExternalDocLinksObj::addDocLink( + const OUString& aDocName ) +{ + SolarMutexGuard aGuard; + OUString aDocUrl( ScGlobal::GetAbsDocName( aDocName, mpDocShell)); + sal_uInt16 nFileId = mpRefMgr->getExternalFileId(aDocUrl); + uno::Reference< sheet::XExternalDocLink > aDocLink(new ScExternalDocLinkObj(mpDocShell, mpRefMgr, nFileId)); + return aDocLink; +} + +Any SAL_CALL ScExternalDocLinksObj::getByName(const OUString &aName) +{ + SolarMutexGuard aGuard; + OUString aDocUrl( ScGlobal::GetAbsDocName( aName, mpDocShell)); + if (!mpRefMgr->hasExternalFile(aDocUrl)) + throw container::NoSuchElementException(); + + sal_uInt16 nFileId = mpRefMgr->getExternalFileId(aDocUrl); + uno::Reference< sheet::XExternalDocLink > aDocLink(new ScExternalDocLinkObj(mpDocShell, mpRefMgr, nFileId)); + + return Any(aDocLink); +} + +Sequence< OUString > SAL_CALL ScExternalDocLinksObj::getElementNames() +{ + SolarMutexGuard aGuard; + sal_uInt16 n = mpRefMgr->getExternalFileCount(); + Sequence<OUString> aSeq(n); + auto aSeqRange = asNonConstRange(aSeq); + for (sal_uInt16 i = 0; i < n; ++i) + { + const OUString* pName = mpRefMgr->getExternalFileName(i); + aSeqRange[i] = pName ? *pName : OUString(); + } + + return aSeq; +} + +sal_Bool SAL_CALL ScExternalDocLinksObj::hasByName(const OUString &aName) +{ + SolarMutexGuard aGuard; + return mpRefMgr->hasExternalFile(aName); +} + +sal_Int32 SAL_CALL ScExternalDocLinksObj::getCount() +{ + SolarMutexGuard aGuard; + return mpRefMgr->getExternalFileCount(); +} + +Any SAL_CALL ScExternalDocLinksObj::getByIndex(sal_Int32 nIndex) +{ + SolarMutexGuard aGuard; + if (nIndex > ::std::numeric_limits<sal_uInt16>::max() || nIndex < ::std::numeric_limits<sal_uInt16>::min()) + throw lang::IndexOutOfBoundsException(); + + sal_uInt16 nFileId = static_cast<sal_uInt16>(nIndex); + + if (!mpRefMgr->hasExternalFile(nFileId)) + throw lang::IndexOutOfBoundsException(); + + uno::Reference< sheet::XExternalDocLink > aDocLink(new ScExternalDocLinkObj(mpDocShell, mpRefMgr, nFileId)); + return Any(aDocLink); +} + +uno::Reference< container::XEnumeration > SAL_CALL ScExternalDocLinksObj::createEnumeration() +{ + SolarMutexGuard aGuard; + uno::Reference< container::XEnumeration > aRef( + new ScIndexEnumeration(this, "com.sun.star.sheet.ExternalDocLinks")); + return aRef; +} + +uno::Type SAL_CALL ScExternalDocLinksObj::getElementType() +{ + return cppu::UnoType<sheet::XExternalDocLinks>::get(); +} + +sal_Bool SAL_CALL ScExternalDocLinksObj::hasElements() +{ + SolarMutexGuard aGuard; + return mpRefMgr->getExternalFileCount() > 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |