/* -*- 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 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& 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 xSink; OUString const aDataMimeType; sal_uInt16 const nAdviseModes; bool const 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> 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& rxData) { return rxData.get() == p; }); if (it != mvData.end()) mvData.erase(it); } }; class SvLinkSource_EntryIter_Impl { std::vector 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(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 pTimer; sal_uInt64 nTimeout; css::uno::Reference 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& 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&) { } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */