1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <sfx2/linksrc.hxx>
22 #include <sfx2/lnkbase.hxx>
23 #include <com/sun/star/uno/Any.hxx>
26 #include <vcl/timer.hxx>
32 using namespace ::com::sun::star::uno
;
39 class SvLinkSourceTimer
: public Timer
41 SvLinkSource
* pOwner
;
42 virtual void Invoke() override
;
44 explicit SvLinkSourceTimer( SvLinkSource
* pOwn
);
49 SvLinkSourceTimer::SvLinkSourceTimer( SvLinkSource
* pOwn
)
50 : Timer("sfx2 SvLinkSourceTimer"), pOwner( pOwn
)
54 void SvLinkSourceTimer::Invoke()
56 // Secure against being destroyed in Handler
57 SvLinkSourceRef
xHoldAlive( pOwner
);
58 pOwner
->SendDataChanged();
61 static void StartTimer( std::unique_ptr
<SvLinkSourceTimer
>& pTimer
, SvLinkSource
* pOwner
,
66 pTimer
.reset( new SvLinkSourceTimer( pOwner
) );
67 pTimer
->SetTimeout( nTimeout
);
74 struct SvLinkSource_Entry_Impl
76 tools::SvRef
<SvBaseLink
> xSink
;
77 OUString aDataMimeType
;
78 sal_uInt16 nAdviseModes
;
81 SvLinkSource_Entry_Impl( SvBaseLink
* pLink
, OUString aMimeType
,
83 : xSink( pLink
), aDataMimeType(std::move( aMimeType
)),
84 nAdviseModes( nAdvMode
), bIsDataSink( true )
87 explicit SvLinkSource_Entry_Impl( SvBaseLink
* pLink
)
88 : xSink( pLink
), nAdviseModes( 0 ), bIsDataSink( false )
92 class SvLinkSource_Array_Impl
94 friend class SvLinkSource_EntryIter_Impl
;
96 std::vector
<std::unique_ptr
<SvLinkSource_Entry_Impl
>> mvData
;
99 SvLinkSource_Array_Impl() {}
101 size_t size() const { return mvData
.size(); }
102 SvLinkSource_Entry_Impl
*operator[](size_t idx
) const { return mvData
[idx
].get(); }
103 void push_back(SvLinkSource_Entry_Impl
* rData
) { mvData
.emplace_back(rData
); }
105 void DeleteAndDestroy(SvLinkSource_Entry_Impl
const * p
)
107 auto it
= std::find_if(mvData
.begin(), mvData
.end(),
108 [&p
](const std::unique_ptr
<SvLinkSource_Entry_Impl
>& rxData
) { return rxData
.get() == p
; });
109 if (it
!= mvData
.end())
114 class SvLinkSource_EntryIter_Impl
116 std::vector
<SvLinkSource_Entry_Impl
*> aArr
;
117 const SvLinkSource_Array_Impl
& rOrigArr
;
120 explicit SvLinkSource_EntryIter_Impl( const SvLinkSource_Array_Impl
& rArr
);
121 SvLinkSource_Entry_Impl
* Curr()
122 { return nPos
< aArr
.size() ? aArr
[ nPos
] : nullptr; }
123 SvLinkSource_Entry_Impl
* Next();
124 bool IsValidCurrValue( SvLinkSource_Entry_Impl
const * pEntry
);
129 SvLinkSource_EntryIter_Impl::SvLinkSource_EntryIter_Impl(
130 const SvLinkSource_Array_Impl
& rArr
)
131 : rOrigArr( rArr
), nPos( 0 )
133 for (auto const & i
: rArr
.mvData
)
134 aArr
.push_back(i
.get());
137 bool SvLinkSource_EntryIter_Impl::IsValidCurrValue( SvLinkSource_Entry_Impl
const * pEntry
)
139 if ( nPos
>= aArr
.size() )
141 if (aArr
[nPos
] != pEntry
)
143 for (auto const & i
: rOrigArr
.mvData
)
144 if (i
.get() == pEntry
)
149 SvLinkSource_Entry_Impl
* SvLinkSource_EntryIter_Impl::Next()
151 SvLinkSource_Entry_Impl
* pRet
= nullptr;
152 if( nPos
+ 1 < static_cast<sal_uInt16
>(aArr
.size()) )
155 if( rOrigArr
.size() == aArr
.size() &&
156 rOrigArr
[ nPos
] == aArr
[ nPos
] )
160 // then we must search the current (or the next) in the orig
163 for (auto const & i
: rOrigArr
.mvData
)
168 } while( nPos
< aArr
.size() );
170 if( nPos
>= aArr
.size() )
177 struct SvLinkSource_Impl
179 SvLinkSource_Array_Impl aArr
;
180 OUString aDataMimeType
;
181 std::unique_ptr
<SvLinkSourceTimer
>
184 css::uno::Reference
<css::io::XInputStream
>
185 m_xInputStreamToLoadFrom
;
190 , m_bIsReadOnly(false)
195 SvLinkSource::SvLinkSource()
196 : pImpl( new SvLinkSource_Impl
)
200 SvLinkSource::~SvLinkSource()
205 SvLinkSource::StreamToLoadFrom
SvLinkSource::getStreamToLoadFrom()
207 return StreamToLoadFrom(
208 pImpl
->m_xInputStreamToLoadFrom
,
209 pImpl
->m_bIsReadOnly
);
212 void SvLinkSource::setStreamToLoadFrom(const css::uno::Reference
<css::io::XInputStream
>& xInputStream
, bool bIsReadOnly
)
214 pImpl
->m_xInputStreamToLoadFrom
= xInputStream
;
215 pImpl
->m_bIsReadOnly
= bIsReadOnly
;
219 void SvLinkSource::clearStreamToLoadFrom()
221 pImpl
->m_xInputStreamToLoadFrom
.clear();
224 void SvLinkSource::Closed()
226 SvLinkSource_EntryIter_Impl
aIter( pImpl
->aArr
);
227 for( SvLinkSource_Entry_Impl
* p
= aIter
.Curr(); p
; p
= aIter
.Next() )
228 if( !p
->bIsDataSink
)
232 sal_uInt64
SvLinkSource::GetUpdateTimeout() const
234 return pImpl
->nTimeout
;
237 void SvLinkSource::SetUpdateTimeout( sal_uInt64 nTimeout
)
239 pImpl
->nTimeout
= nTimeout
;
241 pImpl
->pTimer
->SetTimeout( nTimeout
);
244 void SvLinkSource::SendDataChanged()
246 SvLinkSource_EntryIter_Impl
aIter( pImpl
->aArr
);
247 for( SvLinkSource_Entry_Impl
* p
= aIter
.Curr(); p
; p
= aIter
.Next() )
251 OUString
sDataMimeType( pImpl
->aDataMimeType
);
252 if( sDataMimeType
.isEmpty() )
253 sDataMimeType
= p
->aDataMimeType
;
256 if( ( p
->nAdviseModes
& ADVISEMODE_NODATA
) ||
257 GetData( aVal
, sDataMimeType
, true ) )
259 p
->xSink
->DataChanged( sDataMimeType
, aVal
);
261 if ( !aIter
.IsValidCurrValue( p
) )
264 if( p
->nAdviseModes
& ADVISEMODE_ONLYONCE
)
266 pImpl
->aArr
.DeleteAndDestroy( p
);
272 pImpl
->pTimer
.reset();
273 pImpl
->aDataMimeType
.clear();
276 void SvLinkSource::NotifyDataChanged()
278 if( pImpl
->nTimeout
)
279 StartTimer( pImpl
->pTimer
, this, pImpl
->nTimeout
); // New timeout
282 SvLinkSource_EntryIter_Impl
aIter( pImpl
->aArr
);
283 for( SvLinkSource_Entry_Impl
* p
= aIter
.Curr(); p
; p
= aIter
.Next() )
287 if( ( p
->nAdviseModes
& ADVISEMODE_NODATA
) ||
288 GetData( aVal
, p
->aDataMimeType
, true ) )
290 tools::SvRef
<sfx2::SvBaseLink
> xLink(p
->xSink
);
291 xLink
->DataChanged( p
->aDataMimeType
, aVal
);
293 if ( !aIter
.IsValidCurrValue( p
) )
296 if( p
->nAdviseModes
& ADVISEMODE_ONLYONCE
)
298 pImpl
->aArr
.DeleteAndDestroy( p
);
303 pImpl
->pTimer
.reset();
307 // notify the sink, the mime type is not
308 // a selection criterion
309 void SvLinkSource::DataChanged( const OUString
& rMimeType
,
310 const css::uno::Any
& rVal
)
312 if( pImpl
->nTimeout
&& !rVal
.hasValue() )
313 { // only when no data was included
314 // fire all data to the sink, independent of the requested format
315 pImpl
->aDataMimeType
= rMimeType
;
316 StartTimer( pImpl
->pTimer
, this, pImpl
->nTimeout
); // New timeout
320 SvLinkSource_EntryIter_Impl
aIter( pImpl
->aArr
);
321 for( SvLinkSource_Entry_Impl
* p
= aIter
.Curr(); p
; p
= aIter
.Next() )
325 p
->xSink
->DataChanged( rMimeType
, rVal
);
327 if ( !aIter
.IsValidCurrValue( p
) )
330 if( p
->nAdviseModes
& ADVISEMODE_ONLYONCE
)
332 pImpl
->aArr
.DeleteAndDestroy( p
);
337 pImpl
->pTimer
.reset();
342 // only one link is correct
343 void SvLinkSource::AddDataAdvise( SvBaseLink
* pLink
, const OUString
& rMimeType
,
344 sal_uInt16 nAdviseModes
)
346 SvLinkSource_Entry_Impl
* pNew
= new SvLinkSource_Entry_Impl(
347 pLink
, rMimeType
, nAdviseModes
);
348 pImpl
->aArr
.push_back( pNew
);
351 void SvLinkSource::RemoveAllDataAdvise( SvBaseLink
const * pLink
)
353 SvLinkSource_EntryIter_Impl
aIter( pImpl
->aArr
);
354 for( SvLinkSource_Entry_Impl
* p
= aIter
.Curr(); p
; p
= aIter
.Next() )
355 if( p
->bIsDataSink
&& p
->xSink
.get() == pLink
)
357 pImpl
->aArr
.DeleteAndDestroy( p
);
361 // only one link is correct
362 void SvLinkSource::AddConnectAdvise( SvBaseLink
* pLink
)
364 SvLinkSource_Entry_Impl
* pNew
= new SvLinkSource_Entry_Impl( pLink
);
365 pImpl
->aArr
.push_back( pNew
);
368 void SvLinkSource::RemoveConnectAdvise( SvBaseLink
const * pLink
)
370 SvLinkSource_EntryIter_Impl
aIter( pImpl
->aArr
);
371 for( SvLinkSource_Entry_Impl
* p
= aIter
.Curr(); p
; p
= aIter
.Next() )
372 if( !p
->bIsDataSink
&& p
->xSink
.get() == pLink
)
374 pImpl
->aArr
.DeleteAndDestroy( p
);
378 bool SvLinkSource::HasDataLinks() const
381 for( sal_uInt16 n
= 0, nEnd
= pImpl
->aArr
.size(); n
< nEnd
; ++n
)
382 if( pImpl
->aArr
[ n
]->bIsDataSink
)
390 // sal_True => waitinmg for data
391 bool SvLinkSource::IsPending() const
396 // sal_True => data complete loaded
397 bool SvLinkSource::IsDataComplete() const
402 bool SvLinkSource::Connect( SvBaseLink
* )
407 bool SvLinkSource::GetData( css::uno::Any
&, const OUString
&, bool )
412 void SvLinkSource::Edit(weld::Window
*, SvBaseLink
*, const Link
<const OUString
&, void>&)
418 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */