Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/sc/source/ui/docshell/docsh.cxx
Line
Count
Source (jump to first uncovered line)
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 <docsh.hxx>
23
24
#include <config_features.h>
25
#include <scitems.hxx>
26
#include <sc.hrc>
27
#include <vcl/errinf.hxx>
28
#include <editeng/justifyitem.hxx>
29
#include <comphelper/fileformat.h>
30
#include <comphelper/classids.hxx>
31
#include <comphelper/propertyvalue.hxx>
32
#include <formula/errorcodes.hxx>
33
#include <vcl/stdtext.hxx>
34
#include <vcl/syswin.hxx>
35
#include <vcl/svapp.hxx>
36
#include <vcl/virdev.hxx>
37
#include <vcl/weld.hxx>
38
#include <rtl/bootstrap.hxx>
39
#include <rtl/tencinfo.h>
40
#include <sal/log.hxx>
41
#include <svl/PasswordHelper.hxx>
42
#include <sfx2/app.hxx>
43
#include <sfx2/bindings.hxx>
44
#include <sfx2/dinfdlg.hxx>
45
#include <sfx2/docfile.hxx>
46
#include <sfx2/event.hxx>
47
#include <sfx2/docfilt.hxx>
48
#include <sfx2/lokhelper.hxx>
49
#include <sfx2/objface.hxx>
50
#include <sfx2/viewfrm.hxx>
51
#include <sfx2/infobar.hxx>
52
#include <svl/documentlockfile.hxx>
53
#include <svl/fstathelper.hxx>
54
#include <svl/sharecontrolfile.hxx>
55
#include <svl/urihelper.hxx>
56
#include <osl/file.hxx>
57
#include <chgtrack.hxx>
58
#include <chgviset.hxx>
59
#include <com/sun/star/awt/Key.hpp>
60
#include <com/sun/star/awt/KeyModifier.hpp>
61
#include <com/sun/star/container/XContentEnumerationAccess.hpp>
62
#include <com/sun/star/document/UpdateDocMode.hpp>
63
#include <com/sun/star/script/vba/VBAEventId.hpp>
64
#include <com/sun/star/script/vba/VBAScriptEventId.hpp>
65
#include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
66
#include <com/sun/star/script/vba/XVBAScriptListener.hpp>
67
#include <com/sun/star/script/vba/XVBACompatibility.hpp>
68
#include <com/sun/star/sheet/XSpreadsheetView.hpp>
69
#include <com/sun/star/task/XJob.hpp>
70
#include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
71
#include <com/sun/star/ui/XAcceleratorConfiguration.hpp>
72
#include <com/sun/star/util/VetoException.hpp>
73
#include <com/sun/star/lang/XSingleComponentFactory.hpp>
74
#include <ooo/vba/excel/XWorkbook.hpp>
75
#include <comphelper/diagnose_ex.hxx>
76
77
#include <config_folders.h>
78
79
#include <scabstdlg.hxx>
80
#include <sot/formats.hxx>
81
#include <svx/compatflags.hxx>
82
#include <svx/dialogs.hrc>
83
#include <svx/svdpagv.hxx>
84
#include <svx/svdpage.hxx>
85
#include <docmodel/theme/Theme.hxx>
86
87
#include <inputopt.hxx>
88
#include <formulacell.hxx>
89
#include <global.hxx>
90
#include <filter.hxx>
91
#include <scmod.hxx>
92
#include <tabvwsh.hxx>
93
#include <docfunc.hxx>
94
#include <imoptdlg.hxx>
95
#include <impex.hxx>
96
#include <scresid.hxx>
97
#include <strings.hrc>
98
#include <globstr.hrc>
99
#include <scerrors.hxx>
100
#include <brdcst.hxx>
101
#include <stlpool.hxx>
102
#include <autostyl.hxx>
103
#include <attrib.hxx>
104
#include <asciiopt.hxx>
105
#include <progress.hxx>
106
#include <pntlock.hxx>
107
#include <docuno.hxx>
108
#include <appoptio.hxx>
109
#include <formulaopt.hxx>
110
#include <scdll.hxx>
111
#include <detdata.hxx>
112
#include <printfun.hxx>
113
#include <dociter.hxx>
114
#include <cellform.hxx>
115
#include <chartlis.hxx>
116
#include <hints.hxx>
117
#include <xmlwrap.hxx>
118
#include <drwlayer.hxx>
119
#include <dbdata.hxx>
120
#include <scextopt.hxx>
121
#include <compiler.hxx>
122
#include <warnpassword.hxx>
123
#include <sheetdata.hxx>
124
#include <table.hxx>
125
#include <tabprotection.hxx>
126
#include <docparam.hxx>
127
#include "docshimp.hxx"
128
#include <sizedev.hxx>
129
#include <undomanager.hxx>
130
#include <refreshtimerprotector.hxx>
131
132
#include <officecfg/Office/Calc.hxx>
133
#include <comphelper/processfactory.hxx>
134
#include <comphelper/string.hxx>
135
#include <unotools/configmgr.hxx>
136
#include <unotools/mediadescriptor.hxx>
137
#include <unotools/tempfile.hxx>
138
#include <unotools/ucbstreamhelper.hxx>
139
#include <uiitems.hxx>
140
#include <dpobject.hxx>
141
#include <markdata.hxx>
142
#include <docoptio.hxx>
143
#include <orcusfilters.hxx>
144
#include <datastream.hxx>
145
#include <documentlinkmgr.hxx>
146
#include <refupdatecontext.hxx>
147
#include <DocumentModelAccessor.hxx>
148
149
#include <memory>
150
#include <vector>
151
152
#include <comphelper/lok.hxx>
153
#include <svtools/sfxecode.hxx>
154
#include <unotools/pathoptions.hxx>
155
156
using namespace com::sun::star;
157
using ::com::sun::star::uno::Reference;
158
using ::com::sun::star::lang::XMultiServiceFactory;
159
using std::shared_ptr;
160
using ::std::vector;
161
162
//  Filter names (like in sclib.cxx)
163
164
constexpr OUStringLiteral pFilterSc50 = u"StarCalc 5.0";
165
const char pFilterXML[]      = "StarOffice XML (Calc)";
166
constexpr OUString pFilterLotus = u"Lotus"_ustr;
167
const char pFilterQPro6[]    = "Quattro Pro 6.0";
168
const char16_t pFilterExcel4[] = u"MS Excel 4.0";
169
const char16_t pFilterEx4Temp[] = u"MS Excel 4.0 Vorlage/Template";
170
const char pFilterExcel5[]   = "MS Excel 5.0/95";
171
const char pFilterEx5Temp[]  = "MS Excel 5.0/95 Vorlage/Template";
172
const char pFilterExcel95[]  = "MS Excel 95";
173
const char pFilterEx95Temp[] = "MS Excel 95 Vorlage/Template";
174
const char pFilterExcel97[]  = "MS Excel 97";
175
const char pFilterEx97Temp[] = "MS Excel 97 Vorlage/Template";
176
constexpr OUString pFilterDBase = u"dBase"_ustr;
177
constexpr OUString pFilterDif = u"DIF"_ustr;
178
const char16_t pFilterSylk[] = u"SYLK";
179
constexpr OUString pFilterHtml = u"HTML (StarCalc)"_ustr;
180
constexpr OUString pFilterHtmlWebQ = u"calc_HTML_WebQuery"_ustr;
181
const char16_t pFilterRtf[]  = u"Rich Text Format (StarCalc)";
182
183
#define ShellClass_ScDocShell
184
#include <scslots.hxx>
185
186
SFX_IMPL_INTERFACE(ScDocShell,SfxObjectShell)
187
188
void ScDocShell::InitInterface_Impl()
189
11
{
190
11
}
191
192
//  GlobalName of the current version:
193
SFX_IMPL_OBJECTFACTORY( ScDocShell, SvGlobalName(SO3_SC_CLASSID), u"scalc"_ustr )
194
195
196
void ScDocShell::FillClass( SvGlobalName* pClassName,
197
                                        SotClipboardFormatId* pFormat,
198
                                        OUString* pFullTypeName,
199
                                        sal_Int32 nFileFormat,
200
                                        bool bTemplate /* = false */) const
201
65.6k
{
202
65.6k
    if ( nFileFormat == SOFFICE_FILEFORMAT_60 )
203
0
    {
204
0
        *pClassName     = SvGlobalName( SO3_SC_CLASSID_60 );
205
0
        *pFormat        = SotClipboardFormatId::STARCALC_60;
206
0
        *pFullTypeName  = ScResId( SCSTR_LONG_SCDOC_NAME_60 );
207
0
    }
208
65.6k
    else if ( nFileFormat == SOFFICE_FILEFORMAT_8 )
209
65.6k
    {
210
65.6k
        *pClassName     = SvGlobalName( SO3_SC_CLASSID_60 );
211
65.6k
        *pFormat        = bTemplate ? SotClipboardFormatId::STARCALC_8_TEMPLATE : SotClipboardFormatId::STARCALC_8;
212
65.6k
        *pFullTypeName  = ScResId( SCSTR_LONG_SCDOC_NAME_80 );
213
65.6k
    }
214
0
    else
215
0
    {
216
0
        OSL_FAIL("Which version?");
217
0
    }
218
65.6k
}
219
220
std::set<Color> ScDocShell::GetDocColors()
221
0
{
222
0
    return m_pDocument->GetDocColors();
223
0
}
224
225
std::shared_ptr<sfx::IDocumentModelAccessor> ScDocShell::GetDocumentModelAccessor() const
226
0
{
227
0
    std::shared_ptr<sfx::IDocumentModelAccessor> pReturn;
228
0
    pReturn.reset(new sc::DocumentModelAccessor(m_pDocument));
229
0
    return pReturn;
230
0
}
231
232
std::shared_ptr<model::ColorSet> ScDocShell::GetThemeColors()
233
0
{
234
0
    ScTabViewShell* pShell = GetBestViewShell();
235
0
    if (!pShell)
236
0
        return {};
237
238
0
    SdrModel* pSdrModel = GetDocument().GetDrawLayer();
239
0
    if (!pSdrModel)
240
0
        return {};
241
242
0
    auto const& pTheme = pSdrModel->getTheme();
243
0
    if (!pTheme)
244
0
        return {};
245
246
0
    return pTheme->getColorSet();
247
0
}
248
249
void ScDocShell::DoEnterHandler()
250
0
{
251
0
    ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
252
0
    if (pViewSh && &pViewSh->GetViewData().GetDocShell() == this)
253
0
        ScModule::get()->InputEnterHandler();
254
0
}
255
256
SCTAB ScDocShell::GetSaveTab()
257
0
{
258
0
    SCTAB nTab = 0;
259
0
    ScTabViewShell* pSh = GetBestViewShell();
260
0
    if (pSh)
261
0
    {
262
0
        const ScMarkData& rMark = pSh->GetViewData().GetMarkData();
263
0
        nTab = rMark.GetFirstSelected();
264
0
    }
265
0
    return nTab;
266
0
}
267
268
HiddenInformation ScDocShell::GetHiddenInformationState( HiddenInformation nStates )
269
0
{
270
    // get global state like HiddenInformation::DOCUMENTVERSIONS
271
0
    HiddenInformation nState = SfxObjectShell::GetHiddenInformationState( nStates );
272
273
0
    if ( nStates & HiddenInformation::RECORDEDCHANGES )
274
0
    {
275
0
        if ( m_pDocument->GetChangeTrack() && m_pDocument->GetChangeTrack()->GetFirst() )
276
0
          nState |= HiddenInformation::RECORDEDCHANGES;
277
0
    }
278
0
    if ( nStates & HiddenInformation::NOTES )
279
0
    {
280
0
        SCTAB nTableCount = m_pDocument->GetTableCount();
281
0
        bool bFound = false;
282
0
        for (SCTAB nTab = 0; nTab < nTableCount && !bFound; ++nTab)
283
0
        {
284
0
            if (m_pDocument->HasTabNotes(nTab)) //TODO:
285
0
                bFound = true;
286
0
        }
287
288
0
        if (bFound)
289
0
            nState |= HiddenInformation::NOTES;
290
0
    }
291
292
0
    return nState;
293
0
}
294
295
void ScDocShell::BeforeXMLLoading()
296
44.6k
{
297
44.6k
    m_pDocument->EnableIdle(false);
298
299
    // prevent unnecessary broadcasts and updates
300
44.6k
    OSL_ENSURE(m_pModificator == nullptr, "The Modificator should not exist");
301
44.6k
    m_pModificator.reset( new ScDocShellModificator( *this ) );
302
303
44.6k
    m_pDocument->SetImportingXML( true );
304
44.6k
    m_pDocument->EnableExecuteLink( false );   // #i101304# to be safe, prevent nested loading from external references
305
44.6k
    m_pDocument->EnableUndo( false );
306
    // prevent unnecessary broadcasts and "half way listeners"
307
44.6k
    m_pDocument->SetInsertingFromOtherDoc( true );
308
44.6k
}
309
310
void ScDocShell::AfterXMLLoading(bool bRet)
311
13.9k
{
312
13.9k
    if (GetCreateMode() != SfxObjectCreateMode::ORGANIZER)
313
13.9k
    {
314
13.9k
        UpdateLinks();
315
        // don't prevent establishing of listeners anymore
316
13.9k
        m_pDocument->SetInsertingFromOtherDoc( false );
317
13.9k
        if ( bRet )
318
13.9k
        {
319
13.9k
            ScChartListenerCollection* pChartListener = m_pDocument->GetChartListenerCollection();
320
13.9k
            if (pChartListener)
321
13.9k
                pChartListener->UpdateDirtyCharts();
322
323
            // #95582#; set the table names of linked tables to the new path
324
13.9k
            SCTAB nTabCount = m_pDocument->GetTableCount();
325
32.6k
            for (SCTAB i = 0; i < nTabCount; ++i)
326
18.7k
            {
327
18.7k
                if (m_pDocument->IsLinked( i ))
328
0
                {
329
0
                    OUString aName;
330
0
                    m_pDocument->GetName(i, aName);
331
0
                    OUString aLinkTabName = m_pDocument->GetLinkTab(i);
332
0
                    sal_Int32 nLinkTabNameLength = aLinkTabName.getLength();
333
0
                    sal_Int32 nNameLength = aName.getLength();
334
0
                    if (nLinkTabNameLength < nNameLength)
335
0
                    {
336
337
                        // remove the quotes on begin and end of the docname and restore the escaped quotes
338
0
                        const sal_Unicode* pNameBuffer = aName.getStr();
339
0
                        if ( *pNameBuffer == '\'' && // all docnames have to have a ' character on the first pos
340
0
                            ScGlobal::UnicodeStrChr( pNameBuffer, SC_COMPILER_FILE_TAB_SEP ) )
341
0
                        {
342
0
                            OUStringBuffer aDocURLBuffer;
343
0
                            bool bQuote = true; // Document name is always quoted
344
0
                            ++pNameBuffer;
345
0
                            while ( bQuote && *pNameBuffer )
346
0
                            {
347
0
                                if ( *pNameBuffer == '\'' && *(pNameBuffer-1) != '\\' )
348
0
                                    bQuote = false;
349
0
                                else if( *pNameBuffer != '\\' || *(pNameBuffer+1) != '\'' )
350
0
                                    aDocURLBuffer.append(*pNameBuffer); // If escaped quote: only quote in the name
351
0
                                ++pNameBuffer;
352
0
                            }
353
354
0
                            if( *pNameBuffer == SC_COMPILER_FILE_TAB_SEP )  // after the last quote of the docname should be the # char
355
0
                            {
356
0
                                sal_Int32 nIndex = nNameLength - nLinkTabNameLength;
357
0
                                INetURLObject aINetURLObject(aDocURLBuffer);
358
0
                                if(aName.match( aLinkTabName, nIndex) &&
359
0
                                    (aName[nIndex - 1] == '#') && // before the table name should be the # char
360
0
                                    !aINetURLObject.HasError()) // the docname should be a valid URL
361
0
                                {
362
0
                                    aName = ScGlobal::GetDocTabName( m_pDocument->GetLinkDoc( i ), m_pDocument->GetLinkTab( i ) );
363
0
                                    m_pDocument->RenameTab(i, aName, true/*bExternalDocument*/);
364
0
                                }
365
                                // else;  nothing has to happen, because it is a user given name
366
0
                            }
367
                            // else;  nothing has to happen, because it is a user given name
368
0
                        }
369
                        // else;  nothing has to happen, because it is a user given name
370
0
                    }
371
                    // else;  nothing has to happen, because it is a user given name
372
0
                }
373
18.7k
            }
374
375
            // #i94570# DataPilot table names have to be unique, or the tables can't be accessed by API.
376
            // If no name (or an invalid name, skipped in ScXMLDataPilotTableContext::EndElement) was set, create a new name.
377
13.9k
            ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
378
13.9k
            if ( pDPCollection )
379
13.9k
            {
380
13.9k
                size_t nDPCount = pDPCollection->GetCount();
381
13.9k
                for (size_t nDP=0; nDP<nDPCount; ++nDP)
382
0
                {
383
0
                    ScDPObject& rDPObj = (*pDPCollection)[nDP];
384
0
                    if (rDPObj.GetName().isEmpty())
385
0
                        rDPObj.SetName( pDPCollection->CreateNewName() );
386
0
                }
387
13.9k
            }
388
13.9k
        }
389
13.9k
    }
390
0
    else
391
0
        m_pDocument->SetInsertingFromOtherDoc( false );
392
393
13.9k
    m_pDocument->SetImportingXML( false );
394
13.9k
    m_pDocument->EnableExecuteLink( true );
395
13.9k
    m_pDocument->EnableUndo( true );
396
13.9k
    m_bIsEmpty = false;
397
398
13.9k
    if (m_pModificator)
399
13.9k
    {
400
13.9k
        ScDocument::HardRecalcState eRecalcState = m_pDocument->GetHardRecalcState();
401
        // Temporarily set hard-recalc to prevent calling
402
        // ScFormulaCell::Notify() during destruction of the Modificator which
403
        // will set the cells dirty.
404
13.9k
        if (eRecalcState == ScDocument::HardRecalcState::OFF)
405
13.9k
            m_pDocument->SetHardRecalcState(ScDocument::HardRecalcState::TEMPORARY);
406
13.9k
        m_pModificator.reset();
407
13.9k
        m_pDocument->SetHardRecalcState(eRecalcState);
408
13.9k
    }
409
0
    else
410
0
    {
411
0
        OSL_FAIL("The Modificator should exist");
412
0
    }
413
414
13.9k
    m_pDocument->EnableIdle(true);
415
13.9k
}
416
417
namespace {
418
419
class LoadMediumGuard
420
{
421
public:
422
    explicit LoadMediumGuard(ScDocument* pDoc) :
423
0
        mpDoc(pDoc)
424
0
    {
425
0
        mpDoc->SetLoadingMedium(true);
426
0
    }
427
428
    ~LoadMediumGuard()
429
0
    {
430
0
        mpDoc->SetLoadingMedium(false);
431
0
    }
432
private:
433
    ScDocument* mpDoc;
434
};
435
436
void processDataStream( ScDocShell& rShell, const sc::ImportPostProcessData& rData )
437
0
{
438
0
    if (!rData.mpDataStream)
439
0
        return;
440
441
0
    const sc::ImportPostProcessData::DataStream& r = *rData.mpDataStream;
442
0
    if (!r.maRange.IsValid())
443
0
        return;
444
445
    // Break the streamed range into the top range and the height limit.  A
446
    // height limit of 0 means unlimited i.e. the streamed data will go all
447
    // the way to the last row.
448
449
0
    ScRange aTopRange = r.maRange;
450
0
    aTopRange.aEnd.SetRow(aTopRange.aStart.Row());
451
0
    sal_Int32 nLimit = r.maRange.aEnd.Row() - r.maRange.aStart.Row() + 1;
452
0
    if (r.maRange.aEnd.Row() == rShell.GetDocument().MaxRow())
453
        // Unlimited range.
454
0
        nLimit = 0;
455
456
0
    sc::DataStream::MoveType eMove =
457
0
        r.meInsertPos == sc::ImportPostProcessData::DataStream::InsertTop ?
458
0
        sc::DataStream::MOVE_DOWN : sc::DataStream::RANGE_DOWN;
459
460
0
    sc::DataStream* pStrm = new sc::DataStream(&rShell, r.maURL, aTopRange, nLimit, eMove);
461
0
    pStrm->SetRefreshOnEmptyLine(r.mbRefreshOnEmpty);
462
0
    sc::DocumentLinkManager& rMgr = rShell.GetDocument().GetDocLinkManager();
463
0
    rMgr.setDataStream(pStrm);
464
0
}
465
466
class MessageWithCheck : public weld::MessageDialogController
467
{
468
private:
469
    std::unique_ptr<weld::CheckButton> m_xWarningOnBox;
470
public:
471
    MessageWithCheck(weld::Window *pParent, const OUString& rUIFile, const OUString& rDialogId)
472
0
        : MessageDialogController(pParent, rUIFile, rDialogId, u"ask"_ustr)
473
0
        , m_xWarningOnBox(m_xBuilder->weld_check_button(u"ask"_ustr))
474
0
    {
475
0
    }
476
0
    bool get_active() const { return m_xWarningOnBox->get_active(); }
477
0
    void hide_ask() const { m_xWarningOnBox->set_visible(false); };
478
};
479
480
#if HAVE_FEATURE_SCRIPTING
481
class VBAScriptListener : public ::cppu::WeakImplHelper< css::script::vba::XVBAScriptListener >
482
{
483
private:
484
    ScDocShell* m_pDocSh;
485
public:
486
    VBAScriptListener(ScDocShell* pDocSh) : m_pDocSh(pDocSh)
487
    {
488
    }
489
490
    // XVBAScriptListener
491
    virtual void SAL_CALL notifyVBAScriptEvent( const ::css::script::vba::VBAScriptEvent& aEvent ) override
492
    {
493
        if (aEvent.Identifier == script::vba::VBAScriptEventId::SCRIPT_STOPPED &&
494
            m_pDocSh->GetClipData().is())
495
        {
496
            m_pDocSh->SetClipData(uno::Reference<datatransfer::XTransferable2>());
497
        }
498
    }
499
500
    // XEventListener
501
    virtual void SAL_CALL disposing( const ::css::lang::EventObject& /*Source*/ ) override
502
    {
503
    }
504
};
505
#endif
506
507
}
508
509
bool ScDocShell::GetRecalcRowHeightsMode()
510
15.2k
{
511
15.2k
    const ScRecalcOptions nRecalcMode = static_cast<ScRecalcOptions>(
512
15.2k
        officecfg::Office::Calc::Formula::Load::RecalcOptimalRowHeightMode::get());
513
514
15.2k
    bool bHardRecalc = false;
515
15.2k
    switch (nRecalcMode)
516
15.2k
    {
517
0
        case RECALC_ASK:
518
0
        {
519
0
            if (m_pDocument->IsUserInteractionEnabled())
520
0
            {
521
                // Ask if the user wants to perform full re-calculation.
522
0
                MessageWithCheck aQueryBox(ScDocShell::GetActiveDialogParent(),
523
0
                                           u"modules/scalc/ui/recalcquerydialog.ui"_ustr,
524
0
                                           u"RecalcQueryDialog"_ustr);
525
0
                aQueryBox.set_primary_text(ScResId(STR_QUERY_OPT_ROW_HEIGHT_RECALC_ONLOAD));
526
0
                aQueryBox.set_default_response(RET_YES);
527
528
0
                if (officecfg::Office::Calc::Formula::Load::RecalcOptimalRowHeightMode::isReadOnly())
529
0
                    aQueryBox.hide_ask();
530
531
0
                bHardRecalc = aQueryBox.run() == RET_YES;
532
533
0
                if (aQueryBox.get_active())
534
0
                {
535
                    // Always perform selected action in the future.
536
0
                    std::shared_ptr<comphelper::ConfigurationChanges> batch(
537
0
                        comphelper::ConfigurationChanges::create());
538
0
                    officecfg::Office::Calc::Formula::Load::RecalcOptimalRowHeightMode::set(
539
0
                        bHardRecalc ? static_cast<sal_Int32>(RECALC_ALWAYS)
540
0
                                    : static_cast<sal_Int32>(RECALC_NEVER),
541
0
                        batch);
542
543
0
                    ScModule* mod = ScModule::get();
544
0
                    ScFormulaOptions aOpt = mod->GetFormulaOptions();
545
0
                    aOpt.SetReCalcOptiRowHeights(bHardRecalc ? RECALC_ALWAYS : RECALC_NEVER);
546
0
                    mod->SetFormulaOptions(aOpt);
547
548
0
                    batch->commit();
549
0
                }
550
0
            }
551
0
        }
552
0
        break;
553
15.2k
        case RECALC_ALWAYS:
554
15.2k
            bHardRecalc = true;
555
15.2k
            break;
556
0
        case RECALC_NEVER:
557
0
            bHardRecalc = false;
558
0
            break;
559
0
        default:
560
0
            SAL_WARN("sc", "unknown optimal row height recalc option!");
561
15.2k
    }
562
563
15.2k
    return bHardRecalc;
564
15.2k
}
565
566
bool ScDocShell::LoadXML( SfxMedium* pLoadMedium, const css::uno::Reference< css::embed::XStorage >& xStor )
567
0
{
568
0
    LoadMediumGuard aLoadGuard(m_pDocument.get());
569
570
    //  MacroCallMode is no longer needed, state is kept in SfxObjectShell now
571
572
    // no Seek(0) here - always loading from storage, GetInStream must not be called
573
574
0
    BeforeXMLLoading();
575
576
0
    ScXMLImportWrapper aImport(*this, pLoadMedium, xStor);
577
578
0
    bool bRet = false;
579
0
    ErrCodeMsg nError = ERRCODE_NONE;
580
0
    m_pDocument->LockAdjustHeight();
581
0
    if (GetCreateMode() == SfxObjectCreateMode::ORGANIZER)
582
0
        bRet = aImport.Import(ImportFlags::Styles, nError);
583
0
    else
584
0
        bRet = aImport.Import(ImportFlags::All, nError);
585
586
0
    if ( nError )
587
0
        pLoadMedium->SetError(nError);
588
589
0
    processDataStream(*this, aImport.GetImportPostProcessData());
590
591
    //if the document was not generated by LibreOffice, do hard recalc in case some other document
592
    //generator saved cached formula results that differ from LibreOffice's calculated results or
593
    //did not use cached formula results.
594
0
    uno::Reference<document::XDocumentProperties> xDocProps = GetModel()->getDocumentProperties();
595
596
0
    ScRecalcOptions nRecalcMode =
597
0
        static_cast<ScRecalcOptions>(officecfg::Office::Calc::Formula::Load::ODFRecalcMode::get());
598
599
0
    bool bHardRecalc = false;
600
0
    if (nRecalcMode == RECALC_ASK)
601
0
    {
602
0
        OUString sProductName(utl::ConfigManager::getProductName());
603
0
        if (m_pDocument->IsUserInteractionEnabled() && xDocProps->getGenerator().indexOf(sProductName) == -1)
604
0
        {
605
            // Generator is not LibreOffice.  Ask if the user wants to perform
606
            // full re-calculation.
607
0
            MessageWithCheck aQueryBox(GetActiveDialogParent(),
608
0
                    u"modules/scalc/ui/recalcquerydialog.ui"_ustr, u"RecalcQueryDialog"_ustr);
609
0
            aQueryBox.set_primary_text(ScResId(STR_QUERY_FORMULA_RECALC_ONLOAD_ODS));
610
0
            aQueryBox.set_default_response(RET_YES);
611
612
0
            if ( officecfg::Office::Calc::Formula::Load::OOXMLRecalcMode::isReadOnly() )
613
0
                aQueryBox.hide_ask();
614
615
0
            bHardRecalc = aQueryBox.run() == RET_YES;
616
617
0
            if (aQueryBox.get_active())
618
0
            {
619
                // Always perform selected action in the future.
620
0
                std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
621
0
                officecfg::Office::Calc::Formula::Load::ODFRecalcMode::set(sal_Int32(0), batch);
622
0
                ScModule* mod = ScModule::get();
623
0
                ScFormulaOptions aOpt = mod->GetFormulaOptions();
624
0
                aOpt.SetODFRecalcOptions(bHardRecalc ? RECALC_ALWAYS : RECALC_NEVER);
625
                /* XXX  is this really supposed to set the ScModule options?
626
                 *      Not the ScDocShell options? */
627
0
                mod->SetFormulaOptions(aOpt);
628
629
0
                batch->commit();
630
0
            }
631
0
        }
632
0
    }
633
0
    else if (nRecalcMode == RECALC_ALWAYS)
634
0
        bHardRecalc = true;
635
636
0
    if (bHardRecalc)
637
0
        DoHardRecalc();
638
0
    else
639
0
    {
640
        // still need to recalc volatile formula cells.
641
0
        m_pDocument->Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS));
