/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include 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 lcl_GetSheetLinkMap() { static const SfxItemPropertyMapEntry aSheetLinkMap_Impl[] = { { SC_UNONAME_FILTER, 0, cppu::UnoType::get(), 0, 0 }, { SC_UNONAME_FILTOPT, 0, cppu::UnoType::get(), 0, 0 }, { SC_UNONAME_LINKURL, 0, cppu::UnoType::get(), 0, 0 }, { SC_UNONAME_REFDELAY, 0, cppu::UnoType::get(), 0, 0 }, { SC_UNONAME_REFPERIOD, 0, cppu::UnoType::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 ( auto pRefreshHint = dynamic_cast(&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; iGetLinks()[i].get(); if (auto pTabLink = dynamic_cast( 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& 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& xListener ) { SolarMutexGuard aGuard; size_t nCount = aRefreshListeners.size(); for ( size_t n=nCount; n--; ) { uno::Reference& 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 & xRefreshListener : aRefreshListeners) xRefreshListener->refreshed( aEvent ); } void ScSheetLinkObj::ModifyRefreshDelay_Impl( sal_Int32 nRefresh ) { ScTableLink* pLink = GetLink_Impl(); if( pLink ) pLink->SetRefreshDelay( static_cast(nRefresh) ); } // XPropertySet uno::Reference SAL_CALL ScSheetLinkObj::getPropertySetInfo() { SolarMutexGuard aGuard; static uno::Reference 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; nTabUpdateLinks(); // 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 ScSheetLinksObj::GetObjectByIndex_Impl(sal_Int32 nIndex) { if (!pDocShell) return nullptr; typedef std::unordered_set 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 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 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 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 xLink(GetObjectByIndex_Impl(nIndex)); if (!xLink.is()) throw lang::IndexOutOfBoundsException(); return uno::Any(xLink); } uno::Type SAL_CALL ScSheetLinksObj::getElementType() { return cppu::UnoType::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 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 SAL_CALL ScSheetLinksObj::getElementNames() { typedef std::unordered_set StrSetType; SolarMutexGuard aGuard; // Name is the same as file name if (!pDocShell) return uno::Sequence(); StrSetType aNames; ScDocument& rDoc = pDocShell->GetDocument(); SCTAB nTabCount = rDoc.GetTableCount(); sal_Int32 nLinkCount = getCount(); uno::Sequence 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(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; iGetLinks()[i].get(); if (auto pAreaLink = dynamic_cast( 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(&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& 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& xListener ) { SolarMutexGuard aGuard; size_t nCount = aRefreshListeners.size(); for ( size_t n=nCount; n--; ) { uno::Reference& 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 & xRefreshListener : aRefreshListeners) xRefreshListener->refreshed( aEvent ); } // XPropertySet uno::Reference SAL_CALL ScAreaLinkObj::getPropertySetInfo() { SolarMutexGuard aGuard; static uno::Reference 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 ScAreaLinksObj::GetObjectByIndex_Impl(sal_Int32 nIndex) { if ( pDocShell && nIndex >= 0 && nIndex < getCount() ) return new ScAreaLinkObj( pDocShell, static_cast(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(aDestPos.Column), static_cast(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(nIndex)); if (pLink) { //! SetAddUndo or what sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager(); pLinkManager->Remove( pLink ); } } // XEnumerationAccess uno::Reference 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; iGetLinks()[i].get(); if (dynamic_cast( pBase) != nullptr) ++nAreaCount; } } return nAreaCount; } uno::Any SAL_CALL ScAreaLinksObj::getByIndex( sal_Int32 nIndex ) { SolarMutexGuard aGuard; uno::Reference xLink(GetObjectByIndex_Impl(nIndex)); if (!xLink.is()) throw lang::IndexOutOfBoundsException(); return uno::Any(xLink); } uno::Type SAL_CALL ScAreaLinksObj::getElementType() { return cppu::UnoType::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(&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& 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& xListener ) { SolarMutexGuard aGuard; size_t nCount = aRefreshListeners.size(); for ( size_t n=nCount; n--; ) { uno::Reference& 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 & 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 ScDDELinksObj::GetObjectByIndex_Impl(sal_Int32 nIndex) { if (pDocShell) { OUString aAppl, aTopic, aItem; if ( pDocShell->GetDocument().GetDdeLinkData( static_cast(nIndex), aAppl, aTopic, aItem ) ) return new ScDDELinkObj( pDocShell, aAppl, aTopic, aItem ); } return nullptr; } rtl::Reference 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 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 xLink(GetObjectByIndex_Impl(nIndex)); if (!xLink.is()) throw lang::IndexOutOfBoundsException(); return uno::Any(xLink); } uno::Type SAL_CALL ScDDELinksObj::getElementType() { return cppu::UnoType::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 xLink(GetObjectByName_Impl(aName)); if (!xLink.is()) throw container::NoSuchElementException(); return uno::Any(xLink); } uno::Sequence 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 aSeq(nCount); OUString* pAry = aSeq.getArray(); for (size_t i=0; i(); } 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 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(nCol), static_cast(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(nCol), static_cast(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 aRows; mpTable->getAllRows(aRows); size_t nSize = aRows.size(); Sequence 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 aCols; mpTable->getAllCols(static_cast(nRow), aCols); size_t nSize = aCols.size(); Sequence 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 aTabNames; mpRefMgr->getAllCachedTableNames(mnFileId, aTabNames); // #i116940# be consistent with getByName: include only table names which have a cache already vector aValidNames; std::copy_if(aTabNames.begin(), aTabNames.end(), std::back_inserter(aValidNames), [&](const OUString& rTabName) { return mpRefMgr->getCacheTable(mnFileId, rTabName, false); }); Sequence 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, u"com.sun.star.sheet.ExternalDocLink"_ustr)); return aRef; } uno::Type SAL_CALL ScExternalDocLinkObj::getElementType() { return cppu::UnoType::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(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 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::max() || nIndex < ::std::numeric_limits::min()) throw lang::IndexOutOfBoundsException(); sal_uInt16 nFileId = static_cast(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::get(); } sal_Bool SAL_CALL ScExternalDocLinksObj::hasElements() { SolarMutexGuard aGuard; return mpRefMgr->getExternalFileCount() > 0; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */