summaryrefslogtreecommitdiffstats
path: root/sfx2/source/appl/linksrc.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sfx2/source/appl/linksrc.cxx416
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: */