Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 :
21 : #include <sfx2/linksrc.hxx>
22 : #include <sfx2/lnkbase.hxx>
23 : #include <com/sun/star/uno/Any.hxx>
24 : #include <com/sun/star/uno/Sequence.hxx>
25 :
26 : #include <vcl/timer.hxx>
27 : #include <vector>
28 : #include <algorithm>
29 :
30 :
31 : using namespace ::com::sun::star::uno;
32 :
33 : namespace sfx2
34 : {
35 :
36 4 : TYPEINIT0( SvLinkSource )
37 :
38 0 : class SvLinkSourceTimer : public Timer
39 : {
40 : SvLinkSource * pOwner;
41 : virtual void Invoke() SAL_OVERRIDE;
42 : public:
43 : SvLinkSourceTimer( SvLinkSource * pOwn );
44 : };
45 :
46 0 : SvLinkSourceTimer::SvLinkSourceTimer( SvLinkSource * pOwn )
47 0 : : pOwner( pOwn )
48 : {
49 0 : }
50 :
51 0 : void SvLinkSourceTimer::Invoke()
52 : {
53 : // Secure against being destroyed in Handler
54 0 : SvLinkSourceRef aAdv( pOwner );
55 0 : pOwner->SendDataChanged();
56 0 : }
57 :
58 0 : static void StartTimer( SvLinkSourceTimer ** ppTimer, SvLinkSource * pOwner,
59 : sal_uIntPtr nTimeout )
60 : {
61 0 : if( !*ppTimer )
62 : {
63 0 : *ppTimer = new SvLinkSourceTimer( pOwner );
64 0 : (*ppTimer)->SetTimeout( nTimeout );
65 0 : (*ppTimer)->Start();
66 : }
67 0 : }
68 :
69 :
70 : struct SvLinkSource_Entry_Impl
71 : {
72 : SvBaseLinkRef xSink;
73 : OUString aDataMimeType;
74 : sal_uInt16 nAdviseModes;
75 : bool bIsDataSink;
76 :
77 70 : SvLinkSource_Entry_Impl( SvBaseLink* pLink, const OUString& rMimeType,
78 : sal_uInt16 nAdvMode )
79 : : xSink( pLink ), aDataMimeType( rMimeType ),
80 70 : nAdviseModes( nAdvMode ), bIsDataSink( true )
81 70 : {}
82 :
83 1 : SvLinkSource_Entry_Impl( SvBaseLink* pLink )
84 1 : : xSink( pLink ), nAdviseModes( 0 ), bIsDataSink( false )
85 1 : {}
86 :
87 : ~SvLinkSource_Entry_Impl();
88 : };
89 :
90 70 : SvLinkSource_Entry_Impl::~SvLinkSource_Entry_Impl()
91 : {
92 70 : }
93 :
94 156 : class SvLinkSource_Array_Impl
95 : {
96 : private :
97 : std::vector<SvLinkSource_Entry_Impl*> mvData;
98 :
99 : public:
100 75 : SvLinkSource_Array_Impl() : mvData() {}
101 :
102 286 : size_t size() const { return mvData.size(); }
103 129 : SvLinkSource_Entry_Impl *operator[](size_t idx) const { return mvData[idx]; }
104 18 : std::vector<SvLinkSource_Entry_Impl*>::const_iterator cbegin() const { return mvData.cbegin(); }
105 36 : std::vector<SvLinkSource_Entry_Impl*>::const_iterator cend() const { return mvData.cend(); }
106 156 : void clear() { mvData.clear(); }
107 71 : void push_back(SvLinkSource_Entry_Impl* rData) { mvData.push_back(rData); }
108 :
109 70 : void DeleteAndDestroy(SvLinkSource_Entry_Impl* p)
110 : {
111 70 : std::vector<SvLinkSource_Entry_Impl*>::iterator it = std::find(mvData.begin(), mvData.end(), p);
112 70 : if (it != mvData.end())
113 : {
114 70 : mvData.erase(it);
115 70 : delete p;
116 : }
117 70 : }
118 :
119 230 : ~SvLinkSource_Array_Impl()
120 230 : {
121 230 : for(std::vector<SvLinkSource_Entry_Impl*>::const_iterator it = mvData.begin(); it != mvData.end(); ++it)
122 0 : delete *it;
123 230 : }
124 : };
125 :
126 : class SvLinkSource_EntryIter_Impl
127 : {
128 : SvLinkSource_Array_Impl aArr;
129 : const SvLinkSource_Array_Impl& rOrigArr;
130 : sal_uInt16 nPos;
131 : public:
132 : SvLinkSource_EntryIter_Impl( const SvLinkSource_Array_Impl& rArr );
133 : ~SvLinkSource_EntryIter_Impl();
134 156 : SvLinkSource_Entry_Impl* Curr()
135 156 : { return nPos < aArr.size() ? aArr[ nPos ] : 0; }
136 : SvLinkSource_Entry_Impl* Next();
137 : bool IsValidCurrValue( SvLinkSource_Entry_Impl* pEntry );
138 : };
139 :
140 156 : SvLinkSource_EntryIter_Impl::SvLinkSource_EntryIter_Impl(
141 : const SvLinkSource_Array_Impl& rArr )
142 156 : : aArr( rArr ), rOrigArr( rArr ), nPos( 0 )
143 : {
144 156 : }
145 312 : SvLinkSource_EntryIter_Impl::~SvLinkSource_EntryIter_Impl()
146 : {
147 156 : aArr.clear();
148 156 : }
149 :
150 17 : bool SvLinkSource_EntryIter_Impl::IsValidCurrValue( SvLinkSource_Entry_Impl* pEntry )
151 : {
152 34 : return ( nPos < aArr.size() && aArr[nPos] == pEntry
153 51 : && std::find( rOrigArr.cbegin(), rOrigArr.cend(), pEntry ) != rOrigArr.cend() );
154 : }
155 :
156 89 : SvLinkSource_Entry_Impl* SvLinkSource_EntryIter_Impl::Next()
157 : {
158 89 : SvLinkSource_Entry_Impl* pRet = 0;
159 89 : if( nPos + 1 < (sal_uInt16)aArr.size() )
160 : {
161 2 : ++nPos;
162 3 : if( rOrigArr.size() == aArr.size() &&
163 1 : rOrigArr[ nPos ] == aArr[ nPos ] )
164 1 : pRet = aArr[ nPos ];
165 : else
166 : {
167 : // then we must search the current (or the next) in the orig
168 1 : do {
169 1 : pRet = aArr[ nPos ];
170 1 : if( std::find(rOrigArr.cbegin(), rOrigArr.cend(), pRet ) != rOrigArr.cend() )
171 0 : break;
172 1 : pRet = 0;
173 1 : ++nPos;
174 1 : } while( nPos < aArr.size() );
175 :
176 1 : if( nPos >= aArr.size() )
177 1 : pRet = 0;
178 : }
179 : }
180 89 : return pRet;
181 : }
182 :
183 : struct SvLinkSource_Impl
184 : {
185 : SvLinkSource_Array_Impl aArr;
186 : OUString aDataMimeType;
187 : SvLinkSourceTimer * pTimer;
188 : sal_uIntPtr nTimeout;
189 : css::uno::Reference<css::io::XInputStream>
190 : m_xInputStreamToLoadFrom;
191 : bool m_bIsReadOnly;
192 :
193 75 : SvLinkSource_Impl()
194 : : pTimer(0)
195 : , nTimeout(3000)
196 75 : , m_bIsReadOnly(false)
197 : {
198 75 : }
199 : ~SvLinkSource_Impl();
200 : };
201 :
202 148 : SvLinkSource_Impl::~SvLinkSource_Impl()
203 : {
204 74 : delete pTimer;
205 74 : }
206 :
207 75 : SvLinkSource::SvLinkSource()
208 75 : : pImpl( new SvLinkSource_Impl )
209 : {
210 75 : }
211 :
212 148 : SvLinkSource::~SvLinkSource()
213 : {
214 74 : delete pImpl;
215 74 : }
216 :
217 :
218 11 : SvLinkSource::StreamToLoadFrom SvLinkSource::getStreamToLoadFrom()
219 : {
220 : return StreamToLoadFrom(
221 : pImpl->m_xInputStreamToLoadFrom,
222 11 : pImpl->m_bIsReadOnly);
223 : }
224 :
225 38 : void SvLinkSource::setStreamToLoadFrom(const com::sun::star::uno::Reference<com::sun::star::io::XInputStream>& xInputStream, bool bIsReadOnly )
226 : {
227 38 : pImpl->m_xInputStreamToLoadFrom = xInputStream;
228 38 : pImpl->m_bIsReadOnly = bIsReadOnly;
229 38 : }
230 :
231 : // #i88291#
232 0 : void SvLinkSource::clearStreamToLoadFrom()
233 : {
234 0 : pImpl->m_xInputStreamToLoadFrom.clear();
235 0 : }
236 :
237 1 : void SvLinkSource::Closed()
238 : {
239 1 : SvLinkSource_EntryIter_Impl aIter( pImpl->aArr );
240 2 : for( SvLinkSource_Entry_Impl* p = aIter.Curr(); p; p = aIter.Next() )
241 1 : if( !p->bIsDataSink )
242 2 : p->xSink->Closed();
243 1 : }
244 :
245 1 : sal_uIntPtr SvLinkSource::GetUpdateTimeout() const
246 : {
247 1 : return pImpl->nTimeout;
248 : }
249 :
250 65 : void SvLinkSource::SetUpdateTimeout( sal_uIntPtr nTimeout )
251 : {
252 65 : pImpl->nTimeout = nTimeout;
253 65 : if( pImpl->pTimer )
254 0 : pImpl->pTimer->SetTimeout( nTimeout );
255 65 : }
256 :
257 0 : void SvLinkSource::SendDataChanged()
258 : {
259 0 : SvLinkSource_EntryIter_Impl aIter( pImpl->aArr );
260 0 : for( SvLinkSource_Entry_Impl* p = aIter.Curr(); p; p = aIter.Next() )
261 : {
262 0 : if( p->bIsDataSink )
263 : {
264 0 : OUString sDataMimeType( pImpl->aDataMimeType );
265 0 : if( sDataMimeType.isEmpty() )
266 0 : sDataMimeType = p->aDataMimeType;
267 :
268 0 : Any aVal;
269 0 : if( ( p->nAdviseModes & ADVISEMODE_NODATA ) ||
270 0 : GetData( aVal, sDataMimeType, true ) )
271 : {
272 0 : p->xSink->DataChanged( sDataMimeType, aVal );
273 :
274 0 : if ( !aIter.IsValidCurrValue( p ) )
275 0 : continue;
276 :
277 0 : if( p->nAdviseModes & ADVISEMODE_ONLYONCE )
278 : {
279 0 : pImpl->aArr.DeleteAndDestroy( p );
280 : }
281 :
282 0 : }
283 : }
284 : }
285 0 : if( pImpl->pTimer )
286 : {
287 0 : delete pImpl->pTimer;
288 0 : pImpl->pTimer = NULL;
289 : }
290 0 : pImpl->aDataMimeType.clear();
291 0 : }
292 :
293 3 : void SvLinkSource::NotifyDataChanged()
294 : {
295 3 : if( pImpl->nTimeout )
296 0 : StartTimer( &pImpl->pTimer, this, pImpl->nTimeout ); // New timeout
297 : else
298 : {
299 3 : SvLinkSource_EntryIter_Impl aIter( pImpl->aArr );
300 6 : for( SvLinkSource_Entry_Impl* p = aIter.Curr(); p; p = aIter.Next() )
301 3 : if( p->bIsDataSink )
302 : {
303 3 : Any aVal;
304 6 : if( ( p->nAdviseModes & ADVISEMODE_NODATA ) ||
305 3 : GetData( aVal, p->aDataMimeType, true ) )
306 : {
307 3 : p->xSink->DataChanged( p->aDataMimeType, aVal );
308 :
309 3 : if ( !aIter.IsValidCurrValue( p ) )
310 0 : continue;
311 :
312 3 : if( p->nAdviseModes & ADVISEMODE_ONLYONCE )
313 : {
314 0 : pImpl->aArr.DeleteAndDestroy( p );
315 : }
316 3 : }
317 : }
318 :
319 3 : if( pImpl->pTimer )
320 : {
321 0 : delete pImpl->pTimer;
322 0 : pImpl->pTimer = NULL;
323 3 : }
324 : }
325 3 : }
326 :
327 : // notify the sink, the mime type is not
328 : // a selection criterion
329 14 : void SvLinkSource::DataChanged( const OUString & rMimeType,
330 : const ::com::sun::star::uno::Any & rVal )
331 : {
332 14 : if( pImpl->nTimeout && !rVal.hasValue() )
333 : { // only when no data was included
334 : // fire all data to the sink, independent of the requested format
335 0 : pImpl->aDataMimeType = rMimeType;
336 0 : StartTimer( &pImpl->pTimer, this, pImpl->nTimeout ); // New timeout
337 : }
338 : else
339 : {
340 14 : SvLinkSource_EntryIter_Impl aIter( pImpl->aArr );
341 28 : for( SvLinkSource_Entry_Impl* p = aIter.Curr(); p; p = aIter.Next() )
342 : {
343 14 : if( p->bIsDataSink )
344 : {
345 14 : p->xSink->DataChanged( rMimeType, rVal );
346 :
347 14 : if ( !aIter.IsValidCurrValue( p ) )
348 0 : continue;
349 :
350 14 : if( p->nAdviseModes & ADVISEMODE_ONLYONCE )
351 : {
352 0 : pImpl->aArr.DeleteAndDestroy( p );
353 : }
354 : }
355 : }
356 :
357 14 : if( pImpl->pTimer )
358 : {
359 0 : delete pImpl->pTimer;
360 0 : pImpl->pTimer = NULL;
361 14 : }
362 : }
363 14 : }
364 :
365 :
366 : // only one link is correct
367 70 : void SvLinkSource::AddDataAdvise( SvBaseLink * pLink, const OUString& rMimeType,
368 : sal_uInt16 nAdviseModes )
369 : {
370 : SvLinkSource_Entry_Impl* pNew = new SvLinkSource_Entry_Impl(
371 70 : pLink, rMimeType, nAdviseModes );
372 70 : pImpl->aArr.push_back( pNew );
373 70 : }
374 :
375 69 : void SvLinkSource::RemoveAllDataAdvise( SvBaseLink * pLink )
376 : {
377 69 : SvLinkSource_EntryIter_Impl aIter( pImpl->aArr );
378 139 : for( SvLinkSource_Entry_Impl* p = aIter.Curr(); p; p = aIter.Next() )
379 70 : if( p->bIsDataSink && &p->xSink == pLink )
380 : {
381 69 : pImpl->aArr.DeleteAndDestroy( p );
382 69 : }
383 69 : }
384 :
385 : // only one link is correct
386 1 : void SvLinkSource::AddConnectAdvise( SvBaseLink * pLink )
387 : {
388 1 : SvLinkSource_Entry_Impl* pNew = new SvLinkSource_Entry_Impl( pLink );
389 1 : pImpl->aArr.push_back( pNew );
390 1 : }
391 :
392 69 : void SvLinkSource::RemoveConnectAdvise( SvBaseLink * pLink )
393 : {
394 69 : SvLinkSource_EntryIter_Impl aIter( pImpl->aArr );
395 70 : for( SvLinkSource_Entry_Impl* p = aIter.Curr(); p; p = aIter.Next() )
396 1 : if( !p->bIsDataSink && &p->xSink == pLink )
397 : {
398 1 : pImpl->aArr.DeleteAndDestroy( p );
399 69 : }
400 69 : }
401 :
402 18 : bool SvLinkSource::HasDataLinks( const SvBaseLink* pLink ) const
403 : {
404 18 : bool bRet = false;
405 : const SvLinkSource_Entry_Impl* p;
406 21 : for( sal_uInt16 n = 0, nEnd = pImpl->aArr.size(); n < nEnd; ++n )
407 37 : if( ( p = pImpl->aArr[ n ] )->bIsDataSink &&
408 0 : ( !pLink || &p->xSink == pLink ) )
409 : {
410 17 : bRet = true;
411 17 : break;
412 : }
413 18 : return bRet;
414 : }
415 :
416 : // sal_True => waitinmg for data
417 0 : bool SvLinkSource::IsPending() const
418 : {
419 0 : return false;
420 : }
421 :
422 : // sal_True => data complete loaded
423 0 : bool SvLinkSource::IsDataComplete() const
424 : {
425 0 : return true;
426 : }
427 :
428 0 : bool SvLinkSource::Connect( SvBaseLink* )
429 : {
430 0 : return true;
431 : }
432 :
433 0 : bool SvLinkSource::GetData( ::com::sun::star::uno::Any &, const OUString &, bool )
434 : {
435 0 : return false;
436 : }
437 :
438 0 : void SvLinkSource::Edit( vcl::Window *, SvBaseLink *, const Link<>& )
439 : {
440 0 : }
441 :
442 : }
443 :
444 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|