8c15ccc267
Change-Id: I7984f0b52809091511dc01005fdbfeafd521b4bf Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137048 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
417 lines
11 KiB
C++
417 lines
11 KiB
C++
/* -*- 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 <utility>
|
|
#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 )
|
|
: Timer("sfx2 SvLinkSourceTimer"), 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, OUString aMimeType,
|
|
sal_uInt16 nAdvMode )
|
|
: xSink( pLink ), aDataMimeType(std::move( aMimeType )),
|
|
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() {}
|
|
|
|
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: */
|