642
0
    }
643
644
0
    AfterXMLLoading(bRet);
645
646
0
    m_pDocument->UnlockAdjustHeight();
647
0
    return bRet;
648
0
}
649
650
bool ScDocShell::SaveXML( SfxMedium* pSaveMedium, const css::uno::Reference< css::embed::XStorage >& xStor )
651
0
{
652
0
    m_pDocument->EnableIdle(false);
653
654
0
    ScXMLImportWrapper aImport(*this, pSaveMedium, xStor);
655
0
    bool bRet(false);
656
0
    if (GetCreateMode() != SfxObjectCreateMode::ORGANIZER)
657
0
        bRet = aImport.Export(false);
658
0
    else
659
0
        bRet = aImport.Export(true);
660
661
0
    m_pDocument->EnableIdle(true);
662
663
0
    return bRet;
664
0
}
665
666
bool ScDocShell::Load( SfxMedium& rMedium )
667
0
{
668
0
    LoadMediumGuard aLoadGuard(m_pDocument.get());
669
0
    ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
670
671
    //  only the latin script language is loaded
672
    //  -> initialize the others from options (before loading)
673
0
    InitOptions(true);
674
675
    // If this is an ODF file being loaded, then by default, use legacy processing
676
    // (if required, it will be overridden in *::ReadUserDataSequence())
677
0
    if (IsOwnStorageFormat(rMedium))
678
0
    {
679
0
        if (ScDrawLayer* pDrawLayer = m_pDocument->GetDrawLayer())
680
0
        {
681
0
            pDrawLayer->SetCompatibilityFlag(SdrCompatibilityFlag::AnchoredTextOverflowLegacy,
682
0
                                             true); // for tdf#99729
683
0
            pDrawLayer->SetCompatibilityFlag(SdrCompatibilityFlag::LegacyFontwork,
684
0
                                             true); // for tdf#148000
685
0
        }
686
0
    }
687
688
0
    GetUndoManager()->Clear();
689
690
0
    bool bRet = SfxObjectShell::Load(rMedium);
691
0
    if (bRet)
692
0
    {
693
0
        SetInitialLinkUpdate(&rMedium);
694
695
0
        {
696
            //  prepare a valid document for XML filter
697
            //  (for ConvertFrom, InitNew is called before)
698
0
            m_pDocument->MakeTable(0);
699
0
            m_pDocument->GetStyleSheetPool()->CreateStandardStyles();
700
0
            m_pDocument->getCellAttributeHelper().UpdateAllStyleSheets(*m_pDocument);
701
702
            /* Create styles that are imported through Orcus */
703
704
0
            OUString aURL(u"$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/calc/styles.xml"_ustr);
705
0
            rtl::Bootstrap::expandMacros(aURL);
706
707
0
            OUString aPath;
708
0
            osl::FileBase::getSystemPathFromFileURL(aURL, aPath);
709
710
0
            ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
711
712
0
            if (pOrcus)
713
0
            {
714
0
                pOrcus->importODS_Styles(*m_pDocument, aPath);
715
0
                m_pDocument->GetStyleSheetPool()->setAllParaStandard();
716
0
            }
717
718
0
            bRet = LoadXML( &rMedium, nullptr );
719
0
        }
720
0
    }
721
722
0
    if (!bRet && !rMedium.GetErrorIgnoreWarning())
723
0
        rMedium.SetError(SVSTREAM_FILEFORMAT_ERROR);
724
725
0
    if (rMedium.GetErrorIgnoreWarning())
726
0
        SetError(rMedium.GetErrorIgnoreWarning());
727
728
0
    InitItems();
729
0
    CalcOutputFactor();
730
731
    // invalidate eventually temporary table areas
732
0
    if ( bRet )
733
0
        m_pDocument->InvalidateTableArea();
734
735
0
    m_bIsEmpty = false;
736
0
    FinishedLoading();
737
0
    return bRet;
738
0
}
739
740
void ScDocShell::Notify( SfxBroadcaster&, const SfxHint& rHint )
741
664k
{
742
664k
    if (rHint.GetId() == SfxHintId::ScTables)
743
6.30k
    {
744
6.30k
        const ScTablesHint* pScHint = static_cast< const ScTablesHint* >( &rHint );
745
6.30k
        if (pScHint->GetTablesHintId() == SC_TAB_INSERTED)
746
6.30k
        {
747
6.30k
            uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents = m_pDocument->GetVbaEventProcessor();
748
6.30k
            if ( xVbaEvents.is() ) try
749
0
            {
750
0
                uno::Sequence< uno::Any > aArgs{ uno::Any(pScHint->GetTab1()) };
751
0
                xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKBOOK_NEWSHEET, aArgs );
752
0
            }
753
0
            catch( uno::Exception& )
754
0
            {
755
0
            }
756
6.30k
        }
757
6.30k
    }
758
759
664k
    if ( auto pStyleSheetHint = dynamic_cast<const SfxStyleSheetHint*>(&rHint) ) // Template changed
760
102k
        NotifyStyle( *pStyleSheetHint );
761
562k
    else if ( rHint.GetId() == SfxHintId::ScAutoStyle )
762
0
    {
763
0
        auto pStlHint = static_cast<const ScAutoStyleHint*>(&rHint);
764
        //! direct call for AutoStyles
765
766
        //  this is called synchronously from ScInterpreter::ScStyle,
767
        //  modifying the document must be asynchronous
768
        //  (handled by AddInitial)
769
770
0
        const ScRange& aRange = pStlHint->GetRange();
771
0
        const OUString& aName1 = pStlHint->GetStyle1();
772
0
        const OUString& aName2 = pStlHint->GetStyle2();
773
0
        sal_uInt32 nTimeout = pStlHint->GetTimeout();
774
775
0
        if (!m_pAutoStyleList)
776
0
            m_pAutoStyleList.reset( new ScAutoStyleList(this) );
777
0
        m_pAutoStyleList->AddInitial( aRange, aName1, nTimeout, aName2 );
778
0
    }
779
562k
    else if (rHint.GetId() == SfxHintId::ThisIsAnSfxEventHint)
780
7.33k
    {
781
7.33k
        switch (static_cast<const SfxEventHint&>(rHint).GetEventId())
782
7.33k
        {
783
0
            case SfxEventHintId::LoadFinished:
784
0
                {
785
#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
786
                    // the readonly documents should not be opened in shared mode
787
                    if ( HasSharedXMLFlagSet() && !ScModule::get()->IsInSharedDocLoading() && !IsReadOnly() )
788
                    {
789
                        if ( SwitchToShared( true, false ) )
790
                        {
791
                            ScViewData* pViewData = GetViewData();
792
                            ScTabView* pTabView = ( pViewData ? pViewData->GetView() : nullptr );
793
                            if ( pTabView )
794
                            {
795
                                pTabView->UpdateLayerLocks();
796
                            }
797
                        }
798
                        else
799
                        {
800
                            // switching to shared mode has failed, the document should be opened readonly
801
                            // TODO/LATER: And error message should be shown here probably
802
                            SetReadOnlyUI();
803
                        }
804
                    }
805
#endif
806
0
                }
807
0
                break;
808
0
            case SfxEventHintId::ViewCreated:
809
0
                {
810
 #if HAVE_FEATURE_SCRIPTING
811
                    uno::Reference<script::vba::XVBACompatibility> xVBACompat(GetBasicContainer(), uno::UNO_QUERY);
812
                    if ( !m_xVBAListener.is() && xVBACompat.is() )
813
                    {
814
                        m_xVBAListener.set(new VBAScriptListener(this));
815
                        xVBACompat->addVBAScriptListener(m_xVBAListener);
816
                    }
817
#endif
818
819
#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
820
                    if (ScModule* mod = ScModule::get(); IsDocShared() && !mod->IsInSharedDocLoading()
821
                         && !comphelper::LibreOfficeKit::isActive() )
822
                    {
823
                        ScAppOptions aAppOptions = mod->GetAppOptions();
824
                        if ( aAppOptions.GetShowSharedDocumentWarning() )
825
                        {
826
                            MessageWithCheck aWarningBox(ScDocShell::GetActiveDialogParent(),
827
                                    u"modules/scalc/ui/sharedwarningdialog.ui"_ustr, u"SharedWarningDialog"_ustr);
828
                            aWarningBox.run();
829
830
                            bool bChecked = aWarningBox.get_active();
831
                            if (bChecked)
832
                            {
833
                                aAppOptions.SetShowSharedDocumentWarning(false);
834
                                mod->SetAppOptions(aAppOptions);
835
                            }
836
                        }
837
                    }
838
#endif
839
840
0
                    ScViewData* pViewData = GetViewData();
841
0
                    SfxViewShell* pViewShell = pViewData ? pViewData->GetViewShell() : nullptr;
842
0
                    SfxViewFrame* pViewFrame = pViewShell ? &pViewShell->GetViewFrame() : nullptr;
843
844
0
                    try
845
0
                    {
846
0
                        const uno::Reference< uno::XComponentContext >& xContext(
847
0
                            comphelper::getProcessComponentContext() );
848
0
                        uno::Reference< lang::XMultiServiceFactory > xServiceManager(
849
0
                            xContext->getServiceManager(),
850
0
                            uno::UNO_QUERY_THROW );
851
0
                        uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xServiceManager, uno::UNO_QUERY_THROW );
852
0
                        uno::Reference< container::XEnumeration> xEnum = xEnumAccess->createContentEnumeration(
853
0
                            u"com.sun.star.sheet.SpreadsheetDocumentJob"_ustr );
854
0
                        if ( xEnum.is() )
855
0
                        {
856
0
                            while ( xEnum->hasMoreElements() )
857
0
                            {
858
0
                                uno::Any aAny = xEnum->nextElement();
859
0
                                uno::Reference< lang::XSingleComponentFactory > xFactory;
860
0
                                aAny >>= xFactory;
861
0
                                if ( xFactory.is() )
862
0
                                {
863
0
                                    uno::Reference< task::XJob > xJob( xFactory->createInstanceWithContext( xContext ), uno::UNO_QUERY_THROW );
864
0
                                    SfxFrame* pFrame = ( pViewFrame ? &pViewFrame->GetFrame() : nullptr );
865
0
                                    uno::Reference< frame::XController > xController = ( pFrame ? pFrame->GetController() : nullptr );
866
0
                                    uno::Reference< sheet::XSpreadsheetView > xSpreadsheetView( xController, uno::UNO_QUERY_THROW );
867
0
                                    uno::Sequence< beans::NamedValue > aArgsForJob { { u"SpreadsheetView"_ustr, uno::Any( xSpreadsheetView ) } };
868
0
                                    xJob->execute( aArgsForJob );
869
0
                                }
870
0
                            }
871
0
                        }
872
0
                    }
873
0
                    catch ( uno::Exception & )
874
0
                    {
875
0
                    }
876
877
                    // Show delayed infobar entries
878
0
                    if (pViewFrame)
879
0
                    {
880
0
                        for (auto const& r : m_pImpl->mpDelayedInfobarEntry)
881
0
                        {
882
0
                            pViewFrame->AppendInfoBar(r.msId, r.msPrimaryMessage, r.msSecondaryMessage, r.maInfobarType, r.mbShowCloseButton);
883
0
                        }
884
0
                        m_pImpl->mpDelayedInfobarEntry.clear();
885
0
                    }
886
0
                }
887
0
                break;
888
0
            case SfxEventHintId::SaveDoc:
889
0
                {
890
#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
891
                    if (ScModule* mod = ScModule::get(); IsDocShared() && !mod->IsInSharedDocSaving())
892
                    {
893
                        bool bSuccess = false;
894
                        bool bRetry = true;
895
                        while ( bRetry )
896
                        {
897
                            bRetry = false;
898
                            uno::Reference< frame::XModel > xModel;
899
                            try
900
                            {
901
                                // load shared file
902
                                xModel.set( LoadSharedDocument(), uno::UNO_SET_THROW );
903
                                uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY_THROW );
904
905
                                // check if shared flag is set in shared file
906
                                bool bShared = false;
907
                                ScModelObj* pDocObj = comphelper::getFromUnoTunnel<ScModelObj>( xModel );
908
                                ScDocShell* pSharedDocShell = ( pDocObj ? dynamic_cast< ScDocShell* >( pDocObj->GetObjectShell() ) : nullptr );
909
                                if ( pSharedDocShell )
910
                                {
911
                                    bShared = pSharedDocShell->HasSharedXMLFlagSet();
912
                                }
913
914
                                // #i87870# check if shared status was disabled and enabled again
915
                                bool bOwnEntry = false;
916
                                bool bEntriesNotAccessible = false;
917
                                try
918
                                {
919
                                    ::svt::ShareControlFile aControlFile( GetSharedFileURL() );
920
                                    bOwnEntry = aControlFile.HasOwnEntry();
921
                                }
922
                                catch ( uno::Exception& )
923
                                {
924
                                    bEntriesNotAccessible = true;
925
                                }
926
927
                                if ( bShared && bOwnEntry )
928
                                {
929
                                    uno::Reference< frame::XStorable > xStorable( xModel, uno::UNO_QUERY_THROW );
930
931
                                    if ( xStorable->isReadonly() )
932
                                    {
933
                                        xCloseable->close( true );
934
935
                                        OUString aUserName( ScResId( STR_UNKNOWN_USER ) );
936
                                        bool bNoLockAccess = false;
937
                                        try
938
                                        {
939
                                            ::svt::DocumentLockFile aLockFile( GetSharedFileURL() );
940
                                            LockFileEntry aData = aLockFile.GetLockData();
941
                                            if ( !aData[LockFileComponent::OOOUSERNAME].isEmpty() )
942
                                            {
943
                                                aUserName = aData[LockFileComponent::OOOUSERNAME];
944
                                            }
945
                                            else if ( !aData[LockFileComponent::SYSUSERNAME].isEmpty() )
946
                                            {
947
                                                aUserName = aData[LockFileComponent::SYSUSERNAME];
948
                                            }
949
                                        }
950
                                        catch ( uno::Exception& )
951
                                        {
952
                                            bNoLockAccess = true;
953
                                        }
954
955
                                        if ( bNoLockAccess )
956
                                        {
957
                                            // TODO/LATER: in future an error regarding impossibility to open file for writing could be shown
958
                                            ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
959
                                        }
960
                                        else
961
                                        {
962
                                            OUString aMessage( ScResId( STR_FILE_LOCKED_SAVE_LATER ) );
963
                                            aMessage = aMessage.replaceFirst( "%1", aUserName );
964
965
                                            std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
966
                                                                                       VclMessageType::Warning, VclButtonsType::NONE,
967
                                                                                       aMessage));
968
                                            xWarn->add_button(GetStandardText(StandardButtonType::Retry), RET_RETRY);
969
                                            xWarn->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
970
                                            xWarn->set_default_response(RET_RETRY);
971
                                            if (xWarn->run() == RET_RETRY)
972
                                            {
973
                                                bRetry = true;
974
                                            }
975
                                        }
976
                                    }
977
                                    else
978
                                    {
979
                                        // merge changes from shared file into temp file
980
                                        bool bSaveToShared = false;
981
                                        if ( pSharedDocShell )
982
                                        {
983
                                            bSaveToShared = MergeSharedDocument( pSharedDocShell );
984
                                        }
985
986
                                        // close shared file
987
                                        xCloseable->close( true );
988
989
                                        // TODO: keep file lock on shared file
990
991
                                        // store to shared file
992
                                        if ( bSaveToShared )
993
                                        {
994
                                            bool bChangedViewSettings = false;
995
                                            ScChangeViewSettings* pChangeViewSet = m_pDocument->GetChangeViewSettings();
996
                                            if ( pChangeViewSet && pChangeViewSet->ShowChanges() )
997
                                            {
998
                                                pChangeViewSet->SetShowChanges( false );
999
                                                pChangeViewSet->SetShowAccepted( false );
1000
                                                m_pDocument->SetChangeViewSettings( *pChangeViewSet );
1001
                                                bChangedViewSettings = true;
1002
                                            }
1003
1004
                                            // TODO/LATER: More entries from the MediaDescriptor might be interesting for the merge
1005
                                            uno::Sequence< beans::PropertyValue > aValues{
1006
                                                comphelper::makePropertyValue(
1007
                                                    u"FilterName"_ustr,
1008
                                                    GetMedium()->GetFilter()->GetFilterName())
1009
                                            };
1010
1011
                                            const SfxStringItem* pPasswordItem = GetMedium()->GetItemSet().GetItem(SID_PASSWORD, false);
1012
                                            if ( pPasswordItem && !pPasswordItem->GetValue().isEmpty() )
1013
                                            {
1014
                                                aValues.realloc( 2 );
1015
                                                auto pValues = aValues.getArray();
1016
                                                pValues[1].Name = "Password";
1017
                                                pValues[1].Value <<= pPasswordItem->GetValue();
1018
                                            }
1019
                                            const SfxUnoAnyItem* pEncryptionItem = GetMedium()->GetItemSet().GetItem(SID_ENCRYPTIONDATA, false);
1020
                                            if (pEncryptionItem)
1021
                                            {
1022
                                                aValues.realloc(aValues.getLength() + 1);
1023
                                                auto pValues = aValues.getArray();
1024
                                                pValues[aValues.getLength() - 1].Name = "EncryptionData";
1025
                                                pValues[aValues.getLength() - 1].Value = pEncryptionItem->GetValue();
1026
                                            }
1027
1028
                                            mod->SetInSharedDocSaving(true);
1029
                                            GetModel()->storeToURL( GetSharedFileURL(), aValues );
1030
                                            mod->SetInSharedDocSaving(false);
1031
1032
                                            if ( bChangedViewSettings )
1033
                                            {
1034
                                                pChangeViewSet->SetShowChanges( true );
1035
                                                pChangeViewSet->SetShowAccepted( true );
1036
                                                m_pDocument->SetChangeViewSettings( *pChangeViewSet );
1037
                                            }
1038
                                        }
1039
1040
                                        bSuccess = true;
1041
                                        GetUndoManager()->Clear();
1042
                                    }
1043
                                }
1044
                                else
1045
                                {
1046
                                    xCloseable->close( true );
1047
1048
                                    if ( bEntriesNotAccessible )
1049
                                    {
1050
                                        // TODO/LATER: in future an error regarding impossibility to write to share control file could be shown
1051
                                        ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
1052
                                    }
1053
                                    else
1054
                                    {
1055
                                        std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
1056
                                                                                   VclMessageType::Warning, VclButtonsType::Ok,
1057
                                                                                   ScResId(STR_DOC_NOLONGERSHARED)));
1058
                                        xWarn->run();
1059
1060
                                        SfxBindings* pBindings = GetViewBindings();
1061
                                        if ( pBindings )
1062
                                        {
1063
                                            pBindings->ExecuteSynchron( SID_SAVEASDOC );
1064
                                        }
1065
                                    }
1066
                                }
1067
                            }
1068
                            catch ( uno::Exception& )
1069
                            {
1070
                                TOOLS_WARN_EXCEPTION( "sc", "SfxEventHintId::SaveDoc" );
1071
                                mod->SetInSharedDocSaving(false);
1072
1073
                                try
1074
                                {
1075
                                    uno::Reference< util::XCloseable > xClose( xModel, uno::UNO_QUERY_THROW );
1076
                                    xClose->close( true );
1077
                                }
1078
                                catch ( uno::Exception& )
1079
                                {
1080
                                }
1081
                            }
1082
                        }
1083
1084
                        if ( !bSuccess )
1085
                            SetError(ERRCODE_IO_ABORT); // this error code will produce no error message, but will break the further saving process
1086
                    }
1087
#endif
1088
1089
0
                    if (m_pSheetSaveData)
1090
0
                        m_pSheetSaveData->SetInSupportedSave(true);
1091
0
                }
1092
0
                break;
1093
0
            case SfxEventHintId::SaveAsDoc:
1094
0
                {
1095
0
                    if ( GetDocument().GetExternalRefManager()->containsUnsavedReferences() )
1096
0
                    {
1097
0
                        std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
1098
0
                                                                   VclMessageType::Warning, VclButtonsType::YesNo,
1099
0
                                                                   ScResId(STR_UNSAVED_EXT_REF)));
1100
0
                        if (RET_NO == xWarn->run())
1101
0
                        {
1102
0
                            SetError(ERRCODE_IO_ABORT); // this error code will produce no error message, but will break the further saving process
1103
0
                        }
1104
0
                    }
1105
0
                    [[fallthrough]];
1106
0
                }
1107
0
            case SfxEventHintId::SaveToDoc:
1108
                // #i108978# If no event is sent before saving, there will also be no "...DONE" event,
1109
                // and SAVE/SAVEAS can't be distinguished from SAVETO. So stream copying is only enabled
1110
                // if there is a SAVE/SAVEAS/SAVETO event first.
1111
0
                if (m_pSheetSaveData)
1112
0
                    m_pSheetSaveData->SetInSupportedSave(true);
1113
0
                break;
1114
0
            case SfxEventHintId::SaveDocDone:
1115
0
            case SfxEventHintId::SaveAsDocDone:
1116
0
                {
1117
                    // new positions are used after "save" and "save as", but not "save to"
1118
0
                    UseSheetSaveEntries();      // use positions from saved file for next saving
1119
0
                    [[fallthrough]];
1120
0
                }
1121
0
            case SfxEventHintId::SaveToDocDone:
1122
                // only reset the flag, don't use the new positions
1123
0
                if (m_pSheetSaveData)
1124
0
                    m_pSheetSaveData->SetInSupportedSave(false);
1125
0
                break;
1126
7.33k
            default:
1127
7.33k
                {
1128
7.33k
                }
1129
7.33k
                break;
1130
7.33k
        }
1131
7.33k
    }
1132
554k
    else if (rHint.GetId() == SfxHintId::TitleChanged) // Without parameter
1133
77.1k
    {
1134
77.1k
        m_pDocument->SetName( SfxShell::GetName() );
1135
        //  RegisterNewTargetNames doesn't exist any longer
1136
77.1k
        SfxGetpApp()->Broadcast(SfxHint( SfxHintId::ScDocNameChanged )); // Navigator
1137
77.1k
    }
1138
477k
    else if (rHint.GetId() == SfxHintId::Deinitializing)
1139
77.1k
    {
1140
1141
#if HAVE_FEATURE_SCRIPTING
1142
        uno::Reference<script::vba::XVBACompatibility> xVBACompat(GetBasicContainer(), uno::UNO_QUERY);
1143
        if (m_xVBAListener.is() && xVBACompat.is())
1144
        {
1145
            xVBACompat->removeVBAScriptListener(m_xVBAListener);
1146
        }
1147
#endif
1148
1149
77.1k
        if (m_pDocument->IsClipboardSource())
1150
0
        {
1151
            // Notes copied to the clipboard have a raw SdrCaptionObj pointer
1152
            // copied from this document, forget it as it references this
1153
            // document's drawing layer pages and what not, which otherwise when
1154
            // pasting to another document after this document was destructed would
1155
            // attempt to access non-existing data. Preserve the text data though.
1156
0
            ScDocument* pClipDoc = ScModule::GetClipDoc();
1157
0
            if (pClipDoc)
1158
0
                pClipDoc->ClosingClipboardSource();
1159
0
        }
1160
77.1k
    }
1161
1162
664k
    if (rHint.GetId() != SfxHintId::ThisIsAnSfxEventHint)
1163
657k
        return;
1164
1165
7.33k
    switch(static_cast<const SfxEventHint&>(rHint).GetEventId())
1166
7.33k
    {
1167
0
       case SfxEventHintId::CreateDoc:
1168
0
            {
1169
0
                uno::Any aWorkbook;
1170
0
                aWorkbook <<= mxAutomationWorkbookObject;
1171
0
                uno::Sequence< uno::Any > aArgs{ aWorkbook };
1172
0
                ScModule::get()->CallAutomationApplicationEventSinks(u"NewWorkbook"_ustr, aArgs);
1173
0
            }
1174
0
            break;
1175
0
        case SfxEventHintId::OpenDoc:
1176
0
            {
1177
0
                uno::Any aWorkbook;
1178
0
                aWorkbook <<= mxAutomationWorkbookObject;
1179
0
                uno::Sequence< uno::Any > aArgs{ aWorkbook };
1180
0
                ScModule::get()->CallAutomationApplicationEventSinks(u"WorkbookOpen"_ustr, aArgs);
1181
0
            }
1182
0
            break;
1183
7.33k
        default:
1184
7.33k
            break;
1185
7.33k
    }
1186
7.33k
}
1187
1188
// Load contents for organizer
1189
bool ScDocShell::LoadFrom( SfxMedium& rMedium )
1190
0
{
1191
0
    LoadMediumGuard aLoadGuard(m_pDocument.get());
1192
0
    ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
1193
1194
0
    weld::WaitObject aWait( GetActiveDialogParent() );
1195
1196
0
    bool bRet = false;
1197
1198
0
    SetInitialLinkUpdate(&rMedium);
1199
1200
    //  until loading/saving only the styles in XML is implemented,
1201
    //  load the whole file
1202
0
    bRet = LoadXML( &rMedium, nullptr );
1203
0
    InitItems();
1204
1205
0
    SfxObjectShell::LoadFrom( rMedium );
1206
1207
0
    return bRet;
1208
0
}
1209
1210
static void lcl_parseHtmlFilterOption(const OUString& rOption, LanguageType& rLang, bool& rDateConvert, bool& rScientificConvert)
1211
0
{
1212
0
    OUStringBuffer aBuf;
1213
0
    std::vector< OUString > aTokens;
1214
0
    sal_Int32 n = rOption.getLength();
1215
0
    const sal_Unicode* p = rOption.getStr();
1216
0
    for (sal_Int32 i = 0; i < n; ++i)
1217
0
    {
1218
0
        const sal_Unicode c = p[i];
1219
0
        if (c == ' ')
1220
0
        {
1221
0
            if (!aBuf.isEmpty())
1222
0
                aTokens.push_back( aBuf.makeStringAndClear() );
1223
0
        }
1224
0
        else
1225
0
            aBuf.append(c);
1226
0
    }
1227
1228
0
    if (!aBuf.isEmpty())
1229
0
        aTokens.push_back( aBuf.makeStringAndClear() );
1230
1231
0
    rLang = LanguageType( 0 );
1232
0
    rDateConvert = false;
1233
1234
0
    if (!aTokens.empty())
1235
0
        rLang = static_cast<LanguageType>(aTokens[0].toInt32());
1236
0
    if (aTokens.size() > 1)
1237
0
        rDateConvert = static_cast<bool>(aTokens[1].toInt32());
1238
0
    if (aTokens.size() > 2)
1239
0
        rScientificConvert = static_cast<bool>(aTokens[2].toInt32());
1240
0
}
1241
1242
bool ScDocShell::ConvertFrom( SfxMedium& rMedium )
1243
0
{
1244
0
    LoadMediumGuard aLoadGuard(m_pDocument.get());
1245
1246
0
    bool bRet = false; // sal_False means user quit!
1247
                           // On error: Set error at stream
1248
1249
0
    ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
1250
1251
0
    GetUndoManager()->Clear();
1252
1253
    // Set optimal col width after import?
1254
0
    bool bSetColWidths = false;
1255
0
    bool bSetSimpleTextColWidths = false;
1256
0
    std::map<SCCOL, ScColWidthParam> aColWidthParam;
1257
0
    ScRange aColWidthRange;
1258
    // Set optimal row height after import?
1259
0
    bool bSetRowHeights = false;
1260
1261
0
    vector<ScDocRowHeightUpdater::TabRanges> aRecalcRowRangesArray;
1262
1263
    //  All filters need the complete file in one piece (not asynchronously)
1264
    //  So make sure that we transfer the whole file with CreateFileStream
1265
0
    rMedium.GetPhysicalName();  //! Call CreateFileStream directly, if available
1266
1267
0
    SetInitialLinkUpdate(&rMedium);
1268
1269
0
    std::shared_ptr<const SfxFilter> pFilter = rMedium.GetFilter();
1270
0
    if (pFilter)
1271
0
    {
1272
0
        OUString aFltName = pFilter->GetFilterName();
1273
1274
0
        bool bCalc3 = aFltName == "StarCalc 3.0";
1275
0
        bool bCalc4 = aFltName == "StarCalc 4.0";
1276
0
        if (!bCalc3 && !bCalc4)
1277
0
            m_pDocument->SetInsertingFromOtherDoc( true );
1278
1279
0
        if (aFltName == pFilterXML)
1280
0
            bRet = LoadXML( &rMedium, nullptr );
1281
0
        else if (aFltName == pFilterLotus)
1282
0
        {
1283
0
            OUString sItStr;
1284
0
            if ( const SfxStringItem* pOptionsItem = rMedium.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS, true ) )
1285
0
            {
1286
0
                sItStr = pOptionsItem->GetValue();
1287
0
            }
1288
1289
0
            if (sItStr.isEmpty())
1290
0
            {
1291
                //  default for lotus import (from API without options):
1292
                //  IBM_437 encoding
1293
0
                sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_437 );
1294
0
            }
1295
1296
0
            ErrCode eError = ScFormatFilter::Get().ScImportLotus123( rMedium, *m_pDocument,
1297
0
                                                ScGlobal::GetCharsetValue(sItStr));
1298
0
            if (eError != ERRCODE_NONE)
1299
0
            {
1300
0
                if (!GetErrorIgnoreWarning())
1301
0
                    SetError(eError);
1302
1303
0
                if( eError.IsWarning() )
1304
0
                    bRet = true;
1305
0
            }
1306
0
            else
1307
0
                bRet = true;
1308
0
            bSetColWidths = true;
1309
0
            bSetRowHeights = true;
1310
0
        }
1311
0
        else if ( aFltName == pFilterExcel4 || aFltName == pFilterExcel5 ||
1312
0
                   aFltName == pFilterExcel95 || aFltName == pFilterExcel97 ||
1313
0
                   aFltName == pFilterEx4Temp || aFltName == pFilterEx5Temp ||
1314
0
                   aFltName == pFilterEx95Temp || aFltName == pFilterEx97Temp )
1315
0
        {
1316
0
            EXCIMPFORMAT eFormat = EIF_AUTO;
1317
0
            if ( aFltName == pFilterExcel4 || aFltName == pFilterEx4Temp )
1318
0
                eFormat = EIF_BIFF_LE4;
1319
0
            else if ( aFltName == pFilterExcel5 || aFltName == pFilterExcel95 ||
1320
0
                      aFltName == pFilterEx5Temp || aFltName == pFilterEx95Temp )
1321
0
                eFormat = EIF_BIFF5;
1322
0
            else if ( aFltName == pFilterExcel97 || aFltName == pFilterEx97Temp )
1323
0
                eFormat = EIF_BIFF8;
1324
1325
0
            MakeDrawLayer(); //! In the filter
1326
0
            CalcOutputFactor(); // prepare update of row height
1327
0
            ErrCode eError = ScFormatFilter::Get().ScImportExcel( rMedium, m_pDocument.get(), eFormat );
1328
0
            m_pDocument->UpdateFontCharSet();
1329
0
            if ( m_pDocument->IsChartListenerCollectionNeedsUpdate() )
1330
0
                m_pDocument->UpdateChartListenerCollection(); //! For all imports?
1331
1332
            // all graphics objects must have names
1333
0
            m_pDocument->EnsureGraphicNames();
1334
1335
0
            if (eError == SCWARN_IMPORT_UNKNOWN_ENCRYPTION)
1336
0
            {
1337
1338
0
                m_pImpl->mpDelayedInfobarEntry.push_back({ u"UnknownEncryption"_ustr, ScResId(STR_CONTENT_WITH_UNKNOWN_ENCRYPTION), u""_ustr, InfobarType::INFO, true });
1339
0
                eError = ERRCODE_NONE;
1340
0
            }
1341
1342
0
            if (eError != ERRCODE_NONE)
1343
0
            {
1344
0
                if (!GetErrorIgnoreWarning())
1345
0
                    SetError(eError);
1346
0
                if( eError.IsWarning() )
1347
0
                    bRet = true;
1348
0
            }
1349
0
            else
1350
0
                bRet = true;
1351
0
        }
1352
0
        else if (aFltName == SC_TEXT_CSV_FILTER_NAME)
1353
0
        {
1354
0
            ScAsciiOptions aOptions;
1355
0
            bool bOptInit = false;
1356
1357
0
            if ( const SfxStringItem* pOptionsItem = rMedium.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) )
1358
0
            {
1359
0
                aOptions.ReadFromString( pOptionsItem->GetValue(), rMedium.GetInStream() );
1360
0
                bOptInit = true;
1361
0
            }
1362
1363
0
            if ( !bOptInit )
1364
0
            {
1365
                //  default for ascii import (from API without options):
1366
                //  UTF-8 encoding, comma, double quotes
1367
1368
0
                aOptions.SetCharSet(RTL_TEXTENCODING_UTF8);
1369
0
                aOptions.SetFieldSeps( OUString(',') );
1370
0
                aOptions.SetTextSep( '"' );
1371
0
            }
1372
1373
0
            ErrCode eError = ERRCODE_NONE;
1374
0
            bool bOverflowRow, bOverflowCol, bOverflowCell;
1375
0
            bOverflowRow = bOverflowCol = bOverflowCell = false;
1376
1377
0
            if( ! rMedium.IsStorage() )
1378
0
            {
1379
0
                ScImportExport  aImpEx( *m_pDocument );
1380
0
                aImpEx.SetExtOptions( aOptions );
1381
1382
0
                SvStream* pInStream = rMedium.GetInStream();
1383
0
                if (pInStream)
1384
0
                {
1385
0
                    pInStream->SetStreamCharSet( aOptions.GetCharSet() );
1386
0
                    pInStream->Seek( 0 );
1387
0
                    bRet = aImpEx.ImportStream( *pInStream, rMedium.GetBaseURL(), SotClipboardFormatId::STRING );
1388
0
                    eError = bRet ? ERRCODE_NONE : SCERR_IMPORT_CONNECT;
1389
0
                    m_pDocument->StartAllListeners();
1390
0
                    sc::SetFormulaDirtyContext aCxt;
1391
0
                    m_pDocument->SetAllFormulasDirty(aCxt);
1392
1393
                    // tdf#82254 - check whether to include a byte-order-mark in the output
1394
0
                    if (const bool bIncludeBOM = aImpEx.GetIncludeBOM())
1395
0
                    {
1396
0
                        aOptions.SetIncludeBOM(bIncludeBOM);
1397
0
                        rMedium.GetItemSet().Put(
1398
0
                            SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions.WriteToString()));
1399
0
                    }
1400
1401
                    // for mobile case, we use a copy of the original document and give it a temporary name before editing
1402
                    // Therefore, the sheet name becomes ugly, long and nonsensical.
1403
0
#if !(defined ANDROID)
1404
                    // The same resulting name has to be handled in
1405
                    // ScExternalRefCache::initializeDoc() and related, hence
1406
                    // pass 'true' for RenameTab()'s bExternalDocument for a
1407
                    // composed name so ValidTabName() will not be checked,
1408
                    // which could veto the rename in case it contained
1409
                    // characters that Excel does not handle. If we wanted to
1410
                    // change that then it needed to be handled in all
1411
                    // corresponding places of the external references
1412
                    // manager/cache. Likely then we'd also need a method to
1413
                    // compose a name excluding such characters.
1414
0
                    m_pDocument->RenameTab( 0, INetURLObject( rMedium.GetName()).GetBase(), true/*bExternalDocument*/);
1415
0
#endif
1416
0
                    bOverflowRow = aImpEx.IsOverflowRow();
1417
0
                    bOverflowCol = aImpEx.IsOverflowCol();
1418
0
                    bOverflowCell = aImpEx.IsOverflowCell();
1419
0
                }
1420
0
                else
1421
0
                {
1422
0
                    OSL_FAIL( "No Stream" );
1423
0
                }
1424
0
            }
1425
1426
0
            if (eError != ERRCODE_NONE)
1427
0
            {
1428
0
                if (!GetErrorIgnoreWarning())
1429
0
                    SetError(eError);
1430
0
                if( eError.IsWarning() )
1431
0
                    bRet = true;
1432
0
            }
1433
0
            else if (!GetErrorIgnoreWarning() && (bOverflowRow || bOverflowCol || bOverflowCell))
1434
0
            {
1435
                // precedence: row, column, cell
1436
0
                ErrCode nWarn = (bOverflowRow ? SCWARN_IMPORT_ROW_OVERFLOW :
1437
0
                        (bOverflowCol ? SCWARN_IMPORT_COLUMN_OVERFLOW :
1438
0
                         SCWARN_IMPORT_CELL_OVERFLOW));
1439
0
                SetError(nWarn);
1440
0
            }
1441
0
            bSetColWidths = true;
1442
0
            bSetSimpleTextColWidths = true;
1443
0
        }
1444
0
        else if (aFltName == pFilterDBase)
1445
0
        {
1446
0
            OUString sItStr;
1447
0
            if ( const SfxStringItem* pOptionsItem = rMedium.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) )
1448
0
            {
1449
0
                sItStr = pOptionsItem->GetValue();
1450
0
            }
1451
1452
0
            if (sItStr.isEmpty())
1453
0
            {
1454
                //  default for dBase import (from API without options):
1455
                //  IBM_850 encoding
1456
1457
0
                sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_850 );
1458
0
            }
1459
1460
0
            ScDocRowHeightUpdater::TabRanges aRecalcRanges(0, m_pDocument->MaxRow());
1461
0
            ErrCode eError = DBaseImport( rMedium.GetPhysicalName(),
1462
0
                    ScGlobal::GetCharsetValue(sItStr), aColWidthParam, aRecalcRanges.maRanges );
1463
0
            aRecalcRowRangesArray.push_back(aRecalcRanges);
1464
1465
0
            if (eError != ERRCODE_NONE)
1466
0
            {
1467
0
                if (!GetErrorIgnoreWarning())
1468
0
                    SetError(eError);
1469
0
                if( eError.IsWarning() )
1470
0
                    bRet = true;
1471
0
            }
1472
0
            else
1473
0
                bRet = true;
1474
1475
0
            aColWidthRange.aStart.SetRow( 1 );  // Except for the column header
1476
0
            bSetColWidths = true;
1477
0
            bSetSimpleTextColWidths = true;
1478
0
        }
1479
0
        else if (aFltName == pFilterDif)
1480
0
        {
1481
0
            SvStream* pStream = rMedium.GetInStream();
1482
0
            if (pStream)
1483
0
            {
1484
0
                ErrCode eError;
1485
0
                OUString sItStr;
1486
0
                if ( const SfxStringItem* pOptionsItem = rMedium.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) )
1487
0
                {
1488
0
                    sItStr = pOptionsItem->GetValue();
1489
0
                }
1490
1491
0
                if (sItStr.isEmpty())
1492
0
                {
1493
                    //  default for DIF import (from API without options):
1494
                    //  ISO8859-1/MS_1252 encoding
1495
1496
0
                    sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_MS_1252 );
1497
0
                }
1498
1499
0
                eError = ScFormatFilter::Get().ScImportDif( *pStream, m_pDocument.get(), ScAddress(0,0,0),
1500
0
                                    ScGlobal::GetCharsetValue(sItStr));
1501
0
                if (eError != ERRCODE_NONE)
1502
0
                {
1503
0
                    if (!GetErrorIgnoreWarning())
1504
0
                        SetError(eError);
1505
1506
0
                    if( eError.IsWarning() )
1507
0
                        bRet = true;
1508
0
                }
1509
0
                else
1510
0
                    bRet = true;
1511
0
            }
1512
0
            bSetColWidths = true;
1513
0
            bSetSimpleTextColWidths = true;
1514
0
            bSetRowHeights = true;
1515
0
        }
1516
0
        else if (aFltName == pFilterSylk)
1517
0
        {
1518
0
            ErrCode eError = SCERR_IMPORT_UNKNOWN;
1519
0
            bool bOverflowRow, bOverflowCol, bOverflowCell;
1520
0
            bOverflowRow = bOverflowCol = bOverflowCell = false;
1521
0
            if( !rMedium.IsStorage() )
1522
0
            {
1523
0
                ScImportExport aImpEx( *m_pDocument );
1524
1525
0
                SvStream* pInStream = rMedium.GetInStream();
1526
0
                if (pInStream)
1527
0
                {
1528
0
                    pInStream->Seek( 0 );
1529
0
                    bRet = aImpEx.ImportStream( *pInStream, rMedium.GetBaseURL(), SotClipboardFormatId::SYLK );
1530
0
                    eError = bRet ? ERRCODE_NONE : SCERR_IMPORT_UNKNOWN;
1531
0
                    m_pDocument->StartAllListeners();
1532
0
                    sc::SetFormulaDirtyContext aCxt;
1533
0
                    m_pDocument->SetAllFormulasDirty(aCxt);
1534
1535
0
                    bOverflowRow = aImpEx.IsOverflowRow();
1536
0
                    bOverflowCol = aImpEx.IsOverflowCol();
1537
0
                    bOverflowCell = aImpEx.IsOverflowCell();
1538
0
                }
1539
0
                else
1540
0
                {
1541
0
                    OSL_FAIL( "No Stream" );
1542
0
                }
1543
0
            }
1544
1545
0
            if (eError != ERRCODE_NONE)
1546
0
            {
1547
0
                if (!GetErrorIgnoreWarning())
1548
0
                    SetError(eError);
1549
0
                if( eError.IsWarning() )
1550
0
                    bRet = true;
1551
0
            }
1552
0
            else if (!GetErrorIgnoreWarning() && (bOverflowRow || bOverflowCol || bOverflowCell))
1553
0
            {
1554
                // precedence: row, column, cell
1555
0
                ErrCode nWarn = (bOverflowRow ? SCWARN_IMPORT_ROW_OVERFLOW :
1556
0
                        (bOverflowCol ? SCWARN_IMPORT_COLUMN_OVERFLOW :
1557
0
                         SCWARN_IMPORT_CELL_OVERFLOW));
1558
0
                SetError(nWarn);
1559
0
            }
1560
0
            bSetColWidths = true;
1561
0
            bSetSimpleTextColWidths = true;
1562
0
            bSetRowHeights = true;
1563
0
        }
1564
0
        else if (aFltName == pFilterQPro6)
1565
0
        {
1566
0
            ErrCode eError = ScFormatFilter::Get().ScImportQuattroPro(rMedium.GetInStream(), *m_pDocument);
1567
0
            if (eError != ERRCODE_NONE)
1568
0
            {
1569
0
                if (!GetErrorIgnoreWarning())
1570
0
                    SetError(eError);
1571
0
                if( eError.IsWarning() )
1572
0
                    bRet = true;
1573
0
            }
1574
0
            else
1575
0
                bRet = true;
1576
            // TODO: Filter should set column widths. Not doing it here, it may
1577
            // result in very narrow or wide columns, depending on content.
1578
            // Setting row heights makes cells with font size attribution or
1579
            // wrapping enabled look nicer...
1580
0
            bSetRowHeights = true;
1581
0
        }
1582
0
        else if (aFltName == pFilterRtf)
1583
0
        {
1584
0
            ErrCode eError = SCERR_IMPORT_UNKNOWN;
1585
0
            if( !rMedium.IsStorage() )
1586
0
            {
1587
0
                SvStream* pInStream = rMedium.GetInStream();
1588
0
                if (pInStream)
1589
0
                {
1590
0
                    pInStream->Seek( 0 );
1591
0
                    ScRange aRange;
1592
0
                    eError = ScFormatFilter::Get().ScImportRTF( *pInStream, rMedium.GetBaseURL(), *m_pDocument, aRange );
1593
0
                    if (eError != ERRCODE_NONE)
1594
0
                    {
1595
0
                        if (!GetErrorIgnoreWarning())
1596
0
                            SetError(eError);
1597
1598
0
                        if( eError.IsWarning() )
1599
0
                            bRet = true;
1600
0
                    }
1601
0
                    else
1602
0
                        bRet = true;
1603
0
                    m_pDocument->StartAllListeners();
1604
0
                    sc::SetFormulaDirtyContext aCxt;
1605
0
                    m_pDocument->SetAllFormulasDirty(aCxt);
1606
0
                    bSetColWidths = true;
1607
0
                    bSetRowHeights = true;
1608
0
                }
1609
0
                else
1610
0
                {
1611
0
                    OSL_FAIL( "No Stream" );
1612
0
                }
1613
0
            }
1614
1615
0
            if (eError != ERRCODE_NONE)
1616
0
            {
1617
0
                if (!GetErrorIgnoreWarning())
1618
0
                    SetError(eError);
1619
0
                if( eError.IsWarning() )
1620
0
                    bRet = true;
1621
0
            }
1622
0
        }
1623
0
        else if (aFltName == pFilterHtml || aFltName == pFilterHtmlWebQ)
1624
0
        {
1625
0
            ErrCode eError = SCERR_IMPORT_UNKNOWN;
1626
0
            bool bWebQuery = aFltName == pFilterHtmlWebQ;
1627
0
            if( !rMedium.IsStorage() )
1628
0
            {
1629
0
                SvStream* pInStream = rMedium.GetInStream();
1630
0
                if (pInStream)
1631
0
                {
1632
0
                    LanguageType eLang = LANGUAGE_SYSTEM;
1633
0
                    bool bDateConvert = false;
1634
0
                    bool bScientificConvert = true;
1635
0
                    if ( const SfxStringItem* pOptionsItem = rMedium.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) )
1636
0
                    {
1637
0
                        OUString aFilterOption = pOptionsItem->GetValue();
1638
0
                        lcl_parseHtmlFilterOption(aFilterOption, eLang, bDateConvert, bScientificConvert);
1639
0
                    }
1640
1641
0
                    pInStream->Seek( 0 );
1642
0
                    ScRange aRange;
1643
                    // HTML does its own ColWidth/RowHeight
1644
0
                    CalcOutputFactor();
1645
0
                    SvNumberFormatter aNumFormatter( comphelper::getProcessComponentContext(), eLang);
1646
0
                    eError = ScFormatFilter::Get().ScImportHTML( *pInStream, rMedium.GetBaseURL(), *m_pDocument, aRange,
1647
0
                                            GetOutputFactor(), !bWebQuery, &aNumFormatter, bDateConvert, bScientificConvert );
1648
0
                    if (eError != ERRCODE_NONE)
1649
0
                    {
1650
0
                        if (!GetErrorIgnoreWarning())
1651
0
                            SetError(eError);
1652
1653
0
                        if( eError.IsWarning() )
1654
0
                            bRet = true;
1655
0
                    }
1656
0
                    else
1657
0
                        bRet = true;
1658
0
                    m_pDocument->StartAllListeners();
1659
1660
0
                    sc::SetFormulaDirtyContext aCxt;
1661
0
                    m_pDocument->SetAllFormulasDirty(aCxt);
1662
0
                }
1663
0
                else
1664
0
                {
1665
0
                    OSL_FAIL( "No Stream" );
1666
0
                }
1667
0
            }
1668
1669
0
            if (eError != ERRCODE_NONE)
1670
0
            {
1671
0
                if (!GetErrorIgnoreWarning())
1672
0
                    SetError(eError);
1673
0
                if( eError.IsWarning() )
1674
0
                    bRet = true;
1675
0
            }
1676
0
        }
1677
0
        else
1678
0
        {
1679
0
            ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
1680
0
            if (!pOrcus)
1681
0
                return false;
1682
1683
0
            switch (pOrcus->importByName(*m_pDocument, rMedium, aFltName))
1684
0
            {
1685
0
                case ScOrcusFilters::ImportResult::Success:
1686
0
                    bRet = true;
1687
0
                    break;
1688
0
                case ScOrcusFilters::ImportResult::Failure:
1689
0
                    bRet = false;
1690
0
                    break;
1691
0
                case ScOrcusFilters::ImportResult::NotSupported:
1692
0
                {
1693
0
                    if (!GetErrorIgnoreWarning())
1694
0
                    {
1695
0
                        SAL_WARN("sc.filter", "No match for filter '" << aFltName << "' in ConvertFrom");
1696
0
                        SetError(SCERR_IMPORT_NI);
1697
0
                    }
1698
0
                    break;
1699
0
                }
1700
0
            }
1701
0
        }
1702
1703
0
        if (!bCalc3)
1704
0
            m_pDocument->SetInsertingFromOtherDoc( false );
1705
0
    }
1706
0
    else
1707
0
    {
1708
0
        OSL_FAIL("No Filter in ConvertFrom");
1709
0
    }
1710
1711
0
    InitItems();
1712
0
    CalcOutputFactor();
1713
0
    if ( bRet && (bSetColWidths || bSetRowHeights) )
1714
0
    {   // Adjust column width/row height; base 100% zoom
1715
0
        Fraction aZoom( 1, 1 );
1716
0
        double nPPTX = ScGlobal::nScreenPPTX * static_cast<double>(aZoom) / GetOutputFactor(); // Factor is printer display ratio
1717
0
        double nPPTY = ScGlobal::nScreenPPTY * static_cast<double>(aZoom);
1718
0
        ScopedVclPtrInstance< VirtualDevice > pVirtDev;
1719
        //  all sheets (for Excel import)
1720
0
        SCTAB nTabCount = m_pDocument->GetTableCount();
1721
0
        for (SCTAB nTab=0; nTab<nTabCount; nTab++)
1722
0
        {
1723
0
            SCCOL nEndCol;
1724
0
            SCROW nEndRow;
1725
0
            m_pDocument->GetCellArea( nTab, nEndCol, nEndRow );
1726
0
            aColWidthRange.aEnd.SetCol( nEndCol );
1727
0
            aColWidthRange.aEnd.SetRow( nEndRow );
1728
0
            ScMarkData aMark(m_pDocument->GetSheetLimits());
1729
0
            aMark.SetMarkArea( aColWidthRange );
1730
0
            aMark.MarkToMulti();
1731
1732
            // Order is important: First width, then height
1733
0
            if ( bSetColWidths )
1734
0
            {
1735
0
                for ( SCCOL nCol=0; nCol <= nEndCol; nCol++ )
1736
0
                {
1737
0
                    if (!bSetSimpleTextColWidths)
1738
0
                        aColWidthParam[nCol].mbSimpleText = false;
1739
1740
0
                    sal_uInt16 nWidth = m_pDocument->GetOptimalColWidth(
1741
0
                        nCol, nTab, pVirtDev, nPPTX, nPPTY, aZoom, aZoom, false, &aMark,
1742
0
                        &aColWidthParam[nCol] );
1743
0
                    m_pDocument->SetColWidth( nCol, nTab,
1744
0
                        nWidth + static_cast<sal_uInt16>(ScGlobal::nLastColWidthExtra) );
1745
0
                }
1746
0
            }
1747
0
        }
1748
1749
0
        if (bSetRowHeights)
1750
0
        {
1751
            // Update all rows in all tables.
1752
0
            ScSizeDeviceProvider aProv(*this);
1753
0
            ScDocRowHeightUpdater aUpdater(*m_pDocument, aProv.GetDevice(), aProv.GetPPTX(), aProv.GetPPTY(), nullptr);
1754
0
            aUpdater.update();
1755
0
        }
1756
0
        else if (!aRecalcRowRangesArray.empty())
1757
0
        {
1758
            // Update only specified row ranges for better performance.
1759
0
            ScSizeDeviceProvider aProv(*this);
1760
0
            ScDocRowHeightUpdater aUpdater(*m_pDocument, aProv.GetDevice(), aProv.GetPPTX(), aProv.GetPPTY(), &aRecalcRowRangesArray);
1761
0
            aUpdater.update();
1762
0
        }
1763
0
    }
1764
0
    FinishedLoading();
1765
1766
    // invalidate eventually temporary table areas
1767
0
    if ( bRet )
1768
0
        m_pDocument->InvalidateTableArea();
1769
1770
0
    m_bIsEmpty = false;
1771
1772
0
    return bRet;
1773
0
}
1774
1775
bool ScDocShell::LoadExternal( SfxMedium& rMed )
1776
0
{
1777
0
    std::shared_ptr<const SfxFilter> pFilter = rMed.GetFilter();
1778
0
    if (!pFilter)
1779
0
        return false;
1780
1781
0
    if (pFilter->GetProviderName() == "orcus")
1782
0
    {
1783
0
        ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
1784
0
        if (!pOrcus)
1785
0
            return false;
1786
1787
0
        auto res = pOrcus->importByName(*m_pDocument, rMed, pFilter->GetName());
1788
0
        if (res != ScOrcusFilters::ImportResult::Success)
1789
0
            return false;
1790
1791
0
        FinishedLoading();
1792
0
        return true;
1793
0
    }
1794
1795
0
    return false;
1796
0
}
1797
1798
ScDocShell::PrepareSaveGuard::PrepareSaveGuard( ScDocShell& rDocShell )
1799
0
    : mrDocShell( rDocShell)
1800
0
{
1801
    // DoEnterHandler not here (because of AutoSave), is in ExecuteSave.
1802
1803
0
    ScChartListenerCollection* pCharts = mrDocShell.m_pDocument->GetChartListenerCollection();
1804
0
    if (pCharts)
1805
0
        pCharts->UpdateDirtyCharts();                           // Charts to be updated.
1806
0
    mrDocShell.m_pDocument->StopTemporaryChartLock();
1807
0
    if (mrDocShell.m_pAutoStyleList)
1808
0
        mrDocShell.m_pAutoStyleList->ExecuteAllNow();             // Execute template timeouts now.
1809
0
    if (mrDocShell.m_pDocument->HasExternalRefManager())
1810
0
    {
1811
0
        ScExternalRefManager* pRefMgr = mrDocShell.m_pDocument->GetExternalRefManager();
1812
0
        if (pRefMgr && pRefMgr->hasExternalData())
1813
0
        {
1814
0
            pRefMgr->setAllCacheTableReferencedStati( false);
1815
0
            mrDocShell.m_pDocument->MarkUsedExternalReferences();  // Mark tables of external references to be written.
1816
0
        }
1817
0
    }
1818
0
    if (mrDocShell.GetCreateMode()== SfxObjectCreateMode::STANDARD)
1819
0
        mrDocShell.SfxObjectShell::SetVisArea( tools::Rectangle() );   // "Normally" worked on => no VisArea.
1820
0
}
1821
1822
ScDocShell::PrepareSaveGuard::~PrepareSaveGuard() COVERITY_NOEXCEPT_FALSE
1823
0
{
1824
0
    if (mrDocShell.m_pDocument->HasExternalRefManager())
1825
0
    {
1826
0
        ScExternalRefManager* pRefMgr = mrDocShell.m_pDocument->GetExternalRefManager();
1827
0
        if (pRefMgr && pRefMgr->hasExternalData())
1828
0
        {
1829
            // Prevent accidental data loss due to lack of knowledge.
1830
0
            pRefMgr->setAllCacheTableReferencedStati( true);
1831
0
        }
1832
0
    }
1833
0
}
1834
1835
bool ScDocShell::Save()
1836
0
{
1837
0
    ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
1838
1839
0
    PrepareSaveGuard aPrepareGuard( *this);
1840
1841
0
    if (const auto pFrame1 = SfxViewFrame::GetFirst(this))
1842
0
    {
1843
0
        if (auto pSysWin = pFrame1->GetWindow().GetSystemWindow())
1844
0
        {
1845
0
            pSysWin->SetAccessibleName(OUString());
1846
0
        }
1847
0
    }
1848
    //  wait cursor is handled with progress bar
1849
0
    bool bRet = SfxObjectShell::Save();
1850
0
    if( bRet )
1851
0
        bRet = SaveXML( GetMedium(), nullptr );
1852
0
    return bRet;
1853
0
}
1854
1855
namespace {
1856
1857
/**
1858
 * Remove the file name from the full path, to keep only the directory path.
1859
 */
1860
void popFileName(OUString& rPath)
1861
0
{
1862
0
    if (!rPath.isEmpty())
1863
0
    {
1864
0
        INetURLObject aURLObj(rPath);
1865
0
        aURLObj.removeSegment();
1866
0
        rPath = aURLObj.GetMainURL(INetURLObject::DecodeMechanism::NONE);
1867
0
    }
1868
0
}
1869
1870
}
1871
1872
void ScDocShell::TerminateEditing()
1873
0
{
1874
    // Commit any cell changes before saving.
1875
0
    ScModule::get()->InputEnterHandler();
1876
0
}
1877
1878
bool ScDocShell::SaveAs( SfxMedium& rMedium )
1879
0
{
1880
0
    OUString aCurPath; // empty for new document that hasn't been saved.
1881
0
    const SfxMedium* pCurMedium = GetMedium();
1882
0
    if (pCurMedium)
1883
0
    {
1884
0
        aCurPath = pCurMedium->GetName();
1885
0
        popFileName(aCurPath);
1886
0
    }
1887
1888
0
    if (!aCurPath.isEmpty())
1889
0
    {
1890
        // current document has a path -> not a brand-new document.
1891
0
        OUString aNewPath = rMedium.GetName();
1892
0
        popFileName(aNewPath);
1893
0
        OUString aRel = URIHelper::simpleNormalizedMakeRelative(aCurPath, aNewPath);
1894
0
        if (!aRel.isEmpty())
1895
0
        {
1896
            // Directory path will change before and after the save.
1897
0
            m_pDocument->InvalidateStreamOnSave();
1898
0
        }
1899
0
    }
1900
1901
0
    ScTabViewShell* pViewShell = GetBestViewShell();
1902
0
    bool bNeedsRehash = ScPassHashHelper::needsPassHashRegen(*m_pDocument, PASSHASH_SHA1);
1903
0
    if (bNeedsRehash)
1904
        // legacy xls hash double-hashed by SHA1 is also supported.
1905
0
        bNeedsRehash = ScPassHashHelper::needsPassHashRegen(*m_pDocument, PASSHASH_XL, PASSHASH_SHA1);
1906
0
    if (bNeedsRehash)
1907
0
    {   // SHA256 explicitly supported in ODF 1.2, implicitly in ODF 1.1
1908
0
        bNeedsRehash = ScPassHashHelper::needsPassHashRegen(*m_pDocument, PASSHASH_SHA256);
1909
0
    }
1910
1911
0
    if (pViewShell && bNeedsRehash)
1912
0
    {
1913
0
        bool bAutoSaveEvent = false;
1914
0
        utl::MediaDescriptor lArgs(rMedium.GetArgs());
1915
0
        lArgs[utl::MediaDescriptor::PROP_AUTOSAVEEVENT] >>= bAutoSaveEvent;
1916
0
        if (bAutoSaveEvent)
1917
0
        {
1918
            // skip saving recovery file instead of showing re-type password dialog window
1919
0
            SAL_WARN("sc.filter",
1920
0
                     "Should re-type password for own format, won't export recovery file");
1921
0
            rMedium.SetError(ERRCODE_SFX_WRONGPASSWORD);
1922
0
            return false;
1923
0
        }
1924
1925
0
        if (!pViewShell->ExecuteRetypePassDlg(PASSHASH_SHA1))
1926
            // password re-type cancelled.  Don't save the document.
1927
0
            return false;
1928
0
    }
1929
1930
0
    ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
1931
1932
0
    PrepareSaveGuard aPrepareGuard( *this);
1933
1934
    //  wait cursor is handled with progress bar
1935
0
    bool bRet = SfxObjectShell::SaveAs( rMedium );
1936
0
    if (bRet)
1937
0
        bRet = SaveXML( &rMedium, nullptr );
1938
1939
0
    return bRet;
1940
0
}
1941
1942
namespace {
1943
1944
// Xcl-like column width measured in characters of standard font.
1945
sal_Int32 lcl_ScDocShell_GetColWidthInChars( sal_uInt16 nWidth )
1946
0
{
1947
0
    double f = nWidth;
1948
0
    f *= 1328.0 / 25.0;
1949
0
    f += 90.0;
1950
0
    f *= 1.0 / 23.0;
1951
0
    f /= 256.0;
1952
1953
0
    return sal_Int32( f );
1954
0
}
1955
1956
void lcl_ScDocShell_GetFixedWidthString( OUString& rStr, const ScDocument& rDoc,
1957
        SCTAB nTab, SCCOL nCol, bool bValue, SvxCellHorJustify eHorJust )
1958
0
{
1959
0
    OUString aString = rStr;
1960
0
    sal_Int32 nLen = lcl_ScDocShell_GetColWidthInChars(
1961
0
            rDoc.GetColWidth( nCol, nTab ) );
1962
    //If the text won't fit in the column
1963
0
    if ( nLen < aString.getLength() )
1964
0
    {
1965
0
        OUStringBuffer aReplacement;
1966
0
        if (bValue)
1967
0
            aReplacement.append("###");
1968
0
        else
1969
0
            aReplacement.append(aString);
1970
        //truncate to the number of characters that should fit, even in the
1971
        //bValue case nLen might be < len ###
1972
0
        aString = comphelper::string::truncateToLength(aReplacement, nLen).makeStringAndClear();
1973
0
    }
1974
0
    if ( nLen > aString.getLength() )
1975
0
    {
1976
0
        if ( bValue && eHorJust == SvxCellHorJustify::Standard )
1977
0
            eHorJust = SvxCellHorJustify::Right;
1978
0
        OUStringBuffer aTmp(nLen);
1979
0
        switch ( eHorJust )
1980
0
        {
1981
0
            case SvxCellHorJustify::Right:
1982
0
                comphelper::string::padToLength( aTmp, nLen - aString.getLength(), ' ' );
1983
0
                aString = aTmp.append(aString);
1984
0
                break;
1985
0
            case SvxCellHorJustify::Center:
1986
0
                comphelper::string::padToLength( aTmp, (nLen - aString.getLength()) / 2, ' ' );
1987
0
                [[fallthrough]];
1988
0
            default:
1989
0
                aTmp.append(aString);
1990
0
                comphelper::string::padToLength( aTmp, nLen, ' ' );
1991
0
        }
1992
0
        aString = aTmp.makeStringAndClear();
1993
0
    }
1994
0
    rStr = aString;
1995
0
}
1996
1997
void lcl_ScDocShell_WriteEmptyFixedWidthString( SvStream& rStream,
1998
        const ScDocument& rDoc, SCTAB nTab, SCCOL nCol )
1999
0
{
2000
0
    OUString aString;
2001
0
    lcl_ScDocShell_GetFixedWidthString( aString, rDoc, nTab, nCol, false,
2002
0
            SvxCellHorJustify::Standard );
2003
0
    rStream.WriteUnicodeOrByteText( aString );
2004
0
}
2005
2006
template<typename StrT, typename SepCharT>
2007
sal_Int32 getTextSepPos(
2008
    const StrT& rStr, const ScImportOptions& rAsciiOpt, const SepCharT& rTextSep, const SepCharT& rFieldSep, bool& rNeedQuotes)
2009
0
{
2010
    // #i116636# quotes are needed if text delimiter (quote), field delimiter,
2011
    // or LF or CR is in the cell text.
2012
0
    sal_Int32 nPos = rStr.indexOf(rTextSep);
2013
0
    rNeedQuotes = rAsciiOpt.bQuoteAllText || (nPos >= 0) ||
2014
0
        (rStr.indexOf(rFieldSep) >= 0) ||
2015
0
        (rStr.indexOf('\n') >= 0) ||
2016
0
        (rStr.indexOf('\r') >= 0);
2017
0
    return nPos;
2018
0
}
Unexecuted instantiation: docsh.cxx:int (anonymous namespace)::getTextSepPos<rtl::OUString, char16_t>(rtl::OUString const&, ScImportOptions const&, char16_t const&, char16_t const&, bool&)
Unexecuted instantiation: docsh.cxx:int (anonymous namespace)::getTextSepPos<rtl::OUString, rtl::OUString>(rtl::OUString const&, ScImportOptions const&, rtl::OUString const&, rtl::OUString const&, bool&)
Unexecuted instantiation: docsh.cxx:int (anonymous namespace)::getTextSepPos<rtl::OString, rtl::OString>(rtl::OString const&, ScImportOptions const&, rtl::OString const&, rtl::OString const&, bool&)
2019
2020
}
2021
2022
void ScDocShell::AsciiSave( SvStream& rStream, const ScImportOptions& rAsciiOpt, SCTAB nTab )
2023
0
{
2024
0
    sal_Unicode cDelim    = rAsciiOpt.nFieldSepCode;
2025
0
    sal_Unicode cStrDelim = rAsciiOpt.nTextSepCode;
2026
0
    rtl_TextEncoding eCharSet      = rAsciiOpt.eCharSet;
2027
0
    bool bFixedWidth      = rAsciiOpt.bFixedWidth;
2028
0
    bool bSaveNumberAsSuch = rAsciiOpt.bSaveNumberAsSuch;
2029
0
    bool bSaveAsShown     = rAsciiOpt.bSaveAsShown;
2030
0
    bool bShowFormulas    = rAsciiOpt.bSaveFormulas;
2031
0
    bool bIncludeBOM      = rAsciiOpt.bIncludeBOM;
2032
2033
0
    rtl_TextEncoding eOldCharSet = rStream.GetStreamCharSet();
2034
0
    rStream.SetStreamCharSet( eCharSet );
2035
0
    SvStreamEndian nOldNumberFormatInt = rStream.GetEndian();
2036
0
    OString aStrDelimEncoded;    // only used if not Unicode
2037
0
    OUString aStrDelimDecoded;     // only used if context encoding
2038
0
    OString aDelimEncoded;
2039
0
    OUString aDelimDecoded;
2040
0
    bool bContextOrNotAsciiEncoding;
2041
0
    if ( eCharSet == RTL_TEXTENCODING_UNICODE )
2042
0
    {
2043
0
        rStream.StartWritingUnicodeText();
2044
0
        bContextOrNotAsciiEncoding = false;
2045
0
    }
2046
0
    else
2047
0
    {
2048
        // tdf#82254 - check whether to include a byte-order-mark in the output
2049
0
        if (bIncludeBOM && eCharSet == RTL_TEXTENCODING_UTF8)
2050
0
            rStream.WriteUChar(0xEF).WriteUChar(0xBB).WriteUChar(0xBF);
2051
0
        aStrDelimEncoded = OString(&cStrDelim, 1, eCharSet);
2052
0
        aDelimEncoded = OString(&cDelim, 1, eCharSet);
2053
0
        rtl_TextEncodingInfo aInfo;
2054
0
        aInfo.StructSize = sizeof(aInfo);
2055
0
        if ( rtl_getTextEncodingInfo( eCharSet, &aInfo ) )
2056
0
        {
2057
0
            bContextOrNotAsciiEncoding =
2058
0
                (((aInfo.Flags & RTL_TEXTENCODING_INFO_CONTEXT) != 0) ||
2059
0
                 ((aInfo.Flags & RTL_TEXTENCODING_INFO_ASCII) == 0));
2060
0
            if ( bContextOrNotAsciiEncoding )
2061
0
            {
2062
0
                aStrDelimDecoded = OStringToOUString(aStrDelimEncoded, eCharSet);
2063
0
                aDelimDecoded = OStringToOUString(aDelimEncoded, eCharSet);
2064
0
            }
2065
0
        }
2066
0
        else
2067
0
            bContextOrNotAsciiEncoding = false;
2068
0
    }
2069
2070
0
    SCCOL nStartCol = 0;
2071
0
    SCROW nStartRow = 0;
2072
0
    SCCOL nEndCol;
2073
0
    SCROW nEndRow;
2074
0
    m_pDocument->GetCellArea( nTab, nEndCol, nEndRow );
2075
2076
0
    ScProgress aProgress( this, ScResId( STR_SAVE_DOC ), nEndRow, true );
2077
2078
0
    OUString aString;
2079
2080
0
    bool bTabProtect = m_pDocument->IsTabProtected( nTab );
2081
2082
0
    SCCOL nCol;
2083
0
    SCROW nRow;
2084
2085
    // Treat the top left cell separator "sep=" special.
2086
    // Here nStartRow == 0 && nStartCol == 0
2087
0
    if (!bFixedWidth && cDelim != 0)
2088
0
    {
2089
        // First row iterator.
2090
0
        ScHorizontalCellIterator aIter( *m_pDocument, nTab, nStartCol, nStartRow, nEndCol, nStartRow);
2091
0
        ScRefCellValue* pCell;
2092
        // Must be first column and all following cells on this row must be
2093
        // empty to fiddle with "sep=".
2094
0
        if ((pCell = aIter.GetNext( nCol, nRow)) != nullptr && nCol == nStartCol && !aIter.GetNext( nCol, nRow))
2095
0
        {
2096
0
            if (pCell->getType() == CELLTYPE_STRING)
2097
0
            {
2098
0
                aString = pCell->getSharedString()->getString();
2099
0
                if (aString.getLength() <= 5 && aString.startsWithIgnoreAsciiCase("sep="))
2100
0
                {
2101
                    // Cell content is /^sep=.?$/ so write current separator.
2102
                    // Force the quote character to '"' regardless what is set
2103
                    // for export because that is the only one recognized on
2104
                    // import.
2105
0
                    aString = "sep=" + OUStringChar(cDelim);
2106
0
                    if (cStrDelim != 0)
2107
0
                        rStream.WriteUniOrByteChar( '"', eCharSet);
2108
0
                    rStream.WriteUnicodeOrByteText(aString, eCharSet);
2109
0
                    if (cStrDelim != 0)
2110
0
                        rStream.WriteUniOrByteChar( '"', eCharSet);
2111
0
                    endlub( rStream );
2112
0
                    ++nStartRow;
2113
0
                }
2114
0
            }
2115
0
        }
2116
0
    }
2117
2118
0
    SCCOL nNextCol = nStartCol;
2119
0
    SCROW nNextRow = nStartRow;
2120
0
    SCCOL nEmptyCol;
2121
0
    SCROW nEmptyRow;
2122
0
    ScInterpreterContext& rContext = m_pDocument->GetNonThreadedContext();
2123
2124
0
    ScHorizontalCellIterator aIter( *m_pDocument, nTab, nStartCol, nStartRow,
2125
0
        nEndCol, nEndRow );
2126
0
    ScRefCellValue* pCell;
2127
0
    while ( ( pCell = aIter.GetNext( nCol, nRow ) ) != nullptr )
2128
0
    {
2129
0
        bool bProgress = false;     // only upon line change
2130
0
        if ( nNextRow < nRow )
2131
0
        {   // empty rows or/and empty columns up to end of row
2132
0
            bProgress = true;
2133
0
            for ( nEmptyCol = nNextCol; nEmptyCol < nEndCol; nEmptyCol++ )
2134
0
            {   // remaining columns of last row
2135
0
                if ( bFixedWidth )
2136
0
                    lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2137
0
                            *m_pDocument, nTab, nEmptyCol );
2138
0
                else if ( cDelim != 0 )
2139
0
                    rStream.WriteUniOrByteChar( cDelim );
2140
0
            }
2141
0
            endlub( rStream );
2142
0
            nNextRow++;
2143
0
            for ( nEmptyRow = nNextRow; nEmptyRow < nRow; nEmptyRow++ )
2144
0
            {   // completely empty rows
2145
0
                for ( nEmptyCol = nStartCol; nEmptyCol < nEndCol; nEmptyCol++ )
2146
0
                {
2147
0
                    if ( bFixedWidth )
2148
0
                        lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2149
0
                                *m_pDocument, nTab, nEmptyCol );
2150
0
                    else if ( cDelim != 0 )
2151
0
                        rStream.WriteUniOrByteChar( cDelim );
2152
0
                }
2153
0
                endlub( rStream );
2154
0
            }
2155
0
            for ( nEmptyCol = nStartCol; nEmptyCol < nCol; nEmptyCol++ )
2156
0
            {   // empty columns at beginning of row
2157
0
                if ( bFixedWidth )
2158
0
                    lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2159
0
                            *m_pDocument, nTab, nEmptyCol );
2160
0
                else if ( cDelim != 0 )
2161
0
                    rStream.WriteUniOrByteChar( cDelim );
2162
0
            }
2163
0
            nNextRow = nRow;
2164
0
        }
2165
0
        else if ( nNextCol < nCol )
2166
0
        {   // empty columns in same row
2167
0
            for ( nEmptyCol = nNextCol; nEmptyCol < nCol; nEmptyCol++ )
2168
0
            {   // columns in between
2169
0
                if ( bFixedWidth )
2170
0
                    lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2171
0
                            *m_pDocument, nTab, nEmptyCol );
2172
0
                else if ( cDelim != 0 )
2173
0
                    rStream.WriteUniOrByteChar( cDelim );
2174
0
            }
2175
0
        }
2176
0
        if ( nCol == nEndCol )
2177
0
        {
2178
0
            bProgress = true;
2179
0
            nNextCol = nStartCol;
2180
0
            nNextRow = nRow + 1;
2181
0
        }
2182
0
        else
2183
0
            nNextCol = nCol + 1;
2184
2185
0
        CellType eType = pCell->getType();
2186
0
        ScAddress aPos(nCol, nRow, nTab);
2187
0
        if ( bTabProtect )
2188
0
        {
2189
0
            const ScProtectionAttr* pProtAttr =
2190
0
                m_pDocument->GetAttr( nCol, nRow, nTab, ATTR_PROTECTION );
2191
0
            if ( pProtAttr->GetHideCell() ||
2192
0
                    ( eType == CELLTYPE_FORMULA && bShowFormulas &&
2193
0
                      pProtAttr->GetHideFormula() ) )
2194
0
                eType = CELLTYPE_NONE;  // hide
2195
0
        }
2196
0
        bool bForceQuotes = false;
2197
0
        bool bString;
2198
0
        switch ( eType )
2199
0
        {
2200
0
            case CELLTYPE_NONE:
2201
0
                aString.clear();
2202
0
                bString = false;
2203
0
                break;
2204
0
            case CELLTYPE_FORMULA :
2205
0
                {
2206
0
                    FormulaError nErrCode;
2207
0
                    if ( bShowFormulas )
2208
0
                    {
2209
0
                        aString = pCell->getFormula()->GetFormula();
2210
0
                        bString = true;
2211
0
                    }
2212
0
                    else if ((nErrCode = pCell->getFormula()->GetErrCode()) != FormulaError::NONE)
2213
0
                    {
2214
0
                        aString = ScGlobal::GetErrorString( nErrCode );
2215
0
                        bString = true;
2216
0
                    }
2217
0
                    else if (pCell->getFormula()->IsValue())
2218
0
                    {
2219
0
                        sal_uInt32 nFormat = m_pDocument->GetNumberFormat(ScRange(aPos));
2220
0
                        if ( bFixedWidth || bSaveAsShown )
2221
0
                        {
2222
0
                            const Color* pDummy;
2223
0
                            aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, &rContext, *m_pDocument);
2224
0
                            bString = bSaveAsShown && rContext.NFIsTextFormat( nFormat);
2225
0
                        }
2226
0
                        else
2227
0
                        {
2228
0
                            aString = ScCellFormat::GetInputString(*pCell, nFormat, &rContext, *m_pDocument);
2229
0
                            bString = bForceQuotes = !bSaveNumberAsSuch;
2230
0
                        }
2231
0
                    }
2232
0
                    else
2233
0
                    {
2234
0
                        if ( bSaveAsShown )
2235
0
                        {
2236
0
                            sal_uInt32 nFormat = m_pDocument->GetNumberFormat(ScRange(aPos));
2237
0
                            const Color* pDummy;
2238
0
                            aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, &rContext, *m_pDocument);
2239
0
                        }
2240
0
                        else
2241
0
                            aString = pCell->getFormula()->GetString().getString();
2242
0
                        bString = true;
2243
0
                    }
2244
0
                }
2245
0
                break;
2246
0
            case CELLTYPE_STRING :
2247
0
                if ( bSaveAsShown )
2248
0
                {
2249
0
                    sal_uInt32 nFormat = m_pDocument->GetNumberFormat(ScRange(aPos));
2250
0
                    const Color* pDummy;
2251
0
                    aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, &rContext, *m_pDocument);
2252
0
                }
2253
0
                else
2254
0
                    aString = pCell->getSharedString()->getString();
2255
0
                bString = true;
2256
0
                break;
2257
0
            case CELLTYPE_EDIT :
2258
0
                {
2259
0
                    const EditTextObject* pObj = pCell->getEditText();
2260
0
                    EditEngine& rEngine = m_pDocument->GetEditEngine();
2261
0
                    rEngine.SetText( *pObj);
2262
0
                    aString = rEngine.GetText();  // including LF
2263
0
                    bString = true;
2264
0
                }
2265
0
                break;
2266
0
            case CELLTYPE_VALUE :
2267
0
                {
2268
0
                    sal_uInt32 nFormat = m_pDocument->GetNumberFormat( nCol, nRow, nTab );
2269
0
                    if ( bFixedWidth || bSaveAsShown )
2270
0
                    {
2271
0
                        const Color* pDummy;
2272
0
                        aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, &rContext, *m_pDocument);
2273
0
                        bString = bSaveAsShown && rContext.NFIsTextFormat( nFormat);
2274
0
                    }
2275
0
                    else
2276
0
                    {
2277
0
                        aString = ScCellFormat::GetInputString(*pCell, nFormat, &rContext, *m_pDocument);
2278
0
                        bString = bForceQuotes = !bSaveNumberAsSuch;
2279
0
                    }
2280
0
                }
2281
0
                break;
2282
0
            default:
2283
0
                OSL_FAIL( "ScDocShell::AsciiSave: unknown CellType" );
2284
0
                aString.clear();
2285
0
                bString = false;
2286
0
        }
2287
2288
0
        if ( bFixedWidth )
2289
0
        {
2290
0
            SvxCellHorJustify eHorJust =
2291
0
                m_pDocument->GetAttr( nCol, nRow, nTab, ATTR_HOR_JUSTIFY )->GetValue();
2292
0
            lcl_ScDocShell_GetFixedWidthString( aString, *m_pDocument, nTab, nCol,
2293
0
                    !bString, eHorJust );
2294
0
            rStream.WriteUnicodeOrByteText( aString );
2295
0
        }
2296
0
        else
2297
0
        {
2298
0
            OUString aUniString = aString;// TODO: remove that later
2299
0
            if (!bString && cStrDelim != 0 && !aUniString.isEmpty())
2300
0
            {
2301
0
                sal_Unicode c = aUniString[0];
2302
0
                bString = (c == cStrDelim || c == ' ' ||
2303
0
                        aUniString.endsWith(" ") ||
2304
0
                        aUniString.indexOf(cStrDelim) >= 0);
2305
0
                if (!bString && cDelim != 0)
2306
0
                    bString = (aUniString.indexOf(cDelim) >= 0);
2307
0
            }
2308
0
            if ( bString )
2309
0
            {
2310
0
                if ( cStrDelim != 0 ) //@ BugId 55355
2311
0
                {
2312
0
                    if ( eCharSet == RTL_TEXTENCODING_UNICODE )
2313
0
                    {
2314
0
                        bool bNeedQuotes = false;
2315
0
                        sal_Int32 nPos = getTextSepPos(aUniString, rAsciiOpt, cStrDelim, cDelim, bNeedQuotes);
2316
0
                        if (nPos >= 0)
2317
0
                        {
2318
0
                            OUString strFrom(cStrDelim);
2319
0
                            OUString strTo = strFrom + strFrom;
2320
0
                            aUniString = aUniString.replaceAll(strFrom, strTo);
2321
0
                        }
2322
2323
0
                        if ( bNeedQuotes || bForceQuotes )
2324
0
                            rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
2325
0
                        rStream.WriteUnicodeOrByteText(aUniString, eCharSet);
2326
0
                        if ( bNeedQuotes || bForceQuotes )
2327
0
                            rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
2328
0
                    }
2329
0
                    else
2330
0
                    {
2331
                        // This is nasty. The Unicode to byte encoding
2332
                        // may convert typographical quotation marks to ASCII
2333
                        // quotation marks, which may interfere with the delimiter,
2334
                        // so we have to escape delimiters after the string has
2335
                        // been encoded. Since this may happen also with UTF-8
2336
                        // encoded typographical quotation marks if such was
2337
                        // specified as a delimiter we have to check for the full
2338
                        // encoded delimiter string, not just one character.
2339
                        // Now for RTL_TEXTENCODING_ISO_2022_... and similar brain
2340
                        // dead encodings where one code point (and especially a
2341
                        // low ASCII value) may represent different characters, we
2342
                        // have to convert forth and back and forth again. Same for
2343
                        // UTF-7 since it is a context sensitive encoding too.
2344
2345
0
                        if ( bContextOrNotAsciiEncoding )
2346
0
                        {
2347
                            // to byte encoding
2348
0
                            OString aStrEnc = OUStringToOString(aUniString, eCharSet);
2349
                            // back to Unicode
2350
0
                            OUString aStrDec = OStringToOUString(aStrEnc, eCharSet);
2351
2352
                            // search on re-decoded string
2353
0
                            bool bNeedQuotes = false;
2354
0
                            sal_Int32 nPos = getTextSepPos(aStrDec, rAsciiOpt, aStrDelimDecoded, aDelimDecoded, bNeedQuotes);
2355
0
                            if (nPos >= 0)
2356
0
                            {
2357
0
                                OUString strTo = aStrDelimDecoded + aStrDelimDecoded;
2358
0
                                aStrDec = aStrDec.replaceAll(aStrDelimDecoded, strTo);
2359
0
                            }
2360
2361
                            // write byte re-encoded
2362
0
                            if ( bNeedQuotes || bForceQuotes )
2363
0
                                rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
2364
0
                            rStream.WriteUnicodeOrByteText( aStrDec, eCharSet );
2365
0
                            if ( bNeedQuotes || bForceQuotes )
2366
0
                                rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
2367
0
                        }
2368
0
                        else
2369
0
                        {
2370
0
                            OString aStrEnc = OUStringToOString(aUniString, eCharSet);
2371
2372
                            // search on encoded string
2373
0
                            bool bNeedQuotes = false;
2374
0
                            sal_Int32 nPos = getTextSepPos(aStrEnc, rAsciiOpt, aStrDelimEncoded, aDelimEncoded, bNeedQuotes);
2375
0
                            if (nPos >= 0)
2376
0
                            {
2377
0
                                OString strTo = aStrDelimEncoded + aStrDelimEncoded;
2378
0
                                aStrEnc = aStrEnc.replaceAll(aStrDelimEncoded, strTo);
2379
0
                            }
2380
2381
                            // write byte encoded
2382
0
                            if ( bNeedQuotes || bForceQuotes )
2383
0
                                rStream.WriteBytes(
2384
0
                                    aStrDelimEncoded.getStr(), aStrDelimEncoded.getLength());
2385
0
                            rStream.WriteBytes(aStrEnc.getStr(), aStrEnc.getLength());
2386
0
                            if ( bNeedQuotes || bForceQuotes )
2387
0
                                rStream.WriteBytes(
2388
0
                                    aStrDelimEncoded.getStr(), aStrDelimEncoded.getLength());
2389
0
                        }
2390
0
                    }
2391
0
                }
2392
0
                else
2393
0
                    rStream.WriteUnicodeOrByteText( aUniString );
2394
0
            }
2395
0
            else
2396
0
                rStream.WriteUnicodeOrByteText( aUniString );
2397
0
        }
2398
2399
0
        if( nCol < nEndCol )
2400
0
        {
2401
0
            if(cDelim!=0) //@ BugId 55355
2402
0
                rStream.WriteUniOrByteChar( cDelim );
2403
0
        }
2404
0
        else
2405
0
            endlub( rStream );
2406
2407
0
        if ( bProgress )
2408
0
            aProgress.SetStateOnPercent( nRow );
2409
0
    }
2410
2411
    // write out empty if requested
2412
0
    if ( nNextRow <= nEndRow )
2413
0
    {
2414
0
        for ( nEmptyCol = nNextCol; nEmptyCol < nEndCol; nEmptyCol++ )
2415
0
        {   // remaining empty columns of last row
2416
0
            if ( bFixedWidth )
2417
0
                lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2418
0
                        *m_pDocument, nTab, nEmptyCol );
2419
0
            else if ( cDelim != 0 )
2420
0
                rStream.WriteUniOrByteChar( cDelim );
2421
0
        }
2422
0
        endlub( rStream );
2423
0
        nNextRow++;
2424
0
    }
2425
0
    for ( nEmptyRow = nNextRow; nEmptyRow <= nEndRow; nEmptyRow++ )
2426
0
    {   // entire empty rows
2427
0
        for ( nEmptyCol = nStartCol; nEmptyCol < nEndCol; nEmptyCol++ )
2428
0
        {
2429
0
            if ( bFixedWidth )
2430
0
                lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2431
0
                        *m_pDocument, nTab, nEmptyCol );
2432
0
            else if ( cDelim != 0 )
2433
0
                rStream.WriteUniOrByteChar( cDelim );
2434
0
        }
2435
0
        endlub( rStream );
2436
0
    }
2437
2438
0
    rStream.SetStreamCharSet( eOldCharSet );
2439
0
    rStream.SetEndian( nOldNumberFormatInt );
2440
0
}
2441
2442
bool ScDocShell::ConvertTo( SfxMedium &rMed )
2443
0
{
2444
0
    ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
2445
2446
    //  #i6500# don't call DoEnterHandler here (doesn't work with AutoSave),
2447
    //  it's already in ExecuteSave (as for Save and SaveAs)
2448
2449
0
    if (m_pAutoStyleList)
2450
0
        m_pAutoStyleList->ExecuteAllNow(); // Execute template timeouts now
2451
0
    if (GetCreateMode()== SfxObjectCreateMode::STANDARD)
2452
0
        SfxObjectShell::SetVisArea( tools::Rectangle() ); // Edited normally -> no VisArea
2453
2454
0
    OSL_ENSURE( rMed.GetFilter(), "Filter == 0" );
2455
2456
0
    bool bRet = false;
2457
0
    OUString aFltName = rMed.GetFilter()->GetFilterName();
2458
2459
0
    if (aFltName == pFilterXML)
2460
0
    {
2461
        //TODO/LATER: this shouldn't happen!
2462
0
        OSL_FAIL("XML filter in ConvertFrom?!");
2463
0
        bRet = SaveXML( &rMed, nullptr );
2464
0
    }
2465
0
    else if (aFltName == pFilterExcel5 || aFltName == pFilterExcel95 ||
2466
0
             aFltName == pFilterExcel97 || aFltName == pFilterEx5Temp ||
2467
0
             aFltName == pFilterEx95Temp || aFltName == pFilterEx97Temp)
2468
0
    {
2469
0
        weld::WaitObject aWait( GetActiveDialogParent() );
2470
2471
0
        bool bDoSave = true;
2472
0
        if( ScTabViewShell* pViewShell = GetBestViewShell() )
2473
0
        {
2474
0
            ScExtDocOptions* pExtDocOpt = m_pDocument->GetExtDocOptions();
2475
0
            if( !pExtDocOpt )
2476
0
            {
2477
0
                m_pDocument->SetExtDocOptions( std::make_unique<ScExtDocOptions>() );
2478
0
                pExtDocOpt = m_pDocument->GetExtDocOptions();
2479
0
            }
2480
0
            pViewShell->GetViewData().WriteExtOptions( *pExtDocOpt );
2481
2482
            /*  #i104990# If the imported document contains a medium
2483
                password, determine if we can save it, otherwise ask the users
2484
                whether they want to save without it. */
2485
0
            if( (rMed.GetFilter()->GetFilterFlags() & SfxFilterFlags::ENCRYPTION) == SfxFilterFlags::NONE )
2486
0
            {
2487
0
                SfxItemSet& rItemSet = rMed.GetItemSet();
2488
0
                if( rItemSet.GetItemState( SID_PASSWORD ) == SfxItemState::SET )
2489
0
                {
2490
0
                    bDoSave = ScWarnPassword::WarningOnPassword( rMed );
2491
                    // #i42858# remove password from medium (warn only one time)
2492
0
                    if( bDoSave )
2493
0
                        rItemSet.ClearItem( SID_PASSWORD );
2494
0
                }
2495
0
            }
2496
2497
0
            if( bDoSave )
2498
0
            {
2499
0
                bool bNeedRetypePassDlg = ScPassHashHelper::needsPassHashRegen( *m_pDocument, PASSHASH_XL );
2500
0
                bDoSave = !bNeedRetypePassDlg || pViewShell->ExecuteRetypePassDlg( PASSHASH_XL );
2501
0
            }
2502
0
        }
2503
2504
0
        if( bDoSave )
2505
0
        {
2506
0
            ExportFormatExcel eFormat = ExpBiff5;
2507
0
            if( aFltName == pFilterExcel97 || aFltName == pFilterEx97Temp )
2508
0
                eFormat = ExpBiff8;
2509
0
            ErrCode eError = ScFormatFilter::Get().ScExportExcel5( rMed, m_pDocument.get(), eFormat, RTL_TEXTENCODING_MS_1252 );
2510
2511
0
            if( eError && !GetErrorIgnoreWarning() )
2512
0
                SetError(eError);
2513
2514
            // don't return false for warnings
2515
0
            bRet = eError.IsWarning() || (eError == ERRCODE_NONE);
2516
0
        }
2517
0
        else
2518
0
        {
2519
            // export aborted, i.e. "Save without password" warning
2520
0
            SetError(ERRCODE_ABORT);
2521
0
        }
2522
0
    }
2523
0
    else if (aFltName == SC_TEXT_CSV_FILTER_NAME)
2524
0
    {
2525
0
        OUString sItStr;
2526
0
        if ( const SfxStringItem* pOptionsItem = rMed.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) )
2527
0
        {
2528
0
            sItStr = pOptionsItem->GetValue();
2529
0
        }
2530
2531
0
        if ( sItStr.isEmpty() )
2532
0
        {
2533
            //  default for ascii export (from API without options):
2534
            //  UTF-8 encoding, comma, double quotes
2535
2536
0
            ScImportOptions aDefOptions(',', '"', RTL_TEXTENCODING_UTF8);
2537
0
            sItStr = aDefOptions.BuildString();
2538
0
        }
2539
2540
0
        weld::WaitObject aWait( GetActiveDialogParent() );
2541
0
        ScImportOptions aOptions( sItStr );
2542
2543
0
        if (aOptions.nSheetToExport)
2544
0
        {
2545
            // Only from command line --convert-to
2546
0
            bRet = true;
2547
2548
            // Verbose only from command line, not UI (in case we actually
2549
            // implement that) nor macro filter options.
2550
0
            bool bVerbose = false;
2551
0
            const css::uno::Sequence<css::beans::PropertyValue> & rArgs = rMed.GetArgs();
2552
0
            const auto pProp = std::find_if( rArgs.begin(), rArgs.end(),
2553
0
                    [](const css::beans::PropertyValue& rProp) { return rProp.Name == "ConversionRequestOrigin"; });
2554
0
            if (pProp != rArgs.end())
2555
0
            {
2556
0
                OUString aOrigin;
2557
0
                pProp->Value >>= aOrigin;
2558
0
                bVerbose = (aOrigin == "CommandLine");
2559
0
            }
2560
2561
0
            SCTAB nStartTab;
2562
0
            SCTAB nCount = m_pDocument->GetTableCount();
2563
0
            if (aOptions.nSheetToExport == -1)
2564
0
            {
2565
                // All sheets.
2566
0
                nStartTab = 0;
2567
0
            }
2568
0
            else if (0 < aOptions.nSheetToExport && aOptions.nSheetToExport <= nCount)
2569
0
            {
2570
                // One sheet, 1-based.
2571
0
                nCount = aOptions.nSheetToExport;
2572
0
                nStartTab = nCount - 1;
2573
0
            }
2574
0
            else
2575
0
            {
2576
                // Usage error, no export but log.
2577
0
                if (bVerbose)
2578
0
                {
2579
0
                    if (aOptions.nSheetToExport < 0)
2580
0
                        std::cout << "Bad sheet number string given." << std::endl;
2581
0
                    else
2582
0
                        std::cout << "No sheet number " << aOptions.nSheetToExport
2583
0
                            << ", number of sheets is " << nCount << std::endl;
2584
0
                }
2585
0
                nStartTab = 0;
2586
0
                nCount = 0;
2587
0
                SetError(SCERR_EXPORT_DATA);
2588
0
                bRet = false;
2589
0
            }
2590
2591
0
            INetURLObject aURLObject(rMed.GetURLObject());
2592
0
            OUString sExt = aURLObject.CutExtension();
2593
0
            OUString sBaseName = aURLObject.GetLastName();
2594
0
            aURLObject.CutLastName();
2595
2596
0
            for (SCTAB i = nStartTab; i < nCount; ++i)
2597
0
            {
2598
0
                OUString sTabName;
2599
0
                if (!m_pDocument->GetName(i, sTabName))
2600
0
                    sTabName = OUString::number(i);
2601
0
                INetURLObject aSheetURLObject(aURLObject);
2602
0
                OUString sFileName = sBaseName + "-" + sTabName;
2603
0
                if (!sExt.isEmpty())
2604
0
                    sFileName = sFileName + "." + sExt;
2605
0
                aSheetURLObject.Append(sFileName);
2606
2607
                // log similar to DispatchWatcher::executeDispatchRequests
2608
0
                OUString aOutFile = aSheetURLObject.GetMainURL(INetURLObject::DecodeMechanism::NONE);
2609
0
                if (bVerbose)
2610
0
                {
2611
0
                    OUString aDisplayedName;
2612
0
                    if (osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL(aOutFile, aDisplayedName))
2613
0
                        aDisplayedName = aOutFile;
2614
0
                    std::cout << "Writing sheet " << OUStringToOString(sTabName, osl_getThreadTextEncoding()) << " -> "
2615
0
                                                  << OUStringToOString(aDisplayedName, osl_getThreadTextEncoding())
2616
0
                                                  << std::endl;
2617
2618
0
                    if (FStatHelper::IsDocument(aOutFile))
2619
0
                        std::cout << "Overwriting: " << OUStringToOString(aDisplayedName, osl_getThreadTextEncoding())
2620
0
                                                     << std::endl ;
2621
0
                }
2622
2623
0
                std::unique_ptr<SvStream> xStm = ::utl::UcbStreamHelper::CreateStream(aOutFile, StreamMode::TRUNC | StreamMode::WRITE);
2624
0
                if (!xStm)
2625
0
                {
2626
0
                    SetError(ERRCODE_IO_CANTCREATE);
2627
0
                    bRet = false;
2628
0
                    break;
2629
0
                }
2630
0
                AsciiSave(*xStm, aOptions, i);
2631
0
            }
2632
0
        }
2633
0
        else
2634
0
        {
2635
0
            SvStream* pStream = rMed.GetOutStream();
2636
0
            if (pStream)
2637
0
            {
2638
0
                AsciiSave(*pStream, aOptions, GetSaveTab());
2639
0
                bRet = true;
2640
2641
0
                if (m_pDocument->GetTableCount() > 1)
2642
0
                {
2643
0
                    if (!rMed.GetErrorIgnoreWarning() && ScModule::get()->GetInputOptions().GetWarnActiveSheet())
2644
0
                    {
2645
0
                        if (ScTabViewShell* pViewShell = GetBestViewShell())
2646
0
                            pViewShell->ExecuteOnlyActiveSheetSavedDlg();
2647
0
                    }
2648
0
                }
2649
0
            }
2650
0
        }
2651
0
    }
2652
0
    else if (aFltName == pFilterDBase)
2653
0
    {
2654
0
        OUString sCharSet;
2655
0
        if ( const SfxStringItem* pOptionsItem = rMed.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) )
2656
0
        {
2657
0
            sCharSet = pOptionsItem->GetValue();
2658
0
        }
2659
2660
0
        if (sCharSet.isEmpty())
2661
0
        {
2662
            //  default for dBase export (from API without options):
2663
            //  IBM_850 encoding
2664
2665
0
            sCharSet = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_850 );
2666
0
        }
2667
2668
0
        weld::WaitObject aWait( GetActiveDialogParent() );
2669
        // Hack so that Sba can overwrite the opened TempFile.
2670
0
        rMed.CloseOutStream();
2671
0
        bool bHasMemo = false;
2672
2673
0
        ErrCodeMsg eError = DBaseExport(
2674
0
            rMed.GetPhysicalName(), ScGlobal::GetCharsetValue(sCharSet), bHasMemo);
2675
2676
0
        INetURLObject aTmpFile( rMed.GetPhysicalName(), INetProtocol::File );
2677
0
        if ( bHasMemo )
2678
0
            aTmpFile.setExtension(u"dbt");
2679
0
        if ( eError != ERRCODE_NONE && !eError.IsWarning() )
2680
0
        {
2681
0
            if (!GetErrorIgnoreWarning())
2682
0
                SetError(eError);
2683
0
            if ( bHasMemo && IsDocument( aTmpFile ) )
2684
0
                KillFile( aTmpFile );
2685
0
        }
2686
0
        else
2687
0
        {
2688
0
            bRet = true;
2689
0
            if ( bHasMemo )
2690
0
            {
2691
0
                const SfxStringItem* pNameItem = rMed.GetItemSet().GetItem<SfxStringItem>( SID_FILE_NAME );
2692
0
                assert(pNameItem && "SID_FILE_NAME is required");
2693
0
                INetURLObject aDbtFile( pNameItem->GetValue(), INetProtocol::File );
2694
0
                aDbtFile.setExtension(u"dbt");
2695
2696
                // tdf#40713: don't lose dbt file
2697
                // if aDbtFile corresponds exactly to aTmpFile, we just have to return
2698
0
                if (aDbtFile.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ) ==
2699
0
                    aTmpFile.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ))
2700
0
                {
2701
0
                    if (eError != ERRCODE_NONE && !GetErrorIgnoreWarning())
2702
0
                        SetError(eError);
2703
0
                    return bRet;
2704
0
                }
2705
2706
0
                if ( IsDocument( aDbtFile ) && !KillFile( aDbtFile ) )
2707
0
                    bRet = false;
2708
0
                if ( bRet && !MoveFile( aTmpFile, aDbtFile ) )
2709
0
                    bRet = false;
2710
0
                if ( !bRet )
2711
0
                {
2712
0
                    KillFile( aTmpFile );
2713
0
                    if (eError == ERRCODE_NONE || eError.IsWarning())
2714
0
                        eError = SCERR_EXPORT_DATA;
2715
0
                }
2716
0
            }
2717
0
            if (eError != ERRCODE_NONE && !GetErrorIgnoreWarning())
2718
0
                SetError(eError);
2719
0
        }
2720
0
    }
2721
0
    else if (aFltName == pFilterDif)
2722
0
    {
2723
0
        SvStream* pStream = rMed.GetOutStream();
2724
0
        if (pStream)
2725
0
        {
2726
0
            OUString sItStr;
2727
0
            if ( const SfxStringItem* pOptionsItem = rMed.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) )
2728
0
            {
2729
0
                sItStr = pOptionsItem->GetValue();
2730
0
            }
2731
2732
0
            if (sItStr.isEmpty())
2733
0
            {
2734
                //  default for DIF export (from API without options):
2735
                //  ISO8859-1/MS_1252 encoding
2736
2737
0
                sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_MS_1252 );
2738
0
            }
2739
2740
0
            weld::WaitObject aWait( GetActiveDialogParent() );
2741
0
            ScFormatFilter::Get().ScExportDif( *pStream, *m_pDocument, ScAddress(0,0,0),
2742
0
                ScGlobal::GetCharsetValue(sItStr) );
2743
0
            bRet = true;
2744
2745
0
            if (m_pDocument->GetTableCount() > 1)
2746
0
                if (!rMed.GetErrorIgnoreWarning() && ScModule::get()->GetInputOptions().GetWarnActiveSheet())
2747
0
                    rMed.SetError(SCWARN_EXPORT_ASCII);
2748
0
        }
2749
0
    }
2750
0
    else if (aFltName == pFilterSylk)
2751
0
    {
2752
0
        SvStream* pStream = rMed.GetOutStream();
2753
0
        if ( pStream )
2754
0
        {
2755
0
            weld::WaitObject aWait( GetActiveDialogParent() );
2756
2757
0
            SCCOL nEndCol;
2758
0
            SCROW nEndRow;
2759
0
            m_pDocument->GetCellArea( 0, nEndCol, nEndRow );
2760
0
            ScRange aRange( 0,0,0, nEndCol,nEndRow,0 );
2761
2762
0
            ScImportExport aImExport( *m_pDocument, aRange );
2763
0
            aImExport.SetFormulas( true );
2764
0
            bRet = aImExport.ExportStream( *pStream, rMed.GetBaseURL( true ), SotClipboardFormatId::SYLK );
2765
0
        }
2766
0
    }
2767
0
    else if (aFltName == pFilterHtml)
2768
0
    {
2769
0
        SvStream* pStream = rMed.GetOutStream();
2770
0
        if ( pStream )
2771
0
        {
2772
0
            OUString sFilterOptions;
2773
2774
0
            if (const SfxStringItem* pOptionsItem = rMed.GetItemSet().GetItemIfSet(SID_FILE_FILTEROPTIONS))
2775
0
                sFilterOptions = pOptionsItem->GetValue();
2776
2777
0
            weld::WaitObject aWait(GetActiveDialogParent());
2778
0
            ScImportExport aImExport(*m_pDocument);
2779
0
            aImExport.SetStreamPath(rMed.GetName());
2780
0
            aImExport.SetFilterOptions(sFilterOptions);
2781
0
            bRet = aImExport.ExportStream(*pStream, rMed.GetBaseURL(true), SotClipboardFormatId::HTML);
2782
0
            if (bRet && !aImExport.GetNonConvertibleChars().isEmpty())
2783
0
            {
2784
0
                SetError(ErrCodeMsg(
2785
0
                    SCWARN_EXPORT_NONCONVERTIBLE_CHARS,
2786
0
                    aImExport.GetNonConvertibleChars(),
2787
0
                    DialogMask::ButtonsOk | DialogMask::MessageInfo));
2788
0
            }
2789
0
        }
2790
0
    }
2791
0
    else
2792
0
    {
2793
0
        if (GetErrorIgnoreWarning())
2794
0
            SetError(SCERR_IMPORT_NI);
2795
0
    }
2796
2797
0
    return bRet;
2798
0
}
2799
2800
bool ScDocShell::DoSaveCompleted( SfxMedium * pNewStor, bool bRegisterRecent )
2801
0
{
2802
0
    bool bRet = SfxObjectShell::DoSaveCompleted( pNewStor, bRegisterRecent );
2803
2804
    //  SfxHintId::ScDocSaved for change ReadOnly -> Read/Write
2805
0
    Broadcast( SfxHint( SfxHintId::ScDocSaved ) );
2806
0
    return bRet;
2807
0
}
2808
2809
bool ScDocShell::QuerySlotExecutable( sal_uInt16 nSlotId )
2810
0
{
2811
    // #i112634# ask VBA event handlers whether to save or print the document
2812
2813
0
    using namespace ::com::sun::star::script::vba;
2814
2815
0
    sal_Int32 nVbaEventId = VBAEventId::NO_EVENT;
2816
0
    uno::Sequence< uno::Any > aArgs;
2817
0
    switch( nSlotId )
2818
0
    {
2819
0
        case SID_SAVEDOC:
2820
0
        case SID_SAVEASDOC:
2821
0
            nVbaEventId = VBAEventId::WORKBOOK_BEFORESAVE;
2822
0
            aArgs = { uno::Any(nSlotId == SID_SAVEASDOC) };
2823
0
        break;
2824
0
        case SID_PRINTDOC:
2825
0
        case SID_PRINTDOCDIRECT:
2826
0
            nVbaEventId = VBAEventId::WORKBOOK_BEFOREPRINT;
2827
0
        break;
2828
0
    }
2829
2830
0
    bool bSlotExecutable = true;
2831
0
    if( nVbaEventId != VBAEventId::NO_EVENT ) try
2832
0
    {
2833
0
        uno::Reference< XVBAEventProcessor > xEventProcessor( m_pDocument->GetVbaEventProcessor(), uno::UNO_SET_THROW );
2834
0
        xEventProcessor->processVbaEvent( nVbaEventId, aArgs );
2835
0
    }
2836
0
    catch( util::VetoException& )
2837
0
    {
2838
0
        bSlotExecutable = false;
2839
0
    }
2840
0
    catch( uno::Exception& )
2841
0
    {
2842
0
    }
2843
0
    return bSlotExecutable;
2844
0
}
2845
2846
bool ScDocShell::PrepareClose( bool bUI )
2847
0
{
2848
0
    if (ScModule::get()->GetCurRefDlgId() > 0)
2849
0
    {
2850
0
        SfxViewFrame* pFrame = SfxViewFrame::GetFirst( this );
2851
0
        if( pFrame )
2852
0
        {
2853
0
            SfxViewShell* p = pFrame->GetViewShell();
2854
0
            ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( p );
2855
0
            if(pViewSh!=nullptr)
2856
0
            {
2857
0
                vcl::Window *pWin=pViewSh->GetWindow();
2858
0
                if(pWin!=nullptr) pWin->GrabFocus();
2859
0
            }
2860
0
        }
2861
2862
0
        return false;
2863
0
    }
2864
0
    if ( m_pDocument->IsInLinkUpdate() || m_pDocument->IsInInterpreter() )
2865
0
    {
2866
0
        ErrorMessage(STR_CLOSE_ERROR_LINK);
2867
0
        return false;
2868
0
    }
2869
2870
0
    DoEnterHandler();
2871
2872
    // start 'Workbook_BeforeClose' VBA event handler for possible veto
2873
0
    if( !IsInPrepareClose() )
2874
0
    {
2875
0
        try
2876
0
        {
2877
0
            uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( m_pDocument->GetVbaEventProcessor(), uno::UNO_SET_THROW );
2878
0
            uno::Sequence< uno::Any > aArgs;
2879
0
            xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKBOOK_BEFORECLOSE, aArgs );
2880
0
        }
2881
0
        catch( util::VetoException& )
2882
0
        {
2883
            // if event processor throws VetoException, macro has vetoed close
2884
0
            return false;
2885
0
        }
2886
0
        catch( uno::Exception& )
2887
0
        {
2888
0
        }
2889
0
    }
2890
    // end handler code
2891
2892
0
    bool bRet = SfxObjectShell::PrepareClose( bUI );
2893
0
    if (bRet) // true == close
2894
0
        m_pDocument->EnableIdle(false); // Do not mess around with it anymore!
2895
2896
0
    return bRet;
2897
0
}
2898
2899
OUString ScDocShell::GetOwnFilterName()
2900
2.00k
{
2901
2.00k
    return pFilterSc50;
2902
2.00k
}
2903
2904
const OUString & ScDocShell::GetHtmlFilterName()
2905
0
{
2906
0
    return pFilterHtml;
2907
0
}
2908
2909
const OUString & ScDocShell::GetWebQueryFilterName()
2910
0
{
2911
0
    return pFilterHtmlWebQ;
2912
0
}
2913
2914
const OUString & ScDocShell::GetAsciiFilterName()
2915
0
{
2916
0
    return SC_TEXT_CSV_FILTER_NAME;
2917
0
}
2918
2919
const OUString & ScDocShell::GetLotusFilterName()
2920
0
{
2921
0
    return pFilterLotus;
2922
0
}
2923
2924
const OUString & ScDocShell::GetDBaseFilterName()
2925
0
{
2926
0
    return pFilterDBase;
2927
0
}
2928
2929
const OUString & ScDocShell::GetDifFilterName()
2930
0
{
2931
0
    return pFilterDif;
2932
0
}
2933
2934
bool ScDocShell::HasAutomaticTableName( std::u16string_view rFilter )
2935
0
{
2936
    //  sal_True for those filters that keep the default table name
2937
    //  (which is language specific)
2938
2939
0
    return rFilter == SC_TEXT_CSV_FILTER_NAME
2940
0
        || rFilter == pFilterLotus
2941
0
        || rFilter == pFilterExcel4
2942
0
        || rFilter == pFilterEx4Temp
2943
0
        || rFilter == pFilterDBase
2944
0
        || rFilter == pFilterDif
2945
0
        || rFilter == pFilterSylk
2946
0
        || rFilter == pFilterHtml
2947
0
        || rFilter == pFilterRtf;
2948
0
}
2949
2950
std::unique_ptr<ScDocFunc> ScDocShell::CreateDocFunc()
2951
77.1k
{
2952
77.1k
    return std::make_unique<ScDocFuncDirect>( *this );
2953
77.1k
}
2954
2955
ScDocShell::ScDocShell( const SfxModelFlags i_nSfxCreationFlags, const std::shared_ptr<ScDocument>& pDoc ) :
2956
77.1k
    SfxObjectShell( i_nSfxCreationFlags ),
2957
77.1k
    m_pDocument       ( pDoc ? pDoc : std::make_shared<ScDocument>( SCDOCMODE_DOCUMENT, this )),
2958
77.1k
    m_aDdeTextFmt(u"TEXT"_ustr),
2959
77.1k
    m_nPrtToScreenFactor( 1.0 ),
2960
77.1k
    m_pImpl           ( new DocShell_Impl ),
2961
77.1k
    m_bHeaderOn       ( true ),
2962
77.1k
    m_bFooterOn       ( true ),
2963
77.1k
    m_bIsEmpty        ( true ),
2964
77.1k
    m_bIsInUndo       ( false ),
2965
77.1k
    m_bDocumentModifiedPending( false ),
2966
77.1k
    m_bUpdateEnabled  ( true ),
2967
77.1k
    m_bAreasChangedNeedBroadcast( false ),
2968
77.1k
    m_nDocumentLock   ( 0 ),
2969
77.1k
    m_nCanUpdate (css::document::UpdateDocMode::ACCORDING_TO_CONFIG)
2970
77.1k
{
2971
77.1k
    SetPool(&ScModule::get()->GetPool());
2972
2973
77.1k
    m_bIsInplace = (GetCreateMode() == SfxObjectCreateMode::EMBEDDED);
2974
    //  Will be reset if not in place
2975
2976
77.1k
    m_pDocFunc = CreateDocFunc();
2977
2978
    //  SetBaseModel needs exception handling
2979
77.1k
    ScModelObj::CreateAndSet( this );
2980
2981
77.1k
    StartListening(*this);
2982
77.1k
    SfxStyleSheetPool* pStlPool = m_pDocument->GetStyleSheetPool();
2983
77.1k
    if (pStlPool)
2984
77.1k
        StartListening(*pStlPool);
2985
2986
77.1k
    m_pDocument->GetDBCollection()->SetRefreshHandler(
2987
77.1k
        LINK( this, ScDocShell, RefreshDBDataHdl ) );
2988
2989
    // InitItems and CalcOutputFactor are called now in Load/ConvertFrom/InitNew
2990
77.1k
}
2991
2992
ScDocShell::~ScDocShell()
2993
77.0k
{
2994
77.0k
    ResetDrawObjectShell(); // If the Drawing Layer still tries to access it, access it
2995
2996
77.0k
    SfxStyleSheetPool* pStlPool = m_pDocument->GetStyleSheetPool();
2997
77.0k
    if (pStlPool)
2998
77.0k
        EndListening(*pStlPool);
2999
77.0k
    EndListening(*this);
3000
3001
77.0k
    m_pAutoStyleList.reset();
3002
3003
77.0k
    SfxApplication *pSfxApp = SfxGetpApp();
3004
77.0k
    if ( pSfxApp->GetDdeService() ) // Delete DDE for Document
3005
0
        pSfxApp->RemoveDdeTopic( this );
3006
3007
77.0k
    m_pDocFunc.reset();
3008
77.0k
    delete m_pDocument->mpUndoManager;
3009
77.0k
    m_pDocument->mpUndoManager = nullptr;
3010
77.0k
    m_pImpl.reset();
3011
3012
77.0k
    m_pPaintLockData.reset();
3013
3014
77.0k
    m_pSheetSaveData.reset();
3015
77.0k
    m_pFormatSaveData.reset();
3016
77.0k
    m_pOldAutoDBRange.reset();
3017
3018
77.0k
    if (m_pModificator)
3019
30.7k
    {
3020
30.7k
        OSL_FAIL("The Modificator should not exist");
3021
30.7k
        m_pModificator.reset();
3022
30.7k
    }
3023
77.0k
}
3024
3025
SfxUndoManager* ScDocShell::GetUndoManager()
3026
70
{
3027
70
    return m_pDocument->GetUndoManager();
3028
70
}
3029
3030
void ScDocShell::SetModified( bool bModified )
3031
108k
{
3032
108k
    if ( SfxObjectShell::IsEnableSetModified() )
3033
108k
    {
3034
108k
        SfxObjectShell::SetModified( bModified );
3035
108k
        Broadcast( SfxHint( SfxHintId::DocChanged ) );
3036
108k
    }
3037
108k
}
3038
3039
void ScDocShell::SetDocumentModified()
3040
285k
{
3041
    //  BroadcastUno must also happen right away with pPaintLockData
3042
    //  FIXME: Also for SetDrawModified, if Drawing is connected
3043
    //  FIXME: Then own Hint?
3044
3045
285k
    if ( m_pPaintLockData )
3046
268k
    {
3047
        // #i115009# broadcast BCA_BRDCST_ALWAYS, so a component can read recalculated results
3048
        // of RecalcModeAlways formulas (like OFFSET) after modifying cells
3049
268k
        m_pDocument->Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS));
3050
268k
        m_pDocument->InvalidateTableArea();    // #i105279# needed here
3051
268k
        m_pDocument->BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
3052
3053
268k
        m_pPaintLockData->SetModified(); // Later on ...
3054
268k
        return;
3055
268k
    }
3056
3057
17.7k
    SetDrawModified();
3058
3059
17.7k
    if ( m_pDocument->IsAutoCalcShellDisabled() )
3060
0
        SetDocumentModifiedPending( true );
3061
17.7k
    else
3062
17.7k
    {
3063
17.7k
        SetDocumentModifiedPending( false );
3064
17.7k
        m_pDocument->InvalidateStyleSheetUsage();
3065
17.7k
        m_pDocument->InvalidateTableArea();
3066
17.7k
        m_pDocument->InvalidateLastTableOpParams();
3067
17.7k
        m_pDocument->Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS));
3068
17.7k
        if ( m_pDocument->IsForcedFormulaPending() && m_pDocument->GetAutoCalc() )
3069
0
            m_pDocument->CalcFormulaTree( true );
3070
17.7k
        m_pDocument->RefreshDirtyTableColumnNames();
3071
17.7k
        PostDataChanged();
3072
3073
        //  Detective AutoUpdate:
3074
        //  Update if formulas were modified (DetectiveDirty) or the list contains
3075
        //  "Trace Error" entries (Trace Error can look completely different
3076
        //  after changes to non-formula cells).
3077
3078
17.7k
        ScDetOpList* pList = m_pDocument->GetDetOpList();
3079
17.7k
        if ( pList && ( m_pDocument->IsDetectiveDirty() || pList->HasAddError() ) &&
3080
17.7k
             pList->Count() && !IsInUndo() && ScModule::get()->GetAppOptions().GetDetectiveAuto() )
3081
0
        {
3082
0
            GetDocFunc().DetectiveRefresh(true);    // sal_True = caused by automatic update
3083
0
        }
3084
17.7k
        m_pDocument->SetDetectiveDirty(false);         // always reset, also if not refreshed
3085
17.7k
    }
3086
3087
17.7k
    if (m_bAreasChangedNeedBroadcast)
3088
0
    {
3089
0
        m_bAreasChangedNeedBroadcast = false;
3090
0
        SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged));
3091
0
    }
3092
3093
    // notify UNO objects after BCA_BRDCST_ALWAYS etc.
3094
17.7k
    m_pDocument->BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
3095
17.7k
}
3096
3097
/**
3098
 * SetDrawModified - without Formula update
3099
 *
3100
 * Drawing also needs to be updated for the normal SetDocumentModified
3101
 * e.g.: when deleting tables etc.
3102
 */
