1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
22 #include <config_features.h>
23 #include <scitems.hxx>
25 #include <vcl/errinf.hxx>
26 #include <editeng/justifyitem.hxx>
27 #include <comphelper/fileformat.h>
28 #include <comphelper/classids.hxx>
29 #include <formula/errorcodes.hxx>
30 #include <vcl/stdtext.hxx>
31 #include <vcl/svapp.hxx>
32 #include <vcl/virdev.hxx>
33 #include <vcl/weld.hxx>
34 #include <rtl/bootstrap.hxx>
35 #include <rtl/tencinfo.h>
36 #include <sal/log.hxx>
37 #include <svl/PasswordHelper.hxx>
38 #include <sfx2/app.hxx>
39 #include <sfx2/bindings.hxx>
40 #include <sfx2/dinfdlg.hxx>
41 #include <sfx2/docfile.hxx>
42 #include <sfx2/event.hxx>
43 #include <sfx2/docfilt.hxx>
44 #include <sfx2/objface.hxx>
45 #include <sfx2/viewfrm.hxx>
46 #include <svl/documentlockfile.hxx>
47 #include <svl/fstathelper.hxx>
48 #include <svl/sharecontrolfile.hxx>
49 #include <svl/urihelper.hxx>
50 #include <osl/file.hxx>
51 #include <chgtrack.hxx>
52 #include <chgviset.hxx>
53 #include <com/sun/star/awt/Key.hpp>
54 #include <com/sun/star/awt/KeyModifier.hpp>
55 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
56 #include <com/sun/star/document/UpdateDocMode.hpp>
57 #include <com/sun/star/script/vba/VBAEventId.hpp>
58 #include <com/sun/star/script/vba/VBAScriptEventId.hpp>
59 #include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
60 #include <com/sun/star/script/vba/XVBAScriptListener.hpp>
61 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
62 #include <com/sun/star/sheet/XSpreadsheetView.hpp>
63 #include <com/sun/star/task/XJob.hpp>
64 #include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
65 #include <com/sun/star/ui/XAcceleratorConfiguration.hpp>
66 #include <com/sun/star/util/VetoException.hpp>
67 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
68 #include <ooo/vba/excel/XWorkbook.hpp>
69 #include <tools/diagnose_ex.h>
71 #include <config_folders.h>
73 #include <scabstdlg.hxx>
74 #include <sot/formats.hxx>
75 #include <svx/dialogs.hrc>
77 #include <formulacell.hxx>
81 #include <tabvwsh.hxx>
82 #include <docfunc.hxx>
83 #include <imoptdlg.hxx>
85 #include <scresid.hxx>
86 #include <strings.hrc>
87 #include <globstr.hrc>
88 #include <scerrors.hxx>
90 #include <stlpool.hxx>
91 #include <autostyl.hxx>
93 #include <asciiopt.hxx>
94 #include <progress.hxx>
95 #include <pntlock.hxx>
97 #include <appoptio.hxx>
98 #include <formulaopt.hxx>
100 #include <detdata.hxx>
101 #include <printfun.hxx>
102 #include <dociter.hxx>
103 #include <cellform.hxx>
104 #include <chartlis.hxx>
106 #include <xmlwrap.hxx>
107 #include <drwlayer.hxx>
108 #include <dbdata.hxx>
109 #include <scextopt.hxx>
110 #include <compiler.hxx>
111 #include <warnpassword.hxx>
112 #include <optsolver.hxx>
113 #include <sheetdata.hxx>
114 #include <tabprotection.hxx>
115 #include <docparam.hxx>
116 #include "docshimp.hxx"
117 #include <sizedev.hxx>
118 #include <refreshtimerprotector.hxx>
120 #include <officecfg/Office/Calc.hxx>
121 #include <comphelper/processfactory.hxx>
122 #include <comphelper/string.hxx>
123 #include <unotools/configmgr.hxx>
124 #include <unotools/ucbstreamhelper.hxx>
125 #include <uiitems.hxx>
126 #include <dpobject.hxx>
127 #include <markdata.hxx>
128 #include <docoptio.hxx>
129 #include <orcusfilters.hxx>
130 #include <datastream.hxx>
131 #include <documentlinkmgr.hxx>
132 #include <refupdatecontext.hxx>
137 using namespace com::sun::star
;
138 using ::com::sun::star::uno::Reference
;
139 using ::com::sun::star::lang::XMultiServiceFactory
;
140 using std::shared_ptr
;
143 // Filter names (like in sclib.cxx)
145 constexpr OUStringLiteral pFilterSc50
= u
"StarCalc 5.0";
146 const char pFilterXML
[] = "StarOffice XML (Calc)";
147 constexpr OUStringLiteral pFilterAscii
= u
"" SC_TEXT_CSV_FILTER_NAME
;
148 constexpr OUStringLiteral pFilterLotus
= u
"Lotus";
149 const char pFilterQPro6
[] = "Quattro Pro 6.0";
150 const char16_t pFilterExcel4
[] = u
"MS Excel 4.0";
151 const char16_t pFilterEx4Temp
[] = u
"MS Excel 4.0 Vorlage/Template";
152 const char pFilterExcel5
[] = "MS Excel 5.0/95";
153 const char pFilterEx5Temp
[] = "MS Excel 5.0/95 Vorlage/Template";
154 const char pFilterExcel95
[] = "MS Excel 95";
155 const char pFilterEx95Temp
[] = "MS Excel 95 Vorlage/Template";
156 const char pFilterExcel97
[] = "MS Excel 97";
157 const char pFilterEx97Temp
[] = "MS Excel 97 Vorlage/Template";
158 constexpr OUStringLiteral pFilterDBase
= u
"dBase";
159 constexpr OUStringLiteral pFilterDif
= u
"DIF";
160 const char16_t pFilterSylk
[] = u
"SYLK";
161 constexpr OUStringLiteral pFilterHtml
= u
"HTML (StarCalc)";
162 constexpr OUStringLiteral pFilterHtmlWebQ
= u
"calc_HTML_WebQuery";
163 const char16_t pFilterRtf
[] = u
"Rich Text Format (StarCalc)";
165 #define ShellClass_ScDocShell
166 #include <scslots.hxx>
168 SFX_IMPL_INTERFACE(ScDocShell
,SfxObjectShell
)
170 void ScDocShell::InitInterface_Impl()
174 // GlobalName of the current version:
175 SFX_IMPL_OBJECTFACTORY( ScDocShell
, SvGlobalName(SO3_SC_CLASSID
), "scalc" )
178 void ScDocShell::FillClass( SvGlobalName
* pClassName
,
179 SotClipboardFormatId
* pFormat
,
180 OUString
* pFullTypeName
,
181 sal_Int32 nFileFormat
,
182 bool bTemplate
/* = false */) const
184 if ( nFileFormat
== SOFFICE_FILEFORMAT_60
)
186 *pClassName
= SvGlobalName( SO3_SC_CLASSID_60
);
187 *pFormat
= SotClipboardFormatId::STARCALC_60
;
188 *pFullTypeName
= ScResId( SCSTR_LONG_SCDOC_NAME_60
);
190 else if ( nFileFormat
== SOFFICE_FILEFORMAT_8
)
192 *pClassName
= SvGlobalName( SO3_SC_CLASSID_60
);
193 *pFormat
= bTemplate
? SotClipboardFormatId::STARCALC_8_TEMPLATE
: SotClipboardFormatId::STARCALC_8
;
194 *pFullTypeName
= ScResId( SCSTR_LONG_SCDOC_NAME_80
);
198 OSL_FAIL("Which version?");
202 std::set
<Color
> ScDocShell::GetDocColors()
204 return m_aDocument
.GetDocColors();
207 void ScDocShell::DoEnterHandler()
209 ScTabViewShell
* pViewSh
= ScTabViewShell::GetActiveViewShell();
210 if (pViewSh
&& pViewSh
->GetViewData().GetDocShell() == this)
211 SC_MOD()->InputEnterHandler();
214 SCTAB
ScDocShell::GetSaveTab()
217 ScTabViewShell
* pSh
= GetBestViewShell();
220 const ScMarkData
& rMark
= pSh
->GetViewData().GetMarkData();
221 nTab
= rMark
.GetFirstSelected();
226 HiddenInformation
ScDocShell::GetHiddenInformationState( HiddenInformation nStates
)
228 // get global state like HiddenInformation::DOCUMENTVERSIONS
229 HiddenInformation nState
= SfxObjectShell::GetHiddenInformationState( nStates
);
231 if ( nStates
& HiddenInformation::RECORDEDCHANGES
)
233 if ( m_aDocument
.GetChangeTrack() && m_aDocument
.GetChangeTrack()->GetFirst() )
234 nState
|= HiddenInformation::RECORDEDCHANGES
;
236 if ( nStates
& HiddenInformation::NOTES
)
238 SCTAB nTableCount
= m_aDocument
.GetTableCount();
240 for (SCTAB nTab
= 0; nTab
< nTableCount
&& !bFound
; ++nTab
)
242 if (m_aDocument
.HasTabNotes(nTab
)) //TODO:
247 nState
|= HiddenInformation::NOTES
;
253 void ScDocShell::BeforeXMLLoading()
255 m_aDocument
.EnableIdle(false);
257 // prevent unnecessary broadcasts and updates
258 OSL_ENSURE(m_pModificator
== nullptr, "The Modificator should not exist");
259 m_pModificator
.reset( new ScDocShellModificator( *this ) );
261 m_aDocument
.SetImportingXML( true );
262 m_aDocument
.EnableExecuteLink( false ); // #i101304# to be safe, prevent nested loading from external references
263 m_aDocument
.EnableUndo( false );
264 // prevent unnecessary broadcasts and "half way listeners"
265 m_aDocument
.SetInsertingFromOtherDoc( true );
268 void ScDocShell::AfterXMLLoading(bool bRet
)
270 if (GetCreateMode() != SfxObjectCreateMode::ORGANIZER
)
273 // don't prevent establishing of listeners anymore
274 m_aDocument
.SetInsertingFromOtherDoc( false );
277 ScChartListenerCollection
* pChartListener
= m_aDocument
.GetChartListenerCollection();
279 pChartListener
->UpdateDirtyCharts();
281 // #95582#; set the table names of linked tables to the new path
282 SCTAB nTabCount
= m_aDocument
.GetTableCount();
283 for (SCTAB i
= 0; i
< nTabCount
; ++i
)
285 if (m_aDocument
.IsLinked( i
))
288 m_aDocument
.GetName(i
, aName
);
289 OUString aLinkTabName
= m_aDocument
.GetLinkTab(i
);
290 sal_Int32 nLinkTabNameLength
= aLinkTabName
.getLength();
291 sal_Int32 nNameLength
= aName
.getLength();
292 if (nLinkTabNameLength
< nNameLength
)
295 // remove the quotes on begin and end of the docname and restore the escaped quotes
296 const sal_Unicode
* pNameBuffer
= aName
.getStr();
297 if ( *pNameBuffer
== '\'' && // all docnames have to have a ' character on the first pos
298 ScGlobal::UnicodeStrChr( pNameBuffer
, SC_COMPILER_FILE_TAB_SEP
) )
300 OUStringBuffer aDocURLBuffer
;
301 bool bQuote
= true; // Document name is always quoted
303 while ( bQuote
&& *pNameBuffer
)
305 if ( *pNameBuffer
== '\'' && *(pNameBuffer
-1) != '\\' )
307 else if( *pNameBuffer
!= '\\' || *(pNameBuffer
+1) != '\'' )
308 aDocURLBuffer
.append(*pNameBuffer
); // If escaped quote: only quote in the name
312 if( *pNameBuffer
== SC_COMPILER_FILE_TAB_SEP
) // after the last quote of the docname should be the # char
314 sal_Int32 nIndex
= nNameLength
- nLinkTabNameLength
;
315 INetURLObject
aINetURLObject(aDocURLBuffer
.makeStringAndClear());
316 if(aName
.match( aLinkTabName
, nIndex
) &&
317 (aName
[nIndex
- 1] == '#') && // before the table name should be the # char
318 !aINetURLObject
.HasError()) // the docname should be a valid URL
320 aName
= ScGlobal::GetDocTabName( m_aDocument
.GetLinkDoc( i
), m_aDocument
.GetLinkTab( i
) );
321 m_aDocument
.RenameTab(i
, aName
, true/*bExternalDocument*/);
323 // else; nothing has to happen, because it is a user given name
325 // else; nothing has to happen, because it is a user given name
327 // else; nothing has to happen, because it is a user given name
329 // else; nothing has to happen, because it is a user given name
333 // #i94570# DataPilot table names have to be unique, or the tables can't be accessed by API.
334 // If no name (or an invalid name, skipped in ScXMLDataPilotTableContext::EndElement) was set, create a new name.
335 ScDPCollection
* pDPCollection
= m_aDocument
.GetDPCollection();
338 size_t nDPCount
= pDPCollection
->GetCount();
339 for (size_t nDP
=0; nDP
<nDPCount
; ++nDP
)
341 ScDPObject
& rDPObj
= (*pDPCollection
)[nDP
];
342 if (rDPObj
.GetName().isEmpty())
343 rDPObj
.SetName( pDPCollection
->CreateNewName() );
349 m_aDocument
.SetInsertingFromOtherDoc( false );
351 m_aDocument
.SetImportingXML( false );
352 m_aDocument
.EnableExecuteLink( true );
353 m_aDocument
.EnableUndo( true );
358 ScDocument::HardRecalcState eRecalcState
= m_aDocument
.GetHardRecalcState();
359 // Temporarily set hard-recalc to prevent calling
360 // ScFormulaCell::Notify() during destruction of the Modificator which
361 // will set the cells dirty.
362 if (eRecalcState
== ScDocument::HardRecalcState::OFF
)
363 m_aDocument
.SetHardRecalcState(ScDocument::HardRecalcState::TEMPORARY
);
364 m_pModificator
.reset();
365 m_aDocument
.SetHardRecalcState(eRecalcState
);
369 OSL_FAIL("The Modificator should exist");
372 m_aDocument
.EnableIdle(true);
377 class LoadMediumGuard
380 explicit LoadMediumGuard(ScDocument
* pDoc
) :
383 mpDoc
->SetLoadingMedium(true);
388 mpDoc
->SetLoadingMedium(false);
394 void processDataStream( ScDocShell
& rShell
, const sc::ImportPostProcessData
& rData
)
396 if (!rData
.mpDataStream
)
399 const sc::ImportPostProcessData::DataStream
& r
= *rData
.mpDataStream
;
400 if (!r
.maRange
.IsValid())
403 // Break the streamed range into the top range and the height limit. A
404 // height limit of 0 means unlimited i.e. the streamed data will go all
405 // the way to the last row.
407 ScRange aTopRange
= r
.maRange
;
408 aTopRange
.aEnd
.SetRow(aTopRange
.aStart
.Row());
409 sal_Int32 nLimit
= r
.maRange
.aEnd
.Row() - r
.maRange
.aStart
.Row() + 1;
410 if (r
.maRange
.aEnd
.Row() == rShell
.GetDocument().MaxRow())
414 sc::DataStream::MoveType eMove
=
415 r
.meInsertPos
== sc::ImportPostProcessData::DataStream::InsertTop
?
416 sc::DataStream::MOVE_DOWN
: sc::DataStream::RANGE_DOWN
;
418 sc::DataStream
* pStrm
= new sc::DataStream(&rShell
, r
.maURL
, aTopRange
, nLimit
, eMove
, 0);
419 pStrm
->SetRefreshOnEmptyLine(r
.mbRefreshOnEmpty
);
420 sc::DocumentLinkManager
& rMgr
= rShell
.GetDocument().GetDocLinkManager();
421 rMgr
.setDataStream(pStrm
);
424 class MessageWithCheck
: public weld::MessageDialogController
427 std::unique_ptr
<weld::CheckButton
> m_xWarningOnBox
;
429 MessageWithCheck(weld::Window
*pParent
, const OUString
& rUIFile
, const OString
& rDialogId
)
430 : MessageDialogController(pParent
, rUIFile
, rDialogId
, "ask")
431 , m_xWarningOnBox(m_xBuilder
->weld_check_button("ask"))
434 bool get_active() const { return m_xWarningOnBox
->get_active(); }
435 void hide_ask() const { m_xWarningOnBox
->set_visible(false); };
439 class VBAScriptListener
: public ::cppu::WeakImplHelper
< css::script::vba::XVBAScriptListener
>
442 ScDocShell
* m_pDocSh
;
444 VBAScriptListener(ScDocShell
* pDocSh
) : m_pDocSh(pDocSh
)
448 // XVBAScriptListener
449 virtual void SAL_CALL
notifyVBAScriptEvent( const ::css::script::vba::VBAScriptEvent
& aEvent
) override
451 if (aEvent
.Identifier
== script::vba::VBAScriptEventId::SCRIPT_STOPPED
&&
452 m_pDocSh
->GetClipData().is())
454 m_pDocSh
->SetClipData(uno::Reference
<datatransfer::XTransferable2
>());
459 virtual void SAL_CALL
disposing( const ::css::lang::EventObject
& /*Source*/ ) override
466 bool ScDocShell::LoadXML( SfxMedium
* pLoadMedium
, const css::uno::Reference
< css::embed::XStorage
>& xStor
)
468 LoadMediumGuard
aLoadGuard(&m_aDocument
);
470 // MacroCallMode is no longer needed, state is kept in SfxObjectShell now
472 // no Seek(0) here - always loading from storage, GetInStream must not be called
476 ScXMLImportWrapper
aImport(*this, pLoadMedium
, xStor
);
479 ErrCode nError
= ERRCODE_NONE
;
480 m_aDocument
.LockAdjustHeight();
481 if (GetCreateMode() == SfxObjectCreateMode::ORGANIZER
)
482 bRet
= aImport
.Import(ImportFlags::Styles
, nError
);
484 bRet
= aImport
.Import(ImportFlags::All
, nError
);
487 pLoadMedium
->SetError(nError
);
489 processDataStream(*this, aImport
.GetImportPostProcessData());
491 //if the document was not generated by LibreOffice, do hard recalc in case some other document
492 //generator saved cached formula results that differ from LibreOffice's calculated results or
493 //did not use cached formula results.
494 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(GetModel(), uno::UNO_QUERY_THROW
);
495 uno::Reference
<document::XDocumentProperties
> xDocProps
= xDPS
->getDocumentProperties();
497 Reference
<uno::XComponentContext
> xContext
= comphelper::getProcessComponentContext();
498 ScRecalcOptions nRecalcMode
=
499 static_cast<ScRecalcOptions
>(officecfg::Office::Calc::Formula::Load::ODFRecalcMode::get(xContext
));
501 bool bHardRecalc
= false;
502 if (nRecalcMode
== RECALC_ASK
)
504 OUString
sProductName(utl::ConfigManager::getProductName());
505 if (m_aDocument
.IsUserInteractionEnabled() && xDocProps
->getGenerator().indexOf(sProductName
) == -1)
507 // Generator is not LibreOffice. Ask if the user wants to perform
508 // full re-calculation.
509 MessageWithCheck
aQueryBox(GetActiveDialogParent(),
510 "modules/scalc/ui/recalcquerydialog.ui", "RecalcQueryDialog");
511 aQueryBox
.set_primary_text(ScResId(STR_QUERY_FORMULA_RECALC_ONLOAD_ODS
));
512 aQueryBox
.set_default_response(RET_YES
);
514 if ( officecfg::Office::Calc::Formula::Load::OOXMLRecalcMode::isReadOnly() )
515 aQueryBox
.hide_ask();
517 bHardRecalc
= aQueryBox
.run() == RET_YES
;
519 if (aQueryBox
.get_active())
521 // Always perform selected action in the future.
522 std::shared_ptr
<comphelper::ConfigurationChanges
> batch(comphelper::ConfigurationChanges::create());
523 officecfg::Office::Calc::Formula::Load::ODFRecalcMode::set(sal_Int32(0), batch
);
524 ScFormulaOptions aOpt
= SC_MOD()->GetFormulaOptions();
525 aOpt
.SetODFRecalcOptions(bHardRecalc
? RECALC_ALWAYS
: RECALC_NEVER
);
526 /* XXX is this really supposed to set the ScModule options?
527 * Not the ScDocShell options? */
528 SC_MOD()->SetFormulaOptions(aOpt
);
534 else if (nRecalcMode
== RECALC_ALWAYS
)
541 // still need to recalc volatile formula cells.
542 m_aDocument
.Broadcast(ScHint(SfxHintId::ScDataChanged
, BCA_BRDCST_ALWAYS
));
545 AfterXMLLoading(bRet
);
547 m_aDocument
.UnlockAdjustHeight();
551 bool ScDocShell::SaveXML( SfxMedium
* pSaveMedium
, const css::uno::Reference
< css::embed::XStorage
>& xStor
)
553 m_aDocument
.EnableIdle(false);
555 ScXMLImportWrapper
aImport(*this, pSaveMedium
, xStor
);
557 if (GetCreateMode() != SfxObjectCreateMode::ORGANIZER
)
558 bRet
= aImport
.Export(false);
560 bRet
= aImport
.Export(true);
562 m_aDocument
.EnableIdle(true);
567 bool ScDocShell::Load( SfxMedium
& rMedium
)
569 LoadMediumGuard
aLoadGuard(&m_aDocument
);
570 ScRefreshTimerProtector
aProt( m_aDocument
.GetRefreshTimerControlAddress() );
572 // only the latin script language is loaded
573 // -> initialize the others from options (before loading)
576 // If this is an ODF file being loaded, then by default, use legacy processing
577 // for tdf#99729 (if required, it will be overridden in *::ReadUserDataSequence())
578 if (IsOwnStorageFormat(rMedium
))
580 if (m_aDocument
.GetDrawLayer())
581 m_aDocument
.GetDrawLayer()->SetAnchoredTextOverflowLegacy(true);
584 GetUndoManager()->Clear();
586 bool bRet
= SfxObjectShell::Load(rMedium
);
589 SetInitialLinkUpdate(&rMedium
);
592 // prepare a valid document for XML filter
593 // (for ConvertFrom, InitNew is called before)
594 m_aDocument
.MakeTable(0);
595 m_aDocument
.GetStyleSheetPool()->CreateStandardStyles();
596 m_aDocument
.UpdStlShtPtrsFrmNms();
600 /* Create styles that are imported through Orcus */
602 OUString
aURL("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER
"/calc/styles.xml");
603 rtl::Bootstrap::expandMacros(aURL
);
606 osl::FileBase::getSystemPathFromFileURL(aURL
, aPath
);
608 ScOrcusFilters
* pOrcus
= ScFormatFilter::Get().GetOrcusFilters();
612 pOrcus
->importODS_Styles(m_aDocument
, aPath
);
613 m_aDocument
.GetStyleSheetPool()->setAllParaStandard();
617 bRet
= LoadXML( &rMedium
, nullptr );
621 if (!bRet
&& !rMedium
.GetError())
622 rMedium
.SetError(SVSTREAM_FILEFORMAT_ERROR
);
624 if (rMedium
.GetError())
625 SetError(rMedium
.GetError());
630 // invalidate eventually temporary table areas
632 m_aDocument
.InvalidateTableArea();
639 void ScDocShell::Notify( SfxBroadcaster
&, const SfxHint
& rHint
)
641 const ScTablesHint
* pScHint
= dynamic_cast< const ScTablesHint
* >( &rHint
);
644 if (pScHint
->GetTablesHintId() == SC_TAB_INSERTED
)
646 uno::Reference
< script::vba::XVBAEventProcessor
> xVbaEvents
= m_aDocument
.GetVbaEventProcessor();
647 if ( xVbaEvents
.is() ) try
649 uno::Sequence
< uno::Any
> aArgs( 1 );
650 aArgs
[0] <<= pScHint
->GetTab1();
651 xVbaEvents
->processVbaEvent( script::vba::VBAEventId::WORKBOOK_NEWSHEET
, aArgs
);
653 catch( uno::Exception
& )
659 if ( auto pStyleSheetHint
= dynamic_cast<const SfxStyleSheetHint
*>(&rHint
) ) // Template changed
660 NotifyStyle( *pStyleSheetHint
);
661 else if ( auto pStlHint
= dynamic_cast<const ScAutoStyleHint
*>(&rHint
) )
663 //! direct call for AutoStyles
665 // this is called synchronously from ScInterpreter::ScStyle,
666 // modifying the document must be asynchronous
667 // (handled by AddInitial)
669 const ScRange
& aRange
= pStlHint
->GetRange();
670 const OUString
& aName1
= pStlHint
->GetStyle1();
671 const OUString
& aName2
= pStlHint
->GetStyle2();
672 sal_uInt32 nTimeout
= pStlHint
->GetTimeout();
674 if (!m_pAutoStyleList
)
675 m_pAutoStyleList
.reset( new ScAutoStyleList(this) );
676 m_pAutoStyleList
->AddInitial( aRange
, aName1
, nTimeout
, aName2
);
678 else if ( auto pEventHint
= dynamic_cast<const SfxEventHint
*>(&rHint
) )
680 SfxEventHintId nEventId
= pEventHint
->GetEventId();
684 case SfxEventHintId::LoadFinished
:
686 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
687 // the readonly documents should not be opened in shared mode
688 if ( HasSharedXMLFlagSet() && !SC_MOD()->IsInSharedDocLoading() && !IsReadOnly() )
690 if ( SwitchToShared( true, false ) )
692 ScViewData
* pViewData
= GetViewData();
693 ScTabView
* pTabView
= ( pViewData
? pViewData
->GetView() : nullptr );
696 pTabView
->UpdateLayerLocks();
701 // switching to shared mode has failed, the document should be opened readonly
702 // TODO/LATER: And error message should be shown here probably
709 case SfxEventHintId::ViewCreated
:
711 #if HAVE_FEATURE_SCRIPTING
712 uno::Reference
<script::vba::XVBACompatibility
> xVBACompat(GetBasicContainer(), uno::UNO_QUERY
);
713 if ( !m_xVBAListener
.is() && xVBACompat
.is() )
715 m_xVBAListener
.set(new VBAScriptListener(this));
716 xVBACompat
->addVBAScriptListener(m_xVBAListener
);
720 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
721 if ( IsDocShared() && !SC_MOD()->IsInSharedDocLoading() )
723 ScAppOptions aAppOptions
= SC_MOD()->GetAppOptions();
724 if ( aAppOptions
.GetShowSharedDocumentWarning() )
726 MessageWithCheck
aWarningBox(ScDocShell::GetActiveDialogParent(),
727 "modules/scalc/ui/sharedwarningdialog.ui", "SharedWarningDialog");
730 bool bChecked
= aWarningBox
.get_active();
733 aAppOptions
.SetShowSharedDocumentWarning(false);
734 SC_MOD()->SetAppOptions( aAppOptions
);
741 uno::Reference
< uno::XComponentContext
> xContext(
742 comphelper::getProcessComponentContext() );
743 uno::Reference
< lang::XMultiServiceFactory
> xServiceManager(
744 xContext
->getServiceManager(),
745 uno::UNO_QUERY_THROW
);
746 uno::Reference
< container::XContentEnumerationAccess
> xEnumAccess( xServiceManager
, uno::UNO_QUERY_THROW
);
747 uno::Reference
< container::XEnumeration
> xEnum
= xEnumAccess
->createContentEnumeration(
748 "com.sun.star.sheet.SpreadsheetDocumentJob" );
751 while ( xEnum
->hasMoreElements() )
753 uno::Any aAny
= xEnum
->nextElement();
754 uno::Reference
< lang::XSingleComponentFactory
> xFactory
;
758 uno::Reference
< task::XJob
> xJob( xFactory
->createInstanceWithContext( xContext
), uno::UNO_QUERY_THROW
);
759 ScViewData
* pViewData
= GetViewData();
760 SfxViewShell
* pViewShell
= ( pViewData
? pViewData
->GetViewShell() : nullptr );
761 SfxViewFrame
* pViewFrame
= ( pViewShell
? pViewShell
->GetViewFrame() : nullptr );
762 SfxFrame
* pFrame
= ( pViewFrame
? &pViewFrame
->GetFrame() : nullptr );
763 uno::Reference
< frame::XController
> xController
= ( pFrame
? pFrame
->GetController() : nullptr );
764 uno::Reference
< sheet::XSpreadsheetView
> xSpreadsheetView( xController
, uno::UNO_QUERY_THROW
);
765 uno::Sequence
< beans::NamedValue
> aArgsForJob
{ { "SpreadsheetView", uno::makeAny( xSpreadsheetView
) } };
766 xJob
->execute( aArgsForJob
);
771 catch ( uno::Exception
& )
776 case SfxEventHintId::SaveDoc
:
778 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
779 if ( IsDocShared() && !SC_MOD()->IsInSharedDocSaving() )
781 bool bSuccess
= false;
786 uno::Reference
< frame::XModel
> xModel
;
790 xModel
.set( LoadSharedDocument(), uno::UNO_SET_THROW
);
791 uno::Reference
< util::XCloseable
> xCloseable( xModel
, uno::UNO_QUERY_THROW
);
793 // check if shared flag is set in shared file
794 bool bShared
= false;
795 ScModelObj
* pDocObj
= comphelper::getUnoTunnelImplementation
<ScModelObj
>( xModel
);
796 ScDocShell
* pSharedDocShell
= ( pDocObj
? dynamic_cast< ScDocShell
* >( pDocObj
->GetObjectShell() ) : nullptr );
797 if ( pSharedDocShell
)
799 bShared
= pSharedDocShell
->HasSharedXMLFlagSet();
802 // #i87870# check if shared status was disabled and enabled again
803 bool bOwnEntry
= false;
804 bool bEntriesNotAccessible
= false;
807 ::svt::ShareControlFile
aControlFile( GetSharedFileURL() );
808 bOwnEntry
= aControlFile
.HasOwnEntry();
810 catch ( uno::Exception
& )
812 bEntriesNotAccessible
= true;
815 if ( bShared
&& bOwnEntry
)
817 uno::Reference
< frame::XStorable
> xStorable( xModel
, uno::UNO_QUERY_THROW
);
819 if ( xStorable
->isReadonly() )
821 xCloseable
->close( true );
823 OUString
aUserName( ScResId( STR_UNKNOWN_USER
) );
824 bool bNoLockAccess
= false;
827 ::svt::DocumentLockFile
aLockFile( GetSharedFileURL() );
828 LockFileEntry aData
= aLockFile
.GetLockData();
829 if ( !aData
[LockFileComponent::OOOUSERNAME
].isEmpty() )
831 aUserName
= aData
[LockFileComponent::OOOUSERNAME
];
833 else if ( !aData
[LockFileComponent::SYSUSERNAME
].isEmpty() )
835 aUserName
= aData
[LockFileComponent::SYSUSERNAME
];
838 catch ( uno::Exception
& )
840 bNoLockAccess
= true;
845 // TODO/LATER: in future an error regarding impossibility to open file for writing could be shown
846 ErrorHandler::HandleError( ERRCODE_IO_GENERAL
);
850 OUString
aMessage( ScResId( STR_FILE_LOCKED_SAVE_LATER
) );
851 aMessage
= aMessage
.replaceFirst( "%1", aUserName
);
853 std::unique_ptr
<weld::MessageDialog
> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
854 VclMessageType::Warning
, VclButtonsType::NONE
,
856 xWarn
->add_button(GetStandardText(StandardButtonType::Retry
), RET_RETRY
);
857 xWarn
->add_button(GetStandardText(StandardButtonType::Cancel
), RET_CANCEL
);
858 xWarn
->set_default_response(RET_RETRY
);
859 if (xWarn
->run() == RET_RETRY
)
867 // merge changes from shared file into temp file
868 bool bSaveToShared
= false;
869 if ( pSharedDocShell
)
871 bSaveToShared
= MergeSharedDocument( pSharedDocShell
);
875 xCloseable
->close( true );
877 // TODO: keep file lock on shared file
879 // store to shared file
882 bool bChangedViewSettings
= false;
883 ScChangeViewSettings
* pChangeViewSet
= m_aDocument
.GetChangeViewSettings();
884 if ( pChangeViewSet
&& pChangeViewSet
->ShowChanges() )
886 pChangeViewSet
->SetShowChanges( false );
887 pChangeViewSet
->SetShowAccepted( false );
888 m_aDocument
.SetChangeViewSettings( *pChangeViewSet
);
889 bChangedViewSettings
= true;
892 uno::Reference
< frame::XStorable
> xStor( GetModel(), uno::UNO_QUERY_THROW
);
893 // TODO/LATER: More entries from the MediaDescriptor might be interesting for the merge
894 uno::Sequence
< beans::PropertyValue
> aValues(1);
895 aValues
[0].Name
= "FilterName";
896 aValues
[0].Value
<<= GetMedium()->GetFilter()->GetFilterName();
898 const SfxStringItem
* pPasswordItem
= SfxItemSet::GetItem
<SfxStringItem
>(GetMedium()->GetItemSet(), SID_PASSWORD
, false);
899 if ( pPasswordItem
&& !pPasswordItem
->GetValue().isEmpty() )
901 aValues
.realloc( 2 );
902 aValues
[1].Name
= "Password";
903 aValues
[1].Value
<<= pPasswordItem
->GetValue();
906 SC_MOD()->SetInSharedDocSaving( true );
907 xStor
->storeToURL( GetSharedFileURL(), aValues
);
908 SC_MOD()->SetInSharedDocSaving( false );
910 if ( bChangedViewSettings
)
912 pChangeViewSet
->SetShowChanges( true );
913 pChangeViewSet
->SetShowAccepted( true );
914 m_aDocument
.SetChangeViewSettings( *pChangeViewSet
);
919 GetUndoManager()->Clear();
924 xCloseable
->close( true );
926 if ( bEntriesNotAccessible
)
928 // TODO/LATER: in future an error regarding impossibility to write to share control file could be shown
929 ErrorHandler::HandleError( ERRCODE_IO_GENERAL
);
933 std::unique_ptr
<weld::MessageDialog
> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
934 VclMessageType::Warning
, VclButtonsType::Ok
,
935 ScResId(STR_DOC_NOLONGERSHARED
)));
938 SfxBindings
* pBindings
= GetViewBindings();
941 pBindings
->ExecuteSynchron( SID_SAVEASDOC
);
946 catch ( uno::Exception
& )
948 TOOLS_WARN_EXCEPTION( "sc", "SfxEventHintId::SaveDoc" );
949 SC_MOD()->SetInSharedDocSaving( false );
953 uno::Reference
< util::XCloseable
> xClose( xModel
, uno::UNO_QUERY_THROW
);
954 xClose
->close( true );
956 catch ( uno::Exception
& )
963 SetError(ERRCODE_IO_ABORT
); // this error code will produce no error message, but will break the further saving process
967 if (m_pSheetSaveData
)
968 m_pSheetSaveData
->SetInSupportedSave(true);
971 case SfxEventHintId::SaveAsDoc
:
973 if ( GetDocument().GetExternalRefManager()->containsUnsavedReferences() )
975 std::unique_ptr
<weld::MessageDialog
> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
976 VclMessageType::Warning
, VclButtonsType::YesNo
,
977 ScResId(STR_UNSAVED_EXT_REF
)));
978 if (RET_NO
== xWarn
->run())
980 SetError(ERRCODE_IO_ABORT
); // this error code will produce no error message, but will break the further saving process
985 case SfxEventHintId::SaveToDoc
:
986 // #i108978# If no event is sent before saving, there will also be no "...DONE" event,
987 // and SAVE/SAVEAS can't be distinguished from SAVETO. So stream copying is only enabled
988 // if there is a SAVE/SAVEAS/SAVETO event first.
989 if (m_pSheetSaveData
)
990 m_pSheetSaveData
->SetInSupportedSave(true);
992 case SfxEventHintId::SaveDocDone
:
993 case SfxEventHintId::SaveAsDocDone
:
995 // new positions are used after "save" and "save as", but not "save to"
996 UseSheetSaveEntries(); // use positions from saved file for next saving
999 case SfxEventHintId::SaveToDocDone
:
1000 // only reset the flag, don't use the new positions
1001 if (m_pSheetSaveData
)
1002 m_pSheetSaveData
->SetInSupportedSave(false);
1010 else if (rHint
.GetId() == SfxHintId::TitleChanged
) // Without parameter
1012 m_aDocument
.SetName( SfxShell::GetName() );
1013 // RegisterNewTargetNames doesn't exist any longer
1014 SfxGetpApp()->Broadcast(SfxHint( SfxHintId::ScDocNameChanged
)); // Navigator
1016 else if (rHint
.GetId() == SfxHintId::Deinitializing
)
1019 #if HAVE_FEATURE_SCRIPTING
1020 uno::Reference
<script::vba::XVBACompatibility
> xVBACompat(GetBasicContainer(), uno::UNO_QUERY
);
1021 if (m_xVBAListener
.is() && xVBACompat
.is())
1023 xVBACompat
->removeVBAScriptListener(m_xVBAListener
);
1027 if (m_aDocument
.IsClipboardSource())
1029 // Notes copied to the clipboard have a raw SdrCaptionObj pointer
1030 // copied from this document, forget it as it references this
1031 // document's drawing layer pages and what not, which otherwise when
1032 // pasting to another document after this document was destructed would
1033 // attempt to access non-existing data. Preserve the text data though.
1034 ScDocument
* pClipDoc
= ScModule::GetClipDoc();
1036 pClipDoc
->ClosingClipboardSource();
1040 const SfxEventHint
* pSfxEventHint
= dynamic_cast<const SfxEventHint
*>(&rHint
);
1044 switch( pSfxEventHint
->GetEventId() )
1046 case SfxEventHintId::CreateDoc
:
1049 aWorkbook
<<= mxAutomationWorkbookObject
;
1050 uno::Sequence
< uno::Any
> aArgs(1);
1051 aArgs
[0] = aWorkbook
;
1052 SC_MOD()->CallAutomationApplicationEventSinks( "NewWorkbook", aArgs
);
1055 case SfxEventHintId::OpenDoc
:
1058 aWorkbook
<<= mxAutomationWorkbookObject
;
1059 uno::Sequence
< uno::Any
> aArgs(1);
1060 aArgs
[0] = aWorkbook
;
1061 SC_MOD()->CallAutomationApplicationEventSinks( "WorkbookOpen", aArgs
);
1069 // Load contents for organizer
1070 bool ScDocShell::LoadFrom( SfxMedium
& rMedium
)
1072 LoadMediumGuard
aLoadGuard(&m_aDocument
);
1073 ScRefreshTimerProtector
aProt( m_aDocument
.GetRefreshTimerControlAddress() );
1075 weld::WaitObject
aWait( GetActiveDialogParent() );
1079 SetInitialLinkUpdate(&rMedium
);
1081 // until loading/saving only the styles in XML is implemented,
1082 // load the whole file
1083 bRet
= LoadXML( &rMedium
, nullptr );
1086 SfxObjectShell::LoadFrom( rMedium
);
1091 static void lcl_parseHtmlFilterOption(const OUString
& rOption
, LanguageType
& rLang
, bool& rDateConvert
)
1093 OUStringBuffer aBuf
;
1094 std::vector
< OUString
> aTokens
;
1095 sal_Int32 n
= rOption
.getLength();
1096 const sal_Unicode
* p
= rOption
.getStr();
1097 for (sal_Int32 i
= 0; i
< n
; ++i
)
1099 const sal_Unicode c
= p
[i
];
1102 if (!aBuf
.isEmpty())
1103 aTokens
.push_back( aBuf
.makeStringAndClear() );
1109 if (!aBuf
.isEmpty())
1110 aTokens
.push_back( aBuf
.makeStringAndClear() );
1112 rLang
= LanguageType( 0 );
1113 rDateConvert
= false;
1115 if (!aTokens
.empty())
1116 rLang
= static_cast<LanguageType
>(aTokens
[0].toInt32());
1117 if (aTokens
.size() > 1)
1118 rDateConvert
= static_cast<bool>(aTokens
[1].toInt32());
1121 bool ScDocShell::ConvertFrom( SfxMedium
& rMedium
)
1123 LoadMediumGuard
aLoadGuard(&m_aDocument
);
1125 bool bRet
= false; // sal_False means user quit!
1126 // On error: Set error at stream
1128 ScRefreshTimerProtector
aProt( m_aDocument
.GetRefreshTimerControlAddress() );
1130 GetUndoManager()->Clear();
1132 // Set optimal col width after import?
1133 bool bSetColWidths
= false;
1134 bool bSetSimpleTextColWidths
= false;
1135 std::map
<SCCOL
, ScColWidthParam
> aColWidthParam
;
1136 ScRange aColWidthRange
;
1137 // Set optimal row height after import?
1138 bool bSetRowHeights
= false;
1140 vector
<ScDocRowHeightUpdater::TabRanges
> aRecalcRowRangesArray
;
1142 // All filters need the complete file in one piece (not asynchronously)
1143 // So make sure that we transfer the whole file with CreateFileStream
1144 rMedium
.GetPhysicalName(); //! Call CreateFileStream directly, if available
1146 SetInitialLinkUpdate(&rMedium
);
1148 std::shared_ptr
<const SfxFilter
> pFilter
= rMedium
.GetFilter();
1151 OUString aFltName
= pFilter
->GetFilterName();
1153 bool bCalc3
= aFltName
== "StarCalc 3.0";
1154 bool bCalc4
= aFltName
== "StarCalc 4.0";
1155 if (!bCalc3
&& !bCalc4
)
1156 m_aDocument
.SetInsertingFromOtherDoc( true );
1158 if (aFltName
== pFilterXML
)
1159 bRet
= LoadXML( &rMedium
, nullptr );
1160 else if (aFltName
== pFilterLotus
)
1163 SfxItemSet
* pSet
= rMedium
.GetItemSet();
1164 const SfxPoolItem
* pItem
;
1165 if ( pSet
&& SfxItemState::SET
==
1166 pSet
->GetItemState( SID_FILE_FILTEROPTIONS
, true, &pItem
) )
1168 sItStr
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
1171 if (sItStr
.isEmpty())
1173 // default for lotus import (from API without options):
1175 sItStr
= ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_437
);
1178 ErrCode eError
= ScFormatFilter::Get().ScImportLotus123( rMedium
, m_aDocument
,
1179 ScGlobal::GetCharsetValue(sItStr
));
1180 if (eError
!= ERRCODE_NONE
)
1185 if( eError
.IsWarning() )
1190 bSetColWidths
= true;
1191 bSetRowHeights
= true;
1193 else if ( aFltName
== pFilterExcel4
|| aFltName
== pFilterExcel5
||
1194 aFltName
== pFilterExcel95
|| aFltName
== pFilterExcel97
||
1195 aFltName
== pFilterEx4Temp
|| aFltName
== pFilterEx5Temp
||
1196 aFltName
== pFilterEx95Temp
|| aFltName
== pFilterEx97Temp
)
1198 EXCIMPFORMAT eFormat
= EIF_AUTO
;
1199 if ( aFltName
== pFilterExcel4
|| aFltName
== pFilterEx4Temp
)
1200 eFormat
= EIF_BIFF_LE4
;
1201 else if ( aFltName
== pFilterExcel5
|| aFltName
== pFilterExcel95
||
1202 aFltName
== pFilterEx5Temp
|| aFltName
== pFilterEx95Temp
)
1203 eFormat
= EIF_BIFF5
;
1204 else if ( aFltName
== pFilterExcel97
|| aFltName
== pFilterEx97Temp
)
1205 eFormat
= EIF_BIFF8
;
1207 MakeDrawLayer(); //! In the filter
1208 CalcOutputFactor(); // prepare update of row height
1209 ErrCode eError
= ScFormatFilter::Get().ScImportExcel( rMedium
, &m_aDocument
, eFormat
);
1210 m_aDocument
.UpdateFontCharSet();
1211 if ( m_aDocument
.IsChartListenerCollectionNeedsUpdate() )
1212 m_aDocument
.UpdateChartListenerCollection(); //! For all imports?
1214 // all graphics objects must have names
1215 m_aDocument
.EnsureGraphicNames();
1217 if (eError
== SCWARN_IMPORT_RANGE_OVERFLOW
)
1223 else if (eError
!= ERRCODE_NONE
)
1231 else if (aFltName
== "Gnumeric Spreadsheet")
1233 ScOrcusFilters
* pOrcus
= ScFormatFilter::Get().GetOrcusFilters();
1237 bRet
= pOrcus
->importGnumeric(m_aDocument
, rMedium
);
1239 else if (aFltName
== "MS Excel 2003 XML Orcus")
1241 ScOrcusFilters
* pOrcus
= ScFormatFilter::Get().GetOrcusFilters();
1245 bRet
= pOrcus
->importExcel2003XML(m_aDocument
, rMedium
);
1247 else if (aFltName
== pFilterAscii
)
1249 SfxItemSet
* pSet
= rMedium
.GetItemSet();
1250 const SfxPoolItem
* pItem
;
1251 ScAsciiOptions aOptions
;
1252 bool bOptInit
= false;
1254 if ( pSet
&& SfxItemState::SET
==
1255 pSet
->GetItemState( SID_FILE_FILTEROPTIONS
, true, &pItem
) )
1257 aOptions
.ReadFromString( static_cast<const SfxStringItem
*>(pItem
)->GetValue() );
1263 // default for ascii import (from API without options):
1264 // ISO8859-1/MS_1252 encoding, comma, double quotes
1266 aOptions
.SetCharSet( RTL_TEXTENCODING_MS_1252
);
1267 aOptions
.SetFieldSeps( OUString(',') );
1268 aOptions
.SetTextSep( '"' );
1271 ErrCode eError
= ERRCODE_NONE
;
1272 bool bOverflowRow
, bOverflowCol
, bOverflowCell
;
1273 bOverflowRow
= bOverflowCol
= bOverflowCell
= false;
1275 if( ! rMedium
.IsStorage() )
1277 ScImportExport
aImpEx( m_aDocument
);
1278 aImpEx
.SetExtOptions( aOptions
);
1280 SvStream
* pInStream
= rMedium
.GetInStream();
1283 pInStream
->SetStreamCharSet( aOptions
.GetCharSet() );
1284 pInStream
->Seek( 0 );
1285 bRet
= aImpEx
.ImportStream( *pInStream
, rMedium
.GetBaseURL(), SotClipboardFormatId::STRING
);
1286 eError
= bRet
? ERRCODE_NONE
: SCERR_IMPORT_CONNECT
;
1287 m_aDocument
.StartAllListeners();
1288 sc::SetFormulaDirtyContext aCxt
;
1289 m_aDocument
.SetAllFormulasDirty(aCxt
);
1291 // The same resulting name has to be handled in
1292 // ScExternalRefCache::initializeDoc() and related, hence
1293 // pass 'true' for RenameTab()'s bExternalDocument for a
1294 // composed name so ValidTabName() will not be checked,
1295 // which could veto the rename in case it contained
1296 // characters that Excel does not handle. If we wanted to
1297 // change that then it needed to be handled in all
1298 // corresponding places of the external references
1299 // manager/cache. Likely then we'd also need a method to
1300 // compose a name excluding such characters.
1301 m_aDocument
.RenameTab( 0, INetURLObject( rMedium
.GetName()).GetBase(), true/*bExternalDocument*/);
1303 bOverflowRow
= aImpEx
.IsOverflowRow();
1304 bOverflowCol
= aImpEx
.IsOverflowCol();
1305 bOverflowCell
= aImpEx
.IsOverflowCell();
1309 OSL_FAIL( "No Stream" );
1313 if (eError
!= ERRCODE_NONE
)
1318 else if (!GetError() && (bOverflowRow
|| bOverflowCol
|| bOverflowCell
))
1320 // precedence: row, column, cell
1321 ErrCode nWarn
= (bOverflowRow
? SCWARN_IMPORT_ROW_OVERFLOW
:
1322 (bOverflowCol
? SCWARN_IMPORT_COLUMN_OVERFLOW
:
1323 SCWARN_IMPORT_CELL_OVERFLOW
));
1326 bSetColWidths
= true;
1327 bSetSimpleTextColWidths
= true;
1329 else if (aFltName
== pFilterDBase
)
1332 SfxItemSet
* pSet
= rMedium
.GetItemSet();
1333 const SfxPoolItem
* pItem
;
1334 if ( pSet
&& SfxItemState::SET
==
1335 pSet
->GetItemState( SID_FILE_FILTEROPTIONS
, true, &pItem
) )
1337 sItStr
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
1340 if (sItStr
.isEmpty())
1342 // default for dBase import (from API without options):
1345 sItStr
= ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_850
);
1348 ScDocRowHeightUpdater::TabRanges
aRecalcRanges(0, m_aDocument
.MaxRow());
1349 ErrCode eError
= DBaseImport( rMedium
.GetPhysicalName(),
1350 ScGlobal::GetCharsetValue(sItStr
), aColWidthParam
, aRecalcRanges
.maRanges
);
1351 aRecalcRowRangesArray
.push_back(aRecalcRanges
);
1353 if (eError
!= ERRCODE_NONE
)
1357 bRet
= ( eError
== SCWARN_IMPORT_RANGE_OVERFLOW
);
1362 aColWidthRange
.aStart
.SetRow( 1 ); // Except for the column header
1363 bSetColWidths
= true;
1364 bSetSimpleTextColWidths
= true;
1366 else if (aFltName
== pFilterDif
)
1368 SvStream
* pStream
= rMedium
.GetInStream();
1373 SfxItemSet
* pSet
= rMedium
.GetItemSet();
1374 const SfxPoolItem
* pItem
;
1375 if ( pSet
&& SfxItemState::SET
==
1376 pSet
->GetItemState( SID_FILE_FILTEROPTIONS
, true, &pItem
) )
1378 sItStr
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
1381 if (sItStr
.isEmpty())
1383 // default for DIF import (from API without options):
1384 // ISO8859-1/MS_1252 encoding
1386 sItStr
= ScGlobal::GetCharsetString( RTL_TEXTENCODING_MS_1252
);
1389 eError
= ScFormatFilter::Get().ScImportDif( *pStream
, &m_aDocument
, ScAddress(0,0,0),
1390 ScGlobal::GetCharsetValue(sItStr
));
1391 if (eError
!= ERRCODE_NONE
)
1396 if( eError
.IsWarning() )
1402 bSetColWidths
= true;
1403 bSetSimpleTextColWidths
= true;
1404 bSetRowHeights
= true;
1406 else if (aFltName
== pFilterSylk
)
1408 ErrCode eError
= SCERR_IMPORT_UNKNOWN
;
1409 bool bOverflowRow
, bOverflowCol
, bOverflowCell
;
1410 bOverflowRow
= bOverflowCol
= bOverflowCell
= false;
1411 if( !rMedium
.IsStorage() )
1413 ScImportExport
aImpEx( m_aDocument
);
1415 SvStream
* pInStream
= rMedium
.GetInStream();
1418 pInStream
->Seek( 0 );
1419 bRet
= aImpEx
.ImportStream( *pInStream
, rMedium
.GetBaseURL(), SotClipboardFormatId::SYLK
);
1420 eError
= bRet
? ERRCODE_NONE
: SCERR_IMPORT_UNKNOWN
;
1421 m_aDocument
.StartAllListeners();
1422 sc::SetFormulaDirtyContext aCxt
;
1423 m_aDocument
.SetAllFormulasDirty(aCxt
);
1425 bOverflowRow
= aImpEx
.IsOverflowRow();
1426 bOverflowCol
= aImpEx
.IsOverflowCol();
1427 bOverflowCell
= aImpEx
.IsOverflowCell();
1431 OSL_FAIL( "No Stream" );
1435 if ( eError
!= ERRCODE_NONE
&& !GetError() )
1437 else if (!GetError() && (bOverflowRow
|| bOverflowCol
|| bOverflowCell
))
1439 // precedence: row, column, cell
1440 ErrCode nWarn
= (bOverflowRow
? SCWARN_IMPORT_ROW_OVERFLOW
:
1441 (bOverflowCol
? SCWARN_IMPORT_COLUMN_OVERFLOW
:
1442 SCWARN_IMPORT_CELL_OVERFLOW
));
1445 bSetColWidths
= true;
1446 bSetSimpleTextColWidths
= true;
1447 bSetRowHeights
= true;
1449 else if (aFltName
== pFilterQPro6
)
1451 ErrCode eError
= ScFormatFilter::Get().ScImportQuattroPro(rMedium
.GetInStream(), m_aDocument
);
1452 if (eError
!= ERRCODE_NONE
)
1456 if( eError
.IsWarning() )
1461 // TODO: Filter should set column widths. Not doing it here, it may
1462 // result in very narrow or wide columns, depending on content.
1463 // Setting row heights makes cells with font size attribution or
1464 // wrapping enabled look nicer...
1465 bSetRowHeights
= true;
1467 else if (aFltName
== pFilterRtf
)
1469 ErrCode eError
= SCERR_IMPORT_UNKNOWN
;
1470 if( !rMedium
.IsStorage() )
1472 SvStream
* pInStream
= rMedium
.GetInStream();
1475 pInStream
->Seek( 0 );
1477 eError
= ScFormatFilter::Get().ScImportRTF( *pInStream
, rMedium
.GetBaseURL(), &m_aDocument
, aRange
);
1478 if (eError
!= ERRCODE_NONE
)
1483 if( eError
.IsWarning() )
1488 m_aDocument
.StartAllListeners();
1489 sc::SetFormulaDirtyContext aCxt
;
1490 m_aDocument
.SetAllFormulasDirty(aCxt
);
1491 bSetColWidths
= true;
1492 bSetRowHeights
= true;
1496 OSL_FAIL( "No Stream" );
1500 if ( eError
!= ERRCODE_NONE
&& !GetError() )
1503 else if (aFltName
== pFilterHtml
|| aFltName
== pFilterHtmlWebQ
)
1505 ErrCode eError
= SCERR_IMPORT_UNKNOWN
;
1506 bool bWebQuery
= aFltName
== pFilterHtmlWebQ
;
1507 if( !rMedium
.IsStorage() )
1509 SvStream
* pInStream
= rMedium
.GetInStream();
1512 LanguageType eLang
= LANGUAGE_SYSTEM
;
1513 bool bDateConvert
= false;
1514 SfxItemSet
* pSet
= rMedium
.GetItemSet();
1515 const SfxPoolItem
* pItem
;
1516 if ( pSet
&& SfxItemState::SET
==
1517 pSet
->GetItemState( SID_FILE_FILTEROPTIONS
, true, &pItem
) )
1519 OUString aFilterOption
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
1520 lcl_parseHtmlFilterOption(aFilterOption
, eLang
, bDateConvert
);
1523 pInStream
->Seek( 0 );
1525 // HTML does its own ColWidth/RowHeight
1527 SvNumberFormatter
aNumFormatter( comphelper::getProcessComponentContext(), eLang
);
1528 eError
= ScFormatFilter::Get().ScImportHTML( *pInStream
, rMedium
.GetBaseURL(), &m_aDocument
, aRange
,
1529 GetOutputFactor(), !bWebQuery
, &aNumFormatter
, bDateConvert
);
1530 if (eError
!= ERRCODE_NONE
)
1535 if( eError
.IsWarning() )
1540 m_aDocument
.StartAllListeners();
1542 sc::SetFormulaDirtyContext aCxt
;
1543 m_aDocument
.SetAllFormulasDirty(aCxt
);
1547 OSL_FAIL( "No Stream" );
1551 if ( eError
!= ERRCODE_NONE
&& !GetError() )
1558 SAL_WARN("sc.filter", "No match for filter '" << aFltName
<< "' in ConvertFrom");
1559 SetError(SCERR_IMPORT_NI
);
1564 m_aDocument
.SetInsertingFromOtherDoc( false );
1568 OSL_FAIL("No Filter in ConvertFrom");
1573 if ( bRet
&& (bSetColWidths
|| bSetRowHeights
) )
1574 { // Adjust column width/row height; base 100% zoom
1575 Fraction
aZoom( 1, 1 );
1576 double nPPTX
= ScGlobal::nScreenPPTX
* static_cast<double>(aZoom
) / GetOutputFactor(); // Factor is printer display ratio
1577 double nPPTY
= ScGlobal::nScreenPPTY
* static_cast<double>(aZoom
);
1578 ScopedVclPtrInstance
< VirtualDevice
> pVirtDev
;
1579 // all sheets (for Excel import)
1580 SCTAB nTabCount
= m_aDocument
.GetTableCount();
1581 for (SCTAB nTab
=0; nTab
<nTabCount
; nTab
++)
1585 m_aDocument
.GetCellArea( nTab
, nEndCol
, nEndRow
);
1586 aColWidthRange
.aEnd
.SetCol( nEndCol
);
1587 aColWidthRange
.aEnd
.SetRow( nEndRow
);
1588 ScMarkData
aMark(m_aDocument
.GetSheetLimits());
1589 aMark
.SetMarkArea( aColWidthRange
);
1590 aMark
.MarkToMulti();
1592 // Order is important: First width, then height
1593 if ( bSetColWidths
)
1595 for ( SCCOL nCol
=0; nCol
<= nEndCol
; nCol
++ )
1597 if (!bSetSimpleTextColWidths
)
1598 aColWidthParam
[nCol
].mbSimpleText
= false;
1600 sal_uInt16 nWidth
= m_aDocument
.GetOptimalColWidth(
1601 nCol
, nTab
, pVirtDev
, nPPTX
, nPPTY
, aZoom
, aZoom
, false, &aMark
,
1602 &aColWidthParam
[nCol
] );
1603 m_aDocument
.SetColWidth( nCol
, nTab
,
1604 nWidth
+ static_cast<sal_uInt16
>(ScGlobal::nLastColWidthExtra
) );
1611 // Update all rows in all tables.
1612 ScSizeDeviceProvider
aProv(this);
1613 ScDocRowHeightUpdater
aUpdater(m_aDocument
, aProv
.GetDevice(), aProv
.GetPPTX(), aProv
.GetPPTY(), nullptr);
1616 else if (!aRecalcRowRangesArray
.empty())
1618 // Update only specified row ranges for better performance.
1619 ScSizeDeviceProvider
aProv(this);
1620 ScDocRowHeightUpdater
aUpdater(m_aDocument
, aProv
.GetDevice(), aProv
.GetPPTX(), aProv
.GetPPTY(), &aRecalcRowRangesArray
);
1626 // invalidate eventually temporary table areas
1628 m_aDocument
.InvalidateTableArea();
1635 bool ScDocShell::LoadExternal( SfxMedium
& rMed
)
1637 std::shared_ptr
<const SfxFilter
> pFilter
= rMed
.GetFilter();
1641 if (pFilter
->GetProviderName() == "orcus")
1643 ScOrcusFilters
* pOrcus
= ScFormatFilter::Get().GetOrcusFilters();
1647 const OUString
& rFilterName
= pFilter
->GetName();
1648 if (rFilterName
== "gnumeric")
1650 if (!pOrcus
->importGnumeric(m_aDocument
, rMed
))
1653 else if (rFilterName
== "csv")
1655 if (!pOrcus
->importCSV(m_aDocument
, rMed
))
1658 else if (rFilterName
== "xlsx")
1660 if (!pOrcus
->importXLSX(m_aDocument
, rMed
))
1663 else if (rFilterName
== "ods")
1665 if (!pOrcus
->importODS(m_aDocument
, rMed
))
1676 ScDocShell::PrepareSaveGuard::PrepareSaveGuard( ScDocShell
& rDocShell
)
1677 : mrDocShell( rDocShell
)
1679 // DoEnterHandler not here (because of AutoSave), is in ExecuteSave.
1681 ScChartListenerCollection
* pCharts
= mrDocShell
.m_aDocument
.GetChartListenerCollection();
1683 pCharts
->UpdateDirtyCharts(); // Charts to be updated.
1684 mrDocShell
.m_aDocument
.StopTemporaryChartLock();
1685 if (mrDocShell
.m_pAutoStyleList
)
1686 mrDocShell
.m_pAutoStyleList
->ExecuteAllNow(); // Execute template timeouts now.
1687 if (mrDocShell
.m_aDocument
.HasExternalRefManager())
1689 ScExternalRefManager
* pRefMgr
= mrDocShell
.m_aDocument
.GetExternalRefManager();
1690 if (pRefMgr
&& pRefMgr
->hasExternalData())
1692 pRefMgr
->setAllCacheTableReferencedStati( false);
1693 mrDocShell
.m_aDocument
.MarkUsedExternalReferences(); // Mark tables of external references to be written.
1696 if (mrDocShell
.GetCreateMode()== SfxObjectCreateMode::STANDARD
)
1697 mrDocShell
.SfxObjectShell::SetVisArea( tools::Rectangle() ); // "Normally" worked on => no VisArea.
1700 ScDocShell::PrepareSaveGuard::~PrepareSaveGuard() COVERITY_NOEXCEPT_FALSE
1702 if (mrDocShell
.m_aDocument
.HasExternalRefManager())
1704 ScExternalRefManager
* pRefMgr
= mrDocShell
.m_aDocument
.GetExternalRefManager();
1705 if (pRefMgr
&& pRefMgr
->hasExternalData())
1707 // Prevent accidental data loss due to lack of knowledge.
1708 pRefMgr
->setAllCacheTableReferencedStati( true);
1713 bool ScDocShell::Save()
1715 ScRefreshTimerProtector
aProt( m_aDocument
.GetRefreshTimerControlAddress() );
1717 PrepareSaveGuard
aPrepareGuard( *this);
1719 if (const auto pFrame1
= SfxViewFrame::GetFirst(this))
1721 if (auto pSysWin
= pFrame1
->GetWindow().GetSystemWindow())
1723 pSysWin
->SetAccessibleName(OUString());
1726 // wait cursor is handled with progress bar
1727 bool bRet
= SfxObjectShell::Save();
1729 bRet
= SaveXML( GetMedium(), nullptr );
1736 * Remove the file name from the full path, to keep only the directory path.
1738 void popFileName(OUString
& rPath
)
1740 if (!rPath
.isEmpty())
1742 INetURLObject
aURLObj(rPath
);
1743 aURLObj
.removeSegment();
1744 rPath
= aURLObj
.GetMainURL(INetURLObject::DecodeMechanism::NONE
);
1750 void ScDocShell::TerminateEditing()
1752 // Commit any cell changes before saving.
1753 SC_MOD()->InputEnterHandler();
1756 bool ScDocShell::SaveAs( SfxMedium
& rMedium
)
1758 OUString aCurPath
; // empty for new document that hasn't been saved.
1759 const SfxMedium
* pCurMedium
= GetMedium();
1762 aCurPath
= pCurMedium
->GetName();
1763 popFileName(aCurPath
);
1766 if (!aCurPath
.isEmpty())
1768 // current document has a path -> not a brand-new document.
1769 OUString aNewPath
= rMedium
.GetName();
1770 popFileName(aNewPath
);
1771 OUString aRel
= URIHelper::simpleNormalizedMakeRelative(aCurPath
, aNewPath
);
1772 if (!aRel
.isEmpty())
1774 // Directory path will change before and after the save.
1775 m_aDocument
.InvalidateStreamOnSave();
1779 ScTabViewShell
* pViewShell
= GetBestViewShell();
1780 bool bNeedsRehash
= ScPassHashHelper::needsPassHashRegen(m_aDocument
, PASSHASH_SHA1
);
1782 // legacy xls hash double-hashed by SHA1 is also supported.
1783 bNeedsRehash
= ScPassHashHelper::needsPassHashRegen(m_aDocument
, PASSHASH_XL
, PASSHASH_SHA1
);
1785 { // SHA256 explicitly supported in ODF 1.2, implicitly in ODF 1.1
1786 bNeedsRehash
= ScPassHashHelper::needsPassHashRegen(m_aDocument
, PASSHASH_SHA256
);
1789 if (pViewShell
&& bNeedsRehash
)
1791 if (!pViewShell
->ExecuteRetypePassDlg(PASSHASH_SHA1
))
1792 // password re-type cancelled. Don't save the document.
1796 ScRefreshTimerProtector
aProt( m_aDocument
.GetRefreshTimerControlAddress() );
1798 PrepareSaveGuard
aPrepareGuard( *this);
1800 // wait cursor is handled with progress bar
1801 bool bRet
= SfxObjectShell::SaveAs( rMedium
);
1803 bRet
= SaveXML( &rMedium
, nullptr );
1810 // Xcl-like column width measured in characters of standard font.
1811 sal_Int32
lcl_ScDocShell_GetColWidthInChars( sal_uInt16 nWidth
)
1819 return sal_Int32( f
);
1822 void lcl_ScDocShell_GetFixedWidthString( OUString
& rStr
, const ScDocument
& rDoc
,
1823 SCTAB nTab
, SCCOL nCol
, bool bValue
, SvxCellHorJustify eHorJust
)
1825 OUString aString
= rStr
;
1826 sal_Int32 nLen
= lcl_ScDocShell_GetColWidthInChars(
1827 rDoc
.GetColWidth( nCol
, nTab
) );
1828 //If the text won't fit in the column
1829 if ( nLen
< aString
.getLength() )
1831 OUStringBuffer aReplacement
;
1833 aReplacement
.append("###");
1835 aReplacement
.append(aString
);
1836 //truncate to the number of characters that should fit, even in the
1837 //bValue case nLen might be < len ###
1838 aString
= comphelper::string::truncateToLength(aReplacement
, nLen
).makeStringAndClear();
1840 if ( nLen
> aString
.getLength() )
1842 if ( bValue
&& eHorJust
== SvxCellHorJustify::Standard
)
1843 eHorJust
= SvxCellHorJustify::Right
;
1844 sal_Int32 nBlanks
= nLen
- aString
.getLength();
1847 case SvxCellHorJustify::Right
:
1849 OUStringBuffer aTmp
;
1850 comphelper::string::padToLength( aTmp
, nBlanks
, ' ' );
1851 aString
= aTmp
.append(aString
).makeStringAndClear();
1854 case SvxCellHorJustify::Center
:
1856 sal_Int32 nLeftPad
= nBlanks
/ 2;
1857 OUStringBuffer aTmp
;
1858 comphelper::string::padToLength( aTmp
, nLeftPad
, ' ' );
1859 aTmp
.append(aString
);
1860 comphelper::string::padToLength( aTmp
, nLen
, ' ' );
1861 aString
= aTmp
.makeStringAndClear();
1866 OUStringBuffer
aTmp(aString
);
1867 comphelper::string::padToLength( aTmp
, nLen
, ' ' );
1868 aString
= aTmp
.makeStringAndClear();
1875 void lcl_ScDocShell_WriteEmptyFixedWidthString( SvStream
& rStream
,
1876 const ScDocument
& rDoc
, SCTAB nTab
, SCCOL nCol
)
1879 lcl_ScDocShell_GetFixedWidthString( aString
, rDoc
, nTab
, nCol
, false,
1880 SvxCellHorJustify::Standard
);
1881 rStream
.WriteUnicodeOrByteText( aString
);
1884 template<typename StrT
, typename SepCharT
>
1885 sal_Int32
getTextSepPos(
1886 const StrT
& rStr
, const ScImportOptions
& rAsciiOpt
, const SepCharT
& rTextSep
, const SepCharT
& rFieldSep
, bool& rNeedQuotes
)
1888 // #i116636# quotes are needed if text delimiter (quote), field delimiter,
1889 // or LF or CR is in the cell text.
1890 sal_Int32 nPos
= rStr
.indexOf(rTextSep
);
1891 rNeedQuotes
= rAsciiOpt
.bQuoteAllText
|| (nPos
>= 0) ||
1892 (rStr
.indexOf(rFieldSep
) >= 0) ||
1893 (rStr
.indexOf('\n') >= 0) ||
1894 (rStr
.indexOf('\r') >= 0);
1898 template<typename StrT
, typename StrBufT
>
1899 void escapeTextSep(sal_Int32 nPos
, const StrT
& rStrDelim
, StrT
& rStr
)
1904 aBuf
.insert(nPos
, rStrDelim
);
1905 rStr
= aBuf
.makeStringAndClear();
1906 nPos
= rStr
.indexOf(rStrDelim
, nPos
+1+rStrDelim
.getLength());
1912 void ScDocShell::AsciiSave( SvStream
& rStream
, const ScImportOptions
& rAsciiOpt
, SCTAB nTab
)
1914 sal_Unicode cDelim
= rAsciiOpt
.nFieldSepCode
;
1915 sal_Unicode cStrDelim
= rAsciiOpt
.nTextSepCode
;
1916 rtl_TextEncoding eCharSet
= rAsciiOpt
.eCharSet
;
1917 bool bFixedWidth
= rAsciiOpt
.bFixedWidth
;
1918 bool bSaveNumberAsSuch
= rAsciiOpt
.bSaveNumberAsSuch
;
1919 bool bSaveAsShown
= rAsciiOpt
.bSaveAsShown
;
1920 bool bShowFormulas
= rAsciiOpt
.bSaveFormulas
;
1922 rtl_TextEncoding eOldCharSet
= rStream
.GetStreamCharSet();
1923 rStream
.SetStreamCharSet( eCharSet
);
1924 SvStreamEndian nOldNumberFormatInt
= rStream
.GetEndian();
1925 OString aStrDelimEncoded
; // only used if not Unicode
1926 OUString aStrDelimDecoded
; // only used if context encoding
1927 OString aDelimEncoded
;
1928 OUString aDelimDecoded
;
1929 bool bContextOrNotAsciiEncoding
;
1930 if ( eCharSet
== RTL_TEXTENCODING_UNICODE
)
1932 rStream
.StartWritingUnicodeText();
1933 bContextOrNotAsciiEncoding
= false;
1937 aStrDelimEncoded
= OString(&cStrDelim
, 1, eCharSet
);
1938 aDelimEncoded
= OString(&cDelim
, 1, eCharSet
);
1939 rtl_TextEncodingInfo aInfo
;
1940 aInfo
.StructSize
= sizeof(aInfo
);
1941 if ( rtl_getTextEncodingInfo( eCharSet
, &aInfo
) )
1943 bContextOrNotAsciiEncoding
=
1944 (((aInfo
.Flags
& RTL_TEXTENCODING_INFO_CONTEXT
) != 0) ||
1945 ((aInfo
.Flags
& RTL_TEXTENCODING_INFO_ASCII
) == 0));
1946 if ( bContextOrNotAsciiEncoding
)
1948 aStrDelimDecoded
= OStringToOUString(aStrDelimEncoded
, eCharSet
);
1949 aDelimDecoded
= OStringToOUString(aDelimEncoded
, eCharSet
);
1953 bContextOrNotAsciiEncoding
= false;
1956 SCCOL nStartCol
= 0;
1957 SCROW nStartRow
= 0;
1960 m_aDocument
.GetCellArea( nTab
, nEndCol
, nEndRow
);
1962 ScProgress
aProgress( this, ScResId( STR_SAVE_DOC
), nEndRow
, true );
1966 bool bTabProtect
= m_aDocument
.IsTabProtected( nTab
);
1970 SCCOL nNextCol
= nStartCol
;
1971 SCROW nNextRow
= nStartRow
;
1974 SvNumberFormatter
& rFormatter
= *m_aDocument
.GetFormatTable();
1976 ScHorizontalCellIterator
aIter( m_aDocument
, nTab
, nStartCol
, nStartRow
,
1978 ScRefCellValue
* pCell
;
1979 while ( ( pCell
= aIter
.GetNext( nCol
, nRow
) ) != nullptr )
1981 bool bProgress
= false; // only upon line change
1982 if ( nNextRow
< nRow
)
1983 { // empty rows or/and empty columns up to end of row
1985 for ( nEmptyCol
= nNextCol
; nEmptyCol
< nEndCol
; nEmptyCol
++ )
1986 { // remaining columns of last row
1988 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream
,
1989 m_aDocument
, nTab
, nEmptyCol
);
1990 else if ( cDelim
!= 0 )
1991 rStream
.WriteUniOrByteChar( cDelim
);
1995 for ( nEmptyRow
= nNextRow
; nEmptyRow
< nRow
; nEmptyRow
++ )
1996 { // completely empty rows
1997 for ( nEmptyCol
= nStartCol
; nEmptyCol
< nEndCol
; nEmptyCol
++ )
2000 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream
,
2001 m_aDocument
, nTab
, nEmptyCol
);
2002 else if ( cDelim
!= 0 )
2003 rStream
.WriteUniOrByteChar( cDelim
);
2007 for ( nEmptyCol
= nStartCol
; nEmptyCol
< nCol
; nEmptyCol
++ )
2008 { // empty columns at beginning of row
2010 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream
,
2011 m_aDocument
, nTab
, nEmptyCol
);
2012 else if ( cDelim
!= 0 )
2013 rStream
.WriteUniOrByteChar( cDelim
);
2017 else if ( nNextCol
< nCol
)
2018 { // empty columns in same row
2019 for ( nEmptyCol
= nNextCol
; nEmptyCol
< nCol
; nEmptyCol
++ )
2020 { // columns in between
2022 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream
,
2023 m_aDocument
, nTab
, nEmptyCol
);
2024 else if ( cDelim
!= 0 )
2025 rStream
.WriteUniOrByteChar( cDelim
);
2028 if ( nCol
== nEndCol
)
2031 nNextCol
= nStartCol
;
2032 nNextRow
= nRow
+ 1;
2035 nNextCol
= nCol
+ 1;
2037 CellType eType
= pCell
->meType
;
2038 ScAddress
aPos(nCol
, nRow
, nTab
);
2041 const ScProtectionAttr
* pProtAttr
=
2042 m_aDocument
.GetAttr( nCol
, nRow
, nTab
, ATTR_PROTECTION
);
2043 if ( pProtAttr
->GetHideCell() ||
2044 ( eType
== CELLTYPE_FORMULA
&& bShowFormulas
&&
2045 pProtAttr
->GetHideFormula() ) )
2046 eType
= CELLTYPE_NONE
; // hide
2048 bool bForceQuotes
= false;
2056 case CELLTYPE_FORMULA
:
2058 FormulaError nErrCode
;
2059 if ( bShowFormulas
)
2061 pCell
->mpFormula
->GetFormula(aString
);
2064 else if ((nErrCode
= pCell
->mpFormula
->GetErrCode()) != FormulaError::NONE
)
2066 aString
= ScGlobal::GetErrorString( nErrCode
);
2069 else if (pCell
->mpFormula
->IsValue())
2071 sal_uInt32 nFormat
= m_aDocument
.GetNumberFormat(aPos
);
2072 if ( bFixedWidth
|| bSaveAsShown
)
2074 const Color
* pDummy
;
2075 ScCellFormat::GetString(*pCell
, nFormat
, aString
, &pDummy
, rFormatter
, m_aDocument
);
2076 bString
= bSaveAsShown
&& rFormatter
.IsTextFormat( nFormat
);
2080 ScCellFormat::GetInputString(*pCell
, nFormat
, aString
, rFormatter
, m_aDocument
);
2081 bString
= bForceQuotes
= !bSaveNumberAsSuch
;
2088 sal_uInt32 nFormat
= m_aDocument
.GetNumberFormat(aPos
);
2089 const Color
* pDummy
;
2090 ScCellFormat::GetString(*pCell
, nFormat
, aString
, &pDummy
, rFormatter
, m_aDocument
);
2093 aString
= pCell
->mpFormula
->GetString().getString();
2098 case CELLTYPE_STRING
:
2101 sal_uInt32 nFormat
= m_aDocument
.GetNumberFormat(aPos
);
2102 const Color
* pDummy
;
2103 ScCellFormat::GetString(*pCell
, nFormat
, aString
, &pDummy
, rFormatter
, m_aDocument
);
2106 aString
= pCell
->mpString
->getString();
2109 case CELLTYPE_EDIT
:
2111 const EditTextObject
* pObj
= pCell
->mpEditText
;
2112 EditEngine
& rEngine
= m_aDocument
.GetEditEngine();
2113 rEngine
.SetText( *pObj
);
2114 aString
= rEngine
.GetText(); // including LF
2118 case CELLTYPE_VALUE
:
2121 m_aDocument
.GetNumberFormat( nCol
, nRow
, nTab
, nFormat
);
2122 if ( bFixedWidth
|| bSaveAsShown
)
2124 const Color
* pDummy
;
2125 ScCellFormat::GetString(*pCell
, nFormat
, aString
, &pDummy
, rFormatter
, m_aDocument
);
2126 bString
= bSaveAsShown
&& rFormatter
.IsTextFormat( nFormat
);
2130 ScCellFormat::GetInputString(*pCell
, nFormat
, aString
, rFormatter
, m_aDocument
);
2131 bString
= bForceQuotes
= !bSaveNumberAsSuch
;
2136 OSL_FAIL( "ScDocShell::AsciiSave: unknown CellType" );
2143 SvxCellHorJustify eHorJust
=
2144 m_aDocument
.GetAttr( nCol
, nRow
, nTab
, ATTR_HOR_JUSTIFY
)->GetValue();
2145 lcl_ScDocShell_GetFixedWidthString( aString
, m_aDocument
, nTab
, nCol
,
2146 !bString
, eHorJust
);
2147 rStream
.WriteUnicodeOrByteText( aString
);
2151 OUString aUniString
= aString
;// TODO: remove that later
2152 if (!bString
&& cStrDelim
!= 0 && !aUniString
.isEmpty())
2154 sal_Unicode c
= aUniString
[0];
2155 bString
= (c
== cStrDelim
|| c
== ' ' ||
2156 aUniString
.endsWith(" ") ||
2157 aUniString
.indexOf(cStrDelim
) >= 0);
2158 if (!bString
&& cDelim
!= 0)
2159 bString
= (aUniString
.indexOf(cDelim
) >= 0);
2163 if ( cStrDelim
!= 0 ) //@ BugId 55355
2165 if ( eCharSet
== RTL_TEXTENCODING_UNICODE
)
2167 bool bNeedQuotes
= false;
2168 sal_Int32 nPos
= getTextSepPos(
2169 aUniString
, rAsciiOpt
, cStrDelim
, cDelim
, bNeedQuotes
);
2171 escapeTextSep
<OUString
, OUStringBuffer
>(
2172 nPos
, OUString(cStrDelim
), aUniString
);
2174 if ( bNeedQuotes
|| bForceQuotes
)
2175 rStream
.WriteUniOrByteChar( cStrDelim
, eCharSet
);
2176 write_uInt16s_FromOUString(rStream
, aUniString
);
2177 if ( bNeedQuotes
|| bForceQuotes
)
2178 rStream
.WriteUniOrByteChar( cStrDelim
, eCharSet
);
2182 // This is nasty. The Unicode to byte encoding
2183 // may convert typographical quotation marks to ASCII
2184 // quotation marks, which may interfere with the delimiter,
2185 // so we have to escape delimiters after the string has
2186 // been encoded. Since this may happen also with UTF-8
2187 // encoded typographical quotation marks if such was
2188 // specified as a delimiter we have to check for the full
2189 // encoded delimiter string, not just one character.
2190 // Now for RTL_TEXTENCODING_ISO_2022_... and similar brain
2191 // dead encodings where one code point (and especially a
2192 // low ASCII value) may represent different characters, we
2193 // have to convert forth and back and forth again. Same for
2194 // UTF-7 since it is a context sensitive encoding too.
2196 if ( bContextOrNotAsciiEncoding
)
2199 OString aStrEnc
= OUStringToOString(aUniString
, eCharSet
);
2201 OUString aStrDec
= OStringToOUString(aStrEnc
, eCharSet
);
2203 // search on re-decoded string
2204 bool bNeedQuotes
= false;
2205 sal_Int32 nPos
= getTextSepPos(
2206 aStrDec
, rAsciiOpt
, aStrDelimDecoded
, aDelimDecoded
, bNeedQuotes
);
2208 escapeTextSep
<OUString
, OUStringBuffer
>(
2209 nPos
, aStrDelimDecoded
, aStrDec
);
2211 // write byte re-encoded
2212 if ( bNeedQuotes
|| bForceQuotes
)
2213 rStream
.WriteUniOrByteChar( cStrDelim
, eCharSet
);
2214 rStream
.WriteUnicodeOrByteText( aStrDec
, eCharSet
);
2215 if ( bNeedQuotes
|| bForceQuotes
)
2216 rStream
.WriteUniOrByteChar( cStrDelim
, eCharSet
);
2220 OString aStrEnc
= OUStringToOString(aUniString
, eCharSet
);
2222 // search on encoded string
2223 bool bNeedQuotes
= false;
2224 sal_Int32 nPos
= getTextSepPos(
2225 aStrEnc
, rAsciiOpt
, aStrDelimEncoded
, aDelimEncoded
, bNeedQuotes
);
2227 escapeTextSep
<OString
, OStringBuffer
>(
2228 nPos
, aStrDelimEncoded
, aStrEnc
);
2230 // write byte encoded
2231 if ( bNeedQuotes
|| bForceQuotes
)
2233 aStrDelimEncoded
.getStr(), aStrDelimEncoded
.getLength());
2234 rStream
.WriteBytes(aStrEnc
.getStr(), aStrEnc
.getLength());
2235 if ( bNeedQuotes
|| bForceQuotes
)
2237 aStrDelimEncoded
.getStr(), aStrDelimEncoded
.getLength());
2242 rStream
.WriteUnicodeOrByteText( aUniString
);
2245 rStream
.WriteUnicodeOrByteText( aUniString
);
2248 if( nCol
< nEndCol
)
2250 if(cDelim
!=0) //@ BugId 55355
2251 rStream
.WriteUniOrByteChar( cDelim
);
2257 aProgress
.SetStateOnPercent( nRow
);
2260 // write out empty if requested
2261 if ( nNextRow
<= nEndRow
)
2263 for ( nEmptyCol
= nNextCol
; nEmptyCol
< nEndCol
; nEmptyCol
++ )
2264 { // remaining empty columns of last row
2266 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream
,
2267 m_aDocument
, nTab
, nEmptyCol
);
2268 else if ( cDelim
!= 0 )
2269 rStream
.WriteUniOrByteChar( cDelim
);
2274 for ( nEmptyRow
= nNextRow
; nEmptyRow
<= nEndRow
; nEmptyRow
++ )
2275 { // entire empty rows
2276 for ( nEmptyCol
= nStartCol
; nEmptyCol
< nEndCol
; nEmptyCol
++ )
2279 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream
,
2280 m_aDocument
, nTab
, nEmptyCol
);
2281 else if ( cDelim
!= 0 )
2282 rStream
.WriteUniOrByteChar( cDelim
);
2287 rStream
.SetStreamCharSet( eOldCharSet
);
2288 rStream
.SetEndian( nOldNumberFormatInt
);
2291 bool ScDocShell::ConvertTo( SfxMedium
&rMed
)
2293 ScRefreshTimerProtector
aProt( m_aDocument
.GetRefreshTimerControlAddress() );
2295 // #i6500# don't call DoEnterHandler here (doesn't work with AutoSave),
2296 // it's already in ExecuteSave (as for Save and SaveAs)
2298 if (m_pAutoStyleList
)
2299 m_pAutoStyleList
->ExecuteAllNow(); // Execute template timeouts now
2300 if (GetCreateMode()== SfxObjectCreateMode::STANDARD
)
2301 SfxObjectShell::SetVisArea( tools::Rectangle() ); // Edited normally -> no VisArea
2303 OSL_ENSURE( rMed
.GetFilter(), "Filter == 0" );
2306 OUString aFltName
= rMed
.GetFilter()->GetFilterName();
2308 if (aFltName
== pFilterXML
)
2310 //TODO/LATER: this shouldn't happen!
2311 OSL_FAIL("XML filter in ConvertFrom?!");
2312 bRet
= SaveXML( &rMed
, nullptr );
2314 else if (aFltName
== pFilterExcel5
|| aFltName
== pFilterExcel95
||
2315 aFltName
== pFilterExcel97
|| aFltName
== pFilterEx5Temp
||
2316 aFltName
== pFilterEx95Temp
|| aFltName
== pFilterEx97Temp
)
2318 weld::WaitObject
aWait( GetActiveDialogParent() );
2320 bool bDoSave
= true;
2321 if( ScTabViewShell
* pViewShell
= GetBestViewShell() )
2323 ScExtDocOptions
* pExtDocOpt
= m_aDocument
.GetExtDocOptions();
2326 m_aDocument
.SetExtDocOptions( std::make_unique
<ScExtDocOptions
>() );
2327 pExtDocOpt
= m_aDocument
.GetExtDocOptions();
2329 pViewShell
->GetViewData().WriteExtOptions( *pExtDocOpt
);
2331 /* #i104990# If the imported document contains a medium
2332 password, determine if we can save it, otherwise ask the users
2333 whether they want to save without it. */
2334 if( (rMed
.GetFilter()->GetFilterFlags() & SfxFilterFlags::ENCRYPTION
) == SfxFilterFlags::NONE
)
2336 SfxItemSet
* pItemSet
= rMed
.GetItemSet();
2337 const SfxPoolItem
* pItem
= nullptr;
2338 if( pItemSet
&& pItemSet
->GetItemState( SID_PASSWORD
, true, &pItem
) == SfxItemState::SET
)
2340 bDoSave
= ScWarnPassword::WarningOnPassword( rMed
);
2341 // #i42858# remove password from medium (warn only one time)
2343 pItemSet
->ClearItem( SID_PASSWORD
);
2349 bool bNeedRetypePassDlg
= ScPassHashHelper::needsPassHashRegen( m_aDocument
, PASSHASH_XL
);
2350 bDoSave
= !bNeedRetypePassDlg
|| pViewShell
->ExecuteRetypePassDlg( PASSHASH_XL
);
2356 ExportFormatExcel eFormat
= ExpBiff5
;
2357 if( aFltName
== pFilterExcel97
|| aFltName
== pFilterEx97Temp
)
2359 ErrCode eError
= ScFormatFilter::Get().ScExportExcel5( rMed
, &m_aDocument
, eFormat
, RTL_TEXTENCODING_MS_1252
);
2361 if( eError
&& !GetError() )
2364 // don't return false for warnings
2365 bRet
= eError
.IsWarning() || (eError
== ERRCODE_NONE
);
2369 // export aborted, i.e. "Save without password" warning
2370 SetError(ERRCODE_ABORT
);
2373 else if (aFltName
== pFilterAscii
)
2376 SfxItemSet
* pSet
= rMed
.GetItemSet();
2377 const SfxPoolItem
* pItem
;
2378 if ( pSet
&& SfxItemState::SET
==
2379 pSet
->GetItemState( SID_FILE_FILTEROPTIONS
, true, &pItem
) )
2381 sItStr
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
2384 if ( sItStr
.isEmpty() )
2386 // default for ascii export (from API without options):
2387 // ISO8859-1/MS_1252 encoding, comma, double quotes
2389 ScImportOptions
aDefOptions( ',', '"', RTL_TEXTENCODING_MS_1252
);
2390 sItStr
= aDefOptions
.BuildString();
2393 weld::WaitObject
aWait( GetActiveDialogParent() );
2394 ScImportOptions
aOptions( sItStr
);
2396 if (aOptions
.nSheetToExport
)
2398 // Only from command line --convert-to
2401 // Verbose only from command line, not UI (in case we actually
2402 // implement that) nor macro filter options.
2403 bool bVerbose
= false;
2404 const css::uno::Sequence
<css::beans::PropertyValue
> & rArgs
= rMed
.GetArgs();
2405 const auto pProp
= std::find_if( rArgs
.begin(), rArgs
.end(),
2406 [](const css::beans::PropertyValue
& rProp
) { return rProp
.Name
== "ConversionRequestOrigin"; });
2407 if (pProp
!= rArgs
.end())
2410 pProp
->Value
>>= aOrigin
;
2411 bVerbose
= (aOrigin
== "CommandLine");
2415 SCTAB nCount
= m_aDocument
.GetTableCount();
2416 if (aOptions
.nSheetToExport
== -1)
2421 else if (0 < aOptions
.nSheetToExport
&& aOptions
.nSheetToExport
<= nCount
)
2423 // One sheet, 1-based.
2424 nCount
= aOptions
.nSheetToExport
;
2425 nStartTab
= nCount
- 1;
2429 // Usage error, no export but log.
2432 if (aOptions
.nSheetToExport
< 0)
2433 std::cout
<< "Bad sheet number string given." << std::endl
;
2435 std::cout
<< "No sheet number " << aOptions
.nSheetToExport
2436 << ", number of sheets is " << nCount
<< std::endl
;
2440 SetError(SCERR_EXPORT_DATA
);
2444 INetURLObject
aURLObject(rMed
.GetURLObject());
2445 OUString sExt
= aURLObject
.CutExtension();
2446 OUString sBaseName
= aURLObject
.GetLastName();
2447 aURLObject
.CutLastName();
2449 for (SCTAB i
= nStartTab
; i
< nCount
; ++i
)
2452 if (!m_aDocument
.GetName(i
, sTabName
))
2453 sTabName
= OUString::number(i
);
2454 INetURLObject
aSheetURLObject(aURLObject
);
2455 OUString sFileName
= sBaseName
+ "-" + sTabName
;
2456 if (!sExt
.isEmpty())
2457 sFileName
= sFileName
+ "." + sExt
;
2458 aSheetURLObject
.Append(sFileName
);
2460 // log similar to DispatchWatcher::executeDispatchRequests
2461 OUString aOutFile
= aSheetURLObject
.GetMainURL(INetURLObject::DecodeMechanism::NONE
);
2464 OUString aDisplayedName
;
2465 if (osl::FileBase::E_None
!= osl::FileBase::getSystemPathFromFileURL(aOutFile
, aDisplayedName
))
2466 aDisplayedName
= aOutFile
;
2467 std::cout
<< "Writing sheet " << OUStringToOString(sTabName
, osl_getThreadTextEncoding()) << " -> "
2468 << OUStringToOString(aDisplayedName
, osl_getThreadTextEncoding())
2471 if (FStatHelper::IsDocument(aOutFile
))
2472 std::cout
<< "Overwriting: " << OUStringToOString(aDisplayedName
, osl_getThreadTextEncoding())
2476 std::unique_ptr
<SvStream
> xStm
= ::utl::UcbStreamHelper::CreateStream(aOutFile
, StreamMode::TRUNC
| StreamMode::WRITE
);
2479 SetError(ERRCODE_IO_CANTCREATE
);
2483 AsciiSave(*xStm
, aOptions
, i
);
2488 SvStream
* pStream
= rMed
.GetOutStream();
2491 AsciiSave(*pStream
, aOptions
, GetSaveTab());
2494 if (m_aDocument
.GetTableCount() > 1)
2495 if (!rMed
.GetError())
2496 rMed
.SetError(SCWARN_EXPORT_ASCII
);
2500 else if (aFltName
== pFilterDBase
)
2503 SfxItemSet
* pSet
= rMed
.GetItemSet();
2504 const SfxPoolItem
* pItem
;
2505 if ( pSet
&& SfxItemState::SET
==
2506 pSet
->GetItemState( SID_FILE_FILTEROPTIONS
, true, &pItem
) )
2508 sCharSet
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
2511 if (sCharSet
.isEmpty())
2513 // default for dBase export (from API without options):
2516 sCharSet
= ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_850
);
2519 weld::WaitObject
aWait( GetActiveDialogParent() );
2520 // Hack so that Sba can overwrite the opened TempFile.
2521 rMed
.CloseOutStream();
2522 bool bHasMemo
= false;
2524 ErrCode eError
= DBaseExport(
2525 rMed
.GetPhysicalName(), ScGlobal::GetCharsetValue(sCharSet
), bHasMemo
);
2527 INetURLObject
aTmpFile( rMed
.GetPhysicalName(), INetProtocol::File
);
2529 aTmpFile
.setExtension(u
"dbt");
2530 if ( eError
!= ERRCODE_NONE
&& !eError
.IsWarning() )
2534 if ( bHasMemo
&& IsDocument( aTmpFile
) )
2535 KillFile( aTmpFile
);
2542 const SfxStringItem
* pNameItem
= rMed
.GetItemSet()->GetItem
<SfxStringItem
>( SID_FILE_NAME
);
2543 INetURLObject
aDbtFile( pNameItem
->GetValue(), INetProtocol::File
);
2544 aDbtFile
.setExtension(u
"dbt");
2546 // tdf#40713: don't lose dbt file
2547 // if aDbtFile corresponds exactly to aTmpFile, we just have to return
2548 if (aDbtFile
.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous
) ==
2549 aTmpFile
.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous
))
2551 if (eError
!= ERRCODE_NONE
&& !GetError())
2556 if ( IsDocument( aDbtFile
) && !KillFile( aDbtFile
) )
2558 if ( bRet
&& !MoveFile( aTmpFile
, aDbtFile
) )
2562 KillFile( aTmpFile
);
2563 if (eError
== ERRCODE_NONE
|| eError
.IsWarning())
2564 eError
= SCERR_EXPORT_DATA
;
2567 if (eError
!= ERRCODE_NONE
&& !GetError())
2571 else if (aFltName
== pFilterDif
)
2573 SvStream
* pStream
= rMed
.GetOutStream();
2577 SfxItemSet
* pSet
= rMed
.GetItemSet();
2578 const SfxPoolItem
* pItem
;
2579 if ( pSet
&& SfxItemState::SET
==
2580 pSet
->GetItemState( SID_FILE_FILTEROPTIONS
, true, &pItem
) )
2582 sItStr
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
2585 if (sItStr
.isEmpty())
2587 // default for DIF export (from API without options):
2588 // ISO8859-1/MS_1252 encoding
2590 sItStr
= ScGlobal::GetCharsetString( RTL_TEXTENCODING_MS_1252
);
2593 weld::WaitObject
aWait( GetActiveDialogParent() );
2594 ScFormatFilter::Get().ScExportDif( *pStream
, &m_aDocument
, ScAddress(0,0,0),
2595 ScGlobal::GetCharsetValue(sItStr
) );
2598 if (m_aDocument
.GetTableCount() > 1)
2599 if (!rMed
.GetError())
2600 rMed
.SetError(SCWARN_EXPORT_ASCII
);
2603 else if (aFltName
== pFilterSylk
)
2605 SvStream
* pStream
= rMed
.GetOutStream();
2608 weld::WaitObject
aWait( GetActiveDialogParent() );
2612 m_aDocument
.GetCellArea( 0, nEndCol
, nEndRow
);
2613 ScRange
aRange( 0,0,0, nEndCol
,nEndRow
,0 );
2615 ScImportExport
aImExport( m_aDocument
, aRange
);
2616 aImExport
.SetFormulas( true );
2617 bRet
= aImExport
.ExportStream( *pStream
, rMed
.GetBaseURL( true ), SotClipboardFormatId::SYLK
);
2620 else if (aFltName
== pFilterHtml
)
2622 SvStream
* pStream
= rMed
.GetOutStream();
2625 SfxItemSet
* pSet
= rMed
.GetItemSet();
2626 const SfxPoolItem
* pItem
;
2627 OUString sFilterOptions
;
2629 if (pSet
->GetItemState(SID_FILE_FILTEROPTIONS
, true, &pItem
) == SfxItemState::SET
)
2630 sFilterOptions
= static_cast<const SfxStringItem
*>(pItem
)->GetValue();
2632 weld::WaitObject
aWait(GetActiveDialogParent());
2633 ScImportExport
aImExport(m_aDocument
);
2634 aImExport
.SetStreamPath(rMed
.GetName());
2635 aImExport
.SetFilterOptions(sFilterOptions
);
2636 bRet
= aImExport
.ExportStream(*pStream
, rMed
.GetBaseURL(true), SotClipboardFormatId::HTML
);
2637 if (bRet
&& !aImExport
.GetNonConvertibleChars().isEmpty())
2639 SetError(*new StringErrorInfo(
2640 SCWARN_EXPORT_NONCONVERTIBLE_CHARS
,
2641 aImExport
.GetNonConvertibleChars(),
2642 DialogMask::ButtonsOk
| DialogMask::MessageInfo
));
2649 SetError(SCERR_IMPORT_NI
);
2654 bool ScDocShell::DoSaveCompleted( SfxMedium
* pNewStor
, bool bRegisterRecent
)
2656 bool bRet
= SfxObjectShell::DoSaveCompleted( pNewStor
, bRegisterRecent
);
2658 // SfxHintId::ScDocSaved for change ReadOnly -> Read/Write
2659 Broadcast( SfxHint( SfxHintId::ScDocSaved
) );
2663 bool ScDocShell::QuerySlotExecutable( sal_uInt16 nSlotId
)
2665 // #i112634# ask VBA event handlers whether to save or print the document
2667 using namespace ::com::sun::star::script::vba
;
2669 sal_Int32 nVbaEventId
= VBAEventId::NO_EVENT
;
2670 uno::Sequence
< uno::Any
> aArgs
;
2675 nVbaEventId
= VBAEventId::WORKBOOK_BEFORESAVE
;
2677 aArgs
[ 0 ] <<= (nSlotId
== SID_SAVEASDOC
);
2680 case SID_PRINTDOCDIRECT
:
2681 nVbaEventId
= VBAEventId::WORKBOOK_BEFOREPRINT
;
2685 bool bSlotExecutable
= true;
2686 if( nVbaEventId
!= VBAEventId::NO_EVENT
) try
2688 uno::Reference
< XVBAEventProcessor
> xEventProcessor( m_aDocument
.GetVbaEventProcessor(), uno::UNO_SET_THROW
);
2689 xEventProcessor
->processVbaEvent( nVbaEventId
, aArgs
);
2691 catch( util::VetoException
& )
2693 bSlotExecutable
= false;
2695 catch( uno::Exception
& )
2698 return bSlotExecutable
;
2701 bool ScDocShell::PrepareClose( bool bUI
)
2703 if(SC_MOD()->GetCurRefDlgId()>0)
2705 SfxViewFrame
* pFrame
= SfxViewFrame::GetFirst( this );
2708 SfxViewShell
* p
= pFrame
->GetViewShell();
2709 ScTabViewShell
* pViewSh
= dynamic_cast< ScTabViewShell
*>( p
);
2710 if(pViewSh
!=nullptr)
2712 vcl::Window
*pWin
=pViewSh
->GetWindow();
2713 if(pWin
!=nullptr) pWin
->GrabFocus();
2719 if ( m_aDocument
.IsInLinkUpdate() || m_aDocument
.IsInInterpreter() )
2721 ErrorMessage(STR_CLOSE_ERROR_LINK
);
2727 // start 'Workbook_BeforeClose' VBA event handler for possible veto
2728 if( !IsInPrepareClose() )
2732 uno::Reference
< script::vba::XVBAEventProcessor
> xVbaEvents( m_aDocument
.GetVbaEventProcessor(), uno::UNO_SET_THROW
);
2733 uno::Sequence
< uno::Any
> aArgs
;
2734 xVbaEvents
->processVbaEvent( script::vba::VBAEventId::WORKBOOK_BEFORECLOSE
, aArgs
);
2736 catch( util::VetoException
& )
2738 // if event processor throws VetoException, macro has vetoed close
2741 catch( uno::Exception
& )
2747 bool bRet
= SfxObjectShell::PrepareClose( bUI
);
2748 if (bRet
) // true == close
2749 m_aDocument
.EnableIdle(false); // Do not mess around with it anymore!
2754 OUString
ScDocShell::GetOwnFilterName()
2759 OUString
ScDocShell::GetHtmlFilterName()
2764 OUString
ScDocShell::GetWebQueryFilterName()
2766 return pFilterHtmlWebQ
;
2769 OUString
ScDocShell::GetAsciiFilterName()
2771 return pFilterAscii
;
2774 OUString
ScDocShell::GetLotusFilterName()
2776 return pFilterLotus
;
2779 OUString
ScDocShell::GetDBaseFilterName()
2781 return pFilterDBase
;
2784 OUString
ScDocShell::GetDifFilterName()
2789 bool ScDocShell::HasAutomaticTableName( std::u16string_view rFilter
)
2791 // sal_True for those filters that keep the default table name
2792 // (which is language specific)
2794 return rFilter
== pFilterAscii
2795 || rFilter
== pFilterLotus
2796 || rFilter
== pFilterExcel4
2797 || rFilter
== pFilterEx4Temp
2798 || rFilter
== pFilterDBase
2799 || rFilter
== pFilterDif
2800 || rFilter
== pFilterSylk
2801 || rFilter
== pFilterHtml
2802 || rFilter
== pFilterRtf
;
2805 std::unique_ptr
<ScDocFunc
> ScDocShell::CreateDocFunc()
2807 return std::make_unique
<ScDocFuncDirect
>( *this );
2810 ScDocShell::ScDocShell( const SfxModelFlags i_nSfxCreationFlags
) :
2811 SfxObjectShell( i_nSfxCreationFlags
),
2812 m_aDocument ( SCDOCMODE_DOCUMENT
, this ),
2813 m_aDdeTextFmt(OUString("TEXT")),
2814 m_nPrtToScreenFactor( 1.0 ),
2815 m_pImpl ( new DocShell_Impl
),
2816 m_bHeaderOn ( true ),
2817 m_bFooterOn ( true ),
2818 m_bIsEmpty ( true ),
2819 m_bIsInUndo ( false ),
2820 m_bDocumentModifiedPending( false ),
2821 m_bUpdateEnabled ( true ),
2822 m_bUcalcTest ( false ),
2823 m_bAreasChangedNeedBroadcast( false ),
2824 m_nDocumentLock ( 0 ),
2825 m_nCanUpdate (css::document::UpdateDocMode::ACCORDING_TO_CONFIG
)
2827 SetPool( &SC_MOD()->GetPool() );
2829 m_bIsInplace
= (GetCreateMode() == SfxObjectCreateMode::EMBEDDED
);
2830 // Will be reset if not in place
2832 m_pDocFunc
= CreateDocFunc();
2834 // SetBaseModel needs exception handling
2835 ScModelObj::CreateAndSet( this );
2837 StartListening(*this);
2838 SfxStyleSheetPool
* pStlPool
= m_aDocument
.GetStyleSheetPool();
2840 StartListening(*pStlPool
);
2842 m_aDocument
.GetDBCollection()->SetRefreshHandler(
2843 LINK( this, ScDocShell
, RefreshDBDataHdl
) );
2845 // InitItems and CalcOutputFactor are called now in Load/ConvertFrom/InitNew
2848 ScDocShell::~ScDocShell()
2850 ResetDrawObjectShell(); // If the Drawing Layer still tries to access it, access it
2852 SfxStyleSheetPool
* pStlPool
= m_aDocument
.GetStyleSheetPool();
2854 EndListening(*pStlPool
);
2855 EndListening(*this);
2857 m_pAutoStyleList
.reset();
2859 SfxApplication
*pSfxApp
= SfxGetpApp();
2860 if ( pSfxApp
->GetDdeService() ) // Delete DDE for Document
2861 pSfxApp
->RemoveDdeTopic( this );
2864 delete m_aDocument
.mpUndoManager
;
2865 m_aDocument
.mpUndoManager
= nullptr;
2868 m_pPaintLockData
.reset();
2870 m_pSolverSaveData
.reset();
2871 m_pSheetSaveData
.reset();
2872 m_pFormatSaveData
.reset();
2873 m_pOldAutoDBRange
.reset();
2877 OSL_FAIL("The Modificator should not exist");
2878 m_pModificator
.reset();
2882 SfxUndoManager
* ScDocShell::GetUndoManager()
2884 return m_aDocument
.GetUndoManager();
2887 void ScDocShell::SetModified( bool bModified
)
2889 if ( SfxObjectShell::IsEnableSetModified() )
2891 SfxObjectShell::SetModified( bModified
);
2892 Broadcast( SfxHint( SfxHintId::DocChanged
) );
2896 void ScDocShell::SetDocumentModified()
2898 // BroadcastUno must also happen right away with pPaintLockData
2899 // FIXME: Also for SetDrawModified, if Drawing is connected
2900 // FIXME: Then own Hint?
2902 if ( m_pPaintLockData
)
2904 // #i115009# broadcast BCA_BRDCST_ALWAYS, so a component can read recalculated results
2905 // of RecalcModeAlways formulas (like OFFSET) after modifying cells
2906 m_aDocument
.Broadcast(ScHint(SfxHintId::ScDataChanged
, BCA_BRDCST_ALWAYS
));
2907 m_aDocument
.InvalidateTableArea(); // #i105279# needed here
2908 m_aDocument
.BroadcastUno( SfxHint( SfxHintId::DataChanged
) );
2910 m_pPaintLockData
->SetModified(); // Later on ...
2916 if ( m_aDocument
.IsAutoCalcShellDisabled() )
2917 SetDocumentModifiedPending( true );
2920 SetDocumentModifiedPending( false );
2921 m_aDocument
.InvalidateStyleSheetUsage();
2922 m_aDocument
.InvalidateTableArea();
2923 m_aDocument
.InvalidateLastTableOpParams();
2924 m_aDocument
.Broadcast(ScHint(SfxHintId::ScDataChanged
, BCA_BRDCST_ALWAYS
));
2925 if ( m_aDocument
.IsForcedFormulaPending() && m_aDocument
.GetAutoCalc() )
2926 m_aDocument
.CalcFormulaTree( true );
2927 m_aDocument
.RefreshDirtyTableColumnNames();
2930 // Detective AutoUpdate:
2931 // Update if formulas were modified (DetectiveDirty) or the list contains
2932 // "Trace Error" entries (Trace Error can look completely different
2933 // after changes to non-formula cells).
2935 ScDetOpList
* pList
= m_aDocument
.GetDetOpList();
2936 if ( pList
&& ( m_aDocument
.IsDetectiveDirty() || pList
->HasAddError() ) &&
2937 pList
->Count() && !IsInUndo() && SC_MOD()->GetAppOptions().GetDetectiveAuto() )
2939 GetDocFunc().DetectiveRefresh(true); // sal_True = caused by automatic update
2941 m_aDocument
.SetDetectiveDirty(false); // always reset, also if not refreshed
2944 if (m_bAreasChangedNeedBroadcast
)
2946 m_bAreasChangedNeedBroadcast
= false;
2947 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged
));
2950 // notify UNO objects after BCA_BRDCST_ALWAYS etc.
2951 m_aDocument
.BroadcastUno( SfxHint( SfxHintId::DataChanged
) );
2955 * SetDrawModified - without Formula update
2957 * Drawing also needs to be updated for the normal SetDocumentModified
2958 * e.g.: when deleting tables etc.
2960 void ScDocShell::SetDrawModified()
2962 bool bUpdate
= !IsModified();
2966 SfxBindings
* pBindings
= GetViewBindings();
2967 if (bUpdate
&& pBindings
)
2969 pBindings
->Invalidate( SID_SAVEDOC
);
2970 pBindings
->Invalidate( SID_DOC_MODIFIED
);
2975 // #i105960# Undo etc used to be volatile.
2976 // They always have to be invalidated, including drawing layer or row height changes
2977 // (but not while pPaintLockData is set).
2978 pBindings
->Invalidate( SID_UNDO
);
2979 pBindings
->Invalidate( SID_REDO
);
2980 pBindings
->Invalidate( SID_REPEAT
);
2983 if ( m_aDocument
.IsChartListenerCollectionNeedsUpdate() )
2985 m_aDocument
.UpdateChartListenerCollection();
2986 SfxGetpApp()->Broadcast(SfxHint( SfxHintId::ScDrawChanged
)); // Navigator
2988 SC_MOD()->AnythingChanged();
2991 void ScDocShell::SetInUndo(bool bSet
)
2996 void ScDocShell::GetDocStat( ScDocStat
& rDocStat
)
2998 SfxPrinter
* pPrinter
= GetPrinter();
3000 m_aDocument
.GetDocStat( rDocStat
);
3001 rDocStat
.nPageCount
= 0;
3004 for ( SCTAB i
=0; i
<rDocStat
.nTableCount
; i
++ )
3005 rDocStat
.nPageCount
= sal::static_int_cast
<sal_uInt16
>( rDocStat
.nPageCount
+
3006 static_cast<sal_uInt16
>(ScPrintFunc( this, pPrinter
, i
).GetTotalPages()) );
3009 std::shared_ptr
<SfxDocumentInfoDialog
> ScDocShell::CreateDocumentInfoDialog(weld::Window
* pParent
, const SfxItemSet
&rSet
)
3011 std::shared_ptr
<SfxDocumentInfoDialog
> xDlg
= std::make_shared
<SfxDocumentInfoDialog
>(pParent
, rSet
);
3012 ScDocShell
* pDocSh
= dynamic_cast< ScDocShell
*>( SfxObjectShell::Current() );
3014 // Only for statistics, if this Doc is shown; not from the Doc Manager
3015 if( pDocSh
== this )
3017 ScAbstractDialogFactory
* pFact
= ScAbstractDialogFactory::Create();
3018 ::CreateTabPage ScDocStatPageCreate
= pFact
->GetTabPageCreatorFunc(SID_SC_TP_STAT
);
3019 OSL_ENSURE(ScDocStatPageCreate
, "Tabpage create fail!");
3020 xDlg
->AddFontTabPage();
3021 xDlg
->AddTabPage("calcstats", ScResId(STR_DOC_STAT
), ScDocStatPageCreate
);
3026 weld::Window
* ScDocShell::GetActiveDialogParent()
3028 ScTabViewShell
* pViewSh
= ScTabViewShell::GetActiveViewShell();
3030 return pViewSh
->GetDialogParent();
3031 vcl::Window
* pRet
= Application::GetDefDialogParent();
3032 return pRet
? pRet
->GetFrameWeld() : nullptr;
3035 void ScDocShell::SetSolverSaveData( std::unique_ptr
<ScOptSolverSave
> pData
)
3037 m_pSolverSaveData
= std::move(pData
);
3040 ScSheetSaveData
* ScDocShell::GetSheetSaveData()
3042 if (!m_pSheetSaveData
)
3043 m_pSheetSaveData
.reset( new ScSheetSaveData
);
3045 return m_pSheetSaveData
.get();
3048 ScFormatSaveData
* ScDocShell::GetFormatSaveData()
3050 if (!m_pFormatSaveData
)
3051 m_pFormatSaveData
.reset( new ScFormatSaveData
);
3053 return m_pFormatSaveData
.get();
3058 void removeKeysIfExists(const Reference
<ui::XAcceleratorConfiguration
>& xScAccel
, const vector
<const awt::KeyEvent
*>& rKeys
)
3060 for (const awt::KeyEvent
* p
: rKeys
)
3067 xScAccel
->removeKeyEvent(*p
);
3069 catch (const container::NoSuchElementException
&) {}
3075 void ScDocShell::ResetKeyBindings( ScOptionsUtil::KeyBindingType eType
)
3077 using namespace ::com::sun::star::ui
;
3079 Reference
<uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
3083 Reference
<XModuleUIConfigurationManagerSupplier
> xModuleCfgSupplier(
3084 theModuleUIConfigurationManagerSupplier::get(xContext
) );
3086 // Grab the Calc configuration.
3087 Reference
<XUIConfigurationManager
> xConfigMgr
=
3088 xModuleCfgSupplier
->getUIConfigurationManager(
3089 "com.sun.star.sheet.SpreadsheetDocument");
3091 if (!xConfigMgr
.is())
3095 Reference
<XAcceleratorConfiguration
> xScAccel
= xConfigMgr
->getShortCutManager();
3100 vector
<const awt::KeyEvent
*> aKeys
;
3104 awt::KeyEvent aBackspace
;
3105 aBackspace
.KeyCode
= awt::Key::BACKSPACE
;
3106 aBackspace
.Modifiers
= 0;
3107 aKeys
.push_back(&aBackspace
);
3110 awt::KeyEvent aDelete
;
3111 aDelete
.KeyCode
= awt::Key::DELETE
;
3112 aDelete
.Modifiers
= 0;
3113 aKeys
.push_back(&aDelete
);
3116 awt::KeyEvent aCtrlD
;
3117 aCtrlD
.KeyCode
= awt::Key::D
;
3118 aCtrlD
.Modifiers
= awt::KeyModifier::MOD1
;
3119 aKeys
.push_back(&aCtrlD
);
3122 awt::KeyEvent aAltDown
;
3123 aAltDown
.KeyCode
= awt::Key::DOWN
;
3124 aAltDown
.Modifiers
= awt::KeyModifier::MOD2
;
3125 aKeys
.push_back(&aAltDown
);
3128 awt::KeyEvent aCtrlSpace
;
3129 aCtrlSpace
.KeyCode
= awt::Key::SPACE
;
3130 aCtrlSpace
.Modifiers
= awt::KeyModifier::MOD1
;
3131 aKeys
.push_back(&aCtrlSpace
);
3134 awt::KeyEvent aCtrlShiftSpace
;
3135 aCtrlShiftSpace
.KeyCode
= awt::Key::SPACE
;
3136 aCtrlShiftSpace
.Modifiers
= awt::KeyModifier::MOD1
| awt::KeyModifier::SHIFT
;
3137 aKeys
.push_back(&aCtrlShiftSpace
);
3141 aF4
.KeyCode
= awt::Key::F4
;
3143 aKeys
.push_back(&aF4
);
3146 awt::KeyEvent aCtrlShiftF4
;
3147 aCtrlShiftF4
.KeyCode
= awt::Key::F4
;
3148 aCtrlShiftF4
.Modifiers
= awt::KeyModifier::MOD1
| awt::KeyModifier::SHIFT
;
3149 aKeys
.push_back(&aCtrlShiftF4
);
3152 awt::KeyEvent aShiftF4
;
3153 aShiftF4
.KeyCode
= awt::Key::F4
;
3154 aShiftF4
.Modifiers
= awt::KeyModifier::SHIFT
;
3155 aKeys
.push_back(&aShiftF4
);
3157 // Remove all involved keys first, because swapping commands don't work
3158 // well without doing this.
3159 removeKeysIfExists(xScAccel
, aKeys
);
3164 case ScOptionsUtil::KEY_DEFAULT
:
3165 xScAccel
->setKeyEvent(aDelete
, ".uno:ClearContents");
3166 xScAccel
->setKeyEvent(aBackspace
, ".uno:Delete");
3167 xScAccel
->setKeyEvent(aCtrlD
, ".uno:FillDown");
3168 xScAccel
->setKeyEvent(aAltDown
, ".uno:DataSelect");
3169 xScAccel
->setKeyEvent(aCtrlSpace
, ".uno:SelectColumn");
3170 xScAccel
->setKeyEvent(aCtrlShiftSpace
, ".uno:SelectAll");
3171 xScAccel
->setKeyEvent(aF4
, ".uno:ToggleRelative");
3172 xScAccel
->setKeyEvent(aCtrlShiftF4
, ".uno:ViewDataSourceBrowser");
3174 case ScOptionsUtil::KEY_OOO_LEGACY
:
3175 xScAccel
->setKeyEvent(aDelete
, ".uno:Delete");
3176 xScAccel
->setKeyEvent(aBackspace
, ".uno:ClearContents");
3177 xScAccel
->setKeyEvent(aCtrlD
, ".uno:DataSelect");
3178 xScAccel
->setKeyEvent(aCtrlShiftSpace
, ".uno:SelectColumn");
3179 xScAccel
->setKeyEvent(aF4
, ".uno:ViewDataSourceBrowser");
3180 xScAccel
->setKeyEvent(aShiftF4
, ".uno:ToggleRelative");
3189 void ScDocShell::UseSheetSaveEntries()
3191 if (!m_pSheetSaveData
)
3194 m_pSheetSaveData
->UseSaveEntries(); // use positions from saved file for next saving
3196 bool bHasEntries
= false;
3197 SCTAB nTabCount
= m_aDocument
.GetTableCount();
3199 for (nTab
= 0; nTab
< nTabCount
; ++nTab
)
3200 if (m_pSheetSaveData
->HasStreamPos(nTab
))
3205 // if no positions were set (for example, export to other format),
3206 // reset all "valid" flags
3207 for (nTab
= 0; nTab
< nTabCount
; ++nTab
)
3208 m_aDocument
.SetStreamValid(nTab
, false);
3212 // --- ScDocShellModificator ------------------------------------------
3214 ScDocShellModificator::ScDocShellModificator( ScDocShell
& rDS
)
3217 mpProtector(new ScRefreshTimerProtector(rDS
.GetDocument().GetRefreshTimerControlAddress()))
3219 ScDocument
& rDoc
= rDocShell
.GetDocument();
3220 bAutoCalcShellDisabled
= rDoc
.IsAutoCalcShellDisabled();
3221 bIdleEnabled
= rDoc
.IsIdleEnabled();
3222 rDoc
.SetAutoCalcShellDisabled( true );
3223 rDoc
.EnableIdle(false);
3226 ScDocShellModificator::~ScDocShellModificator() COVERITY_NOEXCEPT_FALSE
3228 ScDocument
& rDoc
= rDocShell
.GetDocument();
3229 rDoc
.SetAutoCalcShellDisabled( bAutoCalcShellDisabled
);
3230 if ( !bAutoCalcShellDisabled
&& rDocShell
.IsDocumentModifiedPending() )
3231 rDocShell
.SetDocumentModified(); // last one shuts off the lights
3232 rDoc
.EnableIdle(bIdleEnabled
);
3235 void ScDocShellModificator::SetDocumentModified()
3237 ScDocument
& rDoc
= rDocShell
.GetDocument();
3238 rDoc
.PrepareFormulaCalc();
3239 if ( !rDoc
.IsImportingXML() )
3241 // temporarily restore AutoCalcShellDisabled
3242 bool bDisabled
= rDoc
.IsAutoCalcShellDisabled();
3243 rDoc
.SetAutoCalcShellDisabled( bAutoCalcShellDisabled
);
3244 rDocShell
.SetDocumentModified();
3245 rDoc
.SetAutoCalcShellDisabled( bDisabled
);
3249 // uno broadcast is necessary for api to work
3250 // -> must also be done during xml import
3251 rDoc
.BroadcastUno( SfxHint( SfxHintId::DataChanged
) );
3255 bool ScDocShell::IsChangeRecording() const
3257 ScChangeTrack
* pChangeTrack
= m_aDocument
.GetChangeTrack();
3258 return pChangeTrack
!= nullptr;
3261 bool ScDocShell::HasChangeRecordProtection() const
3264 ScChangeTrack
* pChangeTrack
= m_aDocument
.GetChangeTrack();
3266 bRes
= pChangeTrack
->IsProtected();
3270 void ScDocShell::SetChangeRecording( bool bActivate
, bool /*bLockAllViews*/ )
3272 bool bOldChangeRecording
= IsChangeRecording();
3276 m_aDocument
.StartChangeTracking();
3277 ScChangeViewSettings aChangeViewSet
;
3278 aChangeViewSet
.SetShowChanges(true);
3279 m_aDocument
.SetChangeViewSettings(aChangeViewSet
);
3283 m_aDocument
.EndChangeTracking();
3287 if (bOldChangeRecording
!= IsChangeRecording())
3289 UpdateAcceptChangesDialog();
3291 SfxBindings
* pBindings
= GetViewBindings();
3293 pBindings
->InvalidateAll(false);
3297 void ScDocShell::SetProtectionPassword( const OUString
&rNewPassword
)
3299 ScChangeTrack
* pChangeTrack
= m_aDocument
.GetChangeTrack();
3303 bool bProtected
= pChangeTrack
->IsProtected();
3305 if (!rNewPassword
.isEmpty())
3307 // when password protection is applied change tracking must always be active
3308 SetChangeRecording( true );
3310 css::uno::Sequence
< sal_Int8
> aProtectionHash
;
3311 SvPasswordHelper::GetHashPassword( aProtectionHash
, rNewPassword
);
3312 pChangeTrack
->SetProtection( aProtectionHash
);
3316 pChangeTrack
->SetProtection( css::uno::Sequence
< sal_Int8
>() );
3319 if ( bProtected
!= pChangeTrack
->IsProtected() )
3321 UpdateAcceptChangesDialog();
3322 SetDocumentModified();
3326 bool ScDocShell::GetProtectionHash( /*out*/ css::uno::Sequence
< sal_Int8
> &rPasswordHash
)
3329 ScChangeTrack
* pChangeTrack
= m_aDocument
.GetChangeTrack();
3330 if (pChangeTrack
&& pChangeTrack
->IsProtected())
3332 rPasswordHash
= pChangeTrack
->GetProtection();
3338 void ScDocShell::SetIsInUcalc()
3340 m_bUcalcTest
= true;
3343 void ScDocShell::RegisterAutomationWorkbookObject(css::uno::Reference
< ooo::vba::excel::XWorkbook
> const& xWorkbook
)
3345 mxAutomationWorkbookObject
= xWorkbook
;
3348 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportSLK(SvStream
&rStream
)
3351 ScDocument aDocument
;
3352 ScDocOptions aDocOpt
= aDocument
.GetDocOptions();
3353 aDocOpt
.SetLookUpColRowNames(false);
3354 aDocument
.SetDocOptions(aDocOpt
);
3355 aDocument
.MakeTable(0);
3356 aDocument
.EnableExecuteLink(false);
3357 aDocument
.SetInsertingFromOtherDoc(true);
3358 aDocument
.SetImportingXML(true);
3360 ScImportExport
aImpEx(aDocument
);
3361 return aImpEx
.ImportStream(rStream
, OUString(), SotClipboardFormatId::SYLK
);
3364 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */