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