/* -*- 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, u"ScAreaLinkObj"_ustr, u"com.sun.star.sheet.CellAreaLink"_ustr )
SC_SIMPLE_SERVICE_INFO( ScAreaLinksObj, u"ScAreaLinksObj"_ustr, u"com.sun.star.sheet.CellAreaLinks"_ustr )
SC_SIMPLE_SERVICE_INFO( ScDDELinkObj, u"ScDDELinkObj"_ustr, u"com.sun.star.sheet.DDELink"_ustr )
SC_SIMPLE_SERVICE_INFO( ScDDELinksObj, u"ScDDELinksObj"_ustr, u"com.sun.star.sheet.DDELinks"_ustr )
SC_SIMPLE_SERVICE_INFO( ScSheetLinkObj, u"ScSheetLinkObj"_ustr, u"com.sun.star.sheet.SheetLink"_ustr )
SC_SIMPLE_SERVICE_INFO( ScSheetLinksObj, u"ScSheetLinksObj"_ustr, u"com.sun.star.sheet.SheetLinks"_ustr )
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 ( rHint.GetId() == SfxHintId::ScLinkRefreshed )
{
auto pRefreshHint = static_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, u"com.sun.star.sheet.SheetLinksEnumeration"_ustr);
}
// 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 ( rHint.GetId() == SfxHintId::ScLinkRefreshed )
{
auto pRefreshedHint = static_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, u"com.sun.star.sheet.CellAreaLinksEnumeration"_ustr);
}
// 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 ( rHint.GetId() == SfxHintId::ScLinkRefreshed )
{
auto pRefreshedHint = static_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(
u"ScDDELinkObj::getResults: failed to get results!"_ustr );
}
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(
u"ScDDELinkObj::setResults: failed to set results!"_ustr );
}
}
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, u"com.sun.star.sheet.DDELinksEnumeration"_ustr);
}
// 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(
u"ScDDELinksObj::addDDELink: cannot add DDE link!"_ustr );
}
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 xTable = mpRefMgr->getCacheTable(mnFileId, aSheetName, true, &nIndex);
if (!bDynamicCache)
{
// Set the whole table cached to prevent access to the source document.
xTable->setWholeTableCached();
}
uno::Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(
mpDocShell, std::move(xTable), nIndex));
return aSheetCache;
}
Any SAL_CALL ScExternalDocLinkObj::getByName(const OUString &aName)
{
SolarMutexGuard aGuard;
size_t nIndex = 0;
ScExternalRefCache::TableTypeRef xTable = mpRefMgr->getCacheTable(mnFileId, aName, false, &nIndex);
if (!xTable)
throw container::NoSuchElementException();
uno::Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(
mpDocShell, std::move(xTable), 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, std::move(pTable), nIndex));
return Any(aSheetCache);
}
uno::Reference< container::XEnumeration > SAL_CALL ScExternalDocLinkObj::createEnumeration()
{
SolarMutexGuard aGuard;
uno::Reference< container::XEnumeration > aRef(
new ScIndexEnumeration(this, u"com.sun.star.sheet.ExternalDocLink"_ustr));
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, u"com.sun.star.sheet.ExternalDocLinks"_ustr));
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: */
↑ V524 It is odd that the body of 'removePropertyChangeListener' function is fully equivalent to the body of 'addPropertyChangeListener' function.
↑ V524 It is odd that the body of 'removeVetoableChangeListener' function is fully equivalent to the body of 'addVetoableChangeListener' function.
↑ V524 It is odd that the body of 'removePropertyChangeListener' function is fully equivalent to the body of 'addPropertyChangeListener' function.
↑ V524 It is odd that the body of 'removeVetoableChangeListener' function is fully equivalent to the body of 'addVetoableChangeListener' function.