3103
void ScDocShell::SetDrawModified()
3104
17.7k
{
3105
17.7k
    bool bUpdate = !IsModified();
3106
3107
17.7k
    SetModified();
3108
3109
17.7k
    SfxBindings* pBindings = GetViewBindings();
3110
17.7k
    if (bUpdate && pBindings)
3111
0
    {
3112
0
        pBindings->Invalidate( SID_SAVEDOC );
3113
0
        pBindings->Invalidate( SID_DOC_MODIFIED );
3114
0
    }
3115
3116
17.7k
    if (pBindings)
3117
0
    {
3118
        // #i105960# Undo etc used to be volatile.
3119
        // They always have to be invalidated, including drawing layer or row height changes
3120
        // (but not while pPaintLockData is set).
3121
0
        pBindings->Invalidate( SID_UNDO );
3122
0
        pBindings->Invalidate( SID_REDO );
3123
0
        pBindings->Invalidate( SID_REPEAT );
3124
0
    }
3125
3126
17.7k
    if ( m_pDocument->IsChartListenerCollectionNeedsUpdate() )
3127
5.27k
    {
3128
5.27k
        m_pDocument->UpdateChartListenerCollection();
3129
5.27k
        SfxGetpApp()->Broadcast(SfxHint( SfxHintId::ScDrawChanged ));    // Navigator
3130
5.27k
    }
3131
17.7k
    ScModule::get()->AnythingChanged();
3132
17.7k
}
3133
3134
void ScDocShell::SetInUndo(bool bSet)
3135
0
{
3136
0
    m_bIsInUndo = bSet;
3137
0
}
3138
3139
void ScDocShell::GetDocStat( ScDocStat& rDocStat )
3140
0
{
3141
0
    SfxPrinter* pPrinter = GetPrinter();
3142
3143
0
    m_pDocument->GetDocStat( rDocStat );
3144
0
    rDocStat.nPageCount = 0;
3145
3146
0
    if ( pPrinter )
3147
0
        for ( SCTAB i=0; i<rDocStat.nTableCount; i++ )
3148
0
            rDocStat.nPageCount = sal::static_int_cast<sal_uInt16>( rDocStat.nPageCount +
3149
0
                static_cast<sal_uInt16>(ScPrintFunc( *this, pPrinter, i ).GetTotalPages()) );
3150
0
}
3151
3152
std::shared_ptr<SfxDocumentInfoDialog> ScDocShell::CreateDocumentInfoDialog(weld::Window* pParent, const SfxItemSet &rSet)
3153
0
{
3154
0
    std::shared_ptr<SfxDocumentInfoDialog> xDlg = std::make_shared<SfxDocumentInfoDialog>(pParent, rSet);
3155
0
    ScDocShell*            pDocSh = dynamic_cast< ScDocShell *>( SfxObjectShell::Current() );
3156
3157
    // Only for statistics, if this Doc is shown; not from the Doc Manager
3158
0
    if( pDocSh == this )
3159
0
    {
3160
0
        ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
3161
0
        ::CreateTabPage ScDocStatPageCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_STAT);
3162
0
        OSL_ENSURE(ScDocStatPageCreate, "Tabpage create fail!");
3163
0
        xDlg->AddFontTabPage();
3164
0
        xDlg->AddTabPage(u"calcstats"_ustr, ScResId(STR_DOC_STAT), ScDocStatPageCreate);
3165
0
    }
3166
0
    return xDlg;
3167
0
}
3168
3169
weld::Window* ScDocShell::GetActiveDialogParent()
3170
15.2k
{
3171
15.2k
    ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
3172
15.2k
    if ( pViewSh )
3173
0
        return pViewSh->GetDialogParent();
3174
15.2k
    return Application::GetDefDialogParent();
3175
15.2k
}
3176
3177
ScSheetSaveData* ScDocShell::GetSheetSaveData()
3178
177k
{
3179
177k
    if (!m_pSheetSaveData)
3180
44.6k
        m_pSheetSaveData.reset( new ScSheetSaveData );
3181
3182
177k
    return m_pSheetSaveData.get();
3183
177k
}
3184
3185
ScFormatSaveData* ScDocShell::GetFormatSaveData()
3186
1.00k
{
3187
1.00k
    if (!m_pFormatSaveData)
3188
612
        m_pFormatSaveData.reset( new ScFormatSaveData );
3189
3190
1.00k
    return m_pFormatSaveData.get();
3191
1.00k
}
3192
3193
namespace {
3194
3195
void removeKeysIfExists(const Reference<ui::XAcceleratorConfiguration>& xScAccel, const vector<const awt::KeyEvent*>& rKeys)
3196
0
{
3197
0
    for (const awt::KeyEvent* p : rKeys)
3198
0
    {
3199
0
        if (!p)
3200
0
            continue;
3201
3202
0
        try
3203
0
        {
3204
0
            xScAccel->removeKeyEvent(*p);
3205
0
        }
3206
0
        catch (const container::NoSuchElementException&) {}
3207
0
    }
3208
0
}
3209
3210
}
3211
3212
void ScDocShell::ResetKeyBindings( ScOptionsUtil::KeyBindingType eType )
3213
0
{
3214
0
    using namespace ::com::sun::star::ui;
3215
3216
0
    const Reference<uno::XComponentContext>& xContext = ::comphelper::getProcessComponentContext();
3217
0
    if (!xContext.is())
3218
0
        return;
3219
3220
0
    Reference<XModuleUIConfigurationManagerSupplier> xModuleCfgSupplier(
3221
0
        theModuleUIConfigurationManagerSupplier::get(xContext) );
3222
3223
    // Grab the Calc configuration.
3224
0
    Reference<XUIConfigurationManager> xConfigMgr =
3225
0
        xModuleCfgSupplier->getUIConfigurationManager(
3226
0
            u"com.sun.star.sheet.SpreadsheetDocument"_ustr);
3227
3228
0
    if (!xConfigMgr.is())
3229
0
        return;
3230
3231
    // shortcut manager
3232
0
    Reference<XAcceleratorConfiguration> xScAccel = xConfigMgr->getShortCutManager();
3233
3234
0
    if (!xScAccel.is())
3235
0
        return;
3236
3237
0
    vector<const awt::KeyEvent*> aKeys;
3238
0
    aKeys.reserve(9);
3239
3240
    // Backspace key
3241
0
    awt::KeyEvent aBackspace;
3242
0
    aBackspace.KeyCode = awt::Key::BACKSPACE;
3243
0
    aBackspace.Modifiers = 0;
3244
0
    aKeys.push_back(&aBackspace);
3245
3246
    // Delete key
3247
0
    awt::KeyEvent aDelete;
3248
0
    aDelete.KeyCode = awt::Key::DELETE;
3249
0
    aDelete.Modifiers = 0;
3250
0
    aKeys.push_back(&aDelete);
3251
3252
    // Ctrl-D
3253
0
    awt::KeyEvent aCtrlD;
3254
0
    aCtrlD.KeyCode = awt::Key::D;
3255
0
    aCtrlD.Modifiers = awt::KeyModifier::MOD1;
3256
0
    aKeys.push_back(&aCtrlD);
3257
3258
    // Alt-Down
3259
0
    awt::KeyEvent aAltDown;
3260
0
    aAltDown.KeyCode = awt::Key::DOWN;
3261
0
    aAltDown.Modifiers = awt::KeyModifier::MOD2;
3262
0
    aKeys.push_back(&aAltDown);
3263
3264
    // Ctrl-Space
3265
0
    awt::KeyEvent aCtrlSpace;
3266
0
    aCtrlSpace.KeyCode = awt::Key::SPACE;
3267
0
    aCtrlSpace.Modifiers = awt::KeyModifier::MOD1;
3268
0
    aKeys.push_back(&aCtrlSpace);
3269
3270
    // Ctrl-Shift-Space
3271
0
    awt::KeyEvent aCtrlShiftSpace;
3272
0
    aCtrlShiftSpace.KeyCode = awt::Key::SPACE;
3273
0
    aCtrlShiftSpace.Modifiers = awt::KeyModifier::MOD1 | awt::KeyModifier::SHIFT;
3274
0
    aKeys.push_back(&aCtrlShiftSpace);
3275
3276
    // F4
3277
0
    awt::KeyEvent aF4;
3278
0
    aF4.KeyCode = awt::Key::F4;
3279
0
    aF4.Modifiers = 0;
3280
0
    aKeys.push_back(&aF4);
3281
3282
    // CTRL+SHIFT+F4
3283
0
    awt::KeyEvent aCtrlShiftF4;
3284
0
    aCtrlShiftF4.KeyCode = awt::Key::F4;
3285
0
    aCtrlShiftF4.Modifiers = awt::KeyModifier::MOD1 | awt::KeyModifier::SHIFT;
3286
0
    aKeys.push_back(&aCtrlShiftF4);
3287
3288
    // SHIFT+F4
3289
0
    awt::KeyEvent aShiftF4;
3290
0
    aShiftF4.KeyCode = awt::Key::F4;
3291
0
    aShiftF4.Modifiers = awt::KeyModifier::SHIFT;
3292
0
    aKeys.push_back(&aShiftF4);
3293
3294
    // Remove all involved keys first, because swapping commands don't work
3295
    // well without doing this.
3296
0
    removeKeysIfExists(xScAccel, aKeys);
3297
0
    xScAccel->store();
3298
3299
0
    switch (eType)
3300
0
    {
3301
0
        case ScOptionsUtil::KEY_DEFAULT:
3302
0
            xScAccel->setKeyEvent(aDelete, u".uno:ClearContents"_ustr);
3303
0
            xScAccel->setKeyEvent(aBackspace, u".uno:Delete"_ustr);
3304
0
            xScAccel->setKeyEvent(aCtrlD, u".uno:FillDown"_ustr);
3305
0
            xScAccel->setKeyEvent(aAltDown, u".uno:DataSelect"_ustr);
3306
0
            xScAccel->setKeyEvent(aCtrlSpace, u".uno:SelectColumn"_ustr);
3307
0
            xScAccel->setKeyEvent(aCtrlShiftSpace, u".uno:SelectAll"_ustr);
3308
0
            xScAccel->setKeyEvent(aF4, u".uno:ToggleRelative"_ustr);
3309
0
            xScAccel->setKeyEvent(aCtrlShiftF4, u".uno:ViewDataSourceBrowser"_ustr);
3310
0
        break;
3311
0
        case ScOptionsUtil::KEY_OOO_LEGACY:
3312
0
            xScAccel->setKeyEvent(aDelete, u".uno:Delete"_ustr);
3313
0
            xScAccel->setKeyEvent(aBackspace, u".uno:ClearContents"_ustr);
3314
0
            xScAccel->setKeyEvent(aCtrlD, u".uno:DataSelect"_ustr);
3315
0
            xScAccel->setKeyEvent(aCtrlShiftSpace, u".uno:SelectColumn"_ustr);
3316
0
            xScAccel->setKeyEvent(aF4, u".uno:ViewDataSourceBrowser"_ustr);
3317
0
            xScAccel->setKeyEvent(aShiftF4, u".uno:ToggleRelative"_ustr);
3318
0
        break;
3319
0
        default:
3320
0
            ;
3321
0
    }
3322
3323
0
    xScAccel->store();
3324
0
}
3325
3326
void ScDocShell::UseSheetSaveEntries()
3327
0
{
3328
0
    if (!m_pSheetSaveData)
3329
0
        return;
3330
3331
0
    m_pSheetSaveData->UseSaveEntries();   // use positions from saved file for next saving
3332
3333
0
    bool bHasEntries = false;
3334
0
    SCTAB nTabCount = m_pDocument->GetTableCount();
3335
0
    SCTAB nTab;
3336
0
    for (nTab = 0; nTab < nTabCount; ++nTab)
3337
0
        if (m_pSheetSaveData->HasStreamPos(nTab))
3338
0
            bHasEntries = true;
3339
3340
0
    if (!bHasEntries)
3341
0
    {
3342
        // if no positions were set (for example, export to other format),
3343
        // reset all "valid" flags
3344
0
        for (nTab = 0; nTab < nTabCount; ++nTab)
3345
0
            m_pDocument->SetStreamValid(nTab, false);
3346
0
    }
3347
0
}
3348
3349
// --- ScDocShellModificator ------------------------------------------
3350
3351
ScDocShellModificator::ScDocShellModificator( ScDocShell& rDS )
3352
        :
3353
738k
        rDocShell( rDS ),
3354
738k
        mpProtector(new ScRefreshTimerProtector(rDS.GetDocument().GetRefreshTimerControlAddress()))
3355
738k
{
3356
738k
    ScDocument& rDoc = rDocShell.GetDocument();
3357
738k
    bAutoCalcShellDisabled = rDoc.IsAutoCalcShellDisabled();
3358
738k
    bIdleEnabled = rDoc.IsIdleEnabled();
3359
738k
    rDoc.SetAutoCalcShellDisabled( true );
3360
738k
    rDoc.EnableIdle(false);
3361
738k
}
3362
3363
void ScDocShellModificator::ImplDestroy()
3364
738k
{
3365
738k
    ScDocument& rDoc = rDocShell.GetDocument();
3366
738k
    rDoc.SetAutoCalcShellDisabled( bAutoCalcShellDisabled );
3367
738k
    if ( !bAutoCalcShellDisabled && rDocShell.IsDocumentModifiedPending() )
3368
0
        rDocShell.SetDocumentModified();    // last one shuts off the lights
3369
738k
    rDoc.EnableIdle(bIdleEnabled);
3370
738k
}
3371
3372
ScDocShellModificator::~ScDocShellModificator()
3373
738k
{
3374
738k
    suppress_fun_call_w_exception(ImplDestroy());
3375
738k
}
3376
3377
void ScDocShellModificator::SetDocumentModified()
3378
563k
{
3379
563k
    ScDocument& rDoc = rDocShell.GetDocument();
3380
563k
    rDoc.PrepareFormulaCalc();
3381
563k
    if ( !rDoc.IsImportingXML() )
3382
227k
    {
3383
        // temporarily restore AutoCalcShellDisabled
3384
227k
        bool bDisabled = rDoc.IsAutoCalcShellDisabled();
3385
227k
        rDoc.SetAutoCalcShellDisabled( bAutoCalcShellDisabled );
3386
227k
        rDocShell.SetDocumentModified();
3387
227k
        rDoc.SetAutoCalcShellDisabled( bDisabled );
3388
227k
    }
3389
336k
    else
3390
336k
    {
3391
        // uno broadcast is necessary for api to work
3392
        // -> must also be done during xml import
3393
336k
        rDoc.BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
3394
336k
    }
3395
563k
}
3396
3397
bool ScDocShell::IsChangeRecording(SfxViewShell* /*pViewShell*/, bool /*bRecordAllViews*/) const
3398
0
{
3399
0
    ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
3400
0
    return pChangeTrack != nullptr;
3401
0
}
3402
3403
bool ScDocShell::HasChangeRecordProtection() const
3404
0
{
3405
0
    bool bRes = false;
3406
0
    ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
3407
0
    if (pChangeTrack)
3408
0
        bRes = pChangeTrack->IsProtected();
3409
0
    return bRes;
3410
0
}
3411
3412
void ScDocShell::SetChangeRecording( bool bActivate, bool /*bLockAllViews*/, SfxRedlineRecordingMode /*eRedlineRecordingMode*/)
3413
0
{
3414
0
    bool bOldChangeRecording = IsChangeRecording();
3415
3416
0
    if (bActivate)
3417
0
    {
3418
0
        m_pDocument->StartChangeTracking();
3419
0
        ScChangeViewSettings aChangeViewSet;
3420
0
        aChangeViewSet.SetShowChanges(true);
3421
0
        m_pDocument->SetChangeViewSettings(aChangeViewSet);
3422
0
    }
3423
0
    else
3424
0
    {
3425
0
        m_pDocument->EndChangeTracking();
3426
0
        PostPaintGridAll();
3427
0
    }
3428
3429
0
    if (bOldChangeRecording != IsChangeRecording())
3430
0
    {
3431
0
        UpdateAcceptChangesDialog();
3432
        // invalidate slots
3433
0
        SfxBindings* pBindings = GetViewBindings();
3434
0
        if (pBindings)
3435
0
            pBindings->InvalidateAll(false);
3436
0
    }
3437
0
}
3438
3439
void ScDocShell::SetProtectionPassword( const OUString &rNewPassword )
3440
0
{
3441
0
    ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
3442
0
    if (!pChangeTrack)
3443
0
        return;
3444
3445
0
    bool bProtected = pChangeTrack->IsProtected();
3446
3447
0
    if (!rNewPassword.isEmpty())
3448
0
    {
3449
        // when password protection is applied change tracking must always be active
3450
0
        SetChangeRecording( true );
3451
3452
0
        css::uno::Sequence< sal_Int8 > aProtectionHash;
3453
0
        SvPasswordHelper::GetHashPassword( aProtectionHash, rNewPassword );
3454
0
        pChangeTrack->SetProtection( aProtectionHash );
3455
0
    }
3456
0
    else
3457
0
    {
3458
0
        pChangeTrack->SetProtection( css::uno::Sequence< sal_Int8 >() );
3459
0
    }
3460
3461
0
    if ( bProtected != pChangeTrack->IsProtected() )
3462
0
    {
3463
0
        UpdateAcceptChangesDialog();
3464
0
        SetDocumentModified();
3465
0
    }
3466
0
}
3467
3468
bool ScDocShell::GetProtectionHash( /*out*/ css::uno::Sequence< sal_Int8 > &rPasswordHash )
3469
0
{
3470
0
    bool bRes = false;
3471
0
    ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
3472
0
    if (pChangeTrack && pChangeTrack->IsProtected())
3473
0
    {
3474
0
        rPasswordHash = pChangeTrack->GetProtection();
3475
0
        bRes = true;
3476
0
    }
3477
0
    return bRes;
3478
0
}
3479
3480
void ScDocShell::RegisterAutomationWorkbookObject(css::uno::Reference< ooo::vba::excel::XWorkbook > const& xWorkbook)
3481
0
{
3482
0
    mxAutomationWorkbookObject = xWorkbook;
3483
0
}
3484
3485
extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportSLK(SvStream &rStream)
3486
24.9k
{
3487
24.9k
    ScDLL::Init();
3488
24.9k
    ScDocument aDocument;
3489
24.9k
    ScDocOptions aDocOpt = aDocument.GetDocOptions();
3490
24.9k
    aDocOpt.SetLookUpColRowNames(false);
3491
24.9k
    aDocument.SetDocOptions(aDocOpt);
3492
24.9k
    aDocument.MakeTable(0);
3493
24.9k
    aDocument.EnableExecuteLink(false);
3494
24.9k
    aDocument.SetInsertingFromOtherDoc(true);
3495
24.9k
    aDocument.SetImportingXML(true);
3496
3497
24.9k
    ScImportExport aImpEx(aDocument);
3498
24.9k
    return aImpEx.ImportStream(rStream, OUString(), SotClipboardFormatId::SYLK);
3499
24.9k
}
3500
3501
extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportCalcHTML(SvStream &rStream)
3502
25.0k
{
3503
25.0k
    ScDLL::Init();
3504
25.0k
    ScDocument aDocument;
3505
25.0k
    ScDocOptions aDocOpt = aDocument.GetDocOptions();
3506
25.0k
    aDocOpt.SetLookUpColRowNames(false);
3507
25.0k
    aDocument.SetDocOptions(aDocOpt);
3508
25.0k
    aDocument.MakeTable(0);
3509
25.0k
    aDocument.EnableExecuteLink(false);
3510
25.0k
    aDocument.SetInsertingFromOtherDoc(true);
3511
25.0k
    aDocument.SetImportingXML(true);
3512
3513
25.0k
    ScImportExport aImpEx(aDocument);
3514
25.0k
    return aImpEx.ImportStream(rStream, OUString(), SotClipboardFormatId::HTML);
3515
25.0k
}
3516
3517
extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportDBF(SvStream &rStream)
3518
9.91k
{
3519
9.91k
    ScDLL::Init();
3520
3521
    // we need a real file for this filter
3522
3523
    // put it in an empty dir
3524
9.91k
    utl::TempFileNamed aTmpDir(nullptr, true);
3525
9.91k
    aTmpDir.EnableKillingFile();
3526
9.91k
    OUString sTmpDir = aTmpDir.GetURL();
3527
3528
9.91k
    utl::TempFileNamed aTempInput(u"", true, u".dbf", &sTmpDir);
3529
9.91k
    aTempInput.EnableKillingFile();
3530
3531
9.91k
    SvStream* pInputStream = aTempInput.GetStream(StreamMode::WRITE);
3532
9.91k
    sal_uInt8 aBuffer[8192];
3533
21.4k
    while (auto nRead = rStream.ReadBytes(aBuffer, SAL_N_ELEMENTS(aBuffer)))
3534
11.4k
        pInputStream->WriteBytes(aBuffer, nRead);
3535
9.91k
    aTempInput.CloseStream();
3536
3537
9.91k
    SfxMedium aMedium(aTempInput.GetURL(), StreamMode::STD_READWRITE);
3538
3539
9.91k
    ScDocShellRef xDocShell = new ScDocShell(SfxModelFlags::EMBEDDED_OBJECT |
3540
9.91k
                                             SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS |
3541
9.91k
                                             SfxModelFlags::DISABLE_DOCUMENT_RECOVERY);
3542
3543
9.91k
    xDocShell->DoInitNew();
3544
3545
9.91k
    ScDocument& rDoc = xDocShell->GetDocument();
3546
3547
9.91k
    ScDocOptions aDocOpt = rDoc.GetDocOptions();
3548
9.91k
    aDocOpt.SetLookUpColRowNames(false);
3549
9.91k
    rDoc.SetDocOptions(aDocOpt);
3550
9.91k
    rDoc.MakeTable(0);
3551
9.91k
    rDoc.EnableExecuteLink(false);
3552
9.91k
    rDoc.SetInsertingFromOtherDoc(true);
3553
3554
9.91k
    ScDocRowHeightUpdater::TabRanges aRecalcRanges(0, rDoc.MaxRow());
3555
9.91k
    std::map<SCCOL, ScColWidthParam> aColWidthParam;
3556
9.91k
    ErrCode eError = xDocShell->DBaseImport(aMedium.GetPhysicalName(), RTL_TEXTENCODING_IBM_850, aColWidthParam, aRecalcRanges.maRanges);
3557
3558
9.91k
    xDocShell->DoClose();
3559
9.91k
    xDocShell.clear();
3560
3561
9.91k
    return eError == ERRCODE_NONE;
3562
9.91k
}
3563
3564
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */