Coverage Report

Created: 2025-12-08 09:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/docshell/tablink.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/task/InteractionHandler.hpp>
23
24
#include <sfx2/sfxsids.hrc>
25
#include <sfx2/app.hxx>
26
#include <svl/itemset.hxx>
27
#include <svl/stritem.hxx>
28
#include <sfx2/docfile.hxx>
29
#include <sfx2/docfilt.hxx>
30
#include <sfx2/fcontnr.hxx>
31
#include <sfx2/frame.hxx>
32
#include <sfx2/linkmgr.hxx>
33
#include <utility>
34
#include <vcl/weld.hxx>
35
#include <tools/urlobj.hxx>
36
#include <unotools/transliterationwrapper.hxx>
37
#include <comphelper/configuration.hxx>
38
#include <comphelper/processfactory.hxx>
39
40
#include <tablink.hxx>
41
42
#include <scextopt.hxx>
43
#include <document.hxx>
44
#include <docsh.hxx>
45
#include <globstr.hrc>
46
#include <scresid.hxx>
47
#include <undoblk.hxx>
48
#include <undotab.hxx>
49
#include <global.hxx>
50
#include <hints.hxx>
51
#include <dociter.hxx>
52
#include <formula/opcode.hxx>
53
#include <formulaiter.hxx>
54
#include <tokenarray.hxx>
55
56
ScTableLink::ScTableLink(ScDocShell& rShell, OUString aFile,
57
                            OUString aFilter, OUString aOpt,
58
                            sal_Int32 nRefreshDelaySeconds ):
59
0
    ::sfx2::SvBaseLink(SfxLinkUpdateMode::ONCALL,SotClipboardFormatId::SIMPLE_FILE),
60
0
    ScRefreshTimer( nRefreshDelaySeconds ),
61
0
    m_rDocSh( rShell ),
62
0
    aFileName(std::move(aFile)),
63
0
    aFilterName(std::move(aFilter)),
64
0
    aOptions(std::move(aOpt)),
65
0
    bInCreate( false ),
66
0
    bInEdit( false ),
67
0
    bAddUndo( true )
68
0
{
69
0
}
70
71
ScTableLink::~ScTableLink()
72
0
{
73
    // cancel connection
74
75
0
    StopRefreshTimer();
76
0
    ScDocument& rDoc = m_rDocSh.GetDocument();
77
0
    SCTAB nCount = rDoc.GetTableCount();
78
0
    for (SCTAB nTab=0; nTab<nCount; nTab++)
79
0
        if (rDoc.IsLinked(nTab) && aFileName == rDoc.GetLinkDoc(nTab))
80
0
            rDoc.SetLink( nTab, ScLinkMode::NONE, u""_ustr, u""_ustr, u""_ustr, u""_ustr, 0 );
81
0
}
82
83
void ScTableLink::Edit(weld::Window* pParent, const Link<SvBaseLink&,void>& rEndEditHdl)
84
0
{
85
0
    m_aEndEditLink = rEndEditHdl;
86
87
0
    bInEdit = true;
88
0
    SvBaseLink::Edit( pParent, LINK( this, ScTableLink, TableEndEditHdl ) );
89
0
}
90
91
::sfx2::SvBaseLink::UpdateResult ScTableLink::DataChanged(
92
    const OUString&, const css::uno::Any& )
93
0
{
94
0
    sfx2::LinkManager* pLinkManager=m_rDocSh.GetDocument().GetLinkManager();
95
0
    if (pLinkManager!=nullptr)
96
0
    {
97
0
        OUString aFile, aFilter;
98
0
        sfx2::LinkManager::GetDisplayNames(this, nullptr, &aFile, nullptr, &aFilter);
99
100
        //  the file dialog returns the filter name with the application prefix
101
        //  -> remove prefix
102
0
        ScDocumentLoader::RemoveAppPrefix( aFilter );
103
104
0
        if (!bInCreate)
105
0
            Refresh( aFile, aFilter, nullptr, GetRefreshDelaySeconds() ); // don't load twice
106
0
    }
107
0
    return SUCCESS;
108
0
}
109
110
void ScTableLink::Closed()
111
0
{
112
    // delete link: Undo
113
0
    ScDocument& rDoc = m_rDocSh.GetDocument();
114
0
    bool bUndo (rDoc.IsUndoEnabled());
115
116
0
    if (bAddUndo && bUndo)
117
0
    {
118
0
        m_rDocSh.GetUndoManager()->AddUndoAction(
119
0
                std::make_unique<ScUndoRemoveLink>( m_rDocSh, aFileName ) );
120
121
0
        bAddUndo = false;   // only once
122
0
    }
123
124
    // connection gets cancelled in the dtor
125
126
0
    SvBaseLink::Closed();
127
0
}
128
129
bool ScTableLink::IsUsed() const
130
0
{
131
0
    return m_rDocSh.GetDocument().HasLink( aFileName, aFilterName, aOptions );
132
0
}
133
134
bool ScTableLink::Refresh(const OUString& rNewFile, const OUString& rNewFilter,
135
                            const OUString* pNewOptions, sal_Int32 nNewRefreshDelaySeconds )
136
0
{
137
    //  load document
138
139
0
    if (rNewFile.isEmpty() || rNewFilter.isEmpty())
140
0
        return false;
141
142
0
    OUString aNewUrl = ScGlobal::GetAbsDocName(rNewFile, &m_rDocSh);
143
0
    bool bNewUrlName = aFileName != aNewUrl;
144
145
0
    std::shared_ptr<const SfxFilter> pFilter = m_rDocSh.GetFactory().GetFilterContainer()->GetFilter4FilterName(rNewFilter);
146
0
    if (!pFilter)
147
0
        return false;
148
149
0
    ScDocument& rDoc = m_rDocSh.GetDocument();
150
0
    rDoc.SetInLinkUpdate( true );
151
152
0
    bool bUndo(rDoc.IsUndoEnabled());
153
154
    //  if new filter has been selected, forget options
155
0
    if (aFilterName != rNewFilter)
156
0
        aOptions.clear();
157
0
    if ( pNewOptions )                  // options hard-specified?
158
0
        aOptions = *pNewOptions;
159
160
    //  always create ItemSet, so that DocShell can set the options
161
0
    auto pSet = std::make_shared<SfxAllItemSet>( SfxGetpApp()->GetPool() );
162
0
    if (!aOptions.isEmpty())
163
0
        pSet->Put( SfxStringItem( SID_FILE_FILTEROPTIONS, aOptions ) );
164
165
0
    SfxMedium* pMed = new SfxMedium(aNewUrl, StreamMode::STD_READ, std::move(pFilter), std::move(pSet));
166
167
0
    if ( bInEdit )                              // only if using the edit dialog,
168
0
        pMed->UseInteractionHandler(true);    // enable the filter options dialog
169
170
    // aRef->DoClose() will be called explicitly, but it is still more safe to use SfxObjectShellLock here
171
0
    rtl::Reference<ScDocShell> pSrcShell = new ScDocShell(SfxModelFlags::EMBEDDED_OBJECT | SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS);
172
0
    pSrcShell->DoLoad(pMed);
173
174
    // options might have been set
175
0
    OUString aNewOpt = ScDocumentLoader::GetOptions(*pMed);
176
0
    if (aNewOpt.isEmpty())
177
0
        aNewOpt = aOptions;
178
179
    //  Undo...
180
181
0
    ScDocumentUniquePtr pUndoDoc;
182
0
    bool bFirst = true;
183
0
    if (bAddUndo && bUndo)
184
0
        pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
185
186
    //  copy tables
187
188
0
    ScDocShellModificator aModificator( m_rDocSh );
189
190
0
    bool bNotFound = false;
191
0
    ScDocument& rSrcDoc = pSrcShell->GetDocument();
192
193
    //  from text filters that don't set the table name,
194
    //  use the one table regardless of link table name
195
0
    bool bAutoTab = (rSrcDoc.GetTableCount() == 1) &&
196
0
                    ScDocShell::HasAutomaticTableName( rNewFilter );
197
198
0
    SCTAB nCount = rDoc.GetTableCount();
199
0
    for (SCTAB nTab=0; nTab<nCount; nTab++)
200
0
    {
201
0
        ScLinkMode nMode = rDoc.GetLinkMode(nTab);
202
0
        if (nMode != ScLinkMode::NONE && aFileName == rDoc.GetLinkDoc(nTab))
203
0
        {
204
0
            OUString aTabName = rDoc.GetLinkTab(nTab);
205
206
            //  Undo
207
208
0
            if (bAddUndo && bUndo)
209
0
            {
210
0
                if (bFirst)
211
0
                    pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true );
212
0
                else
213
0
                    pUndoDoc->AddUndoTab( nTab, nTab, true, true );
214
0
                bFirst = false;
215
0
                ScRange aRange(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab);
216
0
                rDoc.CopyToDocument(aRange, InsertDeleteFlags::ALL, false, *pUndoDoc);
217
0
                pUndoDoc->TransferDrawPage( rDoc, nTab, nTab );
218
0
                pUndoDoc->SetLink( nTab, nMode, aFileName, aFilterName,
219
0
                                   aOptions, aTabName, GetRefreshDelaySeconds() );
220
0
                pUndoDoc->SetTabBgColor( nTab, rDoc.GetTabBgColor(nTab) );
221
0
            }
222
223
            //  adjust table name of an ExtDocRef
224
225
0
            if ( bNewUrlName && nMode == ScLinkMode::VALUE )
226
0
            {
227
0
                OUString aName;
228
0
                rDoc.GetName( nTab, aName );
229
0
                if ( ScGlobal::GetTransliteration().isEqual(
230
0
                        ScGlobal::GetDocTabName( aFileName, aTabName ), aName ) )
231
0
                {
232
0
                    rDoc.RenameTab( nTab,
233
0
                        ScGlobal::GetDocTabName( aNewUrl, aTabName ),
234
0
                        true/*bExternalDocument*/ );
235
0
                }
236
0
            }
237
238
            //  copy
239
240
0
            SCTAB nSrcTab = 0;
241
0
            bool bFound = false;
242
            /*  #i71497# check if external document is loaded successfully,
243
                otherwise we may find the empty default sheet "Sheet1" in
244
                rSrcDoc, even if the document does not exist. */
245
0
            if( pMed->GetErrorIgnoreWarning() == ERRCODE_NONE )
246
0
            {
247
                // no sheet name -> use first sheet
248
0
                if ( !aTabName.isEmpty() && !bAutoTab )
249
0
                    bFound = rSrcDoc.GetTable( aTabName, nSrcTab );
250
0
                else
251
0
                    bFound = true;
252
0
            }
253
254
0
            if (bFound)
255
0
                rDoc.TransferTab( rSrcDoc, nSrcTab, nTab, false,       // don't insert anew
256
0
                                        (nMode == ScLinkMode::VALUE) );     // only values?
257
0
            else
258
0
            {
259
0
                rDoc.DeleteAreaTab( 0,0,rDoc.MaxCol(),rDoc.MaxRow(), nTab, InsertDeleteFlags::ALL );
260
261
0
                bool bShowError = true;
262
0
                if ( nMode == ScLinkMode::VALUE )
263
0
                {
264
                    //  Value link (used with external references in formulas):
265
                    //  Look for formulas that reference the sheet, and put errors in the referenced cells.
266
267
0
                    ScRangeList aErrorCells;        // cells on the linked sheets that need error values
268
269
0
                    ScCellIterator aIter(rDoc, ScRange(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB));          // all sheets
270
0
                    for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
271
0
                    {
272
0
                        if (aIter.getType() != CELLTYPE_FORMULA)
273
0
                            continue;
274
275
0
                        ScFormulaCell* pCell = aIter.getFormulaCell();
276
0
                        ScDetectiveRefIter aRefIter(rDoc, pCell);
277
0
                        ScRange aRefRange;
278
0
                        while ( aRefIter.GetNextRef( aRefRange ) )
279
0
                        {
280
0
                            if ( aRefRange.aStart.Tab() <= nTab && aRefRange.aEnd.Tab() >= nTab )
281
0
                            {
282
                                // use first cell of range references (don't fill potentially large ranges)
283
284
0
                                aErrorCells.Join( ScRange( aRefRange.aStart ) );
285
0
                            }
286
0
                        }
287
0
                    }
288
289
0
                    size_t nRanges = aErrorCells.size();
290
0
                    if ( nRanges )                          // found any?
291
0
                    {
292
0
                        ScTokenArray aTokenArr(rDoc);
293
0
                        aTokenArr.AddOpCode( ocNotAvail );
294
0
                        aTokenArr.AddOpCode( ocOpen );
295
0
                        aTokenArr.AddOpCode( ocClose );
296
0
                        aTokenArr.AddOpCode( ocStop );
297
298
0
                        for (size_t nPos=0; nPos < nRanges; nPos++)
299
0
                        {
300
0
                            const ScRange & rRange = aErrorCells[ nPos ];
301
0
                            SCCOL nStartCol = rRange.aStart.Col();
302
0
                            SCROW nStartRow = rRange.aStart.Row();
303
0
                            SCCOL nEndCol = rRange.aEnd.Col();
304
0
                            SCROW nEndRow = rRange.aEnd.Row();
305
0
                            for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++)
306
0
                                for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
307
0
                                {
308
0
                                    ScAddress aDestPos( nCol, nRow, nTab );
309
0
                                    rDoc.SetFormula(aDestPos, aTokenArr);
310
0
                                }
311
0
                        }
312
313
0
                        bShowError = false;
314
0
                    }
315
                    // if no references were found, insert error message (don't leave the sheet empty)
316
0
                }
317
318
0
                if ( bShowError )
319
0
                {
320
                    //  Normal link or no references: put error message on sheet.
321
322
0
                    rDoc.SetString( 0,0,nTab, ScResId(STR_LINKERROR) );
323
0
                    rDoc.SetString( 0,1,nTab, ScResId(STR_LINKERRORFILE) );
324
0
                    rDoc.SetString( 1,1,nTab, aNewUrl );
325
0
                    rDoc.SetString( 0,2,nTab, ScResId(STR_LINKERRORTAB) );
326
0
                    rDoc.SetString( 1,2,nTab, aTabName );
327
0
                }
328
329
0
                bNotFound = true;
330
0
            }
331
332
0
            if ( bNewUrlName || aFilterName != rNewFilter ||
333
0
                    aOptions != aNewOpt || pNewOptions ||
334
0
                    nNewRefreshDelaySeconds != GetRefreshDelaySeconds() )
335
0
                rDoc.SetLink( nTab, nMode, aNewUrl, rNewFilter, aNewOpt,
336
0
                    aTabName, nNewRefreshDelaySeconds );
337
0
        }
338
0
    }
339
340
    //  memorize new settings
341
342
0
    if ( bNewUrlName )
343
0
        aFileName = aNewUrl;
344
0
    if (aFilterName != rNewFilter)
345
0
        aFilterName = rNewFilter;
346
0
    if (aOptions != aNewOpt)
347
0
        aOptions = aNewOpt;
348
349
    //  clean up
350
351
0
    pSrcShell->DoClose();
352
353
    //  Undo
354
355
0
    if (bAddUndo && bUndo)
356
0
        m_rDocSh.GetUndoManager()->AddUndoAction(
357
0
                    std::make_unique<ScUndoRefreshLink>( m_rDocSh, std::move(pUndoDoc) ) );
358
359
    //  Paint (may be several tables)
360
361
0
    m_rDocSh.PostPaint( ScRange(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB),
362
0
                                PaintPartFlags::Grid | PaintPartFlags::Top | PaintPartFlags::Left | PaintPartFlags::Extras );
363
0
    aModificator.SetDocumentModified();
364
365
0
    if (bNotFound)
366
0
    {
367
        //! output error ?
368
0
    }
369
370
0
    rDoc.SetInLinkUpdate( false );
371
372
    //  notify Uno objects (for XRefreshListener)
373
    //! also notify Uno objects if file name was changed!
374
0
    ScLinkRefreshedHint aHint;
375
0
    aHint.SetSheetLink( aFileName );
376
0
    rDoc.BroadcastUno( aHint );
377
378
0
    return true;
379
0
}
380
381
IMPL_LINK( ScTableLink, TableEndEditHdl, ::sfx2::SvBaseLink&, rLink, void )
382
0
{
383
0
    m_aEndEditLink.Call( rLink );
384
0
    bInEdit = false;
385
0
}
386
387
// === ScDocumentLoader ==================================================
388
389
OUString ScDocumentLoader::GetOptions( const SfxMedium& rMedium )
390
0
{
391
0
    if ( const SfxStringItem* pItem = rMedium.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) )
392
0
        return pItem->GetValue();
393
394
0
    return OUString();
395
0
}
396
397
bool ScDocumentLoader::GetFilterName( const OUString& rFileName,
398
                                      OUString& rFilter, OUString& rOptions,
399
                                      bool bWithContent, bool bWithInteraction )
400
1.86k
{
401
1.86k
    SfxObjectShell* pDocSh = SfxObjectShell::GetFirst( checkSfxObjectShell<ScDocShell> );
402
1.86k
    while ( pDocSh )
403
0
    {
404
0
        if ( pDocSh->HasName() )
405
0
        {
406
0
            SfxMedium* pMed = pDocSh->GetMedium();
407
0
            if ( pMed->GetName() == rFileName )
408
0
            {
409
0
                rFilter = pMed->GetFilter()->GetFilterName();
410
0
                rOptions = GetOptions(*pMed);
411
0
                return true;
412
0
            }
413
0
        }
414
0
        pDocSh = SfxObjectShell::GetNext( *pDocSh, checkSfxObjectShell<ScDocShell> );
415
0
    }
416
417
1.86k
    INetURLObject aUrl( rFileName );
418
1.86k
    INetProtocol eProt = aUrl.GetProtocol();
419
1.86k
    if ( eProt == INetProtocol::NotValid )         // invalid URL?
420
85
        return false;                           // abort without creating a medium
421
422
    //  Filter detection
423
424
1.78k
    std::shared_ptr<const SfxFilter> pSfxFilter;
425
1.78k
    SfxMedium aMedium( rFileName, StreamMode::STD_READ );
426
1.78k
    if (aMedium.GetErrorIgnoreWarning() == ERRCODE_NONE && !comphelper::IsFuzzing())
427
0
    {
428
0
        if ( bWithInteraction )
429
0
            aMedium.UseInteractionHandler(true);   // #i73992# no longer called from GuessFilter
430
431
0
        SfxFilterMatcher aMatcher(u"scalc"_ustr);
432
0
        if( bWithContent )
433
0
            aMatcher.GuessFilter( aMedium, pSfxFilter );
434
0
        else
435
0
            aMatcher.GuessFilterIgnoringContent( aMedium, pSfxFilter );
436
0
    }
437
438
1.78k
    bool bOK = false;
439
1.78k
    if ( aMedium.GetErrorIgnoreWarning() == ERRCODE_NONE )
440
1.78k
    {
441
1.78k
        if ( pSfxFilter )
442
0
            rFilter = pSfxFilter->GetFilterName();
443
1.78k
        else
444
1.78k
            rFilter = ScDocShell::GetOwnFilterName();       //  otherwise Calc file
445
1.78k
        bOK = !rFilter.isEmpty();
446
1.78k
    }
447
448
1.78k
    return bOK;
449
1.86k
}
450
451
void ScDocumentLoader::RemoveAppPrefix( OUString& rFilterName )
452
0
{
453
0
    OUString aAppPrefix( STRING_SCAPP + ": ");
454
0
    if (rFilterName.startsWith( aAppPrefix))
455
0
        rFilterName = rFilterName.copy( aAppPrefix.getLength());
456
0
}
457
458
SfxMedium* ScDocumentLoader::CreateMedium( const OUString& rFileName, std::shared_ptr<const SfxFilter> const & pFilter,
459
        const OUString& rOptions, weld::Window* pInteractionParent )
460
0
{
461
    // Always create SfxItemSet so ScDocShell can set options.
462
0
    auto pSet = std::make_shared<SfxAllItemSet>( SfxGetpApp()->GetPool() );
463
0
    if ( !rOptions.isEmpty() )
464
0
        pSet->Put( SfxStringItem( SID_FILE_FILTEROPTIONS, rOptions ) );
465
466
0
    if (pInteractionParent)
467
0
    {
468
0
        const css::uno::Reference<css::uno::XComponentContext>& xContext = comphelper::getProcessComponentContext();
469
0
        css::uno::Reference<css::task::XInteractionHandler> xIHdl(css::task::InteractionHandler::createWithParent(xContext,
470
0
                    pInteractionParent->GetXWindow()), css::uno::UNO_QUERY_THROW);
471
0
        pSet->Put(SfxUnoAnyItem(SID_INTERACTIONHANDLER, css::uno::Any(xIHdl)));
472
0
    }
473
474
0
    SfxMedium *pRet = new SfxMedium( rFileName, StreamMode::STD_READ, pFilter, std::move(pSet) );
475
0
    if (pInteractionParent)
476
0
        pRet->UseInteractionHandler(true); // to enable the filter options dialog
477
0
    return pRet;
478
0
}
479
480
ScDocumentLoader::ScDocumentLoader(const OUString& rFileName,
481
                                   OUString& rFilterName, OUString& rOptions,
482
                                   sal_uInt32 nRekCnt, weld::Window* pInteractionParent,
483
                                   const css::uno::Reference<css::io::XInputStream>& xInputStream)
484
0
    : pMedium(nullptr)
485
0
{
486
0
    if ( rFilterName.isEmpty() )
487
0
        GetFilterName(rFileName, rFilterName, rOptions, true, pInteractionParent != nullptr);
488
489
0
    std::shared_ptr<const SfxFilter> pFilter = ScDocShell::Factory().GetFilterContainer()->GetFilter4FilterName( rFilterName );
490
491
0
    pMedium = CreateMedium(rFileName, pFilter, rOptions, pInteractionParent);
492
0
    if (xInputStream.is())
493
0
        pMedium->setStreamToLoadFrom(xInputStream, true);
494
0
    if ( pMedium->GetErrorIgnoreWarning() != ERRCODE_NONE )
495
0
        return ;
496
497
0
    pDocShell = new ScDocShell( SfxModelFlags::EMBEDDED_OBJECT | SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS );
498
499
0
    ScDocument& rDoc = pDocShell->GetDocument();
500
0
    ScExtDocOptions*    pExtDocOpt = rDoc.GetExtDocOptions();
501
0
    if( !pExtDocOpt )
502
0
    {
503
0
        rDoc.SetExtDocOptions( std::make_unique<ScExtDocOptions>() );
504
0
        pExtDocOpt = rDoc.GetExtDocOptions();
505
0
    }
506
0
    pExtDocOpt->GetDocSettings().mnLinkCnt = nRekCnt;
507
508
0
    pDocShell->DoLoad( pMedium );
509
510
0
    OUString aNew = GetOptions(*pMedium);         // options are set per dialog on load
511
0
    if (!aNew.isEmpty() && aNew != rOptions)
512
0
        rOptions = aNew;
513
0
}
514
515
ScDocumentLoader::~ScDocumentLoader()
516
0
{
517
0
    if (pDocShell)
518
0
        pDocShell->DoClose();
519
0
    else
520
0
        delete pMedium;
521
0
}
522
523
void ScDocumentLoader::ReleaseDocRef()
524
0
{
525
0
    if (pDocShell)
526
0
    {
527
        //  release reference without calling DoClose - caller must
528
        //  have another reference to the doc and call DoClose later
529
530
0
        pMedium = nullptr;
531
0
        pDocShell.clear();
532
0
    }
533
0
}
534
535
ScDocument* ScDocumentLoader::GetDocument()
536
0
{
537
0
    return pDocShell ? &pDocShell->GetDocument() : nullptr;
538
0
}
539
540
bool ScDocumentLoader::IsError() const
541
0
{
542
0
    if ( pDocShell && pMedium )
543
0
        return pMedium->GetErrorIgnoreWarning() != ERRCODE_NONE;
544
0
    else
545
0
        return true;
546
0
}
547
548
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */