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