nss: upgrade to release 3.73
[LibreOffice.git] / sc / source / ui / docshell / docsh.cxx
blobe588494e30552f9a28708a490a201b00ecb5c7ed
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <docsh.hxx>
22 #include <config_features.h>
23 #include <scitems.hxx>
24 #include <sc.hrc>
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/sharecontrolfile.hxx>
48 #include <svl/urihelper.hxx>
49 #include <osl/file.hxx>
50 #include <chgtrack.hxx>
51 #include <chgviset.hxx>
52 #include <com/sun/star/awt/Key.hpp>
53 #include <com/sun/star/awt/KeyModifier.hpp>
54 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
55 #include <com/sun/star/document/UpdateDocMode.hpp>
56 #include <com/sun/star/script/vba/VBAEventId.hpp>
57 #include <com/sun/star/script/vba/VBAScriptEventId.hpp>
58 #include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
59 #include <com/sun/star/script/vba/XVBAScriptListener.hpp>
60 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
61 #include <com/sun/star/sheet/XSpreadsheetView.hpp>
62 #include <com/sun/star/task/XJob.hpp>
63 #include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
64 #include <com/sun/star/ui/XAcceleratorConfiguration.hpp>
65 #include <com/sun/star/util/VetoException.hpp>
66 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
67 #include <ooo/vba/excel/XWorkbook.hpp>
69 #include <config_folders.h>
71 #include <scabstdlg.hxx>
72 #include <sot/formats.hxx>
73 #include <svx/dialogs.hrc>
75 #include <formulacell.hxx>
76 #include <global.hxx>
77 #include <filter.hxx>
78 #include <scmod.hxx>
79 #include <tabvwsh.hxx>
80 #include <docfunc.hxx>
81 #include <imoptdlg.hxx>
82 #include <impex.hxx>
83 #include <scresid.hxx>
84 #include <strings.hrc>
85 #include <globstr.hrc>
86 #include <scerrors.hxx>
87 #include <brdcst.hxx>
88 #include <stlpool.hxx>
89 #include <autostyl.hxx>
90 #include <attrib.hxx>
91 #include <asciiopt.hxx>
92 #include <progress.hxx>
93 #include <pntlock.hxx>
94 #include <docuno.hxx>
95 #include <appoptio.hxx>
96 #include <formulaopt.hxx>
97 #include <scdll.hxx>
98 #include <detdata.hxx>
99 #include <printfun.hxx>
100 #include <dociter.hxx>
101 #include <cellform.hxx>
102 #include <chartlis.hxx>
103 #include <hints.hxx>
104 #include <xmlwrap.hxx>
105 #include <drwlayer.hxx>
106 #include <dbdata.hxx>
107 #include <scextopt.hxx>
108 #include <compiler.hxx>
109 #include <warnpassword.hxx>
110 #include <optsolver.hxx>
111 #include <sheetdata.hxx>
112 #include <tabprotection.hxx>
113 #include <docparam.hxx>
114 #include "docshimp.hxx"
115 #include <sizedev.hxx>
116 #include <refreshtimerprotector.hxx>
118 #include <officecfg/Office/Calc.hxx>
119 #include <comphelper/processfactory.hxx>
120 #include <comphelper/string.hxx>
121 #include <unotools/configmgr.hxx>
122 #include <uiitems.hxx>
123 #include <dpobject.hxx>
124 #include <markdata.hxx>
125 #include <docoptio.hxx>
126 #include <orcusfilters.hxx>
127 #include <datastream.hxx>
128 #include <documentlinkmgr.hxx>
129 #include <refupdatecontext.hxx>
131 #include <memory>
132 #include <vector>
134 using namespace com::sun::star;
135 using ::com::sun::star::uno::Reference;
136 using ::com::sun::star::lang::XMultiServiceFactory;
137 using std::shared_ptr;
138 using ::std::vector;
140 // Filter names (like in sclib.cxx)
142 const char pFilterSc50[] = "StarCalc 5.0";
143 const char pFilterXML[] = "StarOffice XML (Calc)";
144 const char pFilterAscii[] = SC_TEXT_CSV_FILTER_NAME;
145 const char pFilterLotus[] = "Lotus";
146 const char pFilterQPro6[] = "Quattro Pro 6.0";
147 const char pFilterExcel4[] = "MS Excel 4.0";
148 const char pFilterEx4Temp[] = "MS Excel 4.0 Vorlage/Template";
149 const char pFilterExcel5[] = "MS Excel 5.0/95";
150 const char pFilterEx5Temp[] = "MS Excel 5.0/95 Vorlage/Template";
151 const char pFilterExcel95[] = "MS Excel 95";
152 const char pFilterEx95Temp[] = "MS Excel 95 Vorlage/Template";
153 const char pFilterExcel97[] = "MS Excel 97";
154 const char pFilterEx97Temp[] = "MS Excel 97 Vorlage/Template";
155 const char pFilterDBase[] = "dBase";
156 const char pFilterDif[] = "DIF";
157 const char pFilterSylk[] = "SYLK";
158 const char pFilterHtml[] = "HTML (StarCalc)";
159 const char pFilterHtmlWebQ[] = "calc_HTML_WebQuery";
160 const char pFilterRtf[] = "Rich Text Format (StarCalc)";
162 #define ShellClass_ScDocShell
163 #include <scslots.hxx>
165 SFX_IMPL_INTERFACE(ScDocShell,SfxObjectShell)
167 void ScDocShell::InitInterface_Impl()
171 // GlobalName of the current version:
172 SFX_IMPL_OBJECTFACTORY( ScDocShell, SvGlobalName(SO3_SC_CLASSID), "scalc" )
175 void ScDocShell::FillClass( SvGlobalName* pClassName,
176 SotClipboardFormatId* pFormat,
177 OUString* pFullTypeName,
178 sal_Int32 nFileFormat,
179 bool bTemplate /* = false */) const
181 if ( nFileFormat == SOFFICE_FILEFORMAT_60 )
183 *pClassName = SvGlobalName( SO3_SC_CLASSID_60 );
184 *pFormat = SotClipboardFormatId::STARCALC_60;
185 *pFullTypeName = ScResId( SCSTR_LONG_SCDOC_NAME_60 );
187 else if ( nFileFormat == SOFFICE_FILEFORMAT_8 )
189 *pClassName = SvGlobalName( SO3_SC_CLASSID_60 );
190 *pFormat = bTemplate ? SotClipboardFormatId::STARCALC_8_TEMPLATE : SotClipboardFormatId::STARCALC_8;
191 *pFullTypeName = ScResId( SCSTR_LONG_SCDOC_NAME_80 );
193 else
195 OSL_FAIL("Which version?");
199 std::set<Color> ScDocShell::GetDocColors()
201 return m_aDocument.GetDocColors();
204 void ScDocShell::DoEnterHandler()
206 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
207 if (pViewSh && pViewSh->GetViewData().GetDocShell() == this)
208 SC_MOD()->InputEnterHandler();
211 SCTAB ScDocShell::GetSaveTab()
213 SCTAB nTab = 0;
214 ScTabViewShell* pSh = GetBestViewShell();
215 if (pSh)
217 const ScMarkData& rMark = pSh->GetViewData().GetMarkData();
218 nTab = rMark.GetFirstSelected();
220 return nTab;
223 HiddenInformation ScDocShell::GetHiddenInformationState( HiddenInformation nStates )
225 // get global state like HiddenInformation::DOCUMENTVERSIONS
226 HiddenInformation nState = SfxObjectShell::GetHiddenInformationState( nStates );
228 if ( nStates & HiddenInformation::RECORDEDCHANGES )
230 if ( m_aDocument.GetChangeTrack() && m_aDocument.GetChangeTrack()->GetFirst() )
231 nState |= HiddenInformation::RECORDEDCHANGES;
233 if ( nStates & HiddenInformation::NOTES )
235 SCTAB nTableCount = m_aDocument.GetTableCount();
236 bool bFound = false;
237 for (SCTAB nTab = 0; nTab < nTableCount && !bFound; ++nTab)
239 if (m_aDocument.HasTabNotes(nTab)) //TODO:
240 bFound = true;
243 if (bFound)
244 nState |= HiddenInformation::NOTES;
247 return nState;
250 void ScDocShell::BeforeXMLLoading()
252 m_aDocument.EnableIdle(false);
254 // prevent unnecessary broadcasts and updates
255 OSL_ENSURE(m_pModificator == nullptr, "The Modificator should not exist");
256 m_pModificator.reset( new ScDocShellModificator( *this ) );
258 m_aDocument.SetImportingXML( true );
259 m_aDocument.EnableExecuteLink( false ); // #i101304# to be safe, prevent nested loading from external references
260 m_aDocument.EnableUndo( false );
261 // prevent unnecessary broadcasts and "half way listeners"
262 m_aDocument.SetInsertingFromOtherDoc( true );
265 void ScDocShell::AfterXMLLoading(bool bRet)
267 if (GetCreateMode() != SfxObjectCreateMode::ORGANIZER)
269 UpdateLinks();
270 // don't prevent establishing of listeners anymore
271 m_aDocument.SetInsertingFromOtherDoc( false );
272 if ( bRet )
274 ScChartListenerCollection* pChartListener = m_aDocument.GetChartListenerCollection();
275 if (pChartListener)
276 pChartListener->UpdateDirtyCharts();
278 // #95582#; set the table names of linked tables to the new path
279 SCTAB nTabCount = m_aDocument.GetTableCount();
280 for (SCTAB i = 0; i < nTabCount; ++i)
282 if (m_aDocument.IsLinked( i ))
284 OUString aName;
285 m_aDocument.GetName(i, aName);
286 OUString aLinkTabName = m_aDocument.GetLinkTab(i);
287 sal_Int32 nLinkTabNameLength = aLinkTabName.getLength();
288 sal_Int32 nNameLength = aName.getLength();
289 if (nLinkTabNameLength < nNameLength)
292 // remove the quotes on begin and end of the docname and restore the escaped quotes
293 const sal_Unicode* pNameBuffer = aName.getStr();
294 if ( *pNameBuffer == '\'' && // all docnames have to have a ' character on the first pos
295 ScGlobal::UnicodeStrChr( pNameBuffer, SC_COMPILER_FILE_TAB_SEP ) )
297 OUStringBuffer aDocURLBuffer;
298 bool bQuote = true; // Document name is always quoted
299 ++pNameBuffer;
300 while ( bQuote && *pNameBuffer )
302 if ( *pNameBuffer == '\'' && *(pNameBuffer-1) != '\\' )
303 bQuote = false;
304 else if( *pNameBuffer != '\\' || *(pNameBuffer+1) != '\'' )
305 aDocURLBuffer.append(*pNameBuffer); // If escaped quote: only quote in the name
306 ++pNameBuffer;
309 if( *pNameBuffer == SC_COMPILER_FILE_TAB_SEP ) // after the last quote of the docname should be the # char
311 sal_Int32 nIndex = nNameLength - nLinkTabNameLength;
312 INetURLObject aINetURLObject(aDocURLBuffer.makeStringAndClear());
313 if(aName.match( aLinkTabName, nIndex) &&
314 (aName[nIndex - 1] == '#') && // before the table name should be the # char
315 !aINetURLObject.HasError()) // the docname should be a valid URL
317 aName = ScGlobal::GetDocTabName( m_aDocument.GetLinkDoc( i ), m_aDocument.GetLinkTab( i ) );
318 m_aDocument.RenameTab(i, aName, true/*bExternalDocument*/);
320 // else; nothing has to happen, because it is a user given name
322 // else; nothing has to happen, because it is a user given name
324 // else; nothing has to happen, because it is a user given name
326 // else; nothing has to happen, because it is a user given name
330 // #i94570# DataPilot table names have to be unique, or the tables can't be accessed by API.
331 // If no name (or an invalid name, skipped in ScXMLDataPilotTableContext::EndElement) was set, create a new name.
332 ScDPCollection* pDPCollection = m_aDocument.GetDPCollection();
333 if ( pDPCollection )
335 size_t nDPCount = pDPCollection->GetCount();
336 for (size_t nDP=0; nDP<nDPCount; ++nDP)
338 ScDPObject& rDPObj = (*pDPCollection)[nDP];
339 if (rDPObj.GetName().isEmpty())
340 rDPObj.SetName( pDPCollection->CreateNewName() );
345 else
346 m_aDocument.SetInsertingFromOtherDoc( false );
348 m_aDocument.SetImportingXML( false );
349 m_aDocument.EnableExecuteLink( true );
350 m_aDocument.EnableUndo( true );
351 m_bIsEmpty = false;
353 if (m_pModificator)
355 ScDocument::HardRecalcState eRecalcState = m_aDocument.GetHardRecalcState();
356 // Temporarily set hard-recalc to prevent calling
357 // ScFormulaCell::Notify() during destruction of the Modificator which
358 // will set the cells dirty.
359 if (eRecalcState == ScDocument::HardRecalcState::OFF)
360 m_aDocument.SetHardRecalcState(ScDocument::HardRecalcState::TEMPORARY);
361 m_pModificator.reset();
362 m_aDocument.SetHardRecalcState(eRecalcState);
364 else
366 OSL_FAIL("The Modificator should exist");
369 m_aDocument.EnableIdle(true);
372 namespace {
374 class LoadMediumGuard
376 public:
377 explicit LoadMediumGuard(ScDocument* pDoc) :
378 mpDoc(pDoc)
380 mpDoc->SetLoadingMedium(true);
383 ~LoadMediumGuard()
385 mpDoc->SetLoadingMedium(false);
387 private:
388 ScDocument* mpDoc;
391 void processDataStream( ScDocShell& rShell, const sc::ImportPostProcessData& rData )
393 if (!rData.mpDataStream)
394 return;
396 const sc::ImportPostProcessData::DataStream& r = *rData.mpDataStream;
397 if (!r.maRange.IsValid())
398 return;
400 // Break the streamed range into the top range and the height limit. A
401 // height limit of 0 means unlimited i.e. the streamed data will go all
402 // the way to the last row.
404 ScRange aTopRange = r.maRange;
405 aTopRange.aEnd.SetRow(aTopRange.aStart.Row());
406 sal_Int32 nLimit = r.maRange.aEnd.Row() - r.maRange.aStart.Row() + 1;
407 if (r.maRange.aEnd.Row() == rShell.GetDocument().MaxRow())
408 // Unlimited range.
409 nLimit = 0;
411 sc::DataStream::MoveType eMove =
412 r.meInsertPos == sc::ImportPostProcessData::DataStream::InsertTop ?
413 sc::DataStream::MOVE_DOWN : sc::DataStream::RANGE_DOWN;
415 sc::DataStream* pStrm = new sc::DataStream(&rShell, r.maURL, aTopRange, nLimit, eMove, 0);
416 pStrm->SetRefreshOnEmptyLine(r.mbRefreshOnEmpty);
417 sc::DocumentLinkManager& rMgr = rShell.GetDocument().GetDocLinkManager();
418 rMgr.setDataStream(pStrm);
421 class MessageWithCheck : public weld::MessageDialogController
423 private:
424 std::unique_ptr<weld::CheckButton> m_xWarningOnBox;
425 public:
426 MessageWithCheck(weld::Window *pParent, const OUString& rUIFile, const OString& rDialogId)
427 : MessageDialogController(pParent, rUIFile, rDialogId, "ask")
428 , m_xWarningOnBox(m_xBuilder->weld_check_button("ask"))
431 bool get_active() const { return m_xWarningOnBox->get_active(); }
432 void hide_ask() const { m_xWarningOnBox->set_visible(false); };
436 class VBAScriptListener : public ::cppu::WeakImplHelper< css::script::vba::XVBAScriptListener >
438 private:
439 ScDocShell* m_pDocSh;
440 public:
441 VBAScriptListener(ScDocShell* pDocSh) : m_pDocSh(pDocSh)
445 // XVBAScriptListener
446 virtual void SAL_CALL notifyVBAScriptEvent( const ::css::script::vba::VBAScriptEvent& aEvent ) override
448 if (aEvent.Identifier == script::vba::VBAScriptEventId::SCRIPT_STOPPED &&
449 m_pDocSh->GetClipData().is())
451 m_pDocSh->SetClipData(uno::Reference<datatransfer::XTransferable2>());
455 // XEventListener
456 virtual void SAL_CALL disposing( const ::css::lang::EventObject& /*Source*/ ) override
463 bool ScDocShell::LoadXML( SfxMedium* pLoadMedium, const css::uno::Reference< css::embed::XStorage >& xStor )
465 LoadMediumGuard aLoadGuard(&m_aDocument);
467 // MacroCallMode is no longer needed, state is kept in SfxObjectShell now
469 // no Seek(0) here - always loading from storage, GetInStream must not be called
471 BeforeXMLLoading();
473 ScXMLImportWrapper aImport(*this, pLoadMedium, xStor);
475 bool bRet = false;
476 ErrCode nError = ERRCODE_NONE;
477 m_aDocument.LockAdjustHeight();
478 if (GetCreateMode() == SfxObjectCreateMode::ORGANIZER)
479 bRet = aImport.Import(ImportFlags::Styles, nError);
480 else
481 bRet = aImport.Import(ImportFlags::All, nError);
483 if ( nError )
484 pLoadMedium->SetError(nError);
486 processDataStream(*this, aImport.GetImportPostProcessData());
488 //if the document was not generated by LibreOffice, do hard recalc in case some other document
489 //generator saved cached formula results that differ from LibreOffice's calculated results or
490 //did not use cached formula results.
491 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(GetModel(), uno::UNO_QUERY_THROW);
492 uno::Reference<document::XDocumentProperties> xDocProps = xDPS->getDocumentProperties();
494 Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext();
495 ScRecalcOptions nRecalcMode =
496 static_cast<ScRecalcOptions>(officecfg::Office::Calc::Formula::Load::ODFRecalcMode::get(xContext));
498 bool bHardRecalc = false;
499 if (nRecalcMode == RECALC_ASK)
501 OUString sProductName(utl::ConfigManager::getProductName());
502 if (m_aDocument.IsUserInteractionEnabled() && xDocProps->getGenerator().indexOf(sProductName) == -1)
504 // Generator is not LibreOffice. Ask if the user wants to perform
505 // full re-calculation.
506 MessageWithCheck aQueryBox(GetActiveDialogParent(),
507 "modules/scalc/ui/recalcquerydialog.ui", "RecalcQueryDialog");
508 aQueryBox.set_primary_text(ScResId(STR_QUERY_FORMULA_RECALC_ONLOAD_ODS));
509 aQueryBox.set_default_response(RET_YES);
511 if ( officecfg::Office::Calc::Formula::Load::OOXMLRecalcMode::isReadOnly() )
512 aQueryBox.hide_ask();
514 bHardRecalc = aQueryBox.run() == RET_YES;
516 if (aQueryBox.get_active())
518 // Always perform selected action in the future.
519 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
520 officecfg::Office::Calc::Formula::Load::ODFRecalcMode::set(sal_Int32(0), batch);
521 ScFormulaOptions aOpt = SC_MOD()->GetFormulaOptions();
522 aOpt.SetODFRecalcOptions(bHardRecalc ? RECALC_ALWAYS : RECALC_NEVER);
523 /* XXX is this really supposed to set the ScModule options?
524 * Not the ScDocShell options? */
525 SC_MOD()->SetFormulaOptions(aOpt);
527 batch->commit();
531 else if (nRecalcMode == RECALC_ALWAYS)
532 bHardRecalc = true;
534 if (bHardRecalc)
535 DoHardRecalc();
536 else
538 // still need to recalc volatile formula cells.
539 m_aDocument.Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS));
542 AfterXMLLoading(bRet);
544 m_aDocument.UnlockAdjustHeight();
545 return bRet;
548 bool ScDocShell::SaveXML( SfxMedium* pSaveMedium, const css::uno::Reference< css::embed::XStorage >& xStor )
550 m_aDocument.EnableIdle(false);
552 ScXMLImportWrapper aImport(*this, pSaveMedium, xStor);
553 bool bRet(false);
554 if (GetCreateMode() != SfxObjectCreateMode::ORGANIZER)
555 bRet = aImport.Export(false);
556 else
557 bRet = aImport.Export(true);
559 m_aDocument.EnableIdle(true);
561 return bRet;
564 bool ScDocShell::Load( SfxMedium& rMedium )
566 LoadMediumGuard aLoadGuard(&m_aDocument);
567 ScRefreshTimerProtector aProt( m_aDocument.GetRefreshTimerControlAddress() );
569 // only the latin script language is loaded
570 // -> initialize the others from options (before loading)
571 InitOptions(true);
573 // If this is an ODF file being loaded, then by default, use legacy processing
574 // for tdf#99729 (if required, it will be overridden in *::ReadUserDataSequence())
575 if (IsOwnStorageFormat(rMedium))
577 if (m_aDocument.GetDrawLayer())
578 m_aDocument.GetDrawLayer()->SetAnchoredTextOverflowLegacy(true);
581 GetUndoManager()->Clear();
583 bool bRet = SfxObjectShell::Load(rMedium);
584 if (bRet)
586 SetInitialLinkUpdate(&rMedium);
589 // prepare a valid document for XML filter
590 // (for ConvertFrom, InitNew is called before)
591 m_aDocument.MakeTable(0);
592 m_aDocument.GetStyleSheetPool()->CreateStandardStyles();
593 m_aDocument.UpdStlShtPtrsFrmNms();
595 if (!m_bUcalcTest)
597 /* Create styles that are imported through Orcus */
599 OUString aURL("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/calc/styles.xml");
600 rtl::Bootstrap::expandMacros(aURL);
602 OUString aPath;
603 osl::FileBase::getSystemPathFromFileURL(aURL, aPath);
605 ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
607 if (pOrcus)
609 pOrcus->importODS_Styles(m_aDocument, aPath);
610 m_aDocument.GetStyleSheetPool()->setAllParaStandard();
614 bRet = LoadXML( &rMedium, nullptr );
618 if (!bRet && !rMedium.GetError())
619 rMedium.SetError(SVSTREAM_FILEFORMAT_ERROR);
621 if (rMedium.GetError())
622 SetError(rMedium.GetError());
624 InitItems();
625 CalcOutputFactor();
627 // invalidate eventually temporary table areas
628 if ( bRet )
629 m_aDocument.InvalidateTableArea();
631 m_bIsEmpty = false;
632 FinishedLoading();
633 return bRet;
636 void ScDocShell::Notify( SfxBroadcaster&, const SfxHint& rHint )
638 const ScTablesHint* pScHint = dynamic_cast< const ScTablesHint* >( &rHint );
639 if (pScHint)
641 if (pScHint->GetTablesHintId() == SC_TAB_INSERTED)
643 uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents = m_aDocument.GetVbaEventProcessor();
644 if ( xVbaEvents.is() ) try
646 uno::Sequence< uno::Any > aArgs( 1 );
647 aArgs[0] <<= pScHint->GetTab1();
648 xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKBOOK_NEWSHEET, aArgs );
650 catch( uno::Exception& )
656 if ( auto pStyleSheetHint = dynamic_cast<const SfxStyleSheetHint*>(&rHint) ) // Template changed
657 NotifyStyle( *pStyleSheetHint );
658 else if ( auto pStlHint = dynamic_cast<const ScAutoStyleHint*>(&rHint) )
660 //! direct call for AutoStyles
662 // this is called synchronously from ScInterpreter::ScStyle,
663 // modifying the document must be asynchronous
664 // (handled by AddInitial)
666 const ScRange& aRange = pStlHint->GetRange();
667 const OUString& aName1 = pStlHint->GetStyle1();
668 const OUString& aName2 = pStlHint->GetStyle2();
669 sal_uInt32 nTimeout = pStlHint->GetTimeout();
671 if (!m_pAutoStyleList)
672 m_pAutoStyleList.reset( new ScAutoStyleList(this) );
673 m_pAutoStyleList->AddInitial( aRange, aName1, nTimeout, aName2 );
675 else if ( auto pEventHint = dynamic_cast<const SfxEventHint*>(&rHint) )
677 SfxEventHintId nEventId = pEventHint->GetEventId();
679 switch ( nEventId )
681 case SfxEventHintId::LoadFinished:
683 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
684 // the readonly documents should not be opened in shared mode
685 if ( HasSharedXMLFlagSet() && !SC_MOD()->IsInSharedDocLoading() && !IsReadOnly() )
687 if ( SwitchToShared( true, false ) )
689 ScViewData* pViewData = GetViewData();
690 ScTabView* pTabView = ( pViewData ? dynamic_cast< ScTabView* >( pViewData->GetView() ) : nullptr );
691 if ( pTabView )
693 pTabView->UpdateLayerLocks();
696 else
698 // switching to shared mode has failed, the document should be opened readonly
699 // TODO/LATER: And error message should be shown here probably
700 SetReadOnlyUI();
703 #endif
705 break;
706 case SfxEventHintId::ViewCreated:
708 #if HAVE_FEATURE_SCRIPTING
709 uno::Reference<script::vba::XVBACompatibility> xVBACompat(GetBasicContainer(), uno::UNO_QUERY);
710 if ( !m_xVBAListener.is() && xVBACompat.is() )
712 m_xVBAListener.set(new VBAScriptListener(this));
713 xVBACompat->addVBAScriptListener(m_xVBAListener);
715 #endif
717 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
718 if ( IsDocShared() && !SC_MOD()->IsInSharedDocLoading() )
720 ScAppOptions aAppOptions = SC_MOD()->GetAppOptions();
721 if ( aAppOptions.GetShowSharedDocumentWarning() )
723 MessageWithCheck aWarningBox(ScDocShell::GetActiveDialogParent(),
724 "modules/scalc/ui/sharedwarningdialog.ui", "SharedWarningDialog");
725 aWarningBox.run();
727 bool bChecked = aWarningBox.get_active();
728 if (bChecked)
730 aAppOptions.SetShowSharedDocumentWarning(false);
731 SC_MOD()->SetAppOptions( aAppOptions );
735 #endif
738 uno::Reference< uno::XComponentContext > xContext(
739 comphelper::getProcessComponentContext() );
740 uno::Reference< lang::XMultiServiceFactory > xServiceManager(
741 xContext->getServiceManager(),
742 uno::UNO_QUERY_THROW );
743 uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xServiceManager, uno::UNO_QUERY_THROW );
744 uno::Reference< container::XEnumeration> xEnum = xEnumAccess->createContentEnumeration(
745 "com.sun.star.sheet.SpreadsheetDocumentJob" );
746 if ( xEnum.is() )
748 while ( xEnum->hasMoreElements() )
750 uno::Any aAny = xEnum->nextElement();
751 uno::Reference< lang::XSingleComponentFactory > xFactory;
752 aAny >>= xFactory;
753 if ( xFactory.is() )
755 uno::Reference< task::XJob > xJob( xFactory->createInstanceWithContext( xContext ), uno::UNO_QUERY_THROW );
756 ScViewData* pViewData = GetViewData();
757 SfxViewShell* pViewShell = ( pViewData ? pViewData->GetViewShell() : nullptr );
758 SfxViewFrame* pViewFrame = ( pViewShell ? pViewShell->GetViewFrame() : nullptr );
759 SfxFrame* pFrame = ( pViewFrame ? &pViewFrame->GetFrame() : nullptr );
760 uno::Reference< frame::XController > xController = ( pFrame ? pFrame->GetController() : nullptr );
761 uno::Reference< sheet::XSpreadsheetView > xSpreadsheetView( xController, uno::UNO_QUERY_THROW );
762 uno::Sequence< beans::NamedValue > aArgsForJob { { "SpreadsheetView", uno::makeAny( xSpreadsheetView ) } };
763 xJob->execute( aArgsForJob );
768 catch ( uno::Exception & )
772 break;
773 case SfxEventHintId::SaveDoc:
775 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
776 if ( IsDocShared() && !SC_MOD()->IsInSharedDocSaving() )
778 bool bSuccess = false;
779 bool bRetry = true;
780 while ( bRetry )
782 bRetry = false;
783 uno::Reference< frame::XModel > xModel;
786 // load shared file
787 xModel.set( LoadSharedDocument(), uno::UNO_SET_THROW );
788 uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY_THROW );
790 // check if shared flag is set in shared file
791 bool bShared = false;
792 ScModelObj* pDocObj = comphelper::getUnoTunnelImplementation<ScModelObj>( xModel );
793 ScDocShell* pSharedDocShell = ( pDocObj ? dynamic_cast< ScDocShell* >( pDocObj->GetObjectShell() ) : nullptr );
794 if ( pSharedDocShell )
796 bShared = pSharedDocShell->HasSharedXMLFlagSet();
799 // #i87870# check if shared status was disabled and enabled again
800 bool bOwnEntry = false;
801 bool bEntriesNotAccessible = false;
804 ::svt::ShareControlFile aControlFile( GetSharedFileURL() );
805 bOwnEntry = aControlFile.HasOwnEntry();
807 catch ( uno::Exception& )
809 bEntriesNotAccessible = true;
812 if ( bShared && bOwnEntry )
814 uno::Reference< frame::XStorable > xStorable( xModel, uno::UNO_QUERY_THROW );
816 if ( xStorable->isReadonly() )
818 xCloseable->close( true );
820 OUString aUserName( ScResId( STR_UNKNOWN_USER ) );
821 bool bNoLockAccess = false;
824 ::svt::DocumentLockFile aLockFile( GetSharedFileURL() );
825 LockFileEntry aData = aLockFile.GetLockData();
826 if ( !aData[LockFileComponent::OOOUSERNAME].isEmpty() )
828 aUserName = aData[LockFileComponent::OOOUSERNAME];
830 else if ( !aData[LockFileComponent::SYSUSERNAME].isEmpty() )
832 aUserName = aData[LockFileComponent::SYSUSERNAME];
835 catch ( uno::Exception& )
837 bNoLockAccess = true;
840 if ( bNoLockAccess )
842 // TODO/LATER: in future an error regarding impossibility to open file for writing could be shown
843 ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
845 else
847 OUString aMessage( ScResId( STR_FILE_LOCKED_SAVE_LATER ) );
848 aMessage = aMessage.replaceFirst( "%1", aUserName );
850 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
851 VclMessageType::Warning, VclButtonsType::NONE,
852 aMessage));
853 xWarn->add_button(GetStandardText(StandardButtonType::Retry), RET_RETRY);
854 xWarn->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
855 xWarn->set_default_response(RET_RETRY);
856 if (xWarn->run() == RET_RETRY)
858 bRetry = true;
862 else
864 // merge changes from shared file into temp file
865 bool bSaveToShared = false;
866 if ( pSharedDocShell )
868 bSaveToShared = MergeSharedDocument( pSharedDocShell );
871 // close shared file
872 xCloseable->close( true );
874 // TODO: keep file lock on shared file
876 // store to shared file
877 if ( bSaveToShared )
879 bool bChangedViewSettings = false;
880 ScChangeViewSettings* pChangeViewSet = m_aDocument.GetChangeViewSettings();
881 if ( pChangeViewSet && pChangeViewSet->ShowChanges() )
883 pChangeViewSet->SetShowChanges( false );
884 pChangeViewSet->SetShowAccepted( false );
885 m_aDocument.SetChangeViewSettings( *pChangeViewSet );
886 bChangedViewSettings = true;
889 uno::Reference< frame::XStorable > xStor( GetModel(), uno::UNO_QUERY_THROW );
890 // TODO/LATER: More entries from the MediaDescriptor might be interesting for the merge
891 uno::Sequence< beans::PropertyValue > aValues(1);
892 aValues[0].Name = "FilterName";
893 aValues[0].Value <<= GetMedium()->GetFilter()->GetFilterName();
895 const SfxStringItem* pPasswordItem = SfxItemSet::GetItem<SfxStringItem>(GetMedium()->GetItemSet(), SID_PASSWORD, false);
896 if ( pPasswordItem && !pPasswordItem->GetValue().isEmpty() )
898 aValues.realloc( 2 );
899 aValues[1].Name = "Password";
900 aValues[1].Value <<= pPasswordItem->GetValue();
903 SC_MOD()->SetInSharedDocSaving( true );
904 xStor->storeToURL( GetSharedFileURL(), aValues );
905 SC_MOD()->SetInSharedDocSaving( false );
907 if ( bChangedViewSettings )
909 pChangeViewSet->SetShowChanges( true );
910 pChangeViewSet->SetShowAccepted( true );
911 m_aDocument.SetChangeViewSettings( *pChangeViewSet );
915 bSuccess = true;
916 GetUndoManager()->Clear();
919 else
921 xCloseable->close( true );
923 if ( bEntriesNotAccessible )
925 // TODO/LATER: in future an error regarding impossibility to write to share control file could be shown
926 ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
928 else
930 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
931 VclMessageType::Warning, VclButtonsType::Ok,
932 ScResId(STR_DOC_NOLONGERSHARED)));
933 xWarn->run();
935 SfxBindings* pBindings = GetViewBindings();
936 if ( pBindings )
938 pBindings->ExecuteSynchron( SID_SAVEASDOC );
943 catch ( uno::Exception& )
945 OSL_FAIL( "SfxEventHintId::SaveDoc: caught exception" );
946 SC_MOD()->SetInSharedDocSaving( false );
950 uno::Reference< util::XCloseable > xClose( xModel, uno::UNO_QUERY_THROW );
951 xClose->close( true );
953 catch ( uno::Exception& )
959 if ( !bSuccess )
960 SetError(ERRCODE_IO_ABORT); // this error code will produce no error message, but will break the further saving process
962 #endif
964 if (m_pSheetSaveData)
965 m_pSheetSaveData->SetInSupportedSave(true);
967 break;
968 case SfxEventHintId::SaveAsDoc:
970 if ( GetDocument().GetExternalRefManager()->containsUnsavedReferences() )
972 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
973 VclMessageType::Warning, VclButtonsType::YesNo,
974 ScResId(STR_UNSAVED_EXT_REF)));
975 if (RET_NO == xWarn->run())
977 SetError(ERRCODE_IO_ABORT); // this error code will produce no error message, but will break the further saving process
980 [[fallthrough]];
982 case SfxEventHintId::SaveToDoc:
983 // #i108978# If no event is sent before saving, there will also be no "...DONE" event,
984 // and SAVE/SAVEAS can't be distinguished from SAVETO. So stream copying is only enabled
985 // if there is a SAVE/SAVEAS/SAVETO event first.
986 if (m_pSheetSaveData)
987 m_pSheetSaveData->SetInSupportedSave(true);
988 break;
989 case SfxEventHintId::SaveDocDone:
990 case SfxEventHintId::SaveAsDocDone:
992 // new positions are used after "save" and "save as", but not "save to"
993 UseSheetSaveEntries(); // use positions from saved file for next saving
994 [[fallthrough]];
996 case SfxEventHintId::SaveToDocDone:
997 // only reset the flag, don't use the new positions
998 if (m_pSheetSaveData)
999 m_pSheetSaveData->SetInSupportedSave(false);
1000 break;
1001 default:
1004 break;
1007 else if (rHint.GetId() == SfxHintId::TitleChanged) // Without parameter
1009 m_aDocument.SetName( SfxShell::GetName() );
1010 // RegisterNewTargetNames doesn't exist any longer
1011 SfxGetpApp()->Broadcast(SfxHint( SfxHintId::ScDocNameChanged )); // Navigator
1013 else if (rHint.GetId() == SfxHintId::Deinitializing)
1016 #if HAVE_FEATURE_SCRIPTING
1017 uno::Reference<script::vba::XVBACompatibility> xVBACompat(GetBasicContainer(), uno::UNO_QUERY);
1018 if (m_xVBAListener.is() && xVBACompat.is())
1020 xVBACompat->removeVBAScriptListener(m_xVBAListener);
1022 #endif
1024 if (m_aDocument.IsClipboardSource())
1026 // Notes copied to the clipboard have a raw SdrCaptionObj pointer
1027 // copied from this document, forget it as it references this
1028 // document's drawing layer pages and what not, which otherwise when
1029 // pasting to another document after this document was destructed would
1030 // attempt to access non-existing data. Preserve the text data though.
1031 ScDocument* pClipDoc = ScModule::GetClipDoc();
1032 if (pClipDoc)
1033 pClipDoc->ClosingClipboardSource();
1037 const SfxEventHint* pSfxEventHint = dynamic_cast<const SfxEventHint*>(&rHint);
1038 if (!pSfxEventHint)
1039 return;
1041 switch( pSfxEventHint->GetEventId() )
1043 case SfxEventHintId::CreateDoc:
1045 uno::Any aWorkbook;
1046 aWorkbook <<= mxAutomationWorkbookObject;
1047 uno::Sequence< uno::Any > aArgs(1);
1048 aArgs[0] = aWorkbook;
1049 SC_MOD()->CallAutomationApplicationEventSinks( "NewWorkbook", aArgs );
1051 break;
1052 case SfxEventHintId::OpenDoc:
1054 uno::Any aWorkbook;
1055 aWorkbook <<= mxAutomationWorkbookObject;
1056 uno::Sequence< uno::Any > aArgs(1);
1057 aArgs[0] = aWorkbook;
1058 SC_MOD()->CallAutomationApplicationEventSinks( "WorkbookOpen", aArgs );
1060 break;
1061 default:
1062 break;
1066 // Load contents for organizer
1067 bool ScDocShell::LoadFrom( SfxMedium& rMedium )
1069 LoadMediumGuard aLoadGuard(&m_aDocument);
1070 ScRefreshTimerProtector aProt( m_aDocument.GetRefreshTimerControlAddress() );
1072 weld::WaitObject aWait( GetActiveDialogParent() );
1074 bool bRet = false;
1076 SetInitialLinkUpdate(&rMedium);
1078 // until loading/saving only the styles in XML is implemented,
1079 // load the whole file
1080 bRet = LoadXML( &rMedium, nullptr );
1081 InitItems();
1083 SfxObjectShell::LoadFrom( rMedium );
1085 return bRet;
1088 static void lcl_parseHtmlFilterOption(const OUString& rOption, LanguageType& rLang, bool& rDateConvert)
1090 OUStringBuffer aBuf;
1091 std::vector< OUString > aTokens;
1092 sal_Int32 n = rOption.getLength();
1093 const sal_Unicode* p = rOption.getStr();
1094 for (sal_Int32 i = 0; i < n; ++i)
1096 const sal_Unicode c = p[i];
1097 if (c == ' ')
1099 if (!aBuf.isEmpty())
1100 aTokens.push_back( aBuf.makeStringAndClear() );
1102 else
1103 aBuf.append(c);
1106 if (!aBuf.isEmpty())
1107 aTokens.push_back( aBuf.makeStringAndClear() );
1109 rLang = LanguageType( 0 );
1110 rDateConvert = false;
1112 if (!aTokens.empty())
1113 rLang = static_cast<LanguageType>(aTokens[0].toInt32());
1114 if (aTokens.size() > 1)
1115 rDateConvert = static_cast<bool>(aTokens[1].toInt32());
1118 bool ScDocShell::ConvertFrom( SfxMedium& rMedium )
1120 LoadMediumGuard aLoadGuard(&m_aDocument);
1122 bool bRet = false; // sal_False means user quit!
1123 // On error: Set error at stream
1125 ScRefreshTimerProtector aProt( m_aDocument.GetRefreshTimerControlAddress() );
1127 GetUndoManager()->Clear();
1129 // Set optimal col width after import?
1130 bool bSetColWidths = false;
1131 bool bSetSimpleTextColWidths = false;
1132 std::map<SCCOL, ScColWidthParam> aColWidthParam;
1133 ScRange aColWidthRange;
1134 // Set optimal row height after import?
1135 bool bSetRowHeights = false;
1137 vector<ScDocRowHeightUpdater::TabRanges> aRecalcRowRangesArray;
1139 // All filters need the complete file in one piece (not asynchronously)
1140 // So make sure that we transfer the whole file with CreateFileStream
1141 rMedium.GetPhysicalName(); //! Call CreateFileStream directly, if available
1143 SetInitialLinkUpdate(&rMedium);
1145 std::shared_ptr<const SfxFilter> pFilter = rMedium.GetFilter();
1146 if (pFilter)
1148 OUString aFltName = pFilter->GetFilterName();
1150 bool bCalc3 = aFltName == "StarCalc 3.0";
1151 bool bCalc4 = aFltName == "StarCalc 4.0";
1152 if (!bCalc3 && !bCalc4)
1153 m_aDocument.SetInsertingFromOtherDoc( true );
1155 if (aFltName == pFilterXML)
1156 bRet = LoadXML( &rMedium, nullptr );
1157 else if (aFltName == pFilterLotus)
1159 OUString sItStr;
1160 SfxItemSet* pSet = rMedium.GetItemSet();
1161 const SfxPoolItem* pItem;
1162 if ( pSet && SfxItemState::SET ==
1163 pSet->GetItemState( SID_FILE_FILTEROPTIONS, true, &pItem ) )
1165 sItStr = static_cast<const SfxStringItem*>(pItem)->GetValue();
1168 if (sItStr.isEmpty())
1170 // default for lotus import (from API without options):
1171 // IBM_437 encoding
1172 sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_437 );
1175 ErrCode eError = ScFormatFilter::Get().ScImportLotus123( rMedium, m_aDocument,
1176 ScGlobal::GetCharsetValue(sItStr));
1177 if (eError != ERRCODE_NONE)
1179 if (!GetError())
1180 SetError(eError);
1182 if( eError.IsWarning() )
1183 bRet = true;
1185 else
1186 bRet = true;
1187 bSetColWidths = true;
1188 bSetRowHeights = true;
1190 else if ( aFltName == pFilterExcel4 || aFltName == pFilterExcel5 ||
1191 aFltName == pFilterExcel95 || aFltName == pFilterExcel97 ||
1192 aFltName == pFilterEx4Temp || aFltName == pFilterEx5Temp ||
1193 aFltName == pFilterEx95Temp || aFltName == pFilterEx97Temp )
1195 EXCIMPFORMAT eFormat = EIF_AUTO;
1196 if ( aFltName == pFilterExcel4 || aFltName == pFilterEx4Temp )
1197 eFormat = EIF_BIFF_LE4;
1198 else if ( aFltName == pFilterExcel5 || aFltName == pFilterExcel95 ||
1199 aFltName == pFilterEx5Temp || aFltName == pFilterEx95Temp )
1200 eFormat = EIF_BIFF5;
1201 else if ( aFltName == pFilterExcel97 || aFltName == pFilterEx97Temp )
1202 eFormat = EIF_BIFF8;
1204 MakeDrawLayer(); //! In the filter
1205 CalcOutputFactor(); // prepare update of row height
1206 ErrCode eError = ScFormatFilter::Get().ScImportExcel( rMedium, &m_aDocument, eFormat );
1207 m_aDocument.UpdateFontCharSet();
1208 if ( m_aDocument.IsChartListenerCollectionNeedsUpdate() )
1209 m_aDocument.UpdateChartListenerCollection(); //! For all imports?
1211 // all graphics objects must have names
1212 m_aDocument.EnsureGraphicNames();
1214 if (eError == SCWARN_IMPORT_RANGE_OVERFLOW)
1216 if (!GetError())
1217 SetError(eError);
1218 bRet = true;
1220 else if (eError != ERRCODE_NONE)
1222 if (!GetError())
1223 SetError(eError);
1225 else
1226 bRet = true;
1228 else if (aFltName == "Gnumeric Spreadsheet")
1230 ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
1231 if (!pOrcus)
1232 return false;
1234 bRet = pOrcus->importGnumeric(m_aDocument, rMedium);
1236 else if (aFltName == "MS Excel 2003 XML Orcus")
1238 ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
1239 if (!pOrcus)
1240 return false;
1242 bRet = pOrcus->importExcel2003XML(m_aDocument, rMedium);
1244 else if (aFltName == pFilterAscii)
1246 SfxItemSet* pSet = rMedium.GetItemSet();
1247 const SfxPoolItem* pItem;
1248 ScAsciiOptions aOptions;
1249 bool bOptInit = false;
1251 if ( pSet && SfxItemState::SET ==
1252 pSet->GetItemState( SID_FILE_FILTEROPTIONS, true, &pItem ) )
1254 aOptions.ReadFromString( static_cast<const SfxStringItem*>(pItem)->GetValue() );
1255 bOptInit = true;
1258 if ( !bOptInit )
1260 // default for ascii import (from API without options):
1261 // ISO8859-1/MS_1252 encoding, comma, double quotes
1263 aOptions.SetCharSet( RTL_TEXTENCODING_MS_1252 );
1264 aOptions.SetFieldSeps( OUString(',') );
1265 aOptions.SetTextSep( '"' );
1268 ErrCode eError = ERRCODE_NONE;
1269 bool bOverflowRow, bOverflowCol, bOverflowCell;
1270 bOverflowRow = bOverflowCol = bOverflowCell = false;
1272 if( ! rMedium.IsStorage() )
1274 ScImportExport aImpEx( m_aDocument );
1275 aImpEx.SetExtOptions( aOptions );
1277 SvStream* pInStream = rMedium.GetInStream();
1278 if (pInStream)
1280 pInStream->SetStreamCharSet( aOptions.GetCharSet() );
1281 pInStream->Seek( 0 );
1282 bRet = aImpEx.ImportStream( *pInStream, rMedium.GetBaseURL(), SotClipboardFormatId::STRING );
1283 eError = bRet ? ERRCODE_NONE : SCERR_IMPORT_CONNECT;
1284 m_aDocument.StartAllListeners();
1285 sc::SetFormulaDirtyContext aCxt;
1286 m_aDocument.SetAllFormulasDirty(aCxt);
1288 // The same resulting name has to be handled in
1289 // ScExternalRefCache::initializeDoc() and related, hence
1290 // pass 'true' for RenameTab()'s bExternalDocument for a
1291 // composed name so ValidTabName() will not be checked,
1292 // which could veto the rename in case it contained
1293 // characters that Excel does not handle. If we wanted to
1294 // change that then it needed to be handled in all
1295 // corresponding places of the external references
1296 // manager/cache. Likely then we'd also need a method to
1297 // compose a name excluding such characters.
1298 m_aDocument.RenameTab( 0, INetURLObject( rMedium.GetName()).GetBase(), true/*bExternalDocument*/);
1300 bOverflowRow = aImpEx.IsOverflowRow();
1301 bOverflowCol = aImpEx.IsOverflowCol();
1302 bOverflowCell = aImpEx.IsOverflowCell();
1304 else
1306 OSL_FAIL( "No Stream" );
1310 if (eError != ERRCODE_NONE)
1312 if (!GetError())
1313 SetError(eError);
1315 else if (!GetError() && (bOverflowRow || bOverflowCol || bOverflowCell))
1317 // precedence: row, column, cell
1318 ErrCode nWarn = (bOverflowRow ? SCWARN_IMPORT_ROW_OVERFLOW :
1319 (bOverflowCol ? SCWARN_IMPORT_COLUMN_OVERFLOW :
1320 SCWARN_IMPORT_CELL_OVERFLOW));
1321 SetError(nWarn);
1323 bSetColWidths = true;
1324 bSetSimpleTextColWidths = true;
1326 else if (aFltName == pFilterDBase)
1328 OUString sItStr;
1329 SfxItemSet* pSet = rMedium.GetItemSet();
1330 const SfxPoolItem* pItem;
1331 if ( pSet && SfxItemState::SET ==
1332 pSet->GetItemState( SID_FILE_FILTEROPTIONS, true, &pItem ) )
1334 sItStr = static_cast<const SfxStringItem*>(pItem)->GetValue();
1337 if (sItStr.isEmpty())
1339 // default for dBase import (from API without options):
1340 // IBM_850 encoding
1342 sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_850 );
1345 ScDocRowHeightUpdater::TabRanges aRecalcRanges(0, m_aDocument.MaxRow());
1346 ErrCode eError = DBaseImport( rMedium.GetPhysicalName(),
1347 ScGlobal::GetCharsetValue(sItStr), aColWidthParam, aRecalcRanges.maRanges );
1348 aRecalcRowRangesArray.push_back(aRecalcRanges);
1350 if (eError != ERRCODE_NONE)
1352 if (!GetError())
1353 SetError(eError);
1354 bRet = ( eError == SCWARN_IMPORT_RANGE_OVERFLOW );
1356 else
1357 bRet = true;
1359 aColWidthRange.aStart.SetRow( 1 ); // Except for the column header
1360 bSetColWidths = true;
1361 bSetSimpleTextColWidths = true;
1363 else if (aFltName == pFilterDif)
1365 SvStream* pStream = rMedium.GetInStream();
1366 if (pStream)
1368 ErrCode eError;
1369 OUString sItStr;
1370 SfxItemSet* pSet = rMedium.GetItemSet();
1371 const SfxPoolItem* pItem;
1372 if ( pSet && SfxItemState::SET ==
1373 pSet->GetItemState( SID_FILE_FILTEROPTIONS, true, &pItem ) )
1375 sItStr = static_cast<const SfxStringItem*>(pItem)->GetValue();
1378 if (sItStr.isEmpty())
1380 // default for DIF import (from API without options):
1381 // ISO8859-1/MS_1252 encoding
1383 sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_MS_1252 );
1386 eError = ScFormatFilter::Get().ScImportDif( *pStream, &m_aDocument, ScAddress(0,0,0),
1387 ScGlobal::GetCharsetValue(sItStr));
1388 if (eError != ERRCODE_NONE)
1390 if (!GetError())
1391 SetError(eError);
1393 if( eError.IsWarning() )
1394 bRet = true;
1396 else
1397 bRet = true;
1399 bSetColWidths = true;
1400 bSetSimpleTextColWidths = true;
1401 bSetRowHeights = true;
1403 else if (aFltName == pFilterSylk)
1405 ErrCode eError = SCERR_IMPORT_UNKNOWN;
1406 bool bOverflowRow, bOverflowCol, bOverflowCell;
1407 bOverflowRow = bOverflowCol = bOverflowCell = false;
1408 if( !rMedium.IsStorage() )
1410 ScImportExport aImpEx( m_aDocument );
1412 SvStream* pInStream = rMedium.GetInStream();
1413 if (pInStream)
1415 pInStream->Seek( 0 );
1416 bRet = aImpEx.ImportStream( *pInStream, rMedium.GetBaseURL(), SotClipboardFormatId::SYLK );
1417 eError = bRet ? ERRCODE_NONE : SCERR_IMPORT_UNKNOWN;
1418 m_aDocument.StartAllListeners();
1419 sc::SetFormulaDirtyContext aCxt;
1420 m_aDocument.SetAllFormulasDirty(aCxt);
1422 bOverflowRow = aImpEx.IsOverflowRow();
1423 bOverflowCol = aImpEx.IsOverflowCol();
1424 bOverflowCell = aImpEx.IsOverflowCell();
1426 else
1428 OSL_FAIL( "No Stream" );
1432 if ( eError != ERRCODE_NONE && !GetError() )
1433 SetError(eError);
1434 else if (!GetError() && (bOverflowRow || bOverflowCol || bOverflowCell))
1436 // precedence: row, column, cell
1437 ErrCode nWarn = (bOverflowRow ? SCWARN_IMPORT_ROW_OVERFLOW :
1438 (bOverflowCol ? SCWARN_IMPORT_COLUMN_OVERFLOW :
1439 SCWARN_IMPORT_CELL_OVERFLOW));
1440 SetError(nWarn);
1442 bSetColWidths = true;
1443 bSetSimpleTextColWidths = true;
1444 bSetRowHeights = true;
1446 else if (aFltName == pFilterQPro6)
1448 ErrCode eError = ScFormatFilter::Get().ScImportQuattroPro(rMedium.GetInStream(), m_aDocument);
1449 if (eError != ERRCODE_NONE)
1451 if (!GetError())
1452 SetError(eError);
1453 if( eError.IsWarning() )
1454 bRet = true;
1456 else
1457 bRet = true;
1458 // TODO: Filter should set column widths. Not doing it here, it may
1459 // result in very narrow or wide columns, depending on content.
1460 // Setting row heights makes cells with font size attribution or
1461 // wrapping enabled look nicer...
1462 bSetRowHeights = true;
1464 else if (aFltName == pFilterRtf)
1466 ErrCode eError = SCERR_IMPORT_UNKNOWN;
1467 if( !rMedium.IsStorage() )
1469 SvStream* pInStream = rMedium.GetInStream();
1470 if (pInStream)
1472 pInStream->Seek( 0 );
1473 ScRange aRange;
1474 eError = ScFormatFilter::Get().ScImportRTF( *pInStream, rMedium.GetBaseURL(), &m_aDocument, aRange );
1475 if (eError != ERRCODE_NONE)
1477 if (!GetError())
1478 SetError(eError);
1480 if( eError.IsWarning() )
1481 bRet = true;
1483 else
1484 bRet = true;
1485 m_aDocument.StartAllListeners();
1486 sc::SetFormulaDirtyContext aCxt;
1487 m_aDocument.SetAllFormulasDirty(aCxt);
1488 bSetColWidths = true;
1489 bSetRowHeights = true;
1491 else
1493 OSL_FAIL( "No Stream" );
1497 if ( eError != ERRCODE_NONE && !GetError() )
1498 SetError(eError);
1500 else if (aFltName == pFilterHtml || aFltName == pFilterHtmlWebQ)
1502 ErrCode eError = SCERR_IMPORT_UNKNOWN;
1503 bool bWebQuery = aFltName == pFilterHtmlWebQ;
1504 if( !rMedium.IsStorage() )
1506 SvStream* pInStream = rMedium.GetInStream();
1507 if (pInStream)
1509 LanguageType eLang = LANGUAGE_SYSTEM;
1510 bool bDateConvert = false;
1511 SfxItemSet* pSet = rMedium.GetItemSet();
1512 const SfxPoolItem* pItem;
1513 if ( pSet && SfxItemState::SET ==
1514 pSet->GetItemState( SID_FILE_FILTEROPTIONS, true, &pItem ) )
1516 OUString aFilterOption = static_cast<const SfxStringItem*>(pItem)->GetValue();
1517 lcl_parseHtmlFilterOption(aFilterOption, eLang, bDateConvert);
1520 pInStream->Seek( 0 );
1521 ScRange aRange;
1522 // HTML does its own ColWidth/RowHeight
1523 CalcOutputFactor();
1524 SvNumberFormatter aNumFormatter( comphelper::getProcessComponentContext(), eLang);
1525 eError = ScFormatFilter::Get().ScImportHTML( *pInStream, rMedium.GetBaseURL(), &m_aDocument, aRange,
1526 GetOutputFactor(), !bWebQuery, &aNumFormatter, bDateConvert );
1527 if (eError != ERRCODE_NONE)
1529 if (!GetError())
1530 SetError(eError);
1532 if( eError.IsWarning() )
1533 bRet = true;
1535 else
1536 bRet = true;
1537 m_aDocument.StartAllListeners();
1539 sc::SetFormulaDirtyContext aCxt;
1540 m_aDocument.SetAllFormulasDirty(aCxt);
1542 else
1544 OSL_FAIL( "No Stream" );
1548 if ( eError != ERRCODE_NONE && !GetError() )
1549 SetError(eError);
1551 else
1553 if (!GetError())
1555 SAL_WARN("sc.filter", "No match for filter '" << aFltName << "' in ConvertFrom");
1556 SetError(SCERR_IMPORT_NI);
1560 if (!bCalc3)
1561 m_aDocument.SetInsertingFromOtherDoc( false );
1563 else
1565 OSL_FAIL("No Filter in ConvertFrom");
1568 InitItems();
1569 CalcOutputFactor();
1570 if ( bRet && (bSetColWidths || bSetRowHeights) )
1571 { // Adjust column width/row height; base 100% zoom
1572 Fraction aZoom( 1, 1 );
1573 double nPPTX = ScGlobal::nScreenPPTX * static_cast<double>(aZoom) / GetOutputFactor(); // Factor is printer display ratio
1574 double nPPTY = ScGlobal::nScreenPPTY * static_cast<double>(aZoom);
1575 ScopedVclPtrInstance< VirtualDevice > pVirtDev;
1576 // all sheets (for Excel import)
1577 SCTAB nTabCount = m_aDocument.GetTableCount();
1578 for (SCTAB nTab=0; nTab<nTabCount; nTab++)
1580 SCCOL nEndCol;
1581 SCROW nEndRow;
1582 m_aDocument.GetCellArea( nTab, nEndCol, nEndRow );
1583 aColWidthRange.aEnd.SetCol( nEndCol );
1584 aColWidthRange.aEnd.SetRow( nEndRow );
1585 ScMarkData aMark(m_aDocument.GetSheetLimits());
1586 aMark.SetMarkArea( aColWidthRange );
1587 aMark.MarkToMulti();
1589 // Order is important: First width, then height
1590 if ( bSetColWidths )
1592 for ( SCCOL nCol=0; nCol <= nEndCol; nCol++ )
1594 if (!bSetSimpleTextColWidths)
1595 aColWidthParam[nCol].mbSimpleText = false;
1597 sal_uInt16 nWidth = m_aDocument.GetOptimalColWidth(
1598 nCol, nTab, pVirtDev, nPPTX, nPPTY, aZoom, aZoom, false, &aMark,
1599 &aColWidthParam[nCol] );
1600 m_aDocument.SetColWidth( nCol, nTab,
1601 nWidth + static_cast<sal_uInt16>(ScGlobal::nLastColWidthExtra) );
1606 if (bSetRowHeights)
1608 // Update all rows in all tables.
1609 ScSizeDeviceProvider aProv(this);
1610 ScDocRowHeightUpdater aUpdater(m_aDocument, aProv.GetDevice(), aProv.GetPPTX(), aProv.GetPPTY(), nullptr);
1611 aUpdater.update();
1613 else if (!aRecalcRowRangesArray.empty())
1615 // Update only specified row ranges for better performance.
1616 ScSizeDeviceProvider aProv(this);
1617 ScDocRowHeightUpdater aUpdater(m_aDocument, aProv.GetDevice(), aProv.GetPPTX(), aProv.GetPPTY(), &aRecalcRowRangesArray);
1618 aUpdater.update();
1621 FinishedLoading();
1623 // invalidate eventually temporary table areas
1624 if ( bRet )
1625 m_aDocument.InvalidateTableArea();
1627 m_bIsEmpty = false;
1629 return bRet;
1632 bool ScDocShell::LoadExternal( SfxMedium& rMed )
1634 std::shared_ptr<const SfxFilter> pFilter = rMed.GetFilter();
1635 if (!pFilter)
1636 return false;
1638 if (pFilter->GetProviderName() == "orcus")
1640 ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
1641 if (!pOrcus)
1642 return false;
1644 const OUString& rFilterName = pFilter->GetName();
1645 if (rFilterName == "gnumeric")
1647 if (!pOrcus->importGnumeric(m_aDocument, rMed))
1648 return false;
1650 else if (rFilterName == "csv")
1652 if (!pOrcus->importCSV(m_aDocument, rMed))
1653 return false;
1655 else if (rFilterName == "xlsx")
1657 if (!pOrcus->importXLSX(m_aDocument, rMed))
1658 return false;
1660 else if (rFilterName == "ods")
1662 if (!pOrcus->importODS(m_aDocument, rMed))
1663 return false;
1666 FinishedLoading();
1667 return true;
1670 return false;
1673 ScDocShell::PrepareSaveGuard::PrepareSaveGuard( ScDocShell& rDocShell )
1674 : mrDocShell( rDocShell)
1676 // DoEnterHandler not here (because of AutoSave), is in ExecuteSave.
1678 ScChartListenerCollection* pCharts = mrDocShell.m_aDocument.GetChartListenerCollection();
1679 if (pCharts)
1680 pCharts->UpdateDirtyCharts(); // Charts to be updated.
1681 mrDocShell.m_aDocument.StopTemporaryChartLock();
1682 if (mrDocShell.m_pAutoStyleList)
1683 mrDocShell.m_pAutoStyleList->ExecuteAllNow(); // Execute template timeouts now.
1684 if (mrDocShell.m_aDocument.HasExternalRefManager())
1686 ScExternalRefManager* pRefMgr = mrDocShell.m_aDocument.GetExternalRefManager();
1687 if (pRefMgr && pRefMgr->hasExternalData())
1689 pRefMgr->setAllCacheTableReferencedStati( false);
1690 mrDocShell.m_aDocument.MarkUsedExternalReferences(); // Mark tables of external references to be written.
1693 if (mrDocShell.GetCreateMode()== SfxObjectCreateMode::STANDARD)
1694 mrDocShell.SfxObjectShell::SetVisArea( tools::Rectangle() ); // "Normally" worked on => no VisArea.
1697 ScDocShell::PrepareSaveGuard::~PrepareSaveGuard() COVERITY_NOEXCEPT_FALSE
1699 if (mrDocShell.m_aDocument.HasExternalRefManager())
1701 ScExternalRefManager* pRefMgr = mrDocShell.m_aDocument.GetExternalRefManager();
1702 if (pRefMgr && pRefMgr->hasExternalData())
1704 // Prevent accidental data loss due to lack of knowledge.
1705 pRefMgr->setAllCacheTableReferencedStati( true);
1710 bool ScDocShell::Save()
1712 ScRefreshTimerProtector aProt( m_aDocument.GetRefreshTimerControlAddress() );
1714 PrepareSaveGuard aPrepareGuard( *this);
1716 if (const auto pFrame1 = SfxViewFrame::GetFirst(this))
1718 if (auto pSysWin = pFrame1->GetWindow().GetSystemWindow())
1720 pSysWin->SetAccessibleName(OUString());
1723 // wait cursor is handled with progress bar
1724 bool bRet = SfxObjectShell::Save();
1725 if( bRet )
1726 bRet = SaveXML( GetMedium(), nullptr );
1727 return bRet;
1730 namespace {
1733 * Remove the file name from the full path, to keep only the directory path.
1735 void popFileName(OUString& rPath)
1737 if (!rPath.isEmpty())
1739 INetURLObject aURLObj(rPath);
1740 aURLObj.removeSegment();
1741 rPath = aURLObj.GetMainURL(INetURLObject::DecodeMechanism::NONE);
1747 void ScDocShell::TerminateEditing()
1749 // Commit any cell changes before saving.
1750 SC_MOD()->InputEnterHandler();
1753 bool ScDocShell::SaveAs( SfxMedium& rMedium )
1755 OUString aCurPath; // empty for new document that hasn't been saved.
1756 const SfxMedium* pCurMedium = GetMedium();
1757 if (pCurMedium)
1759 aCurPath = pCurMedium->GetName();
1760 popFileName(aCurPath);
1763 if (!aCurPath.isEmpty())
1765 // current document has a path -> not a brand-new document.
1766 OUString aNewPath = rMedium.GetName();
1767 popFileName(aNewPath);
1768 OUString aRel = URIHelper::simpleNormalizedMakeRelative(aCurPath, aNewPath);
1769 if (!aRel.isEmpty())
1771 // Directory path will change before and after the save.
1772 m_aDocument.InvalidateStreamOnSave();
1776 ScTabViewShell* pViewShell = GetBestViewShell();
1777 bool bNeedsRehash = ScPassHashHelper::needsPassHashRegen(m_aDocument, PASSHASH_SHA1);
1778 if (bNeedsRehash)
1779 // legacy xls hash double-hashed by SHA1 is also supported.
1780 bNeedsRehash = ScPassHashHelper::needsPassHashRegen(m_aDocument, PASSHASH_XL, PASSHASH_SHA1);
1781 if (bNeedsRehash)
1782 { // SHA256 explicitly supported in ODF 1.2, implicitly in ODF 1.1
1783 bNeedsRehash = ScPassHashHelper::needsPassHashRegen(m_aDocument, PASSHASH_SHA256);
1786 if (pViewShell && bNeedsRehash)
1788 if (!pViewShell->ExecuteRetypePassDlg(PASSHASH_SHA1))
1789 // password re-type cancelled. Don't save the document.
1790 return false;
1793 ScRefreshTimerProtector aProt( m_aDocument.GetRefreshTimerControlAddress() );
1795 PrepareSaveGuard aPrepareGuard( *this);
1797 // wait cursor is handled with progress bar
1798 bool bRet = SfxObjectShell::SaveAs( rMedium );
1799 if (bRet)
1800 bRet = SaveXML( &rMedium, nullptr );
1802 return bRet;
1805 namespace {
1807 // Xcl-like column width measured in characters of standard font.
1808 sal_Int32 lcl_ScDocShell_GetColWidthInChars( sal_uInt16 nWidth )
1810 double f = nWidth;
1811 f *= 1328.0 / 25.0;
1812 f += 90.0;
1813 f *= 1.0 / 23.0;
1814 f /= 256.0;
1816 return sal_Int32( f );
1819 void lcl_ScDocShell_GetFixedWidthString( OUString& rStr, const ScDocument& rDoc,
1820 SCTAB nTab, SCCOL nCol, bool bValue, SvxCellHorJustify eHorJust )
1822 OUString aString = rStr;
1823 sal_Int32 nLen = lcl_ScDocShell_GetColWidthInChars(
1824 rDoc.GetColWidth( nCol, nTab ) );
1825 //If the text won't fit in the column
1826 if ( nLen < aString.getLength() )
1828 OUStringBuffer aReplacement;
1829 if (bValue)
1830 aReplacement.append("###");
1831 else
1832 aReplacement.append(aString);
1833 //truncate to the number of characters that should fit, even in the
1834 //bValue case nLen might be < len ###
1835 aString = comphelper::string::truncateToLength(aReplacement, nLen).makeStringAndClear();
1837 if ( nLen > aString.getLength() )
1839 if ( bValue && eHorJust == SvxCellHorJustify::Standard )
1840 eHorJust = SvxCellHorJustify::Right;
1841 sal_Int32 nBlanks = nLen - aString.getLength();
1842 switch ( eHorJust )
1844 case SvxCellHorJustify::Right:
1846 OUStringBuffer aTmp;
1847 comphelper::string::padToLength( aTmp, nBlanks, ' ' );
1848 aString = aTmp.append(aString).makeStringAndClear();
1850 break;
1851 case SvxCellHorJustify::Center:
1853 sal_Int32 nLeftPad = nBlanks / 2;
1854 OUStringBuffer aTmp;
1855 comphelper::string::padToLength( aTmp, nLeftPad, ' ' );
1856 aTmp.append(aString);
1857 comphelper::string::padToLength( aTmp, nLen, ' ' );
1858 aString = aTmp.makeStringAndClear();
1860 break;
1861 default:
1863 OUStringBuffer aTmp(aString);
1864 comphelper::string::padToLength( aTmp, nLen, ' ' );
1865 aString = aTmp.makeStringAndClear();
1869 rStr = aString;
1872 void lcl_ScDocShell_WriteEmptyFixedWidthString( SvStream& rStream,
1873 const ScDocument& rDoc, SCTAB nTab, SCCOL nCol )
1875 OUString aString;
1876 lcl_ScDocShell_GetFixedWidthString( aString, rDoc, nTab, nCol, false,
1877 SvxCellHorJustify::Standard );
1878 rStream.WriteUnicodeOrByteText( aString );
1881 template<typename StrT, typename SepCharT>
1882 sal_Int32 getTextSepPos(
1883 const StrT& rStr, const ScImportOptions& rAsciiOpt, const SepCharT& rTextSep, const SepCharT& rFieldSep, bool& rNeedQuotes)
1885 // #i116636# quotes are needed if text delimiter (quote), field delimiter,
1886 // or LF or CR is in the cell text.
1887 sal_Int32 nPos = rStr.indexOf(rTextSep);
1888 rNeedQuotes = rAsciiOpt.bQuoteAllText || (nPos >= 0) ||
1889 (rStr.indexOf(rFieldSep) >= 0) ||
1890 (rStr.indexOf('\n') >= 0) ||
1891 (rStr.indexOf('\r') >= 0);
1892 return nPos;
1895 template<typename StrT, typename StrBufT>
1896 void escapeTextSep(sal_Int32 nPos, const StrT& rStrDelim, StrT& rStr)
1898 while (nPos >= 0)
1900 StrBufT aBuf(rStr);
1901 aBuf.insert(nPos, rStrDelim);
1902 rStr = aBuf.makeStringAndClear();
1903 nPos = rStr.indexOf(rStrDelim, nPos+1+rStrDelim.getLength());
1909 void ScDocShell::AsciiSave( SvStream& rStream, const ScImportOptions& rAsciiOpt )
1911 sal_Unicode cDelim = rAsciiOpt.nFieldSepCode;
1912 sal_Unicode cStrDelim = rAsciiOpt.nTextSepCode;
1913 rtl_TextEncoding eCharSet = rAsciiOpt.eCharSet;
1914 bool bFixedWidth = rAsciiOpt.bFixedWidth;
1915 bool bSaveNumberAsSuch = rAsciiOpt.bSaveNumberAsSuch;
1916 bool bSaveAsShown = rAsciiOpt.bSaveAsShown;
1917 bool bShowFormulas = rAsciiOpt.bSaveFormulas;
1919 rtl_TextEncoding eOldCharSet = rStream.GetStreamCharSet();
1920 rStream.SetStreamCharSet( eCharSet );
1921 SvStreamEndian nOldNumberFormatInt = rStream.GetEndian();
1922 OString aStrDelimEncoded; // only used if not Unicode
1923 OUString aStrDelimDecoded; // only used if context encoding
1924 OString aDelimEncoded;
1925 OUString aDelimDecoded;
1926 bool bContextOrNotAsciiEncoding;
1927 if ( eCharSet == RTL_TEXTENCODING_UNICODE )
1929 rStream.StartWritingUnicodeText();
1930 bContextOrNotAsciiEncoding = false;
1932 else
1934 aStrDelimEncoded = OString(&cStrDelim, 1, eCharSet);
1935 aDelimEncoded = OString(&cDelim, 1, eCharSet);
1936 rtl_TextEncodingInfo aInfo;
1937 aInfo.StructSize = sizeof(aInfo);
1938 if ( rtl_getTextEncodingInfo( eCharSet, &aInfo ) )
1940 bContextOrNotAsciiEncoding =
1941 (((aInfo.Flags & RTL_TEXTENCODING_INFO_CONTEXT) != 0) ||
1942 ((aInfo.Flags & RTL_TEXTENCODING_INFO_ASCII) == 0));
1943 if ( bContextOrNotAsciiEncoding )
1945 aStrDelimDecoded = OStringToOUString(aStrDelimEncoded, eCharSet);
1946 aDelimDecoded = OStringToOUString(aDelimEncoded, eCharSet);
1949 else
1950 bContextOrNotAsciiEncoding = false;
1953 SCCOL nStartCol = 0;
1954 SCROW nStartRow = 0;
1955 SCTAB nTab = GetSaveTab();
1956 SCCOL nEndCol;
1957 SCROW nEndRow;
1958 m_aDocument.GetCellArea( nTab, nEndCol, nEndRow );
1960 ScProgress aProgress( this, ScResId( STR_SAVE_DOC ), nEndRow, true );
1962 OUString aString;
1964 bool bTabProtect = m_aDocument.IsTabProtected( nTab );
1966 SCCOL nCol;
1967 SCROW nRow;
1968 SCCOL nNextCol = nStartCol;
1969 SCROW nNextRow = nStartRow;
1970 SCCOL nEmptyCol;
1971 SCROW nEmptyRow;
1972 SvNumberFormatter& rFormatter = *m_aDocument.GetFormatTable();
1974 ScHorizontalCellIterator aIter( m_aDocument, nTab, nStartCol, nStartRow,
1975 nEndCol, nEndRow );
1976 ScRefCellValue* pCell;
1977 while ( ( pCell = aIter.GetNext( nCol, nRow ) ) != nullptr )
1979 bool bProgress = false; // only upon line change
1980 if ( nNextRow < nRow )
1981 { // empty rows or/and empty columns up to end of row
1982 bProgress = true;
1983 for ( nEmptyCol = nNextCol; nEmptyCol < nEndCol; nEmptyCol++ )
1984 { // remaining columns of last row
1985 if ( bFixedWidth )
1986 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
1987 m_aDocument, nTab, nEmptyCol );
1988 else if ( cDelim != 0 )
1989 rStream.WriteUniOrByteChar( cDelim );
1991 endlub( rStream );
1992 nNextRow++;
1993 for ( nEmptyRow = nNextRow; nEmptyRow < nRow; nEmptyRow++ )
1994 { // completely empty rows
1995 for ( nEmptyCol = nStartCol; nEmptyCol < nEndCol; nEmptyCol++ )
1997 if ( bFixedWidth )
1998 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
1999 m_aDocument, nTab, nEmptyCol );
2000 else if ( cDelim != 0 )
2001 rStream.WriteUniOrByteChar( cDelim );
2003 endlub( rStream );
2005 for ( nEmptyCol = nStartCol; nEmptyCol < nCol; nEmptyCol++ )
2006 { // empty columns at beginning of row
2007 if ( bFixedWidth )
2008 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2009 m_aDocument, nTab, nEmptyCol );
2010 else if ( cDelim != 0 )
2011 rStream.WriteUniOrByteChar( cDelim );
2013 nNextRow = nRow;
2015 else if ( nNextCol < nCol )
2016 { // empty columns in same row
2017 for ( nEmptyCol = nNextCol; nEmptyCol < nCol; nEmptyCol++ )
2018 { // columns in between
2019 if ( bFixedWidth )
2020 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2021 m_aDocument, nTab, nEmptyCol );
2022 else if ( cDelim != 0 )
2023 rStream.WriteUniOrByteChar( cDelim );
2026 if ( nCol == nEndCol )
2028 bProgress = true;
2029 nNextCol = nStartCol;
2030 nNextRow = nRow + 1;
2032 else
2033 nNextCol = nCol + 1;
2035 CellType eType = pCell->meType;
2036 ScAddress aPos(nCol, nRow, nTab);
2037 if ( bTabProtect )
2039 const ScProtectionAttr* pProtAttr =
2040 m_aDocument.GetAttr( nCol, nRow, nTab, ATTR_PROTECTION );
2041 if ( pProtAttr->GetHideCell() ||
2042 ( eType == CELLTYPE_FORMULA && bShowFormulas &&
2043 pProtAttr->GetHideFormula() ) )
2044 eType = CELLTYPE_NONE; // hide
2046 bool bForceQuotes = false;
2047 bool bString;
2048 switch ( eType )
2050 case CELLTYPE_NONE:
2051 aString.clear();
2052 bString = false;
2053 break;
2054 case CELLTYPE_FORMULA :
2056 FormulaError nErrCode;
2057 if ( bShowFormulas )
2059 pCell->mpFormula->GetFormula(aString);
2060 bString = true;
2062 else if ((nErrCode = pCell->mpFormula->GetErrCode()) != FormulaError::NONE)
2064 aString = ScGlobal::GetErrorString( nErrCode );
2065 bString = true;
2067 else if (pCell->mpFormula->IsValue())
2069 sal_uInt32 nFormat = m_aDocument.GetNumberFormat(aPos);
2070 if ( bFixedWidth || bSaveAsShown )
2072 const Color* pDummy;
2073 ScCellFormat::GetString(*pCell, nFormat, aString, &pDummy, rFormatter, m_aDocument);
2074 bString = bSaveAsShown && rFormatter.IsTextFormat( nFormat);
2076 else
2078 ScCellFormat::GetInputString(*pCell, nFormat, aString, rFormatter, m_aDocument);
2079 bString = bForceQuotes = !bSaveNumberAsSuch;
2082 else
2084 if ( bSaveAsShown )
2086 sal_uInt32 nFormat = m_aDocument.GetNumberFormat(aPos);
2087 const Color* pDummy;
2088 ScCellFormat::GetString(*pCell, nFormat, aString, &pDummy, rFormatter, m_aDocument);
2090 else
2091 aString = pCell->mpFormula->GetString().getString();
2092 bString = true;
2095 break;
2096 case CELLTYPE_STRING :
2097 if ( bSaveAsShown )
2099 sal_uInt32 nFormat = m_aDocument.GetNumberFormat(aPos);
2100 const Color* pDummy;
2101 ScCellFormat::GetString(*pCell, nFormat, aString, &pDummy, rFormatter, m_aDocument);
2103 else
2104 aString = pCell->mpString->getString();
2105 bString = true;
2106 break;
2107 case CELLTYPE_EDIT :
2109 const EditTextObject* pObj = pCell->mpEditText;
2110 EditEngine& rEngine = m_aDocument.GetEditEngine();
2111 rEngine.SetText( *pObj);
2112 aString = rEngine.GetText(); // including LF
2113 bString = true;
2115 break;
2116 case CELLTYPE_VALUE :
2118 sal_uInt32 nFormat;
2119 m_aDocument.GetNumberFormat( nCol, nRow, nTab, nFormat );
2120 if ( bFixedWidth || bSaveAsShown )
2122 const Color* pDummy;
2123 ScCellFormat::GetString(*pCell, nFormat, aString, &pDummy, rFormatter, m_aDocument);
2124 bString = bSaveAsShown && rFormatter.IsTextFormat( nFormat);
2126 else
2128 ScCellFormat::GetInputString(*pCell, nFormat, aString, rFormatter, m_aDocument);
2129 bString = bForceQuotes = !bSaveNumberAsSuch;
2132 break;
2133 default:
2134 OSL_FAIL( "ScDocShell::AsciiSave: unknown CellType" );
2135 aString.clear();
2136 bString = false;
2139 if ( bFixedWidth )
2141 SvxCellHorJustify eHorJust =
2142 m_aDocument.GetAttr( nCol, nRow, nTab, ATTR_HOR_JUSTIFY )->GetValue();
2143 lcl_ScDocShell_GetFixedWidthString( aString, m_aDocument, nTab, nCol,
2144 !bString, eHorJust );
2145 rStream.WriteUnicodeOrByteText( aString );
2147 else
2149 OUString aUniString = aString;// TODO: remove that later
2150 if (!bString && cStrDelim != 0 && !aUniString.isEmpty())
2152 sal_Unicode c = aUniString[0];
2153 bString = (c == cStrDelim || c == ' ' ||
2154 aUniString.endsWith(" ") ||
2155 aUniString.indexOf(cStrDelim) >= 0);
2156 if (!bString && cDelim != 0)
2157 bString = (aUniString.indexOf(cDelim) >= 0);
2159 if ( bString )
2161 if ( cStrDelim != 0 ) //@ BugId 55355
2163 if ( eCharSet == RTL_TEXTENCODING_UNICODE )
2165 bool bNeedQuotes = false;
2166 sal_Int32 nPos = getTextSepPos(
2167 aUniString, rAsciiOpt, cStrDelim, cDelim, bNeedQuotes);
2169 escapeTextSep<OUString, OUStringBuffer>(
2170 nPos, OUString(cStrDelim), aUniString);
2172 if ( bNeedQuotes || bForceQuotes )
2173 rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
2174 write_uInt16s_FromOUString(rStream, aUniString);
2175 if ( bNeedQuotes || bForceQuotes )
2176 rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
2178 else
2180 // This is nasty. The Unicode to byte encoding
2181 // may convert typographical quotation marks to ASCII
2182 // quotation marks, which may interfere with the delimiter,
2183 // so we have to escape delimiters after the string has
2184 // been encoded. Since this may happen also with UTF-8
2185 // encoded typographical quotation marks if such was
2186 // specified as a delimiter we have to check for the full
2187 // encoded delimiter string, not just one character.
2188 // Now for RTL_TEXTENCODING_ISO_2022_... and similar brain
2189 // dead encodings where one code point (and especially a
2190 // low ASCII value) may represent different characters, we
2191 // have to convert forth and back and forth again. Same for
2192 // UTF-7 since it is a context sensitive encoding too.
2194 if ( bContextOrNotAsciiEncoding )
2196 // to byte encoding
2197 OString aStrEnc = OUStringToOString(aUniString, eCharSet);
2198 // back to Unicode
2199 OUString aStrDec = OStringToOUString(aStrEnc, eCharSet);
2201 // search on re-decoded string
2202 bool bNeedQuotes = false;
2203 sal_Int32 nPos = getTextSepPos(
2204 aStrDec, rAsciiOpt, aStrDelimDecoded, aDelimDecoded, bNeedQuotes);
2206 escapeTextSep<OUString, OUStringBuffer>(
2207 nPos, aStrDelimDecoded, aStrDec);
2209 // write byte re-encoded
2210 if ( bNeedQuotes || bForceQuotes )
2211 rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
2212 rStream.WriteUnicodeOrByteText( aStrDec, eCharSet );
2213 if ( bNeedQuotes || bForceQuotes )
2214 rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
2216 else
2218 OString aStrEnc = OUStringToOString(aUniString, eCharSet);
2220 // search on encoded string
2221 bool bNeedQuotes = false;
2222 sal_Int32 nPos = getTextSepPos(
2223 aStrEnc, rAsciiOpt, aStrDelimEncoded, aDelimEncoded, bNeedQuotes);
2225 escapeTextSep<OString, OStringBuffer>(
2226 nPos, aStrDelimEncoded, aStrEnc);
2228 // write byte encoded
2229 if ( bNeedQuotes || bForceQuotes )
2230 rStream.WriteBytes(
2231 aStrDelimEncoded.getStr(), aStrDelimEncoded.getLength());
2232 rStream.WriteBytes(aStrEnc.getStr(), aStrEnc.getLength());
2233 if ( bNeedQuotes || bForceQuotes )
2234 rStream.WriteBytes(
2235 aStrDelimEncoded.getStr(), aStrDelimEncoded.getLength());
2239 else
2240 rStream.WriteUnicodeOrByteText( aUniString );
2242 else
2243 rStream.WriteUnicodeOrByteText( aUniString );
2246 if( nCol < nEndCol )
2248 if(cDelim!=0) //@ BugId 55355
2249 rStream.WriteUniOrByteChar( cDelim );
2251 else
2252 endlub( rStream );
2254 if ( bProgress )
2255 aProgress.SetStateOnPercent( nRow );
2258 // write out empty if requested
2259 if ( nNextRow <= nEndRow )
2261 for ( nEmptyCol = nNextCol; nEmptyCol < nEndCol; nEmptyCol++ )
2262 { // remaining empty columns of last row
2263 if ( bFixedWidth )
2264 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2265 m_aDocument, nTab, nEmptyCol );
2266 else if ( cDelim != 0 )
2267 rStream.WriteUniOrByteChar( cDelim );
2269 endlub( rStream );
2270 nNextRow++;
2272 for ( nEmptyRow = nNextRow; nEmptyRow <= nEndRow; nEmptyRow++ )
2273 { // entire empty rows
2274 for ( nEmptyCol = nStartCol; nEmptyCol < nEndCol; nEmptyCol++ )
2276 if ( bFixedWidth )
2277 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2278 m_aDocument, nTab, nEmptyCol );
2279 else if ( cDelim != 0 )
2280 rStream.WriteUniOrByteChar( cDelim );
2282 endlub( rStream );
2285 rStream.SetStreamCharSet( eOldCharSet );
2286 rStream.SetEndian( nOldNumberFormatInt );
2289 bool ScDocShell::ConvertTo( SfxMedium &rMed )
2291 ScRefreshTimerProtector aProt( m_aDocument.GetRefreshTimerControlAddress() );
2293 // #i6500# don't call DoEnterHandler here (doesn't work with AutoSave),
2294 // it's already in ExecuteSave (as for Save and SaveAs)
2296 if (m_pAutoStyleList)
2297 m_pAutoStyleList->ExecuteAllNow(); // Execute template timeouts now
2298 if (GetCreateMode()== SfxObjectCreateMode::STANDARD)
2299 SfxObjectShell::SetVisArea( tools::Rectangle() ); // Edited normally -> no VisArea
2301 OSL_ENSURE( rMed.GetFilter(), "Filter == 0" );
2303 bool bRet = false;
2304 OUString aFltName = rMed.GetFilter()->GetFilterName();
2306 if (aFltName == pFilterXML)
2308 //TODO/LATER: this shouldn't happen!
2309 OSL_FAIL("XML filter in ConvertFrom?!");
2310 bRet = SaveXML( &rMed, nullptr );
2312 else if (aFltName == pFilterExcel5 || aFltName == pFilterExcel95 ||
2313 aFltName == pFilterExcel97 || aFltName == pFilterEx5Temp ||
2314 aFltName == pFilterEx95Temp || aFltName == pFilterEx97Temp)
2316 weld::WaitObject aWait( GetActiveDialogParent() );
2318 bool bDoSave = true;
2319 if( ScTabViewShell* pViewShell = GetBestViewShell() )
2321 ScExtDocOptions* pExtDocOpt = m_aDocument.GetExtDocOptions();
2322 if( !pExtDocOpt )
2324 m_aDocument.SetExtDocOptions( std::make_unique<ScExtDocOptions>() );
2325 pExtDocOpt = m_aDocument.GetExtDocOptions();
2327 pViewShell->GetViewData().WriteExtOptions( *pExtDocOpt );
2329 /* #i104990# If the imported document contains a medium
2330 password, determine if we can save it, otherwise ask the users
2331 whether they want to save without it. */
2332 if( (rMed.GetFilter()->GetFilterFlags() & SfxFilterFlags::ENCRYPTION) == SfxFilterFlags::NONE )
2334 SfxItemSet* pItemSet = rMed.GetItemSet();
2335 const SfxPoolItem* pItem = nullptr;
2336 if( pItemSet && pItemSet->GetItemState( SID_PASSWORD, true, &pItem ) == SfxItemState::SET )
2338 bDoSave = ScWarnPassword::WarningOnPassword( rMed );
2339 // #i42858# remove password from medium (warn only one time)
2340 if( bDoSave )
2341 pItemSet->ClearItem( SID_PASSWORD );
2345 if( bDoSave )
2347 bool bNeedRetypePassDlg = ScPassHashHelper::needsPassHashRegen( m_aDocument, PASSHASH_XL );
2348 bDoSave = !bNeedRetypePassDlg || pViewShell->ExecuteRetypePassDlg( PASSHASH_XL );
2352 if( bDoSave )
2354 ExportFormatExcel eFormat = ExpBiff5;
2355 if( aFltName == pFilterExcel97 || aFltName == pFilterEx97Temp )
2356 eFormat = ExpBiff8;
2357 ErrCode eError = ScFormatFilter::Get().ScExportExcel5( rMed, &m_aDocument, eFormat, RTL_TEXTENCODING_MS_1252 );
2359 if( eError && !GetError() )
2360 SetError(eError);
2362 // don't return false for warnings
2363 bRet = eError.IsWarning() || (eError == ERRCODE_NONE);
2365 else
2367 // export aborted, i.e. "Save without password" warning
2368 SetError(ERRCODE_ABORT);
2371 else if (aFltName == pFilterAscii)
2373 SvStream* pStream = rMed.GetOutStream();
2374 if (pStream)
2376 OUString sItStr;
2377 SfxItemSet* pSet = rMed.GetItemSet();
2378 const SfxPoolItem* pItem;
2379 if ( pSet && SfxItemState::SET ==
2380 pSet->GetItemState( SID_FILE_FILTEROPTIONS, true, &pItem ) )
2382 sItStr = static_cast<const SfxStringItem*>(pItem)->GetValue();
2385 if ( sItStr.isEmpty() )
2387 // default for ascii export (from API without options):
2388 // ISO8859-1/MS_1252 encoding, comma, double quotes
2390 ScImportOptions aDefOptions( ',', '"', RTL_TEXTENCODING_MS_1252 );
2391 sItStr = aDefOptions.BuildString();
2394 weld::WaitObject aWait( GetActiveDialogParent() );
2395 ScImportOptions aOptions( sItStr );
2396 AsciiSave( *pStream, aOptions );
2397 bRet = true;
2399 if (m_aDocument.GetTableCount() > 1)
2400 if (!rMed.GetError())
2401 rMed.SetError(SCWARN_EXPORT_ASCII);
2404 else if (aFltName == pFilterDBase)
2406 OUString sCharSet;
2407 SfxItemSet* pSet = rMed.GetItemSet();
2408 const SfxPoolItem* pItem;
2409 if ( pSet && SfxItemState::SET ==
2410 pSet->GetItemState( SID_FILE_FILTEROPTIONS, true, &pItem ) )
2412 sCharSet = static_cast<const SfxStringItem*>(pItem)->GetValue();
2415 if (sCharSet.isEmpty())
2417 // default for dBase export (from API without options):
2418 // IBM_850 encoding
2420 sCharSet = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_850 );
2423 weld::WaitObject aWait( GetActiveDialogParent() );
2424 // Hack so that Sba can overwrite the opened TempFile.
2425 rMed.CloseOutStream();
2426 bool bHasMemo = false;
2428 ErrCode eError = DBaseExport(
2429 rMed.GetPhysicalName(), ScGlobal::GetCharsetValue(sCharSet), bHasMemo);
2431 INetURLObject aTmpFile( rMed.GetPhysicalName(), INetProtocol::File );
2432 if ( bHasMemo )
2433 aTmpFile.setExtension("dbt");
2434 if ( eError != ERRCODE_NONE && !eError.IsWarning() )
2436 if (!GetError())
2437 SetError(eError);
2438 if ( bHasMemo && IsDocument( aTmpFile ) )
2439 KillFile( aTmpFile );
2441 else
2443 bRet = true;
2444 if ( bHasMemo )
2446 const SfxStringItem* pNameItem = rMed.GetItemSet()->GetItem<SfxStringItem>( SID_FILE_NAME );
2447 INetURLObject aDbtFile( pNameItem->GetValue(), INetProtocol::File );
2448 aDbtFile.setExtension("dbt");
2450 // tdf#40713: don't lose dbt file
2451 // if aDbtFile corresponds exactly to aTmpFile, we just have to return
2452 if (aDbtFile.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ) ==
2453 aTmpFile.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ))
2455 if (eError != ERRCODE_NONE && !GetError())
2456 SetError(eError);
2457 return bRet;
2460 if ( IsDocument( aDbtFile ) && !KillFile( aDbtFile ) )
2461 bRet = false;
2462 if ( bRet && !MoveFile( aTmpFile, aDbtFile ) )
2463 bRet = false;
2464 if ( !bRet )
2466 KillFile( aTmpFile );
2467 if (eError == ERRCODE_NONE || eError.IsWarning())
2468 eError = SCERR_EXPORT_DATA;
2471 if (eError != ERRCODE_NONE && !GetError())
2472 SetError(eError);
2475 else if (aFltName == pFilterDif)
2477 SvStream* pStream = rMed.GetOutStream();
2478 if (pStream)
2480 OUString sItStr;
2481 SfxItemSet* pSet = rMed.GetItemSet();
2482 const SfxPoolItem* pItem;
2483 if ( pSet && SfxItemState::SET ==
2484 pSet->GetItemState( SID_FILE_FILTEROPTIONS, true, &pItem ) )
2486 sItStr = static_cast<const SfxStringItem*>(pItem)->GetValue();
2489 if (sItStr.isEmpty())
2491 // default for DIF export (from API without options):
2492 // ISO8859-1/MS_1252 encoding
2494 sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_MS_1252 );
2497 weld::WaitObject aWait( GetActiveDialogParent() );
2498 ScFormatFilter::Get().ScExportDif( *pStream, &m_aDocument, ScAddress(0,0,0),
2499 ScGlobal::GetCharsetValue(sItStr) );
2500 bRet = true;
2502 if (m_aDocument.GetTableCount() > 1)
2503 if (!rMed.GetError())
2504 rMed.SetError(SCWARN_EXPORT_ASCII);
2507 else if (aFltName == pFilterSylk)
2509 SvStream* pStream = rMed.GetOutStream();
2510 if ( pStream )
2512 weld::WaitObject aWait( GetActiveDialogParent() );
2514 SCCOL nEndCol;
2515 SCROW nEndRow;
2516 m_aDocument.GetCellArea( 0, nEndCol, nEndRow );
2517 ScRange aRange( 0,0,0, nEndCol,nEndRow,0 );
2519 ScImportExport aImExport( m_aDocument, aRange );
2520 aImExport.SetFormulas( true );
2521 bRet = aImExport.ExportStream( *pStream, rMed.GetBaseURL( true ), SotClipboardFormatId::SYLK );
2524 else if (aFltName == pFilterHtml)
2526 SvStream* pStream = rMed.GetOutStream();
2527 if ( pStream )
2529 SfxItemSet* pSet = rMed.GetItemSet();
2530 const SfxPoolItem* pItem;
2531 OUString sFilterOptions;
2533 if (pSet->GetItemState(SID_FILE_FILTEROPTIONS, true, &pItem) == SfxItemState::SET)
2534 sFilterOptions = static_cast<const SfxStringItem*>(pItem)->GetValue();
2536 weld::WaitObject aWait(GetActiveDialogParent());
2537 ScImportExport aImExport(m_aDocument);
2538 aImExport.SetStreamPath(rMed.GetName());
2539 aImExport.SetFilterOptions(sFilterOptions);
2540 bRet = aImExport.ExportStream(*pStream, rMed.GetBaseURL(true), SotClipboardFormatId::HTML);
2541 if (bRet && !aImExport.GetNonConvertibleChars().isEmpty())
2543 SetError(*new StringErrorInfo(
2544 SCWARN_EXPORT_NONCONVERTIBLE_CHARS,
2545 aImExport.GetNonConvertibleChars(),
2546 DialogMask::ButtonsOk | DialogMask::MessageInfo));
2550 else
2552 if (GetError())
2553 SetError(SCERR_IMPORT_NI);
2555 return bRet;
2558 bool ScDocShell::DoSaveCompleted( SfxMedium * pNewStor, bool bRegisterRecent )
2560 bool bRet = SfxObjectShell::DoSaveCompleted( pNewStor, bRegisterRecent );
2562 // SfxHintId::ScDocSaved for change ReadOnly -> Read/Write
2563 Broadcast( SfxHint( SfxHintId::ScDocSaved ) );
2564 return bRet;
2567 bool ScDocShell::QuerySlotExecutable( sal_uInt16 nSlotId )
2569 // #i112634# ask VBA event handlers whether to save or print the document
2571 using namespace ::com::sun::star::script::vba;
2573 sal_Int32 nVbaEventId = VBAEventId::NO_EVENT;
2574 uno::Sequence< uno::Any > aArgs;
2575 switch( nSlotId )
2577 case SID_SAVEDOC:
2578 case SID_SAVEASDOC:
2579 nVbaEventId = VBAEventId::WORKBOOK_BEFORESAVE;
2580 aArgs.realloc( 1 );
2581 aArgs[ 0 ] <<= (nSlotId == SID_SAVEASDOC);
2582 break;
2583 case SID_PRINTDOC:
2584 case SID_PRINTDOCDIRECT:
2585 nVbaEventId = VBAEventId::WORKBOOK_BEFOREPRINT;
2586 break;
2589 bool bSlotExecutable = true;
2590 if( nVbaEventId != VBAEventId::NO_EVENT ) try
2592 uno::Reference< XVBAEventProcessor > xEventProcessor( m_aDocument.GetVbaEventProcessor(), uno::UNO_SET_THROW );
2593 xEventProcessor->processVbaEvent( nVbaEventId, aArgs );
2595 catch( util::VetoException& )
2597 bSlotExecutable = false;
2599 catch( uno::Exception& )
2602 return bSlotExecutable;
2605 bool ScDocShell::PrepareClose( bool bUI )
2607 if(SC_MOD()->GetCurRefDlgId()>0)
2609 SfxViewFrame* pFrame = SfxViewFrame::GetFirst( this );
2610 if( pFrame )
2612 SfxViewShell* p = pFrame->GetViewShell();
2613 ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( p );
2614 if(pViewSh!=nullptr)
2616 vcl::Window *pWin=pViewSh->GetWindow();
2617 if(pWin!=nullptr) pWin->GrabFocus();
2621 return false;
2623 if ( m_aDocument.IsInLinkUpdate() || m_aDocument.IsInInterpreter() )
2625 ErrorMessage(STR_CLOSE_ERROR_LINK);
2626 return false;
2629 DoEnterHandler();
2631 // start 'Workbook_BeforeClose' VBA event handler for possible veto
2632 if( !IsInPrepareClose() )
2636 uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( m_aDocument.GetVbaEventProcessor(), uno::UNO_SET_THROW );
2637 uno::Sequence< uno::Any > aArgs;
2638 xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKBOOK_BEFORECLOSE, aArgs );
2640 catch( util::VetoException& )
2642 // if event processor throws VetoException, macro has vetoed close
2643 return false;
2645 catch( uno::Exception& )
2649 // end handler code
2651 bool bRet = SfxObjectShell::PrepareClose( bUI );
2652 if (bRet) // true == close
2653 m_aDocument.EnableIdle(false); // Do not mess around with it anymore!
2655 return bRet;
2658 OUString ScDocShell::GetOwnFilterName()
2660 return pFilterSc50;
2663 OUString ScDocShell::GetHtmlFilterName()
2665 return pFilterHtml;
2668 OUString ScDocShell::GetWebQueryFilterName()
2670 return pFilterHtmlWebQ;
2673 OUString ScDocShell::GetAsciiFilterName()
2675 return pFilterAscii;
2678 OUString ScDocShell::GetLotusFilterName()
2680 return pFilterLotus;
2683 OUString ScDocShell::GetDBaseFilterName()
2685 return pFilterDBase;
2688 OUString ScDocShell::GetDifFilterName()
2690 return pFilterDif;
2693 bool ScDocShell::HasAutomaticTableName( const OUString& rFilter )
2695 // sal_True for those filters that keep the default table name
2696 // (which is language specific)
2698 return rFilter == pFilterAscii
2699 || rFilter == pFilterLotus
2700 || rFilter == pFilterExcel4
2701 || rFilter == pFilterEx4Temp
2702 || rFilter == pFilterDBase
2703 || rFilter == pFilterDif
2704 || rFilter == pFilterSylk
2705 || rFilter == pFilterHtml
2706 || rFilter == pFilterRtf;
2709 std::unique_ptr<ScDocFunc> ScDocShell::CreateDocFunc()
2711 return std::make_unique<ScDocFuncDirect>( *this );
2714 ScDocShell::ScDocShell( const SfxModelFlags i_nSfxCreationFlags ) :
2715 SfxObjectShell( i_nSfxCreationFlags ),
2716 m_aDocument ( SCDOCMODE_DOCUMENT, this ),
2717 m_aDdeTextFmt(OUString("TEXT")),
2718 m_nPrtToScreenFactor( 1.0 ),
2719 m_pImpl ( new DocShell_Impl ),
2720 m_bHeaderOn ( true ),
2721 m_bFooterOn ( true ),
2722 m_bIsEmpty ( true ),
2723 m_bIsInUndo ( false ),
2724 m_bDocumentModifiedPending( false ),
2725 m_bUpdateEnabled ( true ),
2726 m_bUcalcTest ( false ),
2727 m_bAreasChangedNeedBroadcast( false ),
2728 m_nDocumentLock ( 0 ),
2729 m_nCanUpdate (css::document::UpdateDocMode::ACCORDING_TO_CONFIG)
2731 SetPool( &SC_MOD()->GetPool() );
2733 m_bIsInplace = (GetCreateMode() == SfxObjectCreateMode::EMBEDDED);
2734 // Will be reset if not in place
2736 m_pDocFunc = CreateDocFunc();
2738 // SetBaseModel needs exception handling
2739 ScModelObj::CreateAndSet( this );
2741 StartListening(*this);
2742 SfxStyleSheetPool* pStlPool = m_aDocument.GetStyleSheetPool();
2743 if (pStlPool)
2744 StartListening(*pStlPool);
2746 m_aDocument.GetDBCollection()->SetRefreshHandler(
2747 LINK( this, ScDocShell, RefreshDBDataHdl ) );
2749 // InitItems and CalcOutputFactor are called now in Load/ConvertFrom/InitNew
2752 ScDocShell::~ScDocShell()
2754 ResetDrawObjectShell(); // If the Drawing Layer still tries to access it, access it
2756 SfxStyleSheetPool* pStlPool = m_aDocument.GetStyleSheetPool();
2757 if (pStlPool)
2758 EndListening(*pStlPool);
2759 EndListening(*this);
2761 m_pAutoStyleList.reset();
2763 SfxApplication *pSfxApp = SfxGetpApp();
2764 if ( pSfxApp->GetDdeService() ) // Delete DDE for Document
2765 pSfxApp->RemoveDdeTopic( this );
2767 m_pDocFunc.reset();
2768 delete m_aDocument.mpUndoManager;
2769 m_aDocument.mpUndoManager = nullptr;
2770 m_pImpl.reset();
2772 m_pPaintLockData.reset();
2774 m_pSolverSaveData.reset();
2775 m_pSheetSaveData.reset();
2776 m_pFormatSaveData.reset();
2777 m_pOldAutoDBRange.reset();
2779 if (m_pModificator)
2781 OSL_FAIL("The Modificator should not exist");
2782 m_pModificator.reset();
2786 SfxUndoManager* ScDocShell::GetUndoManager()
2788 return m_aDocument.GetUndoManager();
2791 void ScDocShell::SetModified( bool bModified )
2793 if ( SfxObjectShell::IsEnableSetModified() )
2795 SfxObjectShell::SetModified( bModified );
2796 Broadcast( SfxHint( SfxHintId::DocChanged ) );
2800 void ScDocShell::SetDocumentModified()
2802 // BroadcastUno must also happen right away with pPaintLockData
2803 // FIXME: Also for SetDrawModified, if Drawing is connected
2804 // FIXME: Then own Hint?
2806 if ( m_pPaintLockData )
2808 // #i115009# broadcast BCA_BRDCST_ALWAYS, so a component can read recalculated results
2809 // of RecalcModeAlways formulas (like OFFSET) after modifying cells
2810 m_aDocument.Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS));
2811 m_aDocument.InvalidateTableArea(); // #i105279# needed here
2812 m_aDocument.BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
2814 m_pPaintLockData->SetModified(); // Later on ...
2815 return;
2818 SetDrawModified();
2820 if ( m_aDocument.IsAutoCalcShellDisabled() )
2821 SetDocumentModifiedPending( true );
2822 else
2824 SetDocumentModifiedPending( false );
2825 m_aDocument.InvalidateStyleSheetUsage();
2826 m_aDocument.InvalidateTableArea();
2827 m_aDocument.InvalidateLastTableOpParams();
2828 m_aDocument.Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS));
2829 if ( m_aDocument.IsForcedFormulaPending() && m_aDocument.GetAutoCalc() )
2830 m_aDocument.CalcFormulaTree( true );
2831 m_aDocument.RefreshDirtyTableColumnNames();
2832 PostDataChanged();
2834 // Detective AutoUpdate:
2835 // Update if formulas were modified (DetectiveDirty) or the list contains
2836 // "Trace Error" entries (Trace Error can look completely different
2837 // after changes to non-formula cells).
2839 ScDetOpList* pList = m_aDocument.GetDetOpList();
2840 if ( pList && ( m_aDocument.IsDetectiveDirty() || pList->HasAddError() ) &&
2841 pList->Count() && !IsInUndo() && SC_MOD()->GetAppOptions().GetDetectiveAuto() )
2843 GetDocFunc().DetectiveRefresh(true); // sal_True = caused by automatic update
2845 m_aDocument.SetDetectiveDirty(false); // always reset, also if not refreshed
2848 if (m_bAreasChangedNeedBroadcast)
2850 m_bAreasChangedNeedBroadcast = false;
2851 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged));
2854 // notify UNO objects after BCA_BRDCST_ALWAYS etc.
2855 m_aDocument.BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
2859 * SetDrawModified - without Formula update
2861 * Drawing also needs to be updated for the normal SetDocumentModified
2862 * e.g.: when deleting tables etc.
2864 void ScDocShell::SetDrawModified()
2866 bool bUpdate = !IsModified();
2868 SetModified();
2870 SfxBindings* pBindings = GetViewBindings();
2871 if (bUpdate && pBindings)
2873 pBindings->Invalidate( SID_SAVEDOC );
2874 pBindings->Invalidate( SID_DOC_MODIFIED );
2877 if (pBindings)
2879 // #i105960# Undo etc used to be volatile.
2880 // They always have to be invalidated, including drawing layer or row height changes
2881 // (but not while pPaintLockData is set).
2882 pBindings->Invalidate( SID_UNDO );
2883 pBindings->Invalidate( SID_REDO );
2884 pBindings->Invalidate( SID_REPEAT );
2887 if ( m_aDocument.IsChartListenerCollectionNeedsUpdate() )
2889 m_aDocument.UpdateChartListenerCollection();
2890 SfxGetpApp()->Broadcast(SfxHint( SfxHintId::ScDrawChanged )); // Navigator
2892 SC_MOD()->AnythingChanged();
2895 void ScDocShell::SetInUndo(bool bSet)
2897 m_bIsInUndo = bSet;
2900 void ScDocShell::GetDocStat( ScDocStat& rDocStat )
2902 SfxPrinter* pPrinter = GetPrinter();
2904 m_aDocument.GetDocStat( rDocStat );
2905 rDocStat.nPageCount = 0;
2907 if ( pPrinter )
2908 for ( SCTAB i=0; i<rDocStat.nTableCount; i++ )
2909 rDocStat.nPageCount = sal::static_int_cast<sal_uInt16>( rDocStat.nPageCount +
2910 static_cast<sal_uInt16>(ScPrintFunc( this, pPrinter, i ).GetTotalPages()) );
2913 std::shared_ptr<SfxDocumentInfoDialog> ScDocShell::CreateDocumentInfoDialog(weld::Window* pParent, const SfxItemSet &rSet)
2915 std::shared_ptr<SfxDocumentInfoDialog> xDlg = std::make_shared<SfxDocumentInfoDialog>(pParent, rSet);
2916 ScDocShell* pDocSh = dynamic_cast< ScDocShell *>( SfxObjectShell::Current() );
2918 // Only for statistics, if this Doc is shown; not from the Doc Manager
2919 if( pDocSh == this )
2921 ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
2922 ::CreateTabPage ScDocStatPageCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_STAT);
2923 OSL_ENSURE(ScDocStatPageCreate, "Tabpage create fail!");
2924 xDlg->AddFontTabPage();
2925 xDlg->AddTabPage("calcstats", ScResId(STR_DOC_STAT), ScDocStatPageCreate);
2927 return xDlg;
2930 weld::Window* ScDocShell::GetActiveDialogParent()
2932 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
2933 if ( pViewSh )
2934 return pViewSh->GetDialogParent();
2935 vcl::Window* pRet = Application::GetDefDialogParent();
2936 return pRet ? pRet->GetFrameWeld() : nullptr;
2939 void ScDocShell::SetSolverSaveData( std::unique_ptr<ScOptSolverSave> pData )
2941 m_pSolverSaveData = std::move(pData);
2944 ScSheetSaveData* ScDocShell::GetSheetSaveData()
2946 if (!m_pSheetSaveData)
2947 m_pSheetSaveData.reset( new ScSheetSaveData );
2949 return m_pSheetSaveData.get();
2952 ScFormatSaveData* ScDocShell::GetFormatSaveData()
2954 if (!m_pFormatSaveData)
2955 m_pFormatSaveData.reset( new ScFormatSaveData );
2957 return m_pFormatSaveData.get();
2960 namespace {
2962 void removeKeysIfExists(const Reference<ui::XAcceleratorConfiguration>& xScAccel, const vector<const awt::KeyEvent*>& rKeys)
2964 for (const awt::KeyEvent* p : rKeys)
2966 if (!p)
2967 continue;
2971 xScAccel->removeKeyEvent(*p);
2973 catch (const container::NoSuchElementException&) {}
2979 void ScDocShell::ResetKeyBindings( ScOptionsUtil::KeyBindingType eType )
2981 using namespace ::com::sun::star::ui;
2983 Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
2984 if (!xContext.is())
2985 return;
2987 Reference<XModuleUIConfigurationManagerSupplier> xModuleCfgSupplier(
2988 theModuleUIConfigurationManagerSupplier::get(xContext) );
2990 // Grab the Calc configuration.
2991 Reference<XUIConfigurationManager> xConfigMgr =
2992 xModuleCfgSupplier->getUIConfigurationManager(
2993 "com.sun.star.sheet.SpreadsheetDocument");
2995 if (!xConfigMgr.is())
2996 return;
2998 // shortcut manager
2999 Reference<XAcceleratorConfiguration> xScAccel = xConfigMgr->getShortCutManager();
3001 if (!xScAccel.is())
3002 return;
3004 vector<const awt::KeyEvent*> aKeys;
3005 aKeys.reserve(9);
3007 // Backspace key
3008 awt::KeyEvent aBackspace;
3009 aBackspace.KeyCode = awt::Key::BACKSPACE;
3010 aBackspace.Modifiers = 0;
3011 aKeys.push_back(&aBackspace);
3013 // Delete key
3014 awt::KeyEvent aDelete;
3015 aDelete.KeyCode = awt::Key::DELETE;
3016 aDelete.Modifiers = 0;
3017 aKeys.push_back(&aDelete);
3019 // Ctrl-D
3020 awt::KeyEvent aCtrlD;
3021 aCtrlD.KeyCode = awt::Key::D;
3022 aCtrlD.Modifiers = awt::KeyModifier::MOD1;
3023 aKeys.push_back(&aCtrlD);
3025 // Alt-Down
3026 awt::KeyEvent aAltDown;
3027 aAltDown.KeyCode = awt::Key::DOWN;
3028 aAltDown.Modifiers = awt::KeyModifier::MOD2;
3029 aKeys.push_back(&aAltDown);
3031 // Ctrl-Space
3032 awt::KeyEvent aCtrlSpace;
3033 aCtrlSpace.KeyCode = awt::Key::SPACE;
3034 aCtrlSpace.Modifiers = awt::KeyModifier::MOD1;
3035 aKeys.push_back(&aCtrlSpace);
3037 // Ctrl-Shift-Space
3038 awt::KeyEvent aCtrlShiftSpace;
3039 aCtrlShiftSpace.KeyCode = awt::Key::SPACE;
3040 aCtrlShiftSpace.Modifiers = awt::KeyModifier::MOD1 | awt::KeyModifier::SHIFT;
3041 aKeys.push_back(&aCtrlShiftSpace);
3043 // F4
3044 awt::KeyEvent aF4;
3045 aF4.KeyCode = awt::Key::F4;
3046 aF4.Modifiers = 0;
3047 aKeys.push_back(&aF4);
3049 // CTRL+SHIFT+F4
3050 awt::KeyEvent aCtrlShiftF4;
3051 aCtrlShiftF4.KeyCode = awt::Key::F4;
3052 aCtrlShiftF4.Modifiers = awt::KeyModifier::MOD1 | awt::KeyModifier::SHIFT;
3053 aKeys.push_back(&aCtrlShiftF4);
3055 // SHIFT+F4
3056 awt::KeyEvent aShiftF4;
3057 aShiftF4.KeyCode = awt::Key::F4;
3058 aShiftF4.Modifiers = awt::KeyModifier::SHIFT;
3059 aKeys.push_back(&aShiftF4);
3061 // Remove all involved keys first, because swapping commands don't work
3062 // well without doing this.
3063 removeKeysIfExists(xScAccel, aKeys);
3064 xScAccel->store();
3066 switch (eType)
3068 case ScOptionsUtil::KEY_DEFAULT:
3069 xScAccel->setKeyEvent(aDelete, ".uno:ClearContents");
3070 xScAccel->setKeyEvent(aBackspace, ".uno:Delete");
3071 xScAccel->setKeyEvent(aCtrlD, ".uno:FillDown");
3072 xScAccel->setKeyEvent(aAltDown, ".uno:DataSelect");
3073 xScAccel->setKeyEvent(aCtrlSpace, ".uno:SelectColumn");
3074 xScAccel->setKeyEvent(aCtrlShiftSpace, ".uno:SelectAll");
3075 xScAccel->setKeyEvent(aF4, ".uno:ToggleRelative");
3076 xScAccel->setKeyEvent(aCtrlShiftF4, ".uno:ViewDataSourceBrowser");
3077 break;
3078 case ScOptionsUtil::KEY_OOO_LEGACY:
3079 xScAccel->setKeyEvent(aDelete, ".uno:Delete");
3080 xScAccel->setKeyEvent(aBackspace, ".uno:ClearContents");
3081 xScAccel->setKeyEvent(aCtrlD, ".uno:DataSelect");
3082 xScAccel->setKeyEvent(aCtrlShiftSpace, ".uno:SelectColumn");
3083 xScAccel->setKeyEvent(aF4, ".uno:ViewDataSourceBrowser");
3084 xScAccel->setKeyEvent(aShiftF4, ".uno:ToggleRelative");
3085 break;
3086 default:
3090 xScAccel->store();
3093 void ScDocShell::UseSheetSaveEntries()
3095 if (!m_pSheetSaveData)
3096 return;
3098 m_pSheetSaveData->UseSaveEntries(); // use positions from saved file for next saving
3100 bool bHasEntries = false;
3101 SCTAB nTabCount = m_aDocument.GetTableCount();
3102 SCTAB nTab;
3103 for (nTab = 0; nTab < nTabCount; ++nTab)
3104 if (m_pSheetSaveData->HasStreamPos(nTab))
3105 bHasEntries = true;
3107 if (!bHasEntries)
3109 // if no positions were set (for example, export to other format),
3110 // reset all "valid" flags
3111 for (nTab = 0; nTab < nTabCount; ++nTab)
3112 m_aDocument.SetStreamValid(nTab, false);
3116 // --- ScDocShellModificator ------------------------------------------
3118 ScDocShellModificator::ScDocShellModificator( ScDocShell& rDS )
3120 rDocShell( rDS ),
3121 mpProtector(new ScRefreshTimerProtector(rDS.GetDocument().GetRefreshTimerControlAddress()))
3123 ScDocument& rDoc = rDocShell.GetDocument();
3124 bAutoCalcShellDisabled = rDoc.IsAutoCalcShellDisabled();
3125 bIdleEnabled = rDoc.IsIdleEnabled();
3126 rDoc.SetAutoCalcShellDisabled( true );
3127 rDoc.EnableIdle(false);
3130 ScDocShellModificator::~ScDocShellModificator() COVERITY_NOEXCEPT_FALSE
3132 ScDocument& rDoc = rDocShell.GetDocument();
3133 rDoc.SetAutoCalcShellDisabled( bAutoCalcShellDisabled );
3134 if ( !bAutoCalcShellDisabled && rDocShell.IsDocumentModifiedPending() )
3135 rDocShell.SetDocumentModified(); // last one shuts off the lights
3136 rDoc.EnableIdle(bIdleEnabled);
3139 void ScDocShellModificator::SetDocumentModified()
3141 ScDocument& rDoc = rDocShell.GetDocument();
3142 rDoc.PrepareFormulaCalc();
3143 if ( !rDoc.IsImportingXML() )
3145 // temporarily restore AutoCalcShellDisabled
3146 bool bDisabled = rDoc.IsAutoCalcShellDisabled();
3147 rDoc.SetAutoCalcShellDisabled( bAutoCalcShellDisabled );
3148 rDocShell.SetDocumentModified();
3149 rDoc.SetAutoCalcShellDisabled( bDisabled );
3151 else
3153 // uno broadcast is necessary for api to work
3154 // -> must also be done during xml import
3155 rDoc.BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
3159 bool ScDocShell::IsChangeRecording() const
3161 ScChangeTrack* pChangeTrack = m_aDocument.GetChangeTrack();
3162 return pChangeTrack != nullptr;
3165 bool ScDocShell::HasChangeRecordProtection() const
3167 bool bRes = false;
3168 ScChangeTrack* pChangeTrack = m_aDocument.GetChangeTrack();
3169 if (pChangeTrack)
3170 bRes = pChangeTrack->IsProtected();
3171 return bRes;
3174 void ScDocShell::SetChangeRecording( bool bActivate, bool /*bLockAllViews*/ )
3176 bool bOldChangeRecording = IsChangeRecording();
3178 if (bActivate)
3180 m_aDocument.StartChangeTracking();
3181 ScChangeViewSettings aChangeViewSet;
3182 aChangeViewSet.SetShowChanges(true);
3183 m_aDocument.SetChangeViewSettings(aChangeViewSet);
3185 else
3187 m_aDocument.EndChangeTracking();
3188 PostPaintGridAll();
3191 if (bOldChangeRecording != IsChangeRecording())
3193 UpdateAcceptChangesDialog();
3194 // invalidate slots
3195 SfxBindings* pBindings = GetViewBindings();
3196 if (pBindings)
3197 pBindings->InvalidateAll(false);
3201 void ScDocShell::SetProtectionPassword( const OUString &rNewPassword )
3203 ScChangeTrack* pChangeTrack = m_aDocument.GetChangeTrack();
3204 if (!pChangeTrack)
3205 return;
3207 bool bProtected = pChangeTrack->IsProtected();
3209 if (!rNewPassword.isEmpty())
3211 // when password protection is applied change tracking must always be active
3212 SetChangeRecording( true );
3214 css::uno::Sequence< sal_Int8 > aProtectionHash;
3215 SvPasswordHelper::GetHashPassword( aProtectionHash, rNewPassword );
3216 pChangeTrack->SetProtection( aProtectionHash );
3218 else
3220 pChangeTrack->SetProtection( css::uno::Sequence< sal_Int8 >() );
3223 if ( bProtected != pChangeTrack->IsProtected() )
3225 UpdateAcceptChangesDialog();
3226 SetDocumentModified();
3230 bool ScDocShell::GetProtectionHash( /*out*/ css::uno::Sequence< sal_Int8 > &rPasswordHash )
3232 bool bRes = false;
3233 ScChangeTrack* pChangeTrack = m_aDocument.GetChangeTrack();
3234 if (pChangeTrack && pChangeTrack->IsProtected())
3236 rPasswordHash = pChangeTrack->GetProtection();
3237 bRes = true;
3239 return bRes;
3242 void ScDocShell::SetIsInUcalc()
3244 m_bUcalcTest = true;
3247 void ScDocShell::RegisterAutomationWorkbookObject(css::uno::Reference< ooo::vba::excel::XWorkbook > const& xWorkbook)
3249 mxAutomationWorkbookObject = xWorkbook;
3252 extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportSLK(SvStream &rStream)
3254 ScDLL::Init();
3255 ScDocument aDocument;
3256 ScDocOptions aDocOpt = aDocument.GetDocOptions();
3257 aDocOpt.SetLookUpColRowNames(false);
3258 aDocument.SetDocOptions(aDocOpt);
3259 aDocument.MakeTable(0);
3260 aDocument.EnableExecuteLink(false);
3261 aDocument.SetInsertingFromOtherDoc(true);
3262 aDocument.SetImportingXML(true);
3264 ScImportExport aImpEx(aDocument);
3265 return aImpEx.ImportStream(rStream, OUString(), SotClipboardFormatId::SYLK);
3268 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */