diff options
Diffstat (limited to '')
-rw-r--r-- | sfx2/source/appl/linksrc.cxx | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/sfx2/source/appl/linksrc.cxx b/sfx2/source/appl/linksrc.cxx new file mode 100644 index 000000000..d249f8e28 --- /dev/null +++ b/sfx2/source/appl/linksrc.cxx @@ -0,0 +1,416 @@ +/* -*- 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 <sfx2/linksrc.hxx> +#include <sfx2/lnkbase.hxx> +#include <com/sun/star/uno/Any.hxx> + +#include <vcl/timer.hxx> +#include <memory> +#include <vector> +#include <algorithm> + + +using namespace ::com::sun::star::uno; + +namespace sfx2 +{ + +namespace { + +class SvLinkSourceTimer : public Timer +{ + SvLinkSource * pOwner; + virtual void Invoke() override; +public: + explicit SvLinkSourceTimer( SvLinkSource * pOwn ); +}; + +} + +SvLinkSourceTimer::SvLinkSourceTimer( SvLinkSource * pOwn ) + : pOwner( pOwn ) +{ +} + +void SvLinkSourceTimer::Invoke() +{ + // Secure against being destroyed in Handler + SvLinkSourceRef xHoldAlive( pOwner ); + pOwner->SendDataChanged(); +} + +static void StartTimer( std::unique_ptr<SvLinkSourceTimer>& pTimer, SvLinkSource * pOwner, + sal_uInt64 nTimeout ) +{ + if( !pTimer ) + { + pTimer.reset( new SvLinkSourceTimer( pOwner ) ); + pTimer->SetTimeout( nTimeout ); + pTimer->Start(); + } +} + +namespace { + +struct SvLinkSource_Entry_Impl +{ + tools::SvRef<SvBaseLink> xSink; + OUString aDataMimeType; + sal_uInt16 nAdviseModes; + bool bIsDataSink; + + SvLinkSource_Entry_Impl( SvBaseLink* pLink, const OUString& rMimeType, + sal_uInt16 nAdvMode ) + : xSink( pLink ), aDataMimeType( rMimeType ), + nAdviseModes( nAdvMode ), bIsDataSink( true ) + {} + + explicit SvLinkSource_Entry_Impl( SvBaseLink* pLink ) + : xSink( pLink ), nAdviseModes( 0 ), bIsDataSink( false ) + {} +}; + +class SvLinkSource_Array_Impl +{ +friend class SvLinkSource_EntryIter_Impl; +private: + std::vector<std::unique_ptr<SvLinkSource_Entry_Impl>> mvData; + +public: + SvLinkSource_Array_Impl() : mvData() {} + + size_t size() const { return mvData.size(); } + SvLinkSource_Entry_Impl *operator[](size_t idx) const { return mvData[idx].get(); } + void push_back(SvLinkSource_Entry_Impl* rData) { mvData.emplace_back(rData); } + + void DeleteAndDestroy(SvLinkSource_Entry_Impl const * p) + { + auto it = std::find_if(mvData.begin(), mvData.end(), + [&p](const std::unique_ptr<SvLinkSource_Entry_Impl>& rxData) { return rxData.get() == p; }); + if (it != mvData.end()) + mvData.erase(it); + } +}; + +class SvLinkSource_EntryIter_Impl +{ + std::vector<SvLinkSource_Entry_Impl*> aArr; + const SvLinkSource_Array_Impl& rOrigArr; + sal_uInt16 nPos; +public: + explicit SvLinkSource_EntryIter_Impl( const SvLinkSource_Array_Impl& rArr ); + SvLinkSource_Entry_Impl* Curr() + { return nPos < aArr.size() ? aArr[ nPos ] : nullptr; } + SvLinkSource_Entry_Impl* Next(); + bool IsValidCurrValue( SvLinkSource_Entry_Impl const * pEntry ); +}; + +} + +SvLinkSource_EntryIter_Impl::SvLinkSource_EntryIter_Impl( + const SvLinkSource_Array_Impl& rArr ) + : rOrigArr( rArr ), nPos( 0 ) +{ + for (auto const & i : rArr.mvData) + aArr.push_back(i.get()); +} + +bool SvLinkSource_EntryIter_Impl::IsValidCurrValue( SvLinkSource_Entry_Impl const * pEntry ) +{ + if ( nPos >= aArr.size() ) + return false; + if (aArr[nPos] != pEntry) + return false; + for (auto const & i : rOrigArr.mvData) + if (i.get() == pEntry) + return true; + return false; +} + +SvLinkSource_Entry_Impl* SvLinkSource_EntryIter_Impl::Next() +{ + SvLinkSource_Entry_Impl* pRet = nullptr; + if( nPos + 1 < static_cast<sal_uInt16>(aArr.size()) ) + { + ++nPos; + if( rOrigArr.size() == aArr.size() && + rOrigArr[ nPos ] == aArr[ nPos ] ) + pRet = aArr[ nPos ]; + else + { + // then we must search the current (or the next) in the orig + do { + pRet = aArr[ nPos ]; + for (auto const & i : rOrigArr.mvData) + if (i.get() == pRet) + return pRet; + pRet = nullptr; + ++nPos; + } while( nPos < aArr.size() ); + + if( nPos >= aArr.size() ) + pRet = nullptr; + } + } + return pRet; +} + +struct SvLinkSource_Impl +{ + SvLinkSource_Array_Impl aArr; + OUString aDataMimeType; + std::unique_ptr<SvLinkSourceTimer> + pTimer; + sal_uInt64 nTimeout; + css::uno::Reference<css::io::XInputStream> + m_xInputStreamToLoadFrom; + bool m_bIsReadOnly; + + SvLinkSource_Impl() + : nTimeout(3000) + , m_bIsReadOnly(false) + { + } +}; + +SvLinkSource::SvLinkSource() + : pImpl( new SvLinkSource_Impl ) +{ +} + +SvLinkSource::~SvLinkSource() +{ +} + + +SvLinkSource::StreamToLoadFrom SvLinkSource::getStreamToLoadFrom() +{ + return StreamToLoadFrom( + pImpl->m_xInputStreamToLoadFrom, + pImpl->m_bIsReadOnly); +} + +void SvLinkSource::setStreamToLoadFrom(const css::uno::Reference<css::io::XInputStream>& xInputStream, bool bIsReadOnly ) +{ + pImpl->m_xInputStreamToLoadFrom = xInputStream; + pImpl->m_bIsReadOnly = bIsReadOnly; +} + +// #i88291# +void SvLinkSource::clearStreamToLoadFrom() +{ + pImpl->m_xInputStreamToLoadFrom.clear(); +} + +void SvLinkSource::Closed() +{ + SvLinkSource_EntryIter_Impl aIter( pImpl->aArr ); + for( SvLinkSource_Entry_Impl* p = aIter.Curr(); p; p = aIter.Next() ) + if( !p->bIsDataSink ) + p->xSink->Closed(); +} + +sal_uInt64 SvLinkSource::GetUpdateTimeout() const +{ + return pImpl->nTimeout; +} + +void SvLinkSource::SetUpdateTimeout( sal_uInt64 nTimeout ) +{ + pImpl->nTimeout = nTimeout; + if( pImpl->pTimer ) + pImpl->pTimer->SetTimeout( nTimeout ); +} + +void SvLinkSource::SendDataChanged() +{ + SvLinkSource_EntryIter_Impl aIter( pImpl->aArr ); + for( SvLinkSource_Entry_Impl* p = aIter.Curr(); p; p = aIter.Next() ) + { + if( p->bIsDataSink ) + { + OUString sDataMimeType( pImpl->aDataMimeType ); + if( sDataMimeType.isEmpty() ) + sDataMimeType = p->aDataMimeType; + + Any aVal; + if( ( p->nAdviseModes & ADVISEMODE_NODATA ) || + GetData( aVal, sDataMimeType, true ) ) + { + p->xSink->DataChanged( sDataMimeType, aVal ); + + if ( !aIter.IsValidCurrValue( p ) ) + continue; + + if( p->nAdviseModes & ADVISEMODE_ONLYONCE ) + { + pImpl->aArr.DeleteAndDestroy( p ); + } + + } + } + } + pImpl->pTimer.reset(); + pImpl->aDataMimeType.clear(); +} + +void SvLinkSource::NotifyDataChanged() +{ + if( pImpl->nTimeout ) + StartTimer( pImpl->pTimer, this, pImpl->nTimeout ); // New timeout + else + { + SvLinkSource_EntryIter_Impl aIter( pImpl->aArr ); + for( SvLinkSource_Entry_Impl* p = aIter.Curr(); p; p = aIter.Next() ) + if( p->bIsDataSink ) + { + Any aVal; + if( ( p->nAdviseModes & ADVISEMODE_NODATA ) || + GetData( aVal, p->aDataMimeType, true ) ) + { + p->xSink->DataChanged( p->aDataMimeType, aVal ); + + if ( !aIter.IsValidCurrValue( p ) ) + continue; + + if( p->nAdviseModes & ADVISEMODE_ONLYONCE ) + { + pImpl->aArr.DeleteAndDestroy( p ); + } + } + } + + pImpl->pTimer.reset(); + } +} + +// notify the sink, the mime type is not +// a selection criterion +void SvLinkSource::DataChanged( const OUString & rMimeType, + const css::uno::Any & rVal ) +{ + if( pImpl->nTimeout && !rVal.hasValue() ) + { // only when no data was included + // fire all data to the sink, independent of the requested format + pImpl->aDataMimeType = rMimeType; + StartTimer( pImpl->pTimer, this, pImpl->nTimeout ); // New timeout + } + else + { + SvLinkSource_EntryIter_Impl aIter( pImpl->aArr ); + for( SvLinkSource_Entry_Impl* p = aIter.Curr(); p; p = aIter.Next() ) + { + if( p->bIsDataSink ) + { + p->xSink->DataChanged( rMimeType, rVal ); + + if ( !aIter.IsValidCurrValue( p ) ) + continue; + + if( p->nAdviseModes & ADVISEMODE_ONLYONCE ) + { + pImpl->aArr.DeleteAndDestroy( p ); + } + } + } + + pImpl->pTimer.reset(); + } +} + + +// only one link is correct +void SvLinkSource::AddDataAdvise( SvBaseLink * pLink, const OUString& rMimeType, + sal_uInt16 nAdviseModes ) +{ + SvLinkSource_Entry_Impl* pNew = new SvLinkSource_Entry_Impl( + pLink, rMimeType, nAdviseModes ); + pImpl->aArr.push_back( pNew ); +} + +void SvLinkSource::RemoveAllDataAdvise( SvBaseLink const * pLink ) +{ + SvLinkSource_EntryIter_Impl aIter( pImpl->aArr ); + for( SvLinkSource_Entry_Impl* p = aIter.Curr(); p; p = aIter.Next() ) + if( p->bIsDataSink && p->xSink.get() == pLink ) + { + pImpl->aArr.DeleteAndDestroy( p ); + } +} + +// only one link is correct +void SvLinkSource::AddConnectAdvise( SvBaseLink * pLink ) +{ + SvLinkSource_Entry_Impl* pNew = new SvLinkSource_Entry_Impl( pLink ); + pImpl->aArr.push_back( pNew ); +} + +void SvLinkSource::RemoveConnectAdvise( SvBaseLink const * pLink ) +{ + SvLinkSource_EntryIter_Impl aIter( pImpl->aArr ); + for( SvLinkSource_Entry_Impl* p = aIter.Curr(); p; p = aIter.Next() ) + if( !p->bIsDataSink && p->xSink.get() == pLink ) + { + pImpl->aArr.DeleteAndDestroy( p ); + } +} + +bool SvLinkSource::HasDataLinks() const +{ + bool bRet = false; + for( sal_uInt16 n = 0, nEnd = pImpl->aArr.size(); n < nEnd; ++n ) + if( pImpl->aArr[ n ]->bIsDataSink ) + { + bRet = true; + break; + } + return bRet; +} + +// sal_True => waitinmg for data +bool SvLinkSource::IsPending() const +{ + return false; +} + +// sal_True => data complete loaded +bool SvLinkSource::IsDataComplete() const +{ + return true; +} + +bool SvLinkSource::Connect( SvBaseLink* ) +{ + return true; +} + +bool SvLinkSource::GetData( css::uno::Any &, const OUString &, bool ) +{ + return false; +} + +void SvLinkSource::Edit(weld::Window *, SvBaseLink *, const Link<const OUString&, void>&) +{ +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |