Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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: */