Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/unoobj/linkuno.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
#include <sal/config.h>
21
22
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
23
#include <comphelper/sequence.hxx>
24
#include <formula/token.hxx>
25
#include <svl/hint.hxx>
26
#include <sfx2/linkmgr.hxx>
27
#include <utility>
28
#include <vcl/svapp.hxx>
29
#include <svl/sharedstringpool.hxx>
30
31
#include <linkuno.hxx>
32
#include <miscuno.hxx>
33
#include <convuno.hxx>
34
#include <docsh.hxx>
35
#include <docfunc.hxx>
36
#include <tablink.hxx>
37
#include <arealink.hxx>
38
#include <hints.hxx>
39
#include <unonames.hxx>
40
#include <rangeseq.hxx>
41
#include <scmatrix.hxx>
42
#include <documentlinkmgr.hxx>
43
44
#include <string_view>
45
#include <vector>
46
47
using namespace com::sun::star;
48
using namespace formula;
49
using ::com::sun::star::uno::Any;
50
using ::com::sun::star::uno::Sequence;
51
using ::com::sun::star::lang::IllegalArgumentException;
52
using ::com::sun::star::uno::RuntimeException;
53
54
//  used for sheet- and area link:
55
static std::span<const SfxItemPropertyMapEntry> lcl_GetSheetLinkMap()
56
0
{
57
0
    static const SfxItemPropertyMapEntry aSheetLinkMap_Impl[] =
58
0
    {
59
0
        { SC_UNONAME_FILTER,   0,  cppu::UnoType<OUString>::get(),    0, 0 },
60
0
        { SC_UNONAME_FILTOPT,  0,  cppu::UnoType<OUString>::get(),    0, 0 },
61
0
        { SC_UNONAME_LINKURL,  0,  cppu::UnoType<OUString>::get(),    0, 0 },
62
0
        { SC_UNONAME_REFDELAY, 0,  cppu::UnoType<sal_Int32>::get(),        0, 0 },
63
0
        { SC_UNONAME_REFPERIOD,    0,  cppu::UnoType<sal_Int32>::get(),        0, 0 },
64
0
    };
65
0
    return aSheetLinkMap_Impl;
66
0
}
67
68
SC_SIMPLE_SERVICE_INFO( ScAreaLinkObj, u"ScAreaLinkObj"_ustr, u"com.sun.star.sheet.CellAreaLink"_ustr )
69
SC_SIMPLE_SERVICE_INFO( ScAreaLinksObj, u"ScAreaLinksObj"_ustr, u"com.sun.star.sheet.CellAreaLinks"_ustr )
70
SC_SIMPLE_SERVICE_INFO( ScDDELinkObj, u"ScDDELinkObj"_ustr, u"com.sun.star.sheet.DDELink"_ustr )
71
SC_SIMPLE_SERVICE_INFO( ScDDELinksObj, u"ScDDELinksObj"_ustr, u"com.sun.star.sheet.DDELinks"_ustr )
72
SC_SIMPLE_SERVICE_INFO( ScSheetLinkObj, u"ScSheetLinkObj"_ustr, u"com.sun.star.sheet.SheetLink"_ustr )
73
SC_SIMPLE_SERVICE_INFO( ScSheetLinksObj, u"ScSheetLinksObj"_ustr, u"com.sun.star.sheet.SheetLinks"_ustr )
74
75
ScSheetLinkObj::ScSheetLinkObj(ScDocShell* pDocSh, OUString aName) :
76
0
    aPropSet( lcl_GetSheetLinkMap() ),
77
0
    pDocShell( pDocSh ),
78
0
    aFileName(std::move( aName ))
79
0
{
80
0
    pDocShell->GetDocument().AddUnoObject(*this);
81
0
}
82
83
ScSheetLinkObj::~ScSheetLinkObj()
84
0
{
85
0
    SolarMutexGuard g;
86
87
0
    if (pDocShell)
88
0
        pDocShell->GetDocument().RemoveUnoObject(*this);
89
0
}
90
91
void ScSheetLinkObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
92
0
{
93
    //! notify if links in document are changed
94
    //  UpdateRef is not needed here
95
96
0
    if ( rHint.GetId() == SfxHintId::ScLinkRefreshed )
97
0
    {
98
0
        auto pRefreshHint = static_cast<const ScLinkRefreshedHint*>(&rHint);
99
0
        if ( pRefreshHint->GetLinkType() == ScLinkRefType::SHEET && pRefreshHint->GetUrl() == aFileName )
100
0
            Refreshed_Impl();
101
0
    }
102
0
    else
103
0
    {
104
0
        if ( rHint.GetId() == SfxHintId::Dying )
105
0
            pDocShell = nullptr;       // pointer is invalid
106
0
    }
107
0
}
108
109
ScTableLink* ScSheetLinkObj::GetLink_Impl() const
110
0
{
111
0
    if (pDocShell)
112
0
    {
113
0
        sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager();
114
0
        size_t nCount = pLinkManager->GetLinks().size();
115
0
        for (size_t i=0; i<nCount; i++)
116
0
        {
117
0
            ::sfx2::SvBaseLink* pBase = pLinkManager->GetLinks()[i].get();
118
0
            if (auto pTabLink = dynamic_cast<ScTableLink*>( pBase))
119
0
            {
120
0
                if ( pTabLink->GetFileName() == aFileName )
121
0
                    return pTabLink;
122
0
            }
123
0
        }
124
0
    }
125
0
    return nullptr;    // not found
126
0
}
127
128
// XNamed
129
130
OUString SAL_CALL ScSheetLinkObj::getName()
131
0
{
132
0
    SolarMutexGuard aGuard;
133
0
    return getFileName();   // Name is the same as filename (URL)
134
0
}
135
136
void SAL_CALL ScSheetLinkObj::setName( const OUString& aName )
137
0
{
138
0
    SolarMutexGuard aGuard;
139
0
    setFileName(aName);     // Name is the same as filename (URL)
140
0
}
141
142
// XRefreshable
143
144
void SAL_CALL ScSheetLinkObj::refresh()
145
0
{
146
0
    SolarMutexGuard aGuard;
147
0
    ScTableLink* pLink = GetLink_Impl();
148
0
    if (pLink)
149
0
        pLink->Refresh( pLink->GetFileName(), pLink->GetFilterName(), nullptr, pLink->GetRefreshDelaySeconds() );
150
0
}
151
152
void SAL_CALL ScSheetLinkObj::addRefreshListener(
153
    const uno::Reference<util::XRefreshListener >& xListener )
154
0
{
155
0
    SolarMutexGuard aGuard;
156
0
    aRefreshListeners.push_back( xListener );
157
158
    //  hold one additional ref to keep this object alive as long as there are listeners
159
0
    if ( aRefreshListeners.size() == 1 )
160
0
        acquire();
161
0
}
162
163
void SAL_CALL ScSheetLinkObj::removeRefreshListener(
164
                                const uno::Reference<util::XRefreshListener >& xListener )
165
0
{
166
0
    SolarMutexGuard aGuard;
167
0
    size_t nCount = aRefreshListeners.size();
168
0
    for ( size_t n=nCount; n--; )
169
0
    {
170
0
        uno::Reference<util::XRefreshListener>& rObj = aRefreshListeners[n];
171
0
        if ( rObj == xListener )
172
0
        {
173
0
            aRefreshListeners.erase( aRefreshListeners.begin() + n );
174
0
            if ( aRefreshListeners.empty() )
175
0
                release();                          // release ref for listeners
176
0
            break;
177
0
        }
178
0
    }
179
0
}
180
181
void ScSheetLinkObj::Refreshed_Impl()
182
0
{
183
0
    lang::EventObject aEvent;
184
0
    aEvent.Source.set(getXWeak());
185
0
    for (uno::Reference<util::XRefreshListener> & xRefreshListener : aRefreshListeners)
186
0
        xRefreshListener->refreshed( aEvent );
187
0
}
188
189
void ScSheetLinkObj::ModifyRefreshDelay_Impl( sal_Int32 nRefresh )
190
0
{
191
0
    ScTableLink* pLink = GetLink_Impl();
192
0
    if( pLink )
193
0
        pLink->SetRefreshDelay( static_cast<sal_uLong>(nRefresh) );
194
0
}
195
196
// XPropertySet
197
198
uno::Reference<beans::XPropertySetInfo> SAL_CALL ScSheetLinkObj::getPropertySetInfo()
199
0
{
200
0
    SolarMutexGuard aGuard;
201
0
    static uno::Reference<beans::XPropertySetInfo> aRef(
202
0
        new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
203
0
    return aRef;
204
0
}
205
206
void SAL_CALL ScSheetLinkObj::setPropertyValue(
207
                        const OUString& aPropertyName, const uno::Any& aValue )
208
0
{
209
0
    SolarMutexGuard aGuard;
210
0
    OUString aValStr;
211
0
    if ( aPropertyName == SC_UNONAME_LINKURL )
212
0
    {
213
0
        if ( aValue >>= aValStr )
214
0
            setFileName( aValStr );
215
0
    }
216
0
    else if ( aPropertyName == SC_UNONAME_FILTER )
217
0
    {
218
0
        if ( aValue >>= aValStr )
219
0
            setFilter( aValStr );
220
0
    }
221
0
    else if ( aPropertyName == SC_UNONAME_FILTOPT )
222
0
    {
223
0
        if ( aValue >>= aValStr )
224
0
            setFilterOptions( aValStr );
225
0
    }
226
0
    else if ( aPropertyName == SC_UNONAME_REFPERIOD )
227
0
    {
228
0
        sal_Int32 nRefresh = 0;
229
0
        if ( aValue >>= nRefresh )
230
0
            setRefreshDelay( nRefresh );
231
0
    }
232
0
    else if ( aPropertyName == SC_UNONAME_REFDELAY )
233
0
    {
234
0
        sal_Int32 nRefresh = 0;
235
0
        if ( aValue >>= nRefresh )
236
0
            setRefreshDelay( nRefresh );
237
0
    }
238
0
}
239
240
uno::Any SAL_CALL ScSheetLinkObj::getPropertyValue( const OUString& aPropertyName )
241
0
{
242
0
    SolarMutexGuard aGuard;
243
0
    uno::Any aRet;
244
0
    if ( aPropertyName == SC_UNONAME_LINKURL )
245
0
        aRet <<= getFileName();
246
0
    else if ( aPropertyName == SC_UNONAME_FILTER )
247
0
        aRet <<= getFilter();
248
0
    else if ( aPropertyName == SC_UNONAME_FILTOPT )
249
0
        aRet <<= getFilterOptions();
250
0
    else if ( aPropertyName == SC_UNONAME_REFPERIOD )
251
0
        aRet <<= getRefreshDelay();
252
0
    else if ( aPropertyName == SC_UNONAME_REFDELAY )
253
0
        aRet <<= getRefreshDelay();
254
0
    return aRet;
255
0
}
256
257
SC_IMPL_DUMMY_PROPERTY_LISTENER( ScSheetLinkObj )
258
259
// internal:
260
261
OUString ScSheetLinkObj::getFileName() const
262
0
{
263
0
    SolarMutexGuard aGuard;
264
0
    return aFileName;
265
0
}
266
267
void ScSheetLinkObj::setFileName(const OUString& rNewName)
268
0
{
269
0
    SolarMutexGuard aGuard;
270
0
    ScTableLink* pLink = GetLink_Impl();
271
0
    if (!pLink)
272
0
        return;
273
274
    //  pLink->Refresh with a new file name confuses sfx2::LinkManager
275
    //  therefore we transplant the sheets manually and create new links with UpdateLinks
276
277
0
    OUString aNewStr(ScGlobal::GetAbsDocName( rNewName, pDocShell ));
278
279
    //  first transplant the sheets
280
281
0
    ScDocument& rDoc = pDocShell->GetDocument();
282
0
    SCTAB nTabCount = rDoc.GetTableCount();
283
0
    for (SCTAB nTab=0; nTab<nTabCount; nTab++)
284
0
        if ( rDoc.IsLinked(nTab) && rDoc.GetLinkDoc(nTab) == aFileName )  // old file
285
0
            rDoc.SetLink( nTab, rDoc.GetLinkMode(nTab), aNewStr,
286
0
                            rDoc.GetLinkFlt(nTab), rDoc.GetLinkOpt(nTab),
287
0
                            rDoc.GetLinkTab(nTab),
288
0
                            rDoc.GetLinkRefreshDelay(nTab) );  // only change the file
289
290
    //  update links
291
    //! Undo !!!
292
293
0
    pDocShell->UpdateLinks();   // remove old links, possibly set up new ones
294
295
    //  copy data
296
297
0
    aFileName = aNewStr;
298
0
    pLink = GetLink_Impl();     // new link with new name
299
0
    if (pLink)
300
0
        pLink->Update();        // incl. paint & undo for data
301
0
}
302
303
OUString ScSheetLinkObj::getFilter() const
304
0
{
305
0
    SolarMutexGuard aGuard;
306
0
    OUString aRet;
307
0
    ScTableLink* pLink = GetLink_Impl();
308
0
    if (pLink)
309
0
        aRet = pLink->GetFilterName();
310
0
    return aRet;
311
0
}
312
313
void ScSheetLinkObj::setFilter(const OUString& rFilter)
314
0
{
315
0
    SolarMutexGuard aGuard;
316
0
    ScTableLink* pLink = GetLink_Impl();
317
0
    if (pLink)
318
0
    {
319
0
        pLink->Refresh( aFileName, rFilter, nullptr, pLink->GetRefreshDelaySeconds() );
320
0
    }
321
0
}
322
323
OUString ScSheetLinkObj::getFilterOptions() const
324
0
{
325
0
    SolarMutexGuard aGuard;
326
0
    OUString aRet;
327
0
    ScTableLink* pLink = GetLink_Impl();
328
0
    if (pLink)
329
0
        aRet = pLink->GetOptions();
330
0
    return aRet;
331
0
}
332
333
void ScSheetLinkObj::setFilterOptions(const OUString& FilterOptions)
334
0
{
335
0
    SolarMutexGuard aGuard;
336
0
    ScTableLink* pLink = GetLink_Impl();
337
0
    if (pLink)
338
0
    {
339
0
        OUString aOptStr(FilterOptions);
340
0
        pLink->Refresh( aFileName, pLink->GetFilterName(), &aOptStr, pLink->GetRefreshDelaySeconds() );
341
0
    }
342
0
}
343
344
sal_Int32 ScSheetLinkObj::getRefreshDelay() const
345
0
{
346
0
    SolarMutexGuard aGuard;
347
0
    sal_Int32 nRet = 0;
348
0
    ScTableLink* pLink = GetLink_Impl();
349
0
    if (pLink)
350
0
        nRet = pLink->GetRefreshDelaySeconds();
351
0
    return nRet;
352
0
}
353
354
void ScSheetLinkObj::setRefreshDelay(sal_Int32 nRefreshDelay)
355
0
{
356
0
    SolarMutexGuard aGuard;
357
0
    ModifyRefreshDelay_Impl( nRefreshDelay );
358
0
}
359
360
ScSheetLinksObj::ScSheetLinksObj(ScDocShell* pDocSh) :
361
0
    pDocShell( pDocSh )
362
0
{
363
0
    pDocShell->GetDocument().AddUnoObject(*this);
364
0
}
365
366
ScSheetLinksObj::~ScSheetLinksObj()
367
0
{
368
0
    SolarMutexGuard g;
369
370
0
    if (pDocShell)
371
0
        pDocShell->GetDocument().RemoveUnoObject(*this);
372
0
}
373
374
void ScSheetLinksObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
375
0
{
376
    // we don't care about update of references here
377
378
0
    if ( rHint.GetId() == SfxHintId::Dying )
379
0
    {
380
0
        pDocShell = nullptr;       // became invalid
381
0
    }
382
0
}
383
384
// XSheetLinks
385
386
rtl::Reference<ScSheetLinkObj> ScSheetLinksObj::GetObjectByIndex_Impl(sal_Int32 nIndex)
387
0
{
388
0
    if (!pDocShell)
389
0
        return nullptr;
390
391
0
    typedef std::unordered_set<OUString> StrSetType;
392
0
    StrSetType aNames;
393
0
    ScDocument& rDoc = pDocShell->GetDocument();
394
0
    SCTAB nTabCount = rDoc.GetTableCount();
395
0
    sal_Int32 nCount = 0;
396
0
    for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
397
0
    {
398
0
        if (!rDoc.IsLinked(nTab))
399
0
            continue;
400
401
0
        OUString aLinkDoc = rDoc.GetLinkDoc(nTab);
402
0
        if (aNames.insert(aLinkDoc).second)
403
0
        {
404
            // unique document name.
405
0
            if (nCount == nIndex)
406
0
                return new ScSheetLinkObj( pDocShell, aLinkDoc );
407
0
            ++nCount;
408
0
        }
409
0
    }
410
411
0
    return nullptr;    // no document or index too large
412
0
}
413
414
rtl::Reference<ScSheetLinkObj> ScSheetLinksObj::GetObjectByName_Impl(const OUString& aName)
415
0
{
416
    //  Name is the same as file name
417
418
0
    if (pDocShell)
419
0
    {
420
0
        ScDocument& rDoc = pDocShell->GetDocument();
421
0
        SCTAB nTabCount = rDoc.GetTableCount();
422
0
        for (SCTAB nTab=0; nTab<nTabCount; nTab++)
423
0
            if (rDoc.IsLinked(nTab))
424
0
            {
425
                //! case-insensitive ???
426
0
                OUString aLinkDoc = rDoc.GetLinkDoc( nTab );
427
0
                if ( aLinkDoc == aName )
428
0
                    return new ScSheetLinkObj( pDocShell, aName );
429
0
            }
430
0
    }
431
432
0
    return nullptr;
433
0
}
434
435
// XEnumerationAccess
436
uno::Reference<container::XEnumeration> SAL_CALL ScSheetLinksObj::createEnumeration()
437
0
{
438
0
    SolarMutexGuard aGuard;
439
0
    return new ScIndexEnumeration(this, u"com.sun.star.sheet.SheetLinksEnumeration"_ustr);
440
0
}
441
442
// XIndexAccess
443
sal_Int32 SAL_CALL ScSheetLinksObj::getCount()
444
0
{
445
0
    typedef std::unordered_set<OUString> StrSetType;
446
447
0
    SolarMutexGuard aGuard;
448
0
    if (!pDocShell)
449
0
        return 0;
450
451
0
    sal_Int32 nCount = 0;
452
453
0
    StrSetType aNames;
454
0
    ScDocument& rDoc = pDocShell->GetDocument();
455
0
    SCTAB nTabCount = rDoc.GetTableCount();
456
0
    for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
457
0
    {
458
0
        if (!rDoc.IsLinked(nTab))
459
0
            continue;
460
461
0
        OUString aLinkDoc = rDoc.GetLinkDoc(nTab);
462
0
        if (aNames.insert(aLinkDoc).second)
463
0
            ++nCount;
464
0
    }
465
0
    return nCount;
466
0
}
467
468
uno::Any SAL_CALL ScSheetLinksObj::getByIndex( sal_Int32 nIndex )
469
0
{
470
0
    SolarMutexGuard aGuard;
471
0
    rtl::Reference<ScSheetLinkObj> xLink(GetObjectByIndex_Impl(nIndex));
472
0
    if (!xLink.is())
473
0
        throw lang::IndexOutOfBoundsException();
474
475
0
    return uno::Any(uno::Reference<beans::XPropertySet>(xLink));
476
0
}
477
478
uno::Type SAL_CALL ScSheetLinksObj::getElementType()
479
0
{
480
0
    return cppu::UnoType<beans::XPropertySet>::get();
481
0
}
482
483
sal_Bool SAL_CALL ScSheetLinksObj::hasElements()
484
0
{
485
0
    SolarMutexGuard aGuard;
486
0
    return ( getCount() != 0 );
487
0
}
488
489
uno::Any SAL_CALL ScSheetLinksObj::getByName( const OUString& aName )
490
0
{
491
0
    SolarMutexGuard aGuard;
492
0
    rtl::Reference<ScSheetLinkObj> xLink(GetObjectByName_Impl(aName));
493
0
    if (!xLink.is())
494
0
        throw container::NoSuchElementException();
495
496
0
    return uno::Any(uno::Reference<beans::XPropertySet>(xLink));
497
0
}
498
499
sal_Bool SAL_CALL ScSheetLinksObj::hasByName( const OUString& aName )
500
0
{
501
0
    SolarMutexGuard aGuard;
502
    //  Name is the same as file name
503
504
0
    if (pDocShell)
505
0
    {
506
0
        ScDocument& rDoc = pDocShell->GetDocument();
507
0
        SCTAB nTabCount = rDoc.GetTableCount();
508
0
        for (SCTAB nTab=0; nTab<nTabCount; nTab++)
509
0
            if (rDoc.IsLinked(nTab))
510
0
            {
511
                //! case-insensitive ???
512
0
                OUString aLinkDoc(rDoc.GetLinkDoc( nTab ));
513
0
                if ( aLinkDoc == aName )
514
0
                    return true;
515
0
            }
516
0
    }
517
0
    return false;
518
0
}
519
520
uno::Sequence<OUString> SAL_CALL ScSheetLinksObj::getElementNames()
521
0
{
522
0
    typedef std::unordered_set<OUString> StrSetType;
523
524
0
    SolarMutexGuard aGuard;
525
    //  Name is the same as file name
526
527
0
    if (!pDocShell)
528
0
        return uno::Sequence<OUString>();
529
530
0
    StrSetType aNames;
531
0
    ScDocument& rDoc = pDocShell->GetDocument();
532
0
    SCTAB nTabCount = rDoc.GetTableCount();
533
534
0
    sal_Int32 nLinkCount = getCount();
535
0
    uno::Sequence<OUString> aSeq(nLinkCount);
536
0
    OUString* pAry = aSeq.getArray();
537
0
    size_t nPos = 0;
538
0
    for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
539
0
    {
540
0
        if (!rDoc.IsLinked(nTab))
541
0
            continue;
542
543
0
        OUString aLinkDoc = rDoc.GetLinkDoc(nTab);
544
0
        if (aNames.insert(aLinkDoc).second)
545
0
            pAry[nPos++] = aLinkDoc;
546
0
    }
547
0
    OSL_ENSURE( nPos==static_cast<size_t>(nLinkCount), "verzaehlt" );
548
0
    return aSeq;
549
0
}
550
551
static ScAreaLink* lcl_GetAreaLink( ScDocShell* pDocShell, size_t nPos )
552
0
{
553
0
    if (pDocShell)
554
0
    {
555
0
        sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager();
556
0
        size_t nTotalCount = pLinkManager->GetLinks().size();
557
0
        size_t nAreaCount = 0;
558
0
        for (size_t i=0; i<nTotalCount; i++)
559
0
        {
560
0
            ::sfx2::SvBaseLink* pBase = pLinkManager->GetLinks()[i].get();
561
0
            if (auto pAreaLink = dynamic_cast<ScAreaLink*>( pBase))
562
0
            {
563
0
                if ( nAreaCount == nPos )
564
0
                    return pAreaLink;
565
0
                ++nAreaCount;
566
0
            }
567
0
        }
568
0
    }
569
0
    return nullptr;    // not found
570
0
}
571
572
ScAreaLinkObj::ScAreaLinkObj(ScDocShell* pDocSh, size_t nP) :
573
0
    aPropSet( lcl_GetSheetLinkMap() ),
574
0
    pDocShell( pDocSh ),
575
0
    nPos( nP )
576
0
{
577
0
    pDocShell->GetDocument().AddUnoObject(*this);
578
0
}
579
580
ScAreaLinkObj::~ScAreaLinkObj()
581
0
{
582
0
    SolarMutexGuard g;
583
584
0
    if (pDocShell)
585
0
        pDocShell->GetDocument().RemoveUnoObject(*this);
586
0
}
587
588
void ScAreaLinkObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
589
0
{
590
    //! notify if links in document are changed
591
    //  UpdateRef is not needed here
592
593
0
    if ( rHint.GetId() == SfxHintId::ScLinkRefreshed )
594
0
    {
595
0
        auto pRefreshedHint = static_cast<const ScLinkRefreshedHint*>(&rHint);
596
0
        if ( pRefreshedHint->GetLinkType() == ScLinkRefType::AREA )
597
0
        {
598
            //  get this link to compare dest position
599
0
            ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
600
0
            if ( pLink && pLink->GetDestArea().aStart == pRefreshedHint->GetDestPos() )
601
0
                Refreshed_Impl();
602
0
        }
603
0
    }
604
0
    else if ( rHint.GetId() == SfxHintId::Dying )
605
0
        pDocShell = nullptr;       // pointer is invalid
606
0
}
607
608
// XFileLink
609
610
void ScAreaLinkObj::Modify_Impl( const OUString* pNewFile, const OUString* pNewFilter,
611
                                 const OUString* pNewOptions, const OUString* pNewSource,
612
                                 const table::CellRangeAddress* pNewDest )
613
0
{
614
0
    ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
615
0
    if (!pLink)
616
0
        return;
617
618
0
    OUString aFile    (pLink->GetFile());
619
0
    OUString aFilter  (pLink->GetFilter());
620
0
    OUString aOptions (pLink->GetOptions());
621
0
    OUString aSource  (pLink->GetSource());
622
0
    ScRange aDest   (pLink->GetDestArea());
623
0
    sal_Int32 nRefreshDelaySeconds  = pLink->GetRefreshDelaySeconds();
624
625
    //! Undo delete
626
    //! Undo merge
627
628
0
    sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager();
629
0
    pLinkManager->Remove( pLink );
630
0
    pLink = nullptr;   // deleted along with remove
631
632
0
    bool bFitBlock = true;          // move, if the size changes with update
633
0
    if (pNewFile)
634
0
    {
635
0
        aFile = ScGlobal::GetAbsDocName( *pNewFile, pDocShell );    //! in InsertAreaLink?
636
0
    }
637
0
    if (pNewFilter)
638
0
        aFilter = *pNewFilter;
639
0
    if (pNewOptions)
640
0
        aOptions = *pNewOptions;
641
0
    if (pNewSource)
642
0
        aSource = *pNewSource;
643
0
    if (pNewDest)
644
0
    {
645
0
        ScUnoConversion::FillScRange( aDest, *pNewDest );
646
0
        bFitBlock = false;  // new range was specified -> do not move the content
647
0
    }
648
0
    pDocShell->GetDocFunc().InsertAreaLink( aFile, aFilter, aOptions, aSource,
649
0
                                            aDest, nRefreshDelaySeconds, bFitBlock, true );
650
0
}
651
652
void ScAreaLinkObj::ModifyRefreshDelay_Impl( sal_Int32 nRefreshDelaySeconds )
653
0
{
654
0
    ScAreaLink* pLink = lcl_GetAreaLink( pDocShell, nPos );
655
0
    if( pLink )
656
0
        pLink->SetRefreshDelay( nRefreshDelaySeconds );
657
0
}
658
659
// XRefreshable
660
661
void SAL_CALL ScAreaLinkObj::refresh()
662
0
{
663
0
    SolarMutexGuard aGuard;
664
0
    ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
665
0
    if (pLink)
666
0
        pLink->Refresh( pLink->GetFile(), pLink->GetFilter(), pLink->GetSource(), pLink->GetRefreshDelaySeconds() );
667
0
}
668
669
void SAL_CALL ScAreaLinkObj::addRefreshListener(
670
    const uno::Reference<util::XRefreshListener >& xListener )
671
0
{
672
0
    SolarMutexGuard aGuard;
673
0
    aRefreshListeners.push_back( xListener );
674
675
    //  hold one additional ref to keep this object alive as long as there are listeners
676
0
    if ( aRefreshListeners.size() == 1 )
677
0
        acquire();
678
0
}
679
680
void SAL_CALL ScAreaLinkObj::removeRefreshListener(
681
                                const uno::Reference<util::XRefreshListener >& xListener )
682
0
{
683
0
    SolarMutexGuard aGuard;
684
0
    size_t nCount = aRefreshListeners.size();
685
0
    for ( size_t n=nCount; n--; )
686
0
    {
687
0
        uno::Reference<util::XRefreshListener>& rObj = aRefreshListeners[n];
688
0
        if ( rObj == xListener )
689
0
        {
690
0
            aRefreshListeners.erase( aRefreshListeners.begin() + n );
691
0
            if ( aRefreshListeners.empty() )
692
0
                release();                          // release ref for listeners
693
0
            break;
694
0
        }
695
696
0
        if(n == 0)
697
0
            break;
698
0
    }
699
0
}
700
701
void ScAreaLinkObj::Refreshed_Impl()
702
0
{
703
0
    lang::EventObject aEvent;
704
0
    aEvent.Source.set(getXWeak());
705
0
    for (uno::Reference<util::XRefreshListener> & xRefreshListener : aRefreshListeners)
706
0
        xRefreshListener->refreshed( aEvent );
707
0
}
708
709
// XPropertySet
710
711
uno::Reference<beans::XPropertySetInfo> SAL_CALL ScAreaLinkObj::getPropertySetInfo()
712
0
{
713
0
    SolarMutexGuard aGuard;
714
0
    static uno::Reference<beans::XPropertySetInfo> aRef(
715
0
        new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
716
0
    return aRef;
717
0
}
718
719
void SAL_CALL ScAreaLinkObj::setPropertyValue(
720
                        const OUString& aPropertyName, const uno::Any& aValue )
721
0
{
722
0
    SolarMutexGuard aGuard;
723
0
    OUString aValStr;
724
0
    if ( aPropertyName == SC_UNONAME_LINKURL )
725
0
    {
726
0
        if ( aValue >>= aValStr )
727
0
            setFileName( aValStr );
728
0
    }
729
0
    else if ( aPropertyName == SC_UNONAME_FILTER )
730
0
    {
731
0
        if ( aValue >>= aValStr )
732
0
            setFilter( aValStr );
733
0
    }
734
0
    else if ( aPropertyName == SC_UNONAME_FILTOPT )
735
0
    {
736
0
        if ( aValue >>= aValStr )
737
0
            setFilterOptions( aValStr );
738
0
    }
739
0
    else if ( aPropertyName == SC_UNONAME_REFPERIOD )
740
0
    {
741
0
        sal_Int32 nRefresh = 0;
742
0
        if ( aValue >>= nRefresh )
743
0
            setRefreshDelay( nRefresh );
744
0
    }
745
0
    else if ( aPropertyName == SC_UNONAME_REFDELAY )
746
0
    {
747
0
        sal_Int32 nRefresh = 0;
748
0
        if ( aValue >>= nRefresh )
749
0
            setRefreshDelay( nRefresh );
750
0
    }
751
0
}
752
753
uno::Any SAL_CALL ScAreaLinkObj::getPropertyValue( const OUString& aPropertyName )
754
0
{
755
0
    SolarMutexGuard aGuard;
756
0
    uno::Any aRet;
757
0
    if ( aPropertyName == SC_UNONAME_LINKURL )
758
0
        aRet <<= getFileName();
759
0
    else if ( aPropertyName == SC_UNONAME_FILTER )
760
0
        aRet <<= getFilter();
761
0
    else if ( aPropertyName == SC_UNONAME_FILTOPT )
762
0
        aRet <<= getFilterOptions();
763
0
    else if ( aPropertyName == SC_UNONAME_REFPERIOD )
764
0
        aRet <<= getRefreshDelay();
765
0
    else if ( aPropertyName == SC_UNONAME_REFDELAY )
766
0
        aRet <<= getRefreshDelay();
767
0
    return aRet;
768
0
}
769
770
SC_IMPL_DUMMY_PROPERTY_LISTENER( ScAreaLinkObj )
771
772
//  internal:
773
774
OUString ScAreaLinkObj::getFileName() const
775
0
{
776
0
    SolarMutexGuard aGuard;
777
0
    OUString aRet;
778
0
    ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
779
0
    if (pLink)
780
0
        aRet = pLink->GetFile();
781
0
    return aRet;
782
0
}
783
784
void ScAreaLinkObj::setFileName(const OUString& rNewName)
785
0
{
786
0
    SolarMutexGuard aGuard;
787
0
    Modify_Impl( &rNewName, nullptr, nullptr, nullptr, nullptr );
788
0
}
789
790
OUString ScAreaLinkObj::getFilter() const
791
0
{
792
0
    SolarMutexGuard aGuard;
793
0
    OUString aRet;
794
0
    ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
795
0
    if (pLink)
796
0
        aRet = pLink->GetFilter();
797
0
    return aRet;
798
0
}
799
800
void ScAreaLinkObj::setFilter(const OUString& Filter)
801
0
{
802
0
    SolarMutexGuard aGuard;
803
0
    Modify_Impl( nullptr, &Filter, nullptr, nullptr, nullptr );
804
0
}
805
806
OUString ScAreaLinkObj::getFilterOptions() const
807
0
{
808
0
    SolarMutexGuard aGuard;
809
0
    OUString aRet;
810
0
    ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
811
0
    if (pLink)
812
0
        aRet = pLink->GetOptions();
813
0
    return aRet;
814
0
}
815
816
void ScAreaLinkObj::setFilterOptions(const OUString& FilterOptions)
817
0
{
818
0
    SolarMutexGuard aGuard;
819
0
    Modify_Impl( nullptr, nullptr, &FilterOptions, nullptr, nullptr );
820
0
}
821
822
sal_Int32 ScAreaLinkObj::getRefreshDelay() const
823
0
{
824
0
    SolarMutexGuard aGuard;
825
0
    sal_Int32 nRet = 0;
826
0
    ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
827
0
    if (pLink)
828
0
        nRet = pLink->GetRefreshDelaySeconds();
829
0
    return nRet;
830
0
}
831
832
void ScAreaLinkObj::setRefreshDelay(sal_Int32 nRefreshDelay)
833
0
{
834
0
    SolarMutexGuard aGuard;
835
0
    ModifyRefreshDelay_Impl( nRefreshDelay );
836
0
}
837
838
// XAreaLink
839
840
OUString SAL_CALL ScAreaLinkObj::getSourceArea()
841
0
{
842
0
    SolarMutexGuard aGuard;
843
0
    OUString aRet;
844
0
    ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
845
0
    if (pLink)
846
0
        aRet = pLink->GetSource();
847
0
    return aRet;
848
0
}
849
850
void SAL_CALL ScAreaLinkObj::setSourceArea( const OUString& aSourceArea )
851
0
{
852
0
    SolarMutexGuard aGuard;
853
0
    Modify_Impl( nullptr, nullptr, nullptr, &aSourceArea, nullptr );
854
0
}
855
856
table::CellRangeAddress SAL_CALL ScAreaLinkObj::getDestArea()
857
0
{
858
0
    SolarMutexGuard aGuard;
859
0
    table::CellRangeAddress aRet;
860
0
    ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
861
0
    if (pLink)
862
0
        ScUnoConversion::FillApiRange( aRet, pLink->GetDestArea() );
863
0
    return aRet;
864
0
}
865
866
void SAL_CALL ScAreaLinkObj::setDestArea( const table::CellRangeAddress& aDestArea )
867
0
{
868
0
    SolarMutexGuard aGuard;
869
0
    Modify_Impl( nullptr, nullptr, nullptr, nullptr, &aDestArea );
870
0
}
871
872
ScAreaLinksObj::ScAreaLinksObj(ScDocShell* pDocSh) :
873
0
    pDocShell( pDocSh )
874
0
{
875
0
    pDocShell->GetDocument().AddUnoObject(*this);
876
0
}
877
878
ScAreaLinksObj::~ScAreaLinksObj()
879
0
{
880
0
    SolarMutexGuard g;
881
882
0
    if (pDocShell)
883
0
        pDocShell->GetDocument().RemoveUnoObject(*this);
884
0
}
885
886
void ScAreaLinksObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
887
0
{
888
    //  we don't care about update of references here
889
890
0
    if ( rHint.GetId() == SfxHintId::Dying )
891
0
    {
892
0
        pDocShell = nullptr;       // became invalid
893
0
    }
894
0
}
895
896
// XAreaLinks
897
898
rtl::Reference<ScAreaLinkObj> ScAreaLinksObj::GetObjectByIndex_Impl(sal_Int32 nIndex)
899
0
{
900
0
    if ( pDocShell && nIndex >= 0 && nIndex < getCount() )
901
0
        return new ScAreaLinkObj( pDocShell, static_cast<size_t>(nIndex) );
902
903
0
    return nullptr;    // not found
904
0
}
905
906
void SAL_CALL ScAreaLinksObj::insertAtPosition( const table::CellAddress& aDestPos,
907
                                                const OUString& aFileName,
908
                                                const OUString& aSourceArea,
909
                                                const OUString& aFilter,
910
                                                const OUString& aFilterOptions )
911
0
{
912
0
    SolarMutexGuard aGuard;
913
0
    if (pDocShell)
914
0
    {
915
0
        OUString aFileStr   (aFileName);
916
0
        ScAddress aDestAddr( static_cast<SCCOL>(aDestPos.Column), static_cast<SCROW>(aDestPos.Row), aDestPos.Sheet );
917
918
0
        aFileStr = ScGlobal::GetAbsDocName( aFileStr, pDocShell );  //! in InsertAreaLink ???
919
0
        pDocShell->GetDocFunc().InsertAreaLink( aFileStr, aFilter, aFilterOptions,
920
0
                                                aSourceArea, ScRange(aDestAddr),
921
0
                                                /*nRefreshDelaySeconds*/0, false, true ); // don't move contents
922
0
    }
923
0
}
924
925
void SAL_CALL ScAreaLinksObj::removeByIndex( sal_Int32 nIndex )
926
0
{
927
0
    SolarMutexGuard aGuard;
928
0
    ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, static_cast<size_t>(nIndex));
929
0
    if (pLink)
930
0
    {
931
        //! SetAddUndo or what
932
933
0
        sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager();
934
0
        pLinkManager->Remove( pLink );
935
0
    }
936
0
}
937
938
// XEnumerationAccess
939
940
uno::Reference<container::XEnumeration> SAL_CALL ScAreaLinksObj::createEnumeration()
941
0
{
942
0
    SolarMutexGuard aGuard;
943
0
    return new ScIndexEnumeration(this, u"com.sun.star.sheet.CellAreaLinksEnumeration"_ustr);
944
0
}
945
946
// XIndexAccess
947
948
sal_Int32 SAL_CALL ScAreaLinksObj::getCount()
949
0
{
950
0
    SolarMutexGuard aGuard;
951
0
    sal_Int32 nAreaCount = 0;
952
0
    if (pDocShell)
953
0
    {
954
0
        sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager();
955
0
        size_t nTotalCount = pLinkManager->GetLinks().size();
956
0
        for (size_t i=0; i<nTotalCount; i++)
957
0
        {
958
0
            ::sfx2::SvBaseLink* pBase = pLinkManager->GetLinks()[i].get();
959
0
            if (dynamic_cast<const ScAreaLink*>( pBase) !=  nullptr)
960
0
                ++nAreaCount;
961
0
        }
962
0
    }
963
0
    return nAreaCount;
964
0
}
965
966
uno::Any SAL_CALL ScAreaLinksObj::getByIndex( sal_Int32 nIndex )
967
0
{
968
0
    SolarMutexGuard aGuard;
969
0
    rtl::Reference<ScAreaLinkObj> xLink(GetObjectByIndex_Impl(nIndex));
970
0
    if (!xLink.is())
971
0
        throw lang::IndexOutOfBoundsException();
972
973
0
    return uno::Any(uno::Reference<sheet::XAreaLink>(xLink));
974
975
0
}
976
977
uno::Type SAL_CALL ScAreaLinksObj::getElementType()
978
0
{
979
0
    return cppu::UnoType<sheet::XAreaLink>::get();
980
0
}
981
982
sal_Bool SAL_CALL ScAreaLinksObj::hasElements()
983
0
{
984
0
    SolarMutexGuard aGuard;
985
0
    return ( getCount() != 0 );
986
0
}
987
988
ScDDELinkObj::ScDDELinkObj(ScDocShell* pDocSh, OUString aA,
989
                            OUString aT, OUString aI) :
990
0
    pDocShell( pDocSh ),
991
0
    aAppl(std::move( aA )),
992
0
    aTopic(std::move( aT )),
993
0
    aItem(std::move( aI ))
994
0
{
995
0
    pDocShell->GetDocument().AddUnoObject(*this);
996
0
}
997
998
ScDDELinkObj::~ScDDELinkObj()
999
0
{
1000
0
    SolarMutexGuard g;
1001
1002
0
    if (pDocShell)
1003
0
        pDocShell->GetDocument().RemoveUnoObject(*this);
1004
0
}
1005
1006
void ScDDELinkObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
1007
0
{
1008
    //! notify if links in document are changed
1009
    //  UpdateRef is not needed here
1010
1011
0
    if ( rHint.GetId() == SfxHintId::ScLinkRefreshed )
1012
0
    {
1013
0
        auto pRefreshedHint = static_cast<const ScLinkRefreshedHint*>(&rHint);
1014
0
        if ( pRefreshedHint->GetLinkType() == ScLinkRefType::DDE &&
1015
0
             pRefreshedHint->GetDdeAppl()  == aAppl &&
1016
0
             pRefreshedHint->GetDdeTopic() == aTopic &&
1017
0
             pRefreshedHint->GetDdeItem()  == aItem )       //! mode is ignored
1018
0
            Refreshed_Impl();
1019
0
    }
1020
0
    else if ( rHint.GetId() == SfxHintId::Dying )
1021
0
        pDocShell = nullptr;       // pointer is invalid
1022
0
}
1023
1024
// XNamed
1025
1026
static OUString lcl_BuildDDEName( std::u16string_view rAppl, std::u16string_view rTopic, std::u16string_view rItem )
1027
0
{
1028
    //  Appl|Topic!Item (like Excel)
1029
0
    OUString aRet = OUString::Concat(rAppl) + "|" + rTopic + "!" + rItem;
1030
0
    return aRet;
1031
0
}
1032
1033
OUString SAL_CALL ScDDELinkObj::getName()
1034
0
{
1035
0
    SolarMutexGuard aGuard;
1036
0
    return lcl_BuildDDEName( aAppl, aTopic, aItem );
1037
0
}
1038
1039
void SAL_CALL ScDDELinkObj::setName( const OUString& /* aName */ )
1040
0
{
1041
    //  name can't be changed (formulas wouldn't find the link)
1042
0
    throw uno::RuntimeException();
1043
0
}
1044
1045
// XDDELink
1046
1047
OUString SAL_CALL ScDDELinkObj::getApplication()
1048
0
{
1049
    //! Test if the link is still in the document?
1050
1051
0
    return aAppl;
1052
0
}
1053
1054
OUString SAL_CALL ScDDELinkObj::getTopic()
1055
0
{
1056
    //! Test if the link is still in the document?
1057
1058
0
    return aTopic;
1059
0
}
1060
1061
OUString SAL_CALL ScDDELinkObj::getItem()
1062
0
{
1063
    //! Test if the link is still in the document?
1064
1065
0
    return aItem;
1066
0
}
1067
1068
// XRefreshable
1069
1070
void SAL_CALL ScDDELinkObj::refresh()
1071
0
{
1072
0
    SolarMutexGuard aGuard;
1073
0
    if (pDocShell)
1074
0
    {
1075
0
        sc::DocumentLinkManager& rMgr = pDocShell->GetDocument().GetDocLinkManager();
1076
0
        rMgr.updateDdeLink(aAppl, aTopic, aItem);
1077
0
    }
1078
0
}
1079
1080
void SAL_CALL ScDDELinkObj::addRefreshListener(
1081
    const uno::Reference<util::XRefreshListener >& xListener )
1082
0
{
1083
0
    SolarMutexGuard aGuard;
1084
0
    aRefreshListeners.push_back( xListener );
1085
1086
    //  hold one additional ref to keep this object alive as long as there are listeners
1087
0
    if ( aRefreshListeners.size() == 1 )
1088
0
        acquire();
1089
0
}
1090
1091
void SAL_CALL ScDDELinkObj::removeRefreshListener(
1092
                                const uno::Reference<util::XRefreshListener >& xListener )
1093
0
{
1094
0
    SolarMutexGuard aGuard;
1095
0
    size_t nCount = aRefreshListeners.size();
1096
0
    for ( size_t n=nCount; n--; )
1097
0
    {
1098
0
        uno::Reference<util::XRefreshListener>& rObj = aRefreshListeners[n];
1099
0
        if ( rObj == xListener )
1100
0
        {
1101
0
            aRefreshListeners.erase( aRefreshListeners.begin() + n );
1102
0
            if ( aRefreshListeners.empty() )
1103
0
                release();                          // release ref for listeners
1104
0
            break;
1105
0
        }
1106
0
    }
1107
0
}
1108
1109
// XDDELinkResults
1110
1111
uno::Sequence< uno::Sequence< uno::Any > > ScDDELinkObj::getResults(  )
1112
0
{
1113
0
    SolarMutexGuard aGuard;
1114
0
    uno::Sequence< uno::Sequence< uno::Any > > aReturn;
1115
0
    bool bSuccess = false;
1116
1117
0
    if ( pDocShell )
1118
0
    {
1119
0
        ScDocument& rDoc = pDocShell->GetDocument();
1120
0
        size_t nPos = 0;
1121
0
        if ( rDoc.FindDdeLink( aAppl, aTopic, aItem, SC_DDE_IGNOREMODE, nPos ) )
1122
0
        {
1123
0
            const ScMatrix* pMatrix = rDoc.GetDdeLinkResultMatrix( nPos );
1124
0
            if ( pMatrix )
1125
0
            {
1126
0
                uno::Any aAny;
1127
0
                if ( ScRangeToSequence::FillMixedArray( aAny, pMatrix, true ) )
1128
0
                {
1129
0
                    aAny >>= aReturn;
1130
0
                }
1131
0
            }
1132
0
            bSuccess = true;
1133
0
        }
1134
0
    }
1135
1136
0
    if ( !bSuccess )
1137
0
    {
1138
0
        throw uno::RuntimeException(
1139
0
            u"ScDDELinkObj::getResults: failed to get results!"_ustr );
1140
0
    }
1141
1142
0
    return aReturn;
1143
0
}
1144
1145
void ScDDELinkObj::setResults( const uno::Sequence< uno::Sequence< uno::Any > >& aResults )
1146
0
{
1147
0
    SolarMutexGuard aGuard;
1148
0
    bool bSuccess = false;
1149
1150
0
    if ( pDocShell )
1151
0
    {
1152
0
        ScDocument& rDoc = pDocShell->GetDocument();
1153
0
        size_t nPos = 0;
1154
0
        if ( rDoc.FindDdeLink( aAppl, aTopic, aItem, SC_DDE_IGNOREMODE, nPos ) )
1155
0
        {
1156
0
            ScMatrixRef xMatrix = ScSequenceToMatrix::CreateMixedMatrix( Any(aResults) );
1157
0
            bSuccess = rDoc.SetDdeLinkResultMatrix( nPos, xMatrix );
1158
0
        }
1159
0
    }
1160
1161
0
    if ( !bSuccess )
1162
0
    {
1163
0
        throw uno::RuntimeException(
1164
0
            u"ScDDELinkObj::setResults: failed to set results!"_ustr );
1165
0
    }
1166
0
}
1167
1168
void ScDDELinkObj::Refreshed_Impl()
1169
0
{
1170
0
    lang::EventObject aEvent;
1171
0
    aEvent.Source.set(getXWeak());
1172
0
    for (uno::Reference<util::XRefreshListener> & xRefreshListener : aRefreshListeners)
1173
0
        xRefreshListener->refreshed( aEvent );
1174
0
}
1175
1176
ScDDELinksObj::ScDDELinksObj(ScDocShell* pDocSh) :
1177
0
    pDocShell( pDocSh )
1178
0
{
1179
0
    pDocShell->GetDocument().AddUnoObject(*this);
1180
0
}
1181
1182
ScDDELinksObj::~ScDDELinksObj()
1183
0
{
1184
0
    SolarMutexGuard g;
1185
1186
0
    if (pDocShell)
1187
0
        pDocShell->GetDocument().RemoveUnoObject(*this);
1188
0
}
1189
1190
void ScDDELinksObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
1191
0
{
1192
    //  we don't care about update of references here
1193
1194
0
    if ( rHint.GetId() == SfxHintId::Dying )
1195
0
    {
1196
0
        pDocShell = nullptr;       // became invalid
1197
0
    }
1198
0
}
1199
1200
// XDDELinks
1201
1202
rtl::Reference<ScDDELinkObj> ScDDELinksObj::GetObjectByIndex_Impl(sal_Int32 nIndex)
1203
0
{
1204
0
    if (pDocShell)
1205
0
    {
1206
0
        OUString aAppl, aTopic, aItem;
1207
0
        if ( pDocShell->GetDocument().GetDdeLinkData( static_cast<size_t>(nIndex), aAppl, aTopic, aItem ) )
1208
0
            return new ScDDELinkObj( pDocShell, aAppl, aTopic, aItem );
1209
0
    }
1210
0
    return nullptr;
1211
0
}
1212
1213
rtl::Reference<ScDDELinkObj> ScDDELinksObj::GetObjectByName_Impl(std::u16string_view aName)
1214
0
{
1215
0
    if (pDocShell)
1216
0
    {
1217
0
        OUString aAppl, aTopic, aItem;
1218
1219
0
        ScDocument& rDoc = pDocShell->GetDocument();
1220
0
        size_t nCount = rDoc.GetDocLinkManager().getDdeLinkCount();
1221
0
        for (size_t i=0; i<nCount; i++)
1222
0
        {
1223
0
            rDoc.GetDdeLinkData( i, aAppl, aTopic, aItem );
1224
0
            if ( lcl_BuildDDEName(aAppl, aTopic, aItem) == aName )
1225
0
                return new ScDDELinkObj( pDocShell, aAppl, aTopic, aItem );
1226
0
        }
1227
0
    }
1228
0
    return nullptr;
1229
0
}
1230
1231
// XEnumerationAccess
1232
1233
uno::Reference<container::XEnumeration> SAL_CALL ScDDELinksObj::createEnumeration()
1234
0
{
1235
0
    SolarMutexGuard aGuard;
1236
0
    return new ScIndexEnumeration(this, u"com.sun.star.sheet.DDELinksEnumeration"_ustr);
1237
0
}
1238
1239
// XIndexAccess
1240
1241
sal_Int32 SAL_CALL ScDDELinksObj::getCount()
1242
0
{
1243
0
    SolarMutexGuard aGuard;
1244
0
    sal_Int32 nAreaCount = 0;
1245
0
    if (pDocShell)
1246
0
        nAreaCount = pDocShell->GetDocument().GetDocLinkManager().getDdeLinkCount();
1247
0
    return nAreaCount;
1248
0
}
1249
1250
uno::Any SAL_CALL ScDDELinksObj::getByIndex( sal_Int32 nIndex )
1251
0
{
1252
0
    SolarMutexGuard aGuard;
1253
0
    rtl::Reference<ScDDELinkObj> xLink(GetObjectByIndex_Impl(nIndex));
1254
0
    if (!xLink.is())
1255
0
        throw lang::IndexOutOfBoundsException();
1256
1257
0
    return uno::Any(uno::Reference<sheet::XDDELink>(xLink));
1258
0
}
1259
1260
uno::Type SAL_CALL ScDDELinksObj::getElementType()
1261
0
{
1262
0
    return cppu::UnoType<sheet::XDDELink>::get();
1263
0
}
1264
1265
sal_Bool SAL_CALL ScDDELinksObj::hasElements()
1266
0
{
1267
0
    SolarMutexGuard aGuard;
1268
0
    return ( getCount() != 0 );
1269
0
}
1270
1271
uno::Any SAL_CALL ScDDELinksObj::getByName( const OUString& aName )
1272
0
{
1273
0
    SolarMutexGuard aGuard;
1274
0
    rtl::Reference<ScDDELinkObj> xLink(GetObjectByName_Impl(aName));
1275
0
    if (!xLink.is())
1276
0
        throw container::NoSuchElementException();
1277
1278
0
    return uno::Any(uno::Reference<sheet::XDDELink>(xLink));
1279
0
}
1280
1281
uno::Sequence<OUString> SAL_CALL ScDDELinksObj::getElementNames()
1282
0
{
1283
0
    SolarMutexGuard aGuard;
1284
0
    if (pDocShell)
1285
0
    {
1286
0
        OUString aAppl, aTopic, aItem;
1287
1288
0
        ScDocument& rDoc = pDocShell->GetDocument();
1289
0
        size_t nCount = pDocShell->GetDocument().GetDocLinkManager().getDdeLinkCount();
1290
0
        uno::Sequence<OUString> aSeq(nCount);
1291
0
        OUString* pAry = aSeq.getArray();
1292
1293
0
        for (size_t i=0; i<nCount; i++)
1294
0
        {
1295
0
            rDoc.GetDdeLinkData( i, aAppl, aTopic, aItem );
1296
0
            pAry[i] = lcl_BuildDDEName(aAppl, aTopic, aItem);
1297
0
        }
1298
0
        return aSeq;
1299
0
    }
1300
0
    return uno::Sequence<OUString>();
1301
0
}
1302
1303
sal_Bool SAL_CALL ScDDELinksObj::hasByName( const OUString& aName )
1304
0
{
1305
0
    SolarMutexGuard aGuard;
1306
0
    if (pDocShell)
1307
0
    {
1308
0
        OUString aAppl, aTopic, aItem;
1309
1310
0
        ScDocument& rDoc = pDocShell->GetDocument();
1311
0
        size_t nCount = pDocShell->GetDocument().GetDocLinkManager().getDdeLinkCount();
1312
0
        for (size_t i=0; i<nCount; i++)
1313
0
        {
1314
0
            rDoc.GetDdeLinkData( i, aAppl, aTopic, aItem );
1315
0
            if ( lcl_BuildDDEName(aAppl, aTopic, aItem) == aName )
1316
0
                return true;
1317
0
        }
1318
0
    }
1319
0
    return false;
1320
0
}
1321
1322
// XDDELinks
1323
1324
uno::Reference< sheet::XDDELink > ScDDELinksObj::addDDELink(
1325
    const OUString& aApplication, const OUString& aTopic,
1326
    const OUString& aItem, css::sheet::DDELinkMode nMode )
1327
0
{
1328
0
    SolarMutexGuard aGuard;
1329
0
    uno::Reference< sheet::XDDELink > xLink;
1330
1331
0
    if ( pDocShell )
1332
0
    {
1333
0
        ScDocument& rDoc = pDocShell->GetDocument();
1334
0
        sal_uInt8 nMod = SC_DDE_DEFAULT;
1335
0
        switch ( nMode )
1336
0
        {
1337
0
            case sheet::DDELinkMode_DEFAULT:
1338
0
                {
1339
0
                    nMod = SC_DDE_DEFAULT;
1340
0
                }
1341
0
                break;
1342
0
            case sheet::DDELinkMode_ENGLISH:
1343
0
                {
1344
0
                    nMod = SC_DDE_ENGLISH;
1345
0
                }
1346
0
                break;
1347
0
            case sheet::DDELinkMode_TEXT:
1348
0
                {
1349
0
                    nMod = SC_DDE_TEXT;
1350
0
                }
1351
0
                break;
1352
0
            default:
1353
0
                {
1354
0
                }
1355
0
                break;
1356
0
        }
1357
1358
0
        if ( rDoc.CreateDdeLink( aApplication, aTopic, aItem, nMod, ScMatrixRef() ) )
1359
0
        {
1360
0
            const OUString aName( lcl_BuildDDEName( aApplication, aTopic, aItem ) );
1361
0
            xLink.set( GetObjectByName_Impl( aName ) );
1362
0
        }
1363
0
    }
1364
1365
0
    if ( !xLink.is() )
1366
0
    {
1367
0
        throw uno::RuntimeException(
1368
0
            u"ScDDELinksObj::addDDELink: cannot add DDE link!"_ustr );
1369
0
    }
1370
1371
0
    return xLink;
1372
0
}
1373
1374
ScExternalSheetCacheObj::ScExternalSheetCacheObj(ScDocShell* pDocShell, ScExternalRefCache::TableTypeRef pTable, size_t nIndex) :
1375
205
    mpDocShell(pDocShell),
1376
205
    mpTable(std::move(pTable)),
1377
205
    mnIndex(nIndex)
1378
205
{
1379
205
}
1380
1381
ScExternalSheetCacheObj::~ScExternalSheetCacheObj()
1382
205
{
1383
205
}
1384
1385
void SAL_CALL ScExternalSheetCacheObj::setCellValue(sal_Int32 nCol, sal_Int32 nRow, const Any& rValue)
1386
2.07k
{
1387
2.07k
    SolarMutexGuard aGuard;
1388
2.07k
    if (nRow < 0 || nCol < 0)
1389
0
        throw IllegalArgumentException();
1390
1391
2.07k
    ScExternalRefCache::TokenRef pToken;
1392
2.07k
    double fVal = 0.0;
1393
2.07k
    OUString aVal;
1394
2.07k
    if (rValue >>= fVal)
1395
1.60k
        pToken.reset(new FormulaDoubleToken(fVal));
1396
466
    else if (rValue >>= aVal)
1397
466
    {
1398
466
        svl::SharedStringPool& rPool = mpDocShell->GetDocument().GetSharedStringPool();
1399
466
        svl::SharedString aSS = rPool.intern(aVal);
1400
466
        pToken.reset(new FormulaStringToken(std::move(aSS)));
1401
466
    }
1402
0
    else
1403
        // unidentified value type.
1404
0
        return;
1405
1406
2.07k
    mpTable->setCell(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), pToken);
1407
2.07k
}
1408
1409
Any SAL_CALL ScExternalSheetCacheObj::getCellValue(sal_Int32 nCol, sal_Int32 nRow)
1410
0
{
1411
0
    SolarMutexGuard aGuard;
1412
0
    if (nRow < 0 || nCol < 0)
1413
0
        throw IllegalArgumentException();
1414
1415
0
    FormulaToken* pToken = mpTable->getCell(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow)).get();
1416
0
    if (!pToken)
1417
0
        throw IllegalArgumentException();
1418
1419
0
    Any aValue;
1420
0
    switch (pToken->GetType())
1421
0
    {
1422
0
        case svDouble:
1423
0
        {
1424
0
            double fVal = pToken->GetDouble();
1425
0
            aValue <<= fVal;
1426
0
        }
1427
0
        break;
1428
0
        case svString:
1429
0
        {
1430
0
            OUString aVal = pToken->GetString().getString();
1431
0
            aValue <<= aVal;
1432
0
        }
1433
0
        break;
1434
0
        default:
1435
0
            throw IllegalArgumentException();
1436
0
    }
1437
0
    return aValue;
1438
0
}
1439
1440
Sequence< sal_Int32 > SAL_CALL ScExternalSheetCacheObj::getAllRows()
1441
0
{
1442
0
    SolarMutexGuard aGuard;
1443
0
    std::vector<SCROW> aRows;
1444
0
    mpTable->getAllRows(aRows);
1445
0
    size_t nSize = aRows.size();
1446
0
    Sequence<sal_Int32> aRowsSeq(nSize);
1447
0
    auto aRowsSeqRange = asNonConstRange(aRowsSeq);
1448
0
    for (size_t i = 0; i < nSize; ++i)
1449
0
        aRowsSeqRange[i] = aRows[i];
1450
1451
0
    return aRowsSeq;
1452
0
}
1453
1454
Sequence< sal_Int32 > SAL_CALL ScExternalSheetCacheObj::getAllColumns(sal_Int32 nRow)
1455
0
{
1456
0
    SolarMutexGuard aGuard;
1457
0
    if (nRow < 0)
1458
0
        throw IllegalArgumentException();
1459
1460
0
    std::vector<SCCOL> aCols;
1461
0
    mpTable->getAllCols(static_cast<SCROW>(nRow), aCols);
1462
0
    size_t nSize = aCols.size();
1463
0
    Sequence<sal_Int32> aColsSeq(nSize);
1464
0
    auto aColsSeqRange = asNonConstRange(aColsSeq);
1465
0
    for (size_t i = 0; i < nSize; ++i)
1466
0
        aColsSeqRange[i] = aCols[i];
1467
1468
0
    return aColsSeq;
1469
0
}
1470
1471
sal_Int32 SAL_CALL ScExternalSheetCacheObj::getTokenIndex()
1472
106
{
1473
106
    return static_cast< sal_Int32 >( mnIndex );
1474
106
}
1475
1476
ScExternalDocLinkObj::ScExternalDocLinkObj(ScDocShell* pDocShell, ScExternalRefManager* pRefMgr, sal_uInt16 nFileId) :
1477
31
    mpDocShell(pDocShell), mpRefMgr(pRefMgr), mnFileId(nFileId)
1478
31
{
1479
31
}
1480
1481
ScExternalDocLinkObj::~ScExternalDocLinkObj()
1482
31
{
1483
31
}
1484
1485
uno::Reference< sheet::XExternalSheetCache > SAL_CALL ScExternalDocLinkObj::addSheetCache(
1486
    const OUString& aSheetName, sal_Bool bDynamicCache )
1487
106
{
1488
106
    SolarMutexGuard aGuard;
1489
106
    size_t nIndex = 0;
1490
106
    ScExternalRefCache::TableTypeRef xTable = mpRefMgr->getCacheTable(mnFileId, aSheetName, true, &nIndex);
1491
106
    if (!bDynamicCache)
1492
106
    {
1493
        // Set the whole table cached to prevent access to the source document.
1494
106
        xTable->setWholeTableCached();
1495
106
    }
1496
1497
106
    uno::Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(
1498
106
        mpDocShell, std::move(xTable), nIndex));
1499
106
    return aSheetCache;
1500
106
}
1501
1502
Any SAL_CALL ScExternalDocLinkObj::getByName(const OUString &aName)
1503
0
{
1504
0
    SolarMutexGuard aGuard;
1505
0
    size_t nIndex = 0;
1506
0
    ScExternalRefCache::TableTypeRef xTable = mpRefMgr->getCacheTable(mnFileId, aName, false, &nIndex);
1507
0
    if (!xTable)
1508
0
        throw container::NoSuchElementException();
1509
1510
0
    uno::Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(
1511
0
        mpDocShell, std::move(xTable), nIndex));
1512
1513
0
    return Any(aSheetCache);
1514
0
}
1515
1516
Sequence< OUString > SAL_CALL ScExternalDocLinkObj::getElementNames()
1517
99
{
1518
99
    SolarMutexGuard aGuard;
1519
99
    std::vector<OUString> aTabNames;
1520
99
    mpRefMgr->getAllCachedTableNames(mnFileId, aTabNames);
1521
1522
    // #i116940# be consistent with getByName: include only table names which have a cache already
1523
99
    std::vector<OUString> aValidNames;
1524
99
    std::copy_if(aTabNames.begin(), aTabNames.end(), std::back_inserter(aValidNames),
1525
381
        [&](const OUString& rTabName) { return mpRefMgr->getCacheTable(mnFileId, rTabName, false); });
1526
1527
99
    Sequence<OUString> aSeq(comphelper::containerToSequence(aValidNames));
1528
99
    return aSeq;
1529
99
}
1530
1531
sal_Bool SAL_CALL ScExternalDocLinkObj::hasByName(const OUString &aName)
1532
0
{
1533
0
    SolarMutexGuard aGuard;
1534
1535
    // #i116940# be consistent with getByName: allow only table names which have a cache already
1536
0
    ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aName, false);
1537
0
    return bool(pTable);
1538
0
}
1539
1540
sal_Int32 SAL_CALL ScExternalDocLinkObj::getCount()
1541
0
{
1542
0
    SolarMutexGuard aGuard;
1543
1544
    // #i116940# be consistent with getByName: count only table names which have a cache already
1545
0
    return getElementNames().getLength();
1546
0
}
1547
1548
Any SAL_CALL ScExternalDocLinkObj::getByIndex(sal_Int32 nApiIndex)
1549
99
{
1550
99
    SolarMutexGuard aGuard;
1551
1552
    // #i116940# Can't use nApiIndex as index for the ref manager, because the API counts only
1553
    // the entries which have a cache already. Quick solution: Use getElementNames.
1554
99
    Sequence< OUString > aNames( getElementNames() );
1555
99
    if (nApiIndex < 0 || nApiIndex >= aNames.getLength())
1556
0
        throw lang::IndexOutOfBoundsException();
1557
1558
99
    size_t nIndex = 0;
1559
99
    ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aNames[nApiIndex], false, &nIndex);
1560
99
    if (!pTable)
1561
0
        throw lang::IndexOutOfBoundsException();
1562
1563
99
    uno::Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(mpDocShell, std::move(pTable), nIndex));
1564
1565
99
    return Any(aSheetCache);
1566
99
}
1567
1568
uno::Reference< container::XEnumeration > SAL_CALL ScExternalDocLinkObj::createEnumeration()
1569
0
{
1570
0
    SolarMutexGuard aGuard;
1571
0
    uno::Reference< container::XEnumeration > aRef(
1572
0
        new ScIndexEnumeration(this, u"com.sun.star.sheet.ExternalDocLink"_ustr));
1573
0
    return aRef;
1574
0
}
1575
1576
uno::Type SAL_CALL ScExternalDocLinkObj::getElementType()
1577
0
{
1578
0
    return cppu::UnoType<sheet::XExternalDocLink>::get();
1579
0
}
1580
1581
sal_Bool SAL_CALL ScExternalDocLinkObj::hasElements()
1582
0
{
1583
0
    SolarMutexGuard aGuard;
1584
1585
    // #i116940# be consistent with getByName: count only table names which have a cache already
1586
0
    return getElementNames().hasElements();
1587
0
}
1588
1589
sal_Int32 SAL_CALL ScExternalDocLinkObj::getTokenIndex()
1590
0
{
1591
0
    return static_cast<sal_Int32>(mnFileId);
1592
0
}
1593
1594
ScExternalDocLinksObj::ScExternalDocLinksObj(ScDocShell* pDocShell) :
1595
31
    mpDocShell(pDocShell),
1596
31
    mpRefMgr(pDocShell->GetDocument().GetExternalRefManager())
1597
31
{
1598
31
}
1599
1600
ScExternalDocLinksObj::~ScExternalDocLinksObj()
1601
31
{
1602
31
}
1603
1604
uno::Reference< sheet::XExternalDocLink > SAL_CALL ScExternalDocLinksObj::addDocLink(
1605
    const OUString& aDocName )
1606
31
{
1607
31
    SolarMutexGuard aGuard;
1608
31
    OUString aDocUrl( ScGlobal::GetAbsDocName( aDocName, mpDocShell));
1609
31
    sal_uInt16 nFileId = mpRefMgr->getExternalFileId(aDocUrl);
1610
31
    uno::Reference< sheet::XExternalDocLink > aDocLink(new ScExternalDocLinkObj(mpDocShell, mpRefMgr, nFileId));
1611
31
    return aDocLink;
1612
31
}
1613
1614
Any SAL_CALL ScExternalDocLinksObj::getByName(const OUString &aName)
1615
0
{
1616
0
    SolarMutexGuard aGuard;
1617
0
    OUString aDocUrl( ScGlobal::GetAbsDocName( aName, mpDocShell));
1618
0
    if (!mpRefMgr->hasExternalFile(aDocUrl))
1619
0
        throw container::NoSuchElementException();
1620
1621
0
    sal_uInt16 nFileId = mpRefMgr->getExternalFileId(aDocUrl);
1622
0
    uno::Reference< sheet::XExternalDocLink > aDocLink(new ScExternalDocLinkObj(mpDocShell, mpRefMgr, nFileId));
1623
1624
0
    return Any(aDocLink);
1625
0
}
1626
1627
Sequence< OUString > SAL_CALL ScExternalDocLinksObj::getElementNames()
1628
0
{
1629
0
    SolarMutexGuard aGuard;
1630
0
    sal_uInt16 n = mpRefMgr->getExternalFileCount();
1631
0
    Sequence<OUString> aSeq(n);
1632
0
    auto aSeqRange = asNonConstRange(aSeq);
1633
0
    for (sal_uInt16 i = 0; i < n; ++i)
1634
0
    {
1635
0
        const OUString* pName = mpRefMgr->getExternalFileName(i);
1636
0
        aSeqRange[i] = pName ? *pName : OUString();
1637
0
    }
1638
1639
0
    return aSeq;
1640
0
}
1641
1642
sal_Bool SAL_CALL ScExternalDocLinksObj::hasByName(const OUString &aName)
1643
0
{
1644
0
    SolarMutexGuard aGuard;
1645
0
    return mpRefMgr->hasExternalFile(aName);
1646
0
}
1647
1648
sal_Int32 SAL_CALL ScExternalDocLinksObj::getCount()
1649
0
{
1650
0
    SolarMutexGuard aGuard;
1651
0
    return mpRefMgr->getExternalFileCount();
1652
0
}
1653
1654
Any SAL_CALL ScExternalDocLinksObj::getByIndex(sal_Int32 nIndex)
1655
0
{
1656
0
    SolarMutexGuard aGuard;
1657
0
    if (nIndex > ::std::numeric_limits<sal_uInt16>::max() || nIndex < ::std::numeric_limits<sal_uInt16>::min())
1658
0
        throw lang::IndexOutOfBoundsException();
1659
1660
0
    sal_uInt16 nFileId = static_cast<sal_uInt16>(nIndex);
1661
1662
0
    if (!mpRefMgr->hasExternalFile(nFileId))
1663
0
        throw lang::IndexOutOfBoundsException();
1664
1665
0
    uno::Reference< sheet::XExternalDocLink > aDocLink(new ScExternalDocLinkObj(mpDocShell, mpRefMgr, nFileId));
1666
0
    return Any(aDocLink);
1667
0
}
1668
1669
uno::Reference< container::XEnumeration > SAL_CALL ScExternalDocLinksObj::createEnumeration()
1670
0
{
1671
0
    SolarMutexGuard aGuard;
1672
0
    uno::Reference< container::XEnumeration > aRef(
1673
0
        new ScIndexEnumeration(this, u"com.sun.star.sheet.ExternalDocLinks"_ustr));
1674
0
    return aRef;
1675
0
}
1676
1677
uno::Type SAL_CALL ScExternalDocLinksObj::getElementType()
1678
0
{
1679
0
    return cppu::UnoType<sheet::XExternalDocLinks>::get();
1680
0
}
1681
1682
sal_Bool SAL_CALL ScExternalDocLinksObj::hasElements()
1683
0
{
1684
0
    SolarMutexGuard aGuard;
1685
0
    return mpRefMgr->getExternalFileCount() > 0;
1686
0
}
1687
1688
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */