tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / docshell / docsh.cxx
blob1756c5d2b3cae27d74b48cf46e52a2f0dec27f16
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 <sal/config.h>
22 #include <docsh.hxx>
24 #include <config_features.h>
25 #include <scitems.hxx>
26 #include <sc.hrc>
27 #include <vcl/errinf.hxx>
28 #include <editeng/justifyitem.hxx>
29 #include <comphelper/fileformat.h>
30 #include <comphelper/classids.hxx>
31 #include <comphelper/propertyvalue.hxx>
32 #include <formula/errorcodes.hxx>
33 #include <vcl/stdtext.hxx>
34 #include <vcl/syswin.hxx>
35 #include <vcl/svapp.hxx>
36 #include <vcl/virdev.hxx>
37 #include <vcl/weld.hxx>
38 #include <rtl/bootstrap.hxx>
39 #include <rtl/tencinfo.h>
40 #include <sal/log.hxx>
41 #include <svl/PasswordHelper.hxx>
42 #include <sfx2/app.hxx>
43 #include <sfx2/bindings.hxx>
44 #include <sfx2/dinfdlg.hxx>
45 #include <sfx2/docfile.hxx>
46 #include <sfx2/event.hxx>
47 #include <sfx2/docfilt.hxx>
48 #include <sfx2/lokhelper.hxx>
49 #include <sfx2/objface.hxx>
50 #include <sfx2/viewfrm.hxx>
51 #include <sfx2/infobar.hxx>
52 #include <svl/documentlockfile.hxx>
53 #include <svl/fstathelper.hxx>
54 #include <svl/sharecontrolfile.hxx>
55 #include <svl/urihelper.hxx>
56 #include <osl/file.hxx>
57 #include <chgtrack.hxx>
58 #include <chgviset.hxx>
59 #include <com/sun/star/awt/Key.hpp>
60 #include <com/sun/star/awt/KeyModifier.hpp>
61 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
62 #include <com/sun/star/document/UpdateDocMode.hpp>
63 #include <com/sun/star/script/vba/VBAEventId.hpp>
64 #include <com/sun/star/script/vba/VBAScriptEventId.hpp>
65 #include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
66 #include <com/sun/star/script/vba/XVBAScriptListener.hpp>
67 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
68 #include <com/sun/star/sheet/XSpreadsheetView.hpp>
69 #include <com/sun/star/task/XJob.hpp>
70 #include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
71 #include <com/sun/star/ui/XAcceleratorConfiguration.hpp>
72 #include <com/sun/star/util/VetoException.hpp>
73 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
74 #include <ooo/vba/excel/XWorkbook.hpp>
75 #include <comphelper/diagnose_ex.hxx>
77 #include <config_folders.h>
79 #include <scabstdlg.hxx>
80 #include <sot/formats.hxx>
81 #include <svx/compatflags.hxx>
82 #include <svx/dialogs.hrc>
83 #include <svx/svdpagv.hxx>
84 #include <svx/svdpage.hxx>
85 #include <docmodel/theme/Theme.hxx>
87 #include <inputopt.hxx>
88 #include <formulacell.hxx>
89 #include <global.hxx>
90 #include <filter.hxx>
91 #include <scmod.hxx>
92 #include <tabvwsh.hxx>
93 #include <docfunc.hxx>
94 #include <imoptdlg.hxx>
95 #include <impex.hxx>
96 #include <scresid.hxx>
97 #include <strings.hrc>
98 #include <globstr.hrc>
99 #include <scerrors.hxx>
100 #include <brdcst.hxx>
101 #include <stlpool.hxx>
102 #include <autostyl.hxx>
103 #include <attrib.hxx>
104 #include <asciiopt.hxx>
105 #include <progress.hxx>
106 #include <pntlock.hxx>
107 #include <docuno.hxx>
108 #include <appoptio.hxx>
109 #include <formulaopt.hxx>
110 #include <scdll.hxx>
111 #include <detdata.hxx>
112 #include <printfun.hxx>
113 #include <dociter.hxx>
114 #include <cellform.hxx>
115 #include <chartlis.hxx>
116 #include <hints.hxx>
117 #include <xmlwrap.hxx>
118 #include <drwlayer.hxx>
119 #include <dbdata.hxx>
120 #include <scextopt.hxx>
121 #include <compiler.hxx>
122 #include <warnpassword.hxx>
123 #include <sheetdata.hxx>
124 #include <table.hxx>
125 #include <tabprotection.hxx>
126 #include <docparam.hxx>
127 #include "docshimp.hxx"
128 #include <sizedev.hxx>
129 #include <undomanager.hxx>
130 #include <refreshtimerprotector.hxx>
132 #include <officecfg/Office/Calc.hxx>
133 #include <comphelper/processfactory.hxx>
134 #include <comphelper/string.hxx>
135 #include <unotools/configmgr.hxx>
136 #include <unotools/mediadescriptor.hxx>
137 #include <unotools/tempfile.hxx>
138 #include <unotools/ucbstreamhelper.hxx>
139 #include <uiitems.hxx>
140 #include <dpobject.hxx>
141 #include <markdata.hxx>
142 #include <docoptio.hxx>
143 #include <orcusfilters.hxx>
144 #include <datastream.hxx>
145 #include <documentlinkmgr.hxx>
146 #include <refupdatecontext.hxx>
147 #include <DocumentModelAccessor.hxx>
149 #include <memory>
150 #include <vector>
152 #include <comphelper/lok.hxx>
153 #include <svtools/sfxecode.hxx>
154 #include <unotools/pathoptions.hxx>
156 using namespace com::sun::star;
157 using ::com::sun::star::uno::Reference;
158 using ::com::sun::star::lang::XMultiServiceFactory;
159 using std::shared_ptr;
160 using ::std::vector;
162 // Filter names (like in sclib.cxx)
164 constexpr OUStringLiteral pFilterSc50 = u"StarCalc 5.0";
165 const char pFilterXML[] = "StarOffice XML (Calc)";
166 constexpr OUString pFilterLotus = u"Lotus"_ustr;
167 const char pFilterQPro6[] = "Quattro Pro 6.0";
168 const char16_t pFilterExcel4[] = u"MS Excel 4.0";
169 const char16_t pFilterEx4Temp[] = u"MS Excel 4.0 Vorlage/Template";
170 const char pFilterExcel5[] = "MS Excel 5.0/95";
171 const char pFilterEx5Temp[] = "MS Excel 5.0/95 Vorlage/Template";
172 const char pFilterExcel95[] = "MS Excel 95";
173 const char pFilterEx95Temp[] = "MS Excel 95 Vorlage/Template";
174 const char pFilterExcel97[] = "MS Excel 97";
175 const char pFilterEx97Temp[] = "MS Excel 97 Vorlage/Template";
176 constexpr OUString pFilterDBase = u"dBase"_ustr;
177 constexpr OUString pFilterDif = u"DIF"_ustr;
178 const char16_t pFilterSylk[] = u"SYLK";
179 constexpr OUString pFilterHtml = u"HTML (StarCalc)"_ustr;
180 constexpr OUString pFilterHtmlWebQ = u"calc_HTML_WebQuery"_ustr;
181 const char16_t pFilterRtf[] = u"Rich Text Format (StarCalc)";
183 #define ShellClass_ScDocShell
184 #include <scslots.hxx>
186 SFX_IMPL_INTERFACE(ScDocShell,SfxObjectShell)
188 void ScDocShell::InitInterface_Impl()
192 // GlobalName of the current version:
193 SFX_IMPL_OBJECTFACTORY( ScDocShell, SvGlobalName(SO3_SC_CLASSID), u"scalc"_ustr )
196 void ScDocShell::FillClass( SvGlobalName* pClassName,
197 SotClipboardFormatId* pFormat,
198 OUString* pFullTypeName,
199 sal_Int32 nFileFormat,
200 bool bTemplate /* = false */) const
202 if ( nFileFormat == SOFFICE_FILEFORMAT_60 )
204 *pClassName = SvGlobalName( SO3_SC_CLASSID_60 );
205 *pFormat = SotClipboardFormatId::STARCALC_60;
206 *pFullTypeName = ScResId( SCSTR_LONG_SCDOC_NAME_60 );
208 else if ( nFileFormat == SOFFICE_FILEFORMAT_8 )
210 *pClassName = SvGlobalName( SO3_SC_CLASSID_60 );
211 *pFormat = bTemplate ? SotClipboardFormatId::STARCALC_8_TEMPLATE : SotClipboardFormatId::STARCALC_8;
212 *pFullTypeName = ScResId( SCSTR_LONG_SCDOC_NAME_80 );
214 else
216 OSL_FAIL("Which version?");
220 std::set<Color> ScDocShell::GetDocColors()
222 return m_pDocument->GetDocColors();
225 std::shared_ptr<sfx::IDocumentModelAccessor> ScDocShell::GetDocumentModelAccessor() const
227 std::shared_ptr<sfx::IDocumentModelAccessor> pReturn;
228 pReturn.reset(new sc::DocumentModelAccessor(m_pDocument));
229 return pReturn;
232 std::shared_ptr<model::ColorSet> ScDocShell::GetThemeColors()
234 ScTabViewShell* pShell = GetBestViewShell();
235 if (!pShell)
236 return {};
238 SdrModel* pSdrModel = GetDocument().GetDrawLayer();
239 if (!pSdrModel)
240 return {};
242 auto const& pTheme = pSdrModel->getTheme();
243 if (!pTheme)
244 return {};
246 return pTheme->getColorSet();
249 void ScDocShell::DoEnterHandler()
251 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
252 if (pViewSh && pViewSh->GetViewData().GetDocShell() == this)
253 ScModule::get()->InputEnterHandler();
256 SCTAB ScDocShell::GetSaveTab()
258 SCTAB nTab = 0;
259 ScTabViewShell* pSh = GetBestViewShell();
260 if (pSh)
262 const ScMarkData& rMark = pSh->GetViewData().GetMarkData();
263 nTab = rMark.GetFirstSelected();
265 return nTab;
268 HiddenInformation ScDocShell::GetHiddenInformationState( HiddenInformation nStates )
270 // get global state like HiddenInformation::DOCUMENTVERSIONS
271 HiddenInformation nState = SfxObjectShell::GetHiddenInformationState( nStates );
273 if ( nStates & HiddenInformation::RECORDEDCHANGES )
275 if ( m_pDocument->GetChangeTrack() && m_pDocument->GetChangeTrack()->GetFirst() )
276 nState |= HiddenInformation::RECORDEDCHANGES;
278 if ( nStates & HiddenInformation::NOTES )
280 SCTAB nTableCount = m_pDocument->GetTableCount();
281 bool bFound = false;
282 for (SCTAB nTab = 0; nTab < nTableCount && !bFound; ++nTab)
284 if (m_pDocument->HasTabNotes(nTab)) //TODO:
285 bFound = true;
288 if (bFound)
289 nState |= HiddenInformation::NOTES;
292 return nState;
295 void ScDocShell::BeforeXMLLoading()
297 m_pDocument->EnableIdle(false);
299 // prevent unnecessary broadcasts and updates
300 OSL_ENSURE(m_pModificator == nullptr, "The Modificator should not exist");
301 m_pModificator.reset( new ScDocShellModificator( *this ) );
303 m_pDocument->SetImportingXML( true );
304 m_pDocument->EnableExecuteLink( false ); // #i101304# to be safe, prevent nested loading from external references
305 m_pDocument->EnableUndo( false );
306 // prevent unnecessary broadcasts and "half way listeners"
307 m_pDocument->SetInsertingFromOtherDoc( true );
310 void ScDocShell::AfterXMLLoading(bool bRet)
312 if (GetCreateMode() != SfxObjectCreateMode::ORGANIZER)
314 UpdateLinks();
315 // don't prevent establishing of listeners anymore
316 m_pDocument->SetInsertingFromOtherDoc( false );
317 if ( bRet )
319 ScChartListenerCollection* pChartListener = m_pDocument->GetChartListenerCollection();
320 if (pChartListener)
321 pChartListener->UpdateDirtyCharts();
323 // #95582#; set the table names of linked tables to the new path
324 SCTAB nTabCount = m_pDocument->GetTableCount();
325 for (SCTAB i = 0; i < nTabCount; ++i)
327 if (m_pDocument->IsLinked( i ))
329 OUString aName;
330 m_pDocument->GetName(i, aName);
331 OUString aLinkTabName = m_pDocument->GetLinkTab(i);
332 sal_Int32 nLinkTabNameLength = aLinkTabName.getLength();
333 sal_Int32 nNameLength = aName.getLength();
334 if (nLinkTabNameLength < nNameLength)
337 // remove the quotes on begin and end of the docname and restore the escaped quotes
338 const sal_Unicode* pNameBuffer = aName.getStr();
339 if ( *pNameBuffer == '\'' && // all docnames have to have a ' character on the first pos
340 ScGlobal::UnicodeStrChr( pNameBuffer, SC_COMPILER_FILE_TAB_SEP ) )
342 OUStringBuffer aDocURLBuffer;
343 bool bQuote = true; // Document name is always quoted
344 ++pNameBuffer;
345 while ( bQuote && *pNameBuffer )
347 if ( *pNameBuffer == '\'' && *(pNameBuffer-1) != '\\' )
348 bQuote = false;
349 else if( *pNameBuffer != '\\' || *(pNameBuffer+1) != '\'' )
350 aDocURLBuffer.append(*pNameBuffer); // If escaped quote: only quote in the name
351 ++pNameBuffer;
354 if( *pNameBuffer == SC_COMPILER_FILE_TAB_SEP ) // after the last quote of the docname should be the # char
356 sal_Int32 nIndex = nNameLength - nLinkTabNameLength;
357 INetURLObject aINetURLObject(aDocURLBuffer);
358 if(aName.match( aLinkTabName, nIndex) &&
359 (aName[nIndex - 1] == '#') && // before the table name should be the # char
360 !aINetURLObject.HasError()) // the docname should be a valid URL
362 aName = ScGlobal::GetDocTabName( m_pDocument->GetLinkDoc( i ), m_pDocument->GetLinkTab( i ) );
363 m_pDocument->RenameTab(i, aName, true/*bExternalDocument*/);
365 // else; nothing has to happen, because it is a user given name
367 // else; nothing has to happen, because it is a user given name
369 // else; nothing has to happen, because it is a user given name
371 // else; nothing has to happen, because it is a user given name
375 // #i94570# DataPilot table names have to be unique, or the tables can't be accessed by API.
376 // If no name (or an invalid name, skipped in ScXMLDataPilotTableContext::EndElement) was set, create a new name.
377 ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
378 if ( pDPCollection )
380 size_t nDPCount = pDPCollection->GetCount();
381 for (size_t nDP=0; nDP<nDPCount; ++nDP)
383 ScDPObject& rDPObj = (*pDPCollection)[nDP];
384 if (rDPObj.GetName().isEmpty())
385 rDPObj.SetName( pDPCollection->CreateNewName() );
390 else
391 m_pDocument->SetInsertingFromOtherDoc( false );
393 m_pDocument->SetImportingXML( false );
394 m_pDocument->EnableExecuteLink( true );
395 m_pDocument->EnableUndo( true );
396 m_bIsEmpty = false;
398 if (m_pModificator)
400 ScDocument::HardRecalcState eRecalcState = m_pDocument->GetHardRecalcState();
401 // Temporarily set hard-recalc to prevent calling
402 // ScFormulaCell::Notify() during destruction of the Modificator which
403 // will set the cells dirty.
404 if (eRecalcState == ScDocument::HardRecalcState::OFF)
405 m_pDocument->SetHardRecalcState(ScDocument::HardRecalcState::TEMPORARY);
406 m_pModificator.reset();
407 m_pDocument->SetHardRecalcState(eRecalcState);
409 else
411 OSL_FAIL("The Modificator should exist");
414 m_pDocument->EnableIdle(true);
417 namespace {
419 class LoadMediumGuard
421 public:
422 explicit LoadMediumGuard(ScDocument* pDoc) :
423 mpDoc(pDoc)
425 mpDoc->SetLoadingMedium(true);
428 ~LoadMediumGuard()
430 mpDoc->SetLoadingMedium(false);
432 private:
433 ScDocument* mpDoc;
436 void processDataStream( ScDocShell& rShell, const sc::ImportPostProcessData& rData )
438 if (!rData.mpDataStream)
439 return;
441 const sc::ImportPostProcessData::DataStream& r = *rData.mpDataStream;
442 if (!r.maRange.IsValid())
443 return;
445 // Break the streamed range into the top range and the height limit. A
446 // height limit of 0 means unlimited i.e. the streamed data will go all
447 // the way to the last row.
449 ScRange aTopRange = r.maRange;
450 aTopRange.aEnd.SetRow(aTopRange.aStart.Row());
451 sal_Int32 nLimit = r.maRange.aEnd.Row() - r.maRange.aStart.Row() + 1;
452 if (r.maRange.aEnd.Row() == rShell.GetDocument().MaxRow())
453 // Unlimited range.
454 nLimit = 0;
456 sc::DataStream::MoveType eMove =
457 r.meInsertPos == sc::ImportPostProcessData::DataStream::InsertTop ?
458 sc::DataStream::MOVE_DOWN : sc::DataStream::RANGE_DOWN;
460 sc::DataStream* pStrm = new sc::DataStream(&rShell, r.maURL, aTopRange, nLimit, eMove);
461 pStrm->SetRefreshOnEmptyLine(r.mbRefreshOnEmpty);
462 sc::DocumentLinkManager& rMgr = rShell.GetDocument().GetDocLinkManager();
463 rMgr.setDataStream(pStrm);
466 class MessageWithCheck : public weld::MessageDialogController
468 private:
469 std::unique_ptr<weld::CheckButton> m_xWarningOnBox;
470 public:
471 MessageWithCheck(weld::Window *pParent, const OUString& rUIFile, const OUString& rDialogId)
472 : MessageDialogController(pParent, rUIFile, rDialogId, u"ask"_ustr)
473 , m_xWarningOnBox(m_xBuilder->weld_check_button(u"ask"_ustr))
476 bool get_active() const { return m_xWarningOnBox->get_active(); }
477 void hide_ask() const { m_xWarningOnBox->set_visible(false); };
480 #if HAVE_FEATURE_SCRIPTING
481 class VBAScriptListener : public ::cppu::WeakImplHelper< css::script::vba::XVBAScriptListener >
483 private:
484 ScDocShell* m_pDocSh;
485 public:
486 VBAScriptListener(ScDocShell* pDocSh) : m_pDocSh(pDocSh)
490 // XVBAScriptListener
491 virtual void SAL_CALL notifyVBAScriptEvent( const ::css::script::vba::VBAScriptEvent& aEvent ) override
493 if (aEvent.Identifier == script::vba::VBAScriptEventId::SCRIPT_STOPPED &&
494 m_pDocSh->GetClipData().is())
496 m_pDocSh->SetClipData(uno::Reference<datatransfer::XTransferable2>());
500 // XEventListener
501 virtual void SAL_CALL disposing( const ::css::lang::EventObject& /*Source*/ ) override
505 #endif
509 bool ScDocShell::GetRecalcRowHeightsMode()
511 const ScRecalcOptions nRecalcMode = static_cast<ScRecalcOptions>(
512 officecfg::Office::Calc::Formula::Load::RecalcOptimalRowHeightMode::get());
514 bool bHardRecalc = false;
515 switch (nRecalcMode)
517 case RECALC_ASK:
519 if (m_pDocument->IsUserInteractionEnabled())
521 // Ask if the user wants to perform full re-calculation.
522 MessageWithCheck aQueryBox(ScDocShell::GetActiveDialogParent(),
523 u"modules/scalc/ui/recalcquerydialog.ui"_ustr,
524 u"RecalcQueryDialog"_ustr);
525 aQueryBox.set_primary_text(ScResId(STR_QUERY_OPT_ROW_HEIGHT_RECALC_ONLOAD));
526 aQueryBox.set_default_response(RET_YES);
528 if (officecfg::Office::Calc::Formula::Load::RecalcOptimalRowHeightMode::isReadOnly())
529 aQueryBox.hide_ask();
531 bHardRecalc = aQueryBox.run() == RET_YES;
533 if (aQueryBox.get_active())
535 // Always perform selected action in the future.
536 std::shared_ptr<comphelper::ConfigurationChanges> batch(
537 comphelper::ConfigurationChanges::create());
538 officecfg::Office::Calc::Formula::Load::RecalcOptimalRowHeightMode::set(
539 bHardRecalc ? static_cast<sal_Int32>(RECALC_ALWAYS)
540 : static_cast<sal_Int32>(RECALC_NEVER),
541 batch);
543 ScModule* mod = ScModule::get();
544 ScFormulaOptions aOpt = mod->GetFormulaOptions();
545 aOpt.SetReCalcOptiRowHeights(bHardRecalc ? RECALC_ALWAYS : RECALC_NEVER);
546 mod->SetFormulaOptions(aOpt);
548 batch->commit();
552 break;
553 case RECALC_ALWAYS:
554 bHardRecalc = true;
555 break;
556 case RECALC_NEVER:
557 bHardRecalc = false;
558 break;
559 default:
560 SAL_WARN("sc", "unknown optimal row height recalc option!");
563 return bHardRecalc;
566 bool ScDocShell::LoadXML( SfxMedium* pLoadMedium, const css::uno::Reference< css::embed::XStorage >& xStor )
568 LoadMediumGuard aLoadGuard(m_pDocument.get());
570 // MacroCallMode is no longer needed, state is kept in SfxObjectShell now
572 // no Seek(0) here - always loading from storage, GetInStream must not be called
574 BeforeXMLLoading();
576 ScXMLImportWrapper aImport(*this, pLoadMedium, xStor);
578 bool bRet = false;
579 ErrCodeMsg nError = ERRCODE_NONE;
580 m_pDocument->LockAdjustHeight();
581 if (GetCreateMode() == SfxObjectCreateMode::ORGANIZER)
582 bRet = aImport.Import(ImportFlags::Styles, nError);
583 else
584 bRet = aImport.Import(ImportFlags::All, nError);
586 if ( nError )
587 pLoadMedium->SetError(nError);
589 processDataStream(*this, aImport.GetImportPostProcessData());
591 //if the document was not generated by LibreOffice, do hard recalc in case some other document
592 //generator saved cached formula results that differ from LibreOffice's calculated results or
593 //did not use cached formula results.
594 uno::Reference<document::XDocumentProperties> xDocProps = GetModel()->getDocumentProperties();
596 ScRecalcOptions nRecalcMode =
597 static_cast<ScRecalcOptions>(officecfg::Office::Calc::Formula::Load::ODFRecalcMode::get());
599 bool bHardRecalc = false;
600 if (nRecalcMode == RECALC_ASK)
602 OUString sProductName(utl::ConfigManager::getProductName());
603 if (m_pDocument->IsUserInteractionEnabled() && xDocProps->getGenerator().indexOf(sProductName) == -1)
605 // Generator is not LibreOffice. Ask if the user wants to perform
606 // full re-calculation.
607 MessageWithCheck aQueryBox(GetActiveDialogParent(),
608 u"modules/scalc/ui/recalcquerydialog.ui"_ustr, u"RecalcQueryDialog"_ustr);
609 aQueryBox.set_primary_text(ScResId(STR_QUERY_FORMULA_RECALC_ONLOAD_ODS));
610 aQueryBox.set_default_response(RET_YES);
612 if ( officecfg::Office::Calc::Formula::Load::OOXMLRecalcMode::isReadOnly() )
613 aQueryBox.hide_ask();
615 bHardRecalc = aQueryBox.run() == RET_YES;
617 if (aQueryBox.get_active())
619 // Always perform selected action in the future.
620 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
621 officecfg::Office::Calc::Formula::Load::ODFRecalcMode::set(sal_Int32(0), batch);
622 ScModule* mod = ScModule::get();
623 ScFormulaOptions aOpt = mod->GetFormulaOptions();
624 aOpt.SetODFRecalcOptions(bHardRecalc ? RECALC_ALWAYS : RECALC_NEVER);
625 /* XXX is this really supposed to set the ScModule options?
626 * Not the ScDocShell options? */
627 mod->SetFormulaOptions(aOpt);
629 batch->commit();
633 else if (nRecalcMode == RECALC_ALWAYS)
634 bHardRecalc = true;
636 if (bHardRecalc)
637 DoHardRecalc();
638 else
640 // still need to recalc volatile formula cells.
641 m_pDocument->Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS));
644 AfterXMLLoading(bRet);
646 m_pDocument->UnlockAdjustHeight();
647 return bRet;
650 bool ScDocShell::SaveXML( SfxMedium* pSaveMedium, const css::uno::Reference< css::embed::XStorage >& xStor )
652 m_pDocument->EnableIdle(false);
654 ScXMLImportWrapper aImport(*this, pSaveMedium, xStor);
655 bool bRet(false);
656 if (GetCreateMode() != SfxObjectCreateMode::ORGANIZER)
657 bRet = aImport.Export(false);
658 else
659 bRet = aImport.Export(true);
661 m_pDocument->EnableIdle(true);
663 return bRet;
666 bool ScDocShell::Load( SfxMedium& rMedium )
668 LoadMediumGuard aLoadGuard(m_pDocument.get());
669 ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
671 // only the latin script language is loaded
672 // -> initialize the others from options (before loading)
673 InitOptions(true);
675 // If this is an ODF file being loaded, then by default, use legacy processing
676 // (if required, it will be overridden in *::ReadUserDataSequence())
677 if (IsOwnStorageFormat(rMedium))
679 if (ScDrawLayer* pDrawLayer = m_pDocument->GetDrawLayer())
681 pDrawLayer->SetCompatibilityFlag(SdrCompatibilityFlag::AnchoredTextOverflowLegacy,
682 true); // for tdf#99729
683 pDrawLayer->SetCompatibilityFlag(SdrCompatibilityFlag::LegacyFontwork,
684 true); // for tdf#148000
688 GetUndoManager()->Clear();
690 bool bRet = SfxObjectShell::Load(rMedium);
691 if (bRet)
693 SetInitialLinkUpdate(&rMedium);
696 // prepare a valid document for XML filter
697 // (for ConvertFrom, InitNew is called before)
698 m_pDocument->MakeTable(0);
699 m_pDocument->GetStyleSheetPool()->CreateStandardStyles();
700 m_pDocument->getCellAttributeHelper().UpdateAllStyleSheets(*m_pDocument);
702 /* Create styles that are imported through Orcus */
704 OUString aURL(u"$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/calc/styles.xml"_ustr);
705 rtl::Bootstrap::expandMacros(aURL);
707 OUString aPath;
708 osl::FileBase::getSystemPathFromFileURL(aURL, aPath);
710 ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
712 if (pOrcus)
714 pOrcus->importODS_Styles(*m_pDocument, aPath);
715 m_pDocument->GetStyleSheetPool()->setAllParaStandard();
718 bRet = LoadXML( &rMedium, nullptr );
722 if (!bRet && !rMedium.GetErrorIgnoreWarning())
723 rMedium.SetError(SVSTREAM_FILEFORMAT_ERROR);
725 if (rMedium.GetErrorIgnoreWarning())
726 SetError(rMedium.GetErrorIgnoreWarning());
728 InitItems();
729 CalcOutputFactor();
731 // invalidate eventually temporary table areas
732 if ( bRet )
733 m_pDocument->InvalidateTableArea();
735 m_bIsEmpty = false;
736 FinishedLoading();
737 return bRet;
740 void ScDocShell::Notify( SfxBroadcaster&, const SfxHint& rHint )
742 if (rHint.GetId() == SfxHintId::ScTables)
744 const ScTablesHint* pScHint = static_cast< const ScTablesHint* >( &rHint );
745 if (pScHint->GetTablesHintId() == SC_TAB_INSERTED)
747 uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents = m_pDocument->GetVbaEventProcessor();
748 if ( xVbaEvents.is() ) try
750 uno::Sequence< uno::Any > aArgs{ uno::Any(pScHint->GetTab1()) };
751 xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKBOOK_NEWSHEET, aArgs );
753 catch( uno::Exception& )
759 if ( auto pStyleSheetHint = dynamic_cast<const SfxStyleSheetHint*>(&rHint) ) // Template changed
760 NotifyStyle( *pStyleSheetHint );
761 else if ( rHint.GetId() == SfxHintId::ScAutoStyle )
763 auto pStlHint = static_cast<const ScAutoStyleHint*>(&rHint);
764 //! direct call for AutoStyles
766 // this is called synchronously from ScInterpreter::ScStyle,
767 // modifying the document must be asynchronous
768 // (handled by AddInitial)
770 const ScRange& aRange = pStlHint->GetRange();
771 const OUString& aName1 = pStlHint->GetStyle1();
772 const OUString& aName2 = pStlHint->GetStyle2();
773 sal_uInt32 nTimeout = pStlHint->GetTimeout();
775 if (!m_pAutoStyleList)
776 m_pAutoStyleList.reset( new ScAutoStyleList(this) );
777 m_pAutoStyleList->AddInitial( aRange, aName1, nTimeout, aName2 );
779 else if (rHint.GetId() == SfxHintId::ThisIsAnSfxEventHint)
781 switch (static_cast<const SfxEventHint&>(rHint).GetEventId())
783 case SfxEventHintId::LoadFinished:
785 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
786 // the readonly documents should not be opened in shared mode
787 if ( HasSharedXMLFlagSet() && !ScModule::get()->IsInSharedDocLoading() && !IsReadOnly() )
789 if ( SwitchToShared( true, false ) )
791 ScViewData* pViewData = GetViewData();
792 ScTabView* pTabView = ( pViewData ? pViewData->GetView() : nullptr );
793 if ( pTabView )
795 pTabView->UpdateLayerLocks();
798 else
800 // switching to shared mode has failed, the document should be opened readonly
801 // TODO/LATER: And error message should be shown here probably
802 SetReadOnlyUI();
805 #endif
807 break;
808 case SfxEventHintId::ViewCreated:
810 #if HAVE_FEATURE_SCRIPTING
811 uno::Reference<script::vba::XVBACompatibility> xVBACompat(GetBasicContainer(), uno::UNO_QUERY);
812 if ( !m_xVBAListener.is() && xVBACompat.is() )
814 m_xVBAListener.set(new VBAScriptListener(this));
815 xVBACompat->addVBAScriptListener(m_xVBAListener);
817 #endif
819 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
820 if (ScModule* mod = ScModule::get(); IsDocShared() && !mod->IsInSharedDocLoading()
821 && !comphelper::LibreOfficeKit::isActive() )
823 ScAppOptions aAppOptions = mod->GetAppOptions();
824 if ( aAppOptions.GetShowSharedDocumentWarning() )
826 MessageWithCheck aWarningBox(ScDocShell::GetActiveDialogParent(),
827 u"modules/scalc/ui/sharedwarningdialog.ui"_ustr, u"SharedWarningDialog"_ustr);
828 aWarningBox.run();
830 bool bChecked = aWarningBox.get_active();
831 if (bChecked)
833 aAppOptions.SetShowSharedDocumentWarning(false);
834 mod->SetAppOptions(aAppOptions);
838 #endif
840 ScViewData* pViewData = GetViewData();
841 SfxViewShell* pViewShell = pViewData ? pViewData->GetViewShell() : nullptr;
842 SfxViewFrame* pViewFrame = pViewShell ? &pViewShell->GetViewFrame() : nullptr;
846 const uno::Reference< uno::XComponentContext >& xContext(
847 comphelper::getProcessComponentContext() );
848 uno::Reference< lang::XMultiServiceFactory > xServiceManager(
849 xContext->getServiceManager(),
850 uno::UNO_QUERY_THROW );
851 uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xServiceManager, uno::UNO_QUERY_THROW );
852 uno::Reference< container::XEnumeration> xEnum = xEnumAccess->createContentEnumeration(
853 u"com.sun.star.sheet.SpreadsheetDocumentJob"_ustr );
854 if ( xEnum.is() )
856 while ( xEnum->hasMoreElements() )
858 uno::Any aAny = xEnum->nextElement();
859 uno::Reference< lang::XSingleComponentFactory > xFactory;
860 aAny >>= xFactory;
861 if ( xFactory.is() )
863 uno::Reference< task::XJob > xJob( xFactory->createInstanceWithContext( xContext ), uno::UNO_QUERY_THROW );
864 SfxFrame* pFrame = ( pViewFrame ? &pViewFrame->GetFrame() : nullptr );
865 uno::Reference< frame::XController > xController = ( pFrame ? pFrame->GetController() : nullptr );
866 uno::Reference< sheet::XSpreadsheetView > xSpreadsheetView( xController, uno::UNO_QUERY_THROW );
867 uno::Sequence< beans::NamedValue > aArgsForJob { { u"SpreadsheetView"_ustr, uno::Any( xSpreadsheetView ) } };
868 xJob->execute( aArgsForJob );
873 catch ( uno::Exception & )
877 // Show delayed infobar entries
878 if (pViewFrame)
880 for (auto const& r : m_pImpl->mpDelayedInfobarEntry)
882 pViewFrame->AppendInfoBar(r.msId, r.msPrimaryMessage, r.msSecondaryMessage, r.maInfobarType, r.mbShowCloseButton);
884 m_pImpl->mpDelayedInfobarEntry.clear();
887 break;
888 case SfxEventHintId::SaveDoc:
890 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
891 if (ScModule* mod = ScModule::get(); IsDocShared() && !mod->IsInSharedDocSaving())
893 bool bSuccess = false;
894 bool bRetry = true;
895 while ( bRetry )
897 bRetry = false;
898 uno::Reference< frame::XModel > xModel;
901 // load shared file
902 xModel.set( LoadSharedDocument(), uno::UNO_SET_THROW );
903 uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY_THROW );
905 // check if shared flag is set in shared file
906 bool bShared = false;
907 ScModelObj* pDocObj = comphelper::getFromUnoTunnel<ScModelObj>( xModel );
908 ScDocShell* pSharedDocShell = ( pDocObj ? dynamic_cast< ScDocShell* >( pDocObj->GetObjectShell() ) : nullptr );
909 if ( pSharedDocShell )
911 bShared = pSharedDocShell->HasSharedXMLFlagSet();
914 // #i87870# check if shared status was disabled and enabled again
915 bool bOwnEntry = false;
916 bool bEntriesNotAccessible = false;
919 ::svt::ShareControlFile aControlFile( GetSharedFileURL() );
920 bOwnEntry = aControlFile.HasOwnEntry();
922 catch ( uno::Exception& )
924 bEntriesNotAccessible = true;
927 if ( bShared && bOwnEntry )
929 uno::Reference< frame::XStorable > xStorable( xModel, uno::UNO_QUERY_THROW );
931 if ( xStorable->isReadonly() )
933 xCloseable->close( true );
935 OUString aUserName( ScResId( STR_UNKNOWN_USER ) );
936 bool bNoLockAccess = false;
939 ::svt::DocumentLockFile aLockFile( GetSharedFileURL() );
940 LockFileEntry aData = aLockFile.GetLockData();
941 if ( !aData[LockFileComponent::OOOUSERNAME].isEmpty() )
943 aUserName = aData[LockFileComponent::OOOUSERNAME];
945 else if ( !aData[LockFileComponent::SYSUSERNAME].isEmpty() )
947 aUserName = aData[LockFileComponent::SYSUSERNAME];
950 catch ( uno::Exception& )
952 bNoLockAccess = true;
955 if ( bNoLockAccess )
957 // TODO/LATER: in future an error regarding impossibility to open file for writing could be shown
958 ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
960 else
962 OUString aMessage( ScResId( STR_FILE_LOCKED_SAVE_LATER ) );
963 aMessage = aMessage.replaceFirst( "%1", aUserName );
965 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
966 VclMessageType::Warning, VclButtonsType::NONE,
967 aMessage));
968 xWarn->add_button(GetStandardText(StandardButtonType::Retry), RET_RETRY);
969 xWarn->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
970 xWarn->set_default_response(RET_RETRY);
971 if (xWarn->run() == RET_RETRY)
973 bRetry = true;
977 else
979 // merge changes from shared file into temp file
980 bool bSaveToShared = false;
981 if ( pSharedDocShell )
983 bSaveToShared = MergeSharedDocument( pSharedDocShell );
986 // close shared file
987 xCloseable->close( true );
989 // TODO: keep file lock on shared file
991 // store to shared file
992 if ( bSaveToShared )
994 bool bChangedViewSettings = false;
995 ScChangeViewSettings* pChangeViewSet = m_pDocument->GetChangeViewSettings();
996 if ( pChangeViewSet && pChangeViewSet->ShowChanges() )
998 pChangeViewSet->SetShowChanges( false );
999 pChangeViewSet->SetShowAccepted( false );
1000 m_pDocument->SetChangeViewSettings( *pChangeViewSet );
1001 bChangedViewSettings = true;
1004 // TODO/LATER: More entries from the MediaDescriptor might be interesting for the merge
1005 uno::Sequence< beans::PropertyValue > aValues{
1006 comphelper::makePropertyValue(
1007 u"FilterName"_ustr,
1008 GetMedium()->GetFilter()->GetFilterName())
1011 const SfxStringItem* pPasswordItem = GetMedium()->GetItemSet().GetItem(SID_PASSWORD, false);
1012 if ( pPasswordItem && !pPasswordItem->GetValue().isEmpty() )
1014 aValues.realloc( 2 );
1015 auto pValues = aValues.getArray();
1016 pValues[1].Name = "Password";
1017 pValues[1].Value <<= pPasswordItem->GetValue();
1019 const SfxUnoAnyItem* pEncryptionItem = GetMedium()->GetItemSet().GetItem(SID_ENCRYPTIONDATA, false);
1020 if (pEncryptionItem)
1022 aValues.realloc(aValues.getLength() + 1);
1023 auto pValues = aValues.getArray();
1024 pValues[aValues.getLength() - 1].Name = "EncryptionData";
1025 pValues[aValues.getLength() - 1].Value = pEncryptionItem->GetValue();
1028 mod->SetInSharedDocSaving(true);
1029 GetModel()->storeToURL( GetSharedFileURL(), aValues );
1030 mod->SetInSharedDocSaving(false);
1032 if ( bChangedViewSettings )
1034 pChangeViewSet->SetShowChanges( true );
1035 pChangeViewSet->SetShowAccepted( true );
1036 m_pDocument->SetChangeViewSettings( *pChangeViewSet );
1040 bSuccess = true;
1041 GetUndoManager()->Clear();
1044 else
1046 xCloseable->close( true );
1048 if ( bEntriesNotAccessible )
1050 // TODO/LATER: in future an error regarding impossibility to write to share control file could be shown
1051 ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
1053 else
1055 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
1056 VclMessageType::Warning, VclButtonsType::Ok,
1057 ScResId(STR_DOC_NOLONGERSHARED)));
1058 xWarn->run();
1060 SfxBindings* pBindings = GetViewBindings();
1061 if ( pBindings )
1063 pBindings->ExecuteSynchron( SID_SAVEASDOC );
1068 catch ( uno::Exception& )
1070 TOOLS_WARN_EXCEPTION( "sc", "SfxEventHintId::SaveDoc" );
1071 mod->SetInSharedDocSaving(false);
1075 uno::Reference< util::XCloseable > xClose( xModel, uno::UNO_QUERY_THROW );
1076 xClose->close( true );
1078 catch ( uno::Exception& )
1084 if ( !bSuccess )
1085 SetError(ERRCODE_IO_ABORT); // this error code will produce no error message, but will break the further saving process
1087 #endif
1089 if (m_pSheetSaveData)
1090 m_pSheetSaveData->SetInSupportedSave(true);
1092 break;
1093 case SfxEventHintId::SaveAsDoc:
1095 if ( GetDocument().GetExternalRefManager()->containsUnsavedReferences() )
1097 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
1098 VclMessageType::Warning, VclButtonsType::YesNo,
1099 ScResId(STR_UNSAVED_EXT_REF)));
1100 if (RET_NO == xWarn->run())
1102 SetError(ERRCODE_IO_ABORT); // this error code will produce no error message, but will break the further saving process
1105 [[fallthrough]];
1107 case SfxEventHintId::SaveToDoc:
1108 // #i108978# If no event is sent before saving, there will also be no "...DONE" event,
1109 // and SAVE/SAVEAS can't be distinguished from SAVETO. So stream copying is only enabled
1110 // if there is a SAVE/SAVEAS/SAVETO event first.
1111 if (m_pSheetSaveData)
1112 m_pSheetSaveData->SetInSupportedSave(true);
1113 break;
1114 case SfxEventHintId::SaveDocDone:
1115 case SfxEventHintId::SaveAsDocDone:
1117 // new positions are used after "save" and "save as", but not "save to"
1118 UseSheetSaveEntries(); // use positions from saved file for next saving
1119 [[fallthrough]];
1121 case SfxEventHintId::SaveToDocDone:
1122 // only reset the flag, don't use the new positions
1123 if (m_pSheetSaveData)
1124 m_pSheetSaveData->SetInSupportedSave(false);
1125 break;
1126 default:
1129 break;
1132 else if (rHint.GetId() == SfxHintId::TitleChanged) // Without parameter
1134 m_pDocument->SetName( SfxShell::GetName() );
1135 // RegisterNewTargetNames doesn't exist any longer
1136 SfxGetpApp()->Broadcast(SfxHint( SfxHintId::ScDocNameChanged )); // Navigator
1138 else if (rHint.GetId() == SfxHintId::Deinitializing)
1141 #if HAVE_FEATURE_SCRIPTING
1142 uno::Reference<script::vba::XVBACompatibility> xVBACompat(GetBasicContainer(), uno::UNO_QUERY);
1143 if (m_xVBAListener.is() && xVBACompat.is())
1145 xVBACompat->removeVBAScriptListener(m_xVBAListener);
1147 #endif
1149 if (m_pDocument->IsClipboardSource())
1151 // Notes copied to the clipboard have a raw SdrCaptionObj pointer
1152 // copied from this document, forget it as it references this
1153 // document's drawing layer pages and what not, which otherwise when
1154 // pasting to another document after this document was destructed would
1155 // attempt to access non-existing data. Preserve the text data though.
1156 ScDocument* pClipDoc = ScModule::GetClipDoc();
1157 if (pClipDoc)
1158 pClipDoc->ClosingClipboardSource();
1162 if (rHint.GetId() != SfxHintId::ThisIsAnSfxEventHint)
1163 return;
1165 switch(static_cast<const SfxEventHint&>(rHint).GetEventId())
1167 case SfxEventHintId::CreateDoc:
1169 uno::Any aWorkbook;
1170 aWorkbook <<= mxAutomationWorkbookObject;
1171 uno::Sequence< uno::Any > aArgs{ aWorkbook };
1172 ScModule::get()->CallAutomationApplicationEventSinks(u"NewWorkbook"_ustr, aArgs);
1174 break;
1175 case SfxEventHintId::OpenDoc:
1177 uno::Any aWorkbook;
1178 aWorkbook <<= mxAutomationWorkbookObject;
1179 uno::Sequence< uno::Any > aArgs{ aWorkbook };
1180 ScModule::get()->CallAutomationApplicationEventSinks(u"WorkbookOpen"_ustr, aArgs);
1182 break;
1183 default:
1184 break;
1188 // Load contents for organizer
1189 bool ScDocShell::LoadFrom( SfxMedium& rMedium )
1191 LoadMediumGuard aLoadGuard(m_pDocument.get());
1192 ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
1194 weld::WaitObject aWait( GetActiveDialogParent() );
1196 bool bRet = false;
1198 SetInitialLinkUpdate(&rMedium);
1200 // until loading/saving only the styles in XML is implemented,
1201 // load the whole file
1202 bRet = LoadXML( &rMedium, nullptr );
1203 InitItems();
1205 SfxObjectShell::LoadFrom( rMedium );
1207 return bRet;
1210 static void lcl_parseHtmlFilterOption(const OUString& rOption, LanguageType& rLang, bool& rDateConvert, bool& rScientificConvert)
1212 OUStringBuffer aBuf;
1213 std::vector< OUString > aTokens;
1214 sal_Int32 n = rOption.getLength();
1215 const sal_Unicode* p = rOption.getStr();
1216 for (sal_Int32 i = 0; i < n; ++i)
1218 const sal_Unicode c = p[i];
1219 if (c == ' ')
1221 if (!aBuf.isEmpty())
1222 aTokens.push_back( aBuf.makeStringAndClear() );
1224 else
1225 aBuf.append(c);
1228 if (!aBuf.isEmpty())
1229 aTokens.push_back( aBuf.makeStringAndClear() );
1231 rLang = LanguageType( 0 );
1232 rDateConvert = false;
1234 if (!aTokens.empty())
1235 rLang = static_cast<LanguageType>(aTokens[0].toInt32());
1236 if (aTokens.size() > 1)
1237 rDateConvert = static_cast<bool>(aTokens[1].toInt32());
1238 if (aTokens.size() > 2)
1239 rScientificConvert = static_cast<bool>(aTokens[2].toInt32());
1242 bool ScDocShell::ConvertFrom( SfxMedium& rMedium )
1244 LoadMediumGuard aLoadGuard(m_pDocument.get());
1246 bool bRet = false; // sal_False means user quit!
1247 // On error: Set error at stream
1249 ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
1251 GetUndoManager()->Clear();
1253 // Set optimal col width after import?
1254 bool bSetColWidths = false;
1255 bool bSetSimpleTextColWidths = false;
1256 std::map<SCCOL, ScColWidthParam> aColWidthParam;
1257 ScRange aColWidthRange;
1258 // Set optimal row height after import?
1259 bool bSetRowHeights = false;
1261 vector<ScDocRowHeightUpdater::TabRanges> aRecalcRowRangesArray;
1263 // All filters need the complete file in one piece (not asynchronously)
1264 // So make sure that we transfer the whole file with CreateFileStream
1265 rMedium.GetPhysicalName(); //! Call CreateFileStream directly, if available
1267 SetInitialLinkUpdate(&rMedium);
1269 std::shared_ptr<const SfxFilter> pFilter = rMedium.GetFilter();
1270 if (pFilter)
1272 OUString aFltName = pFilter->GetFilterName();
1274 bool bCalc3 = aFltName == "StarCalc 3.0";
1275 bool bCalc4 = aFltName == "StarCalc 4.0";
1276 if (!bCalc3 && !bCalc4)
1277 m_pDocument->SetInsertingFromOtherDoc( true );
1279 if (aFltName == pFilterXML)
1280 bRet = LoadXML( &rMedium, nullptr );
1281 else if (aFltName == pFilterLotus)
1283 OUString sItStr;
1284 if ( const SfxStringItem* pOptionsItem = rMedium.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS, true ) )
1286 sItStr = pOptionsItem->GetValue();
1289 if (sItStr.isEmpty())
1291 // default for lotus import (from API without options):
1292 // IBM_437 encoding
1293 sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_437 );
1296 ErrCode eError = ScFormatFilter::Get().ScImportLotus123( rMedium, *m_pDocument,
1297 ScGlobal::GetCharsetValue(sItStr));
1298 if (eError != ERRCODE_NONE)
1300 if (!GetErrorIgnoreWarning())
1301 SetError(eError);
1303 if( eError.IsWarning() )
1304 bRet = true;
1306 else
1307 bRet = true;
1308 bSetColWidths = true;
1309 bSetRowHeights = true;
1311 else if ( aFltName == pFilterExcel4 || aFltName == pFilterExcel5 ||
1312 aFltName == pFilterExcel95 || aFltName == pFilterExcel97 ||
1313 aFltName == pFilterEx4Temp || aFltName == pFilterEx5Temp ||
1314 aFltName == pFilterEx95Temp || aFltName == pFilterEx97Temp )
1316 EXCIMPFORMAT eFormat = EIF_AUTO;
1317 if ( aFltName == pFilterExcel4 || aFltName == pFilterEx4Temp )
1318 eFormat = EIF_BIFF_LE4;
1319 else if ( aFltName == pFilterExcel5 || aFltName == pFilterExcel95 ||
1320 aFltName == pFilterEx5Temp || aFltName == pFilterEx95Temp )
1321 eFormat = EIF_BIFF5;
1322 else if ( aFltName == pFilterExcel97 || aFltName == pFilterEx97Temp )
1323 eFormat = EIF_BIFF8;
1325 MakeDrawLayer(); //! In the filter
1326 CalcOutputFactor(); // prepare update of row height
1327 ErrCode eError = ScFormatFilter::Get().ScImportExcel( rMedium, m_pDocument.get(), eFormat );
1328 m_pDocument->UpdateFontCharSet();
1329 if ( m_pDocument->IsChartListenerCollectionNeedsUpdate() )
1330 m_pDocument->UpdateChartListenerCollection(); //! For all imports?
1332 // all graphics objects must have names
1333 m_pDocument->EnsureGraphicNames();
1335 if (eError == SCWARN_IMPORT_UNKNOWN_ENCRYPTION)
1338 m_pImpl->mpDelayedInfobarEntry.push_back({ u"UnknownEncryption"_ustr, ScResId(STR_CONTENT_WITH_UNKNOWN_ENCRYPTION), u""_ustr, InfobarType::INFO, true });
1339 eError = ERRCODE_NONE;
1342 if (eError != ERRCODE_NONE)
1344 if (!GetErrorIgnoreWarning())
1345 SetError(eError);
1346 if( eError.IsWarning() )
1347 bRet = true;
1349 else
1350 bRet = true;
1352 else if (aFltName == SC_TEXT_CSV_FILTER_NAME)
1354 ScAsciiOptions aOptions;
1355 bool bOptInit = false;
1357 if ( const SfxStringItem* pOptionsItem = rMedium.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) )
1359 aOptions.ReadFromString( pOptionsItem->GetValue(), rMedium.GetInStream() );
1360 bOptInit = true;
1363 if ( !bOptInit )
1365 // default for ascii import (from API without options):
1366 // UTF-8 encoding, comma, double quotes
1368 aOptions.SetCharSet(RTL_TEXTENCODING_UTF8);
1369 aOptions.SetFieldSeps( OUString(',') );
1370 aOptions.SetTextSep( '"' );
1373 ErrCode eError = ERRCODE_NONE;
1374 bool bOverflowRow, bOverflowCol, bOverflowCell;
1375 bOverflowRow = bOverflowCol = bOverflowCell = false;
1377 if( ! rMedium.IsStorage() )
1379 ScImportExport aImpEx( *m_pDocument );
1380 aImpEx.SetExtOptions( aOptions );
1382 SvStream* pInStream = rMedium.GetInStream();
1383 if (pInStream)
1385 pInStream->SetStreamCharSet( aOptions.GetCharSet() );
1386 pInStream->Seek( 0 );
1387 bRet = aImpEx.ImportStream( *pInStream, rMedium.GetBaseURL(), SotClipboardFormatId::STRING );
1388 eError = bRet ? ERRCODE_NONE : SCERR_IMPORT_CONNECT;
1389 m_pDocument->StartAllListeners();
1390 sc::SetFormulaDirtyContext aCxt;
1391 m_pDocument->SetAllFormulasDirty(aCxt);
1393 // tdf#82254 - check whether to include a byte-order-mark in the output
1394 if (const bool bIncludeBOM = aImpEx.GetIncludeBOM())
1396 aOptions.SetIncludeBOM(bIncludeBOM);
1397 rMedium.GetItemSet().Put(
1398 SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions.WriteToString()));
1401 // for mobile case, we use a copy of the original document and give it a temporary name before editing
1402 // Therefore, the sheet name becomes ugly, long and nonsensical.
1403 #if !(defined ANDROID)
1404 // The same resulting name has to be handled in
1405 // ScExternalRefCache::initializeDoc() and related, hence
1406 // pass 'true' for RenameTab()'s bExternalDocument for a
1407 // composed name so ValidTabName() will not be checked,
1408 // which could veto the rename in case it contained
1409 // characters that Excel does not handle. If we wanted to
1410 // change that then it needed to be handled in all
1411 // corresponding places of the external references
1412 // manager/cache. Likely then we'd also need a method to
1413 // compose a name excluding such characters.
1414 m_pDocument->RenameTab( 0, INetURLObject( rMedium.GetName()).GetBase(), true/*bExternalDocument*/);
1415 #endif
1416 bOverflowRow = aImpEx.IsOverflowRow();
1417 bOverflowCol = aImpEx.IsOverflowCol();
1418 bOverflowCell = aImpEx.IsOverflowCell();
1420 else
1422 OSL_FAIL( "No Stream" );
1426 if (eError != ERRCODE_NONE)
1428 if (!GetErrorIgnoreWarning())
1429 SetError(eError);
1430 if( eError.IsWarning() )
1431 bRet = true;
1433 else if (!GetErrorIgnoreWarning() && (bOverflowRow || bOverflowCol || bOverflowCell))
1435 // precedence: row, column, cell
1436 ErrCode nWarn = (bOverflowRow ? SCWARN_IMPORT_ROW_OVERFLOW :
1437 (bOverflowCol ? SCWARN_IMPORT_COLUMN_OVERFLOW :
1438 SCWARN_IMPORT_CELL_OVERFLOW));
1439 SetError(nWarn);
1441 bSetColWidths = true;
1442 bSetSimpleTextColWidths = true;
1444 else if (aFltName == pFilterDBase)
1446 OUString sItStr;
1447 if ( const SfxStringItem* pOptionsItem = rMedium.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) )
1449 sItStr = pOptionsItem->GetValue();
1452 if (sItStr.isEmpty())
1454 // default for dBase import (from API without options):
1455 // IBM_850 encoding
1457 sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_850 );
1460 ScDocRowHeightUpdater::TabRanges aRecalcRanges(0, m_pDocument->MaxRow());
1461 ErrCode eError = DBaseImport( rMedium.GetPhysicalName(),
1462 ScGlobal::GetCharsetValue(sItStr), aColWidthParam, aRecalcRanges.maRanges );
1463 aRecalcRowRangesArray.push_back(aRecalcRanges);
1465 if (eError != ERRCODE_NONE)
1467 if (!GetErrorIgnoreWarning())
1468 SetError(eError);
1469 if( eError.IsWarning() )
1470 bRet = true;
1472 else
1473 bRet = true;
1475 aColWidthRange.aStart.SetRow( 1 ); // Except for the column header
1476 bSetColWidths = true;
1477 bSetSimpleTextColWidths = true;
1479 else if (aFltName == pFilterDif)
1481 SvStream* pStream = rMedium.GetInStream();
1482 if (pStream)
1484 ErrCode eError;
1485 OUString sItStr;
1486 if ( const SfxStringItem* pOptionsItem = rMedium.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) )
1488 sItStr = pOptionsItem->GetValue();
1491 if (sItStr.isEmpty())
1493 // default for DIF import (from API without options):
1494 // ISO8859-1/MS_1252 encoding
1496 sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_MS_1252 );
1499 eError = ScFormatFilter::Get().ScImportDif( *pStream, m_pDocument.get(), ScAddress(0,0,0),
1500 ScGlobal::GetCharsetValue(sItStr));
1501 if (eError != ERRCODE_NONE)
1503 if (!GetErrorIgnoreWarning())
1504 SetError(eError);
1506 if( eError.IsWarning() )
1507 bRet = true;
1509 else
1510 bRet = true;
1512 bSetColWidths = true;
1513 bSetSimpleTextColWidths = true;
1514 bSetRowHeights = true;
1516 else if (aFltName == pFilterSylk)
1518 ErrCode eError = SCERR_IMPORT_UNKNOWN;
1519 bool bOverflowRow, bOverflowCol, bOverflowCell;
1520 bOverflowRow = bOverflowCol = bOverflowCell = false;
1521 if( !rMedium.IsStorage() )
1523 ScImportExport aImpEx( *m_pDocument );
1525 SvStream* pInStream = rMedium.GetInStream();
1526 if (pInStream)
1528 pInStream->Seek( 0 );
1529 bRet = aImpEx.ImportStream( *pInStream, rMedium.GetBaseURL(), SotClipboardFormatId::SYLK );
1530 eError = bRet ? ERRCODE_NONE : SCERR_IMPORT_UNKNOWN;
1531 m_pDocument->StartAllListeners();
1532 sc::SetFormulaDirtyContext aCxt;
1533 m_pDocument->SetAllFormulasDirty(aCxt);
1535 bOverflowRow = aImpEx.IsOverflowRow();
1536 bOverflowCol = aImpEx.IsOverflowCol();
1537 bOverflowCell = aImpEx.IsOverflowCell();
1539 else
1541 OSL_FAIL( "No Stream" );
1545 if (eError != ERRCODE_NONE)
1547 if (!GetErrorIgnoreWarning())
1548 SetError(eError);
1549 if( eError.IsWarning() )
1550 bRet = true;
1552 else if (!GetErrorIgnoreWarning() && (bOverflowRow || bOverflowCol || bOverflowCell))
1554 // precedence: row, column, cell
1555 ErrCode nWarn = (bOverflowRow ? SCWARN_IMPORT_ROW_OVERFLOW :
1556 (bOverflowCol ? SCWARN_IMPORT_COLUMN_OVERFLOW :
1557 SCWARN_IMPORT_CELL_OVERFLOW));
1558 SetError(nWarn);
1560 bSetColWidths = true;
1561 bSetSimpleTextColWidths = true;
1562 bSetRowHeights = true;
1564 else if (aFltName == pFilterQPro6)
1566 ErrCode eError = ScFormatFilter::Get().ScImportQuattroPro(rMedium.GetInStream(), *m_pDocument);
1567 if (eError != ERRCODE_NONE)
1569 if (!GetErrorIgnoreWarning())
1570 SetError(eError);
1571 if( eError.IsWarning() )
1572 bRet = true;
1574 else
1575 bRet = true;
1576 // TODO: Filter should set column widths. Not doing it here, it may
1577 // result in very narrow or wide columns, depending on content.
1578 // Setting row heights makes cells with font size attribution or
1579 // wrapping enabled look nicer...
1580 bSetRowHeights = true;
1582 else if (aFltName == pFilterRtf)
1584 ErrCode eError = SCERR_IMPORT_UNKNOWN;
1585 if( !rMedium.IsStorage() )
1587 SvStream* pInStream = rMedium.GetInStream();
1588 if (pInStream)
1590 pInStream->Seek( 0 );
1591 ScRange aRange;
1592 eError = ScFormatFilter::Get().ScImportRTF( *pInStream, rMedium.GetBaseURL(), m_pDocument.get(), aRange );
1593 if (eError != ERRCODE_NONE)
1595 if (!GetErrorIgnoreWarning())
1596 SetError(eError);
1598 if( eError.IsWarning() )
1599 bRet = true;
1601 else
1602 bRet = true;
1603 m_pDocument->StartAllListeners();
1604 sc::SetFormulaDirtyContext aCxt;
1605 m_pDocument->SetAllFormulasDirty(aCxt);
1606 bSetColWidths = true;
1607 bSetRowHeights = true;
1609 else
1611 OSL_FAIL( "No Stream" );
1615 if (eError != ERRCODE_NONE)
1617 if (!GetErrorIgnoreWarning())
1618 SetError(eError);
1619 if( eError.IsWarning() )
1620 bRet = true;
1623 else if (aFltName == pFilterHtml || aFltName == pFilterHtmlWebQ)
1625 ErrCode eError = SCERR_IMPORT_UNKNOWN;
1626 bool bWebQuery = aFltName == pFilterHtmlWebQ;
1627 if( !rMedium.IsStorage() )
1629 SvStream* pInStream = rMedium.GetInStream();
1630 if (pInStream)
1632 LanguageType eLang = LANGUAGE_SYSTEM;
1633 bool bDateConvert = false;
1634 bool bScientificConvert = true;
1635 if ( const SfxStringItem* pOptionsItem = rMedium.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) )
1637 OUString aFilterOption = pOptionsItem->GetValue();
1638 lcl_parseHtmlFilterOption(aFilterOption, eLang, bDateConvert, bScientificConvert);
1641 pInStream->Seek( 0 );
1642 ScRange aRange;
1643 // HTML does its own ColWidth/RowHeight
1644 CalcOutputFactor();
1645 SvNumberFormatter aNumFormatter( comphelper::getProcessComponentContext(), eLang);
1646 eError = ScFormatFilter::Get().ScImportHTML( *pInStream, rMedium.GetBaseURL(), m_pDocument.get(), aRange,
1647 GetOutputFactor(), !bWebQuery, &aNumFormatter, bDateConvert, bScientificConvert );
1648 if (eError != ERRCODE_NONE)
1650 if (!GetErrorIgnoreWarning())
1651 SetError(eError);
1653 if( eError.IsWarning() )
1654 bRet = true;
1656 else
1657 bRet = true;
1658 m_pDocument->StartAllListeners();
1660 sc::SetFormulaDirtyContext aCxt;
1661 m_pDocument->SetAllFormulasDirty(aCxt);
1663 else
1665 OSL_FAIL( "No Stream" );
1669 if (eError != ERRCODE_NONE)
1671 if (!GetErrorIgnoreWarning())
1672 SetError(eError);
1673 if( eError.IsWarning() )
1674 bRet = true;
1677 else
1679 ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
1680 if (!pOrcus)
1681 return false;
1683 switch (pOrcus->importByName(*m_pDocument, rMedium, aFltName))
1685 case ScOrcusFilters::ImportResult::Success:
1686 bRet = true;
1687 break;
1688 case ScOrcusFilters::ImportResult::Failure:
1689 bRet = false;
1690 break;
1691 case ScOrcusFilters::ImportResult::NotSupported:
1693 if (!GetErrorIgnoreWarning())
1695 SAL_WARN("sc.filter", "No match for filter '" << aFltName << "' in ConvertFrom");
1696 SetError(SCERR_IMPORT_NI);
1698 break;
1703 if (!bCalc3)
1704 m_pDocument->SetInsertingFromOtherDoc( false );
1706 else
1708 OSL_FAIL("No Filter in ConvertFrom");
1711 InitItems();
1712 CalcOutputFactor();
1713 if ( bRet && (bSetColWidths || bSetRowHeights) )
1714 { // Adjust column width/row height; base 100% zoom
1715 Fraction aZoom( 1, 1 );
1716 double nPPTX = ScGlobal::nScreenPPTX * static_cast<double>(aZoom) / GetOutputFactor(); // Factor is printer display ratio
1717 double nPPTY = ScGlobal::nScreenPPTY * static_cast<double>(aZoom);
1718 ScopedVclPtrInstance< VirtualDevice > pVirtDev;
1719 // all sheets (for Excel import)
1720 SCTAB nTabCount = m_pDocument->GetTableCount();
1721 for (SCTAB nTab=0; nTab<nTabCount; nTab++)
1723 SCCOL nEndCol;
1724 SCROW nEndRow;
1725 m_pDocument->GetCellArea( nTab, nEndCol, nEndRow );
1726 aColWidthRange.aEnd.SetCol( nEndCol );
1727 aColWidthRange.aEnd.SetRow( nEndRow );
1728 ScMarkData aMark(m_pDocument->GetSheetLimits());
1729 aMark.SetMarkArea( aColWidthRange );
1730 aMark.MarkToMulti();
1732 // Order is important: First width, then height
1733 if ( bSetColWidths )
1735 for ( SCCOL nCol=0; nCol <= nEndCol; nCol++ )
1737 if (!bSetSimpleTextColWidths)
1738 aColWidthParam[nCol].mbSimpleText = false;
1740 sal_uInt16 nWidth = m_pDocument->GetOptimalColWidth(
1741 nCol, nTab, pVirtDev, nPPTX, nPPTY, aZoom, aZoom, false, &aMark,
1742 &aColWidthParam[nCol] );
1743 m_pDocument->SetColWidth( nCol, nTab,
1744 nWidth + static_cast<sal_uInt16>(ScGlobal::nLastColWidthExtra) );
1749 if (bSetRowHeights)
1751 // Update all rows in all tables.
1752 ScSizeDeviceProvider aProv(this);
1753 ScDocRowHeightUpdater aUpdater(*m_pDocument, aProv.GetDevice(), aProv.GetPPTX(), aProv.GetPPTY(), nullptr);
1754 aUpdater.update();
1756 else if (!aRecalcRowRangesArray.empty())
1758 // Update only specified row ranges for better performance.
1759 ScSizeDeviceProvider aProv(this);
1760 ScDocRowHeightUpdater aUpdater(*m_pDocument, aProv.GetDevice(), aProv.GetPPTX(), aProv.GetPPTY(), &aRecalcRowRangesArray);
1761 aUpdater.update();
1764 FinishedLoading();
1766 // invalidate eventually temporary table areas
1767 if ( bRet )
1768 m_pDocument->InvalidateTableArea();
1770 m_bIsEmpty = false;
1772 return bRet;
1775 bool ScDocShell::LoadExternal( SfxMedium& rMed )
1777 std::shared_ptr<const SfxFilter> pFilter = rMed.GetFilter();
1778 if (!pFilter)
1779 return false;
1781 if (pFilter->GetProviderName() == "orcus")
1783 ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
1784 if (!pOrcus)
1785 return false;
1787 auto res = pOrcus->importByName(*m_pDocument, rMed, pFilter->GetName());
1788 if (res != ScOrcusFilters::ImportResult::Success)
1789 return false;
1791 FinishedLoading();
1792 return true;
1795 return false;
1798 ScDocShell::PrepareSaveGuard::PrepareSaveGuard( ScDocShell& rDocShell )
1799 : mrDocShell( rDocShell)
1801 // DoEnterHandler not here (because of AutoSave), is in ExecuteSave.
1803 ScChartListenerCollection* pCharts = mrDocShell.m_pDocument->GetChartListenerCollection();
1804 if (pCharts)
1805 pCharts->UpdateDirtyCharts(); // Charts to be updated.
1806 mrDocShell.m_pDocument->StopTemporaryChartLock();
1807 if (mrDocShell.m_pAutoStyleList)
1808 mrDocShell.m_pAutoStyleList->ExecuteAllNow(); // Execute template timeouts now.
1809 if (mrDocShell.m_pDocument->HasExternalRefManager())
1811 ScExternalRefManager* pRefMgr = mrDocShell.m_pDocument->GetExternalRefManager();
1812 if (pRefMgr && pRefMgr->hasExternalData())
1814 pRefMgr->setAllCacheTableReferencedStati( false);
1815 mrDocShell.m_pDocument->MarkUsedExternalReferences(); // Mark tables of external references to be written.
1818 if (mrDocShell.GetCreateMode()== SfxObjectCreateMode::STANDARD)
1819 mrDocShell.SfxObjectShell::SetVisArea( tools::Rectangle() ); // "Normally" worked on => no VisArea.
1822 ScDocShell::PrepareSaveGuard::~PrepareSaveGuard() COVERITY_NOEXCEPT_FALSE
1824 if (mrDocShell.m_pDocument->HasExternalRefManager())
1826 ScExternalRefManager* pRefMgr = mrDocShell.m_pDocument->GetExternalRefManager();
1827 if (pRefMgr && pRefMgr->hasExternalData())
1829 // Prevent accidental data loss due to lack of knowledge.
1830 pRefMgr->setAllCacheTableReferencedStati( true);
1835 bool ScDocShell::Save()
1837 ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
1839 PrepareSaveGuard aPrepareGuard( *this);
1841 if (const auto pFrame1 = SfxViewFrame::GetFirst(this))
1843 if (auto pSysWin = pFrame1->GetWindow().GetSystemWindow())
1845 pSysWin->SetAccessibleName(OUString());
1848 // wait cursor is handled with progress bar
1849 bool bRet = SfxObjectShell::Save();
1850 if( bRet )
1851 bRet = SaveXML( GetMedium(), nullptr );
1852 return bRet;
1855 namespace {
1858 * Remove the file name from the full path, to keep only the directory path.
1860 void popFileName(OUString& rPath)
1862 if (!rPath.isEmpty())
1864 INetURLObject aURLObj(rPath);
1865 aURLObj.removeSegment();
1866 rPath = aURLObj.GetMainURL(INetURLObject::DecodeMechanism::NONE);
1872 void ScDocShell::TerminateEditing()
1874 // Commit any cell changes before saving.
1875 ScModule::get()->InputEnterHandler();
1878 bool ScDocShell::SaveAs( SfxMedium& rMedium )
1880 OUString aCurPath; // empty for new document that hasn't been saved.
1881 const SfxMedium* pCurMedium = GetMedium();
1882 if (pCurMedium)
1884 aCurPath = pCurMedium->GetName();
1885 popFileName(aCurPath);
1888 if (!aCurPath.isEmpty())
1890 // current document has a path -> not a brand-new document.
1891 OUString aNewPath = rMedium.GetName();
1892 popFileName(aNewPath);
1893 OUString aRel = URIHelper::simpleNormalizedMakeRelative(aCurPath, aNewPath);
1894 if (!aRel.isEmpty())
1896 // Directory path will change before and after the save.
1897 m_pDocument->InvalidateStreamOnSave();
1901 ScTabViewShell* pViewShell = GetBestViewShell();
1902 bool bNeedsRehash = ScPassHashHelper::needsPassHashRegen(*m_pDocument, PASSHASH_SHA1);
1903 if (bNeedsRehash)
1904 // legacy xls hash double-hashed by SHA1 is also supported.
1905 bNeedsRehash = ScPassHashHelper::needsPassHashRegen(*m_pDocument, PASSHASH_XL, PASSHASH_SHA1);
1906 if (bNeedsRehash)
1907 { // SHA256 explicitly supported in ODF 1.2, implicitly in ODF 1.1
1908 bNeedsRehash = ScPassHashHelper::needsPassHashRegen(*m_pDocument, PASSHASH_SHA256);
1911 if (pViewShell && bNeedsRehash)
1913 bool bAutoSaveEvent = false;
1914 utl::MediaDescriptor lArgs(rMedium.GetArgs());
1915 lArgs[utl::MediaDescriptor::PROP_AUTOSAVEEVENT] >>= bAutoSaveEvent;
1916 if (bAutoSaveEvent)
1918 // skip saving recovery file instead of showing re-type password dialog window
1919 SAL_WARN("sc.filter",
1920 "Should re-type password for own format, won't export recovery file");
1921 rMedium.SetError(ERRCODE_SFX_WRONGPASSWORD);
1922 return false;
1925 if (!pViewShell->ExecuteRetypePassDlg(PASSHASH_SHA1))
1926 // password re-type cancelled. Don't save the document.
1927 return false;
1930 ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
1932 PrepareSaveGuard aPrepareGuard( *this);
1934 // wait cursor is handled with progress bar
1935 bool bRet = SfxObjectShell::SaveAs( rMedium );
1936 if (bRet)
1937 bRet = SaveXML( &rMedium, nullptr );
1939 return bRet;
1942 namespace {
1944 // Xcl-like column width measured in characters of standard font.
1945 sal_Int32 lcl_ScDocShell_GetColWidthInChars( sal_uInt16 nWidth )
1947 double f = nWidth;
1948 f *= 1328.0 / 25.0;
1949 f += 90.0;
1950 f *= 1.0 / 23.0;
1951 f /= 256.0;
1953 return sal_Int32( f );
1956 void lcl_ScDocShell_GetFixedWidthString( OUString& rStr, const ScDocument& rDoc,
1957 SCTAB nTab, SCCOL nCol, bool bValue, SvxCellHorJustify eHorJust )
1959 OUString aString = rStr;
1960 sal_Int32 nLen = lcl_ScDocShell_GetColWidthInChars(
1961 rDoc.GetColWidth( nCol, nTab ) );
1962 //If the text won't fit in the column
1963 if ( nLen < aString.getLength() )
1965 OUStringBuffer aReplacement;
1966 if (bValue)
1967 aReplacement.append("###");
1968 else
1969 aReplacement.append(aString);
1970 //truncate to the number of characters that should fit, even in the
1971 //bValue case nLen might be < len ###
1972 aString = comphelper::string::truncateToLength(aReplacement, nLen).makeStringAndClear();
1974 if ( nLen > aString.getLength() )
1976 if ( bValue && eHorJust == SvxCellHorJustify::Standard )
1977 eHorJust = SvxCellHorJustify::Right;
1978 OUStringBuffer aTmp(nLen);
1979 switch ( eHorJust )
1981 case SvxCellHorJustify::Right:
1982 comphelper::string::padToLength( aTmp, nLen - aString.getLength(), ' ' );
1983 aString = aTmp.append(aString);
1984 break;
1985 case SvxCellHorJustify::Center:
1986 comphelper::string::padToLength( aTmp, (nLen - aString.getLength()) / 2, ' ' );
1987 [[fallthrough]];
1988 default:
1989 aTmp.append(aString);
1990 comphelper::string::padToLength( aTmp, nLen, ' ' );
1992 aString = aTmp.makeStringAndClear();
1994 rStr = aString;
1997 void lcl_ScDocShell_WriteEmptyFixedWidthString( SvStream& rStream,
1998 const ScDocument& rDoc, SCTAB nTab, SCCOL nCol )
2000 OUString aString;
2001 lcl_ScDocShell_GetFixedWidthString( aString, rDoc, nTab, nCol, false,
2002 SvxCellHorJustify::Standard );
2003 rStream.WriteUnicodeOrByteText( aString );
2006 template<typename StrT, typename SepCharT>
2007 sal_Int32 getTextSepPos(
2008 const StrT& rStr, const ScImportOptions& rAsciiOpt, const SepCharT& rTextSep, const SepCharT& rFieldSep, bool& rNeedQuotes)
2010 // #i116636# quotes are needed if text delimiter (quote), field delimiter,
2011 // or LF or CR is in the cell text.
2012 sal_Int32 nPos = rStr.indexOf(rTextSep);
2013 rNeedQuotes = rAsciiOpt.bQuoteAllText || (nPos >= 0) ||
2014 (rStr.indexOf(rFieldSep) >= 0) ||
2015 (rStr.indexOf('\n') >= 0) ||
2016 (rStr.indexOf('\r') >= 0);
2017 return nPos;
2022 void ScDocShell::AsciiSave( SvStream& rStream, const ScImportOptions& rAsciiOpt, SCTAB nTab )
2024 sal_Unicode cDelim = rAsciiOpt.nFieldSepCode;
2025 sal_Unicode cStrDelim = rAsciiOpt.nTextSepCode;
2026 rtl_TextEncoding eCharSet = rAsciiOpt.eCharSet;
2027 bool bFixedWidth = rAsciiOpt.bFixedWidth;
2028 bool bSaveNumberAsSuch = rAsciiOpt.bSaveNumberAsSuch;
2029 bool bSaveAsShown = rAsciiOpt.bSaveAsShown;
2030 bool bShowFormulas = rAsciiOpt.bSaveFormulas;
2031 bool bIncludeBOM = rAsciiOpt.bIncludeBOM;
2033 rtl_TextEncoding eOldCharSet = rStream.GetStreamCharSet();
2034 rStream.SetStreamCharSet( eCharSet );
2035 SvStreamEndian nOldNumberFormatInt = rStream.GetEndian();
2036 OString aStrDelimEncoded; // only used if not Unicode
2037 OUString aStrDelimDecoded; // only used if context encoding
2038 OString aDelimEncoded;
2039 OUString aDelimDecoded;
2040 bool bContextOrNotAsciiEncoding;
2041 if ( eCharSet == RTL_TEXTENCODING_UNICODE )
2043 rStream.StartWritingUnicodeText();
2044 bContextOrNotAsciiEncoding = false;
2046 else
2048 // tdf#82254 - check whether to include a byte-order-mark in the output
2049 if (bIncludeBOM && eCharSet == RTL_TEXTENCODING_UTF8)
2050 rStream.WriteUChar(0xEF).WriteUChar(0xBB).WriteUChar(0xBF);
2051 aStrDelimEncoded = OString(&cStrDelim, 1, eCharSet);
2052 aDelimEncoded = OString(&cDelim, 1, eCharSet);
2053 rtl_TextEncodingInfo aInfo;
2054 aInfo.StructSize = sizeof(aInfo);
2055 if ( rtl_getTextEncodingInfo( eCharSet, &aInfo ) )
2057 bContextOrNotAsciiEncoding =
2058 (((aInfo.Flags & RTL_TEXTENCODING_INFO_CONTEXT) != 0) ||
2059 ((aInfo.Flags & RTL_TEXTENCODING_INFO_ASCII) == 0));
2060 if ( bContextOrNotAsciiEncoding )
2062 aStrDelimDecoded = OStringToOUString(aStrDelimEncoded, eCharSet);
2063 aDelimDecoded = OStringToOUString(aDelimEncoded, eCharSet);
2066 else
2067 bContextOrNotAsciiEncoding = false;
2070 SCCOL nStartCol = 0;
2071 SCROW nStartRow = 0;
2072 SCCOL nEndCol;
2073 SCROW nEndRow;
2074 m_pDocument->GetCellArea( nTab, nEndCol, nEndRow );
2076 ScProgress aProgress( this, ScResId( STR_SAVE_DOC ), nEndRow, true );
2078 OUString aString;
2080 bool bTabProtect = m_pDocument->IsTabProtected( nTab );
2082 SCCOL nCol;
2083 SCROW nRow;
2085 // Treat the top left cell separator "sep=" special.
2086 // Here nStartRow == 0 && nStartCol == 0
2087 if (!bFixedWidth && cDelim != 0)
2089 // First row iterator.
2090 ScHorizontalCellIterator aIter( *m_pDocument, nTab, nStartCol, nStartRow, nEndCol, nStartRow);
2091 ScRefCellValue* pCell;
2092 // Must be first column and all following cells on this row must be
2093 // empty to fiddle with "sep=".
2094 if ((pCell = aIter.GetNext( nCol, nRow)) != nullptr && nCol == nStartCol && !aIter.GetNext( nCol, nRow))
2096 if (pCell->getType() == CELLTYPE_STRING)
2098 aString = pCell->getSharedString()->getString();
2099 if (aString.getLength() <= 5 && aString.startsWithIgnoreAsciiCase("sep="))
2101 // Cell content is /^sep=.?$/ so write current separator.
2102 // Force the quote character to '"' regardless what is set
2103 // for export because that is the only one recognized on
2104 // import.
2105 aString = "sep=" + OUStringChar(cDelim);
2106 if (cStrDelim != 0)
2107 rStream.WriteUniOrByteChar( '"', eCharSet);
2108 rStream.WriteUnicodeOrByteText(aString, eCharSet);
2109 if (cStrDelim != 0)
2110 rStream.WriteUniOrByteChar( '"', eCharSet);
2111 endlub( rStream );
2112 ++nStartRow;
2118 SCCOL nNextCol = nStartCol;
2119 SCROW nNextRow = nStartRow;
2120 SCCOL nEmptyCol;
2121 SCROW nEmptyRow;
2122 ScInterpreterContext& rContext = m_pDocument->GetNonThreadedContext();
2124 ScHorizontalCellIterator aIter( *m_pDocument, nTab, nStartCol, nStartRow,
2125 nEndCol, nEndRow );
2126 ScRefCellValue* pCell;
2127 while ( ( pCell = aIter.GetNext( nCol, nRow ) ) != nullptr )
2129 bool bProgress = false; // only upon line change
2130 if ( nNextRow < nRow )
2131 { // empty rows or/and empty columns up to end of row
2132 bProgress = true;
2133 for ( nEmptyCol = nNextCol; nEmptyCol < nEndCol; nEmptyCol++ )
2134 { // remaining columns of last row
2135 if ( bFixedWidth )
2136 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2137 *m_pDocument, nTab, nEmptyCol );
2138 else if ( cDelim != 0 )
2139 rStream.WriteUniOrByteChar( cDelim );
2141 endlub( rStream );
2142 nNextRow++;
2143 for ( nEmptyRow = nNextRow; nEmptyRow < nRow; nEmptyRow++ )
2144 { // completely empty rows
2145 for ( nEmptyCol = nStartCol; nEmptyCol < nEndCol; nEmptyCol++ )
2147 if ( bFixedWidth )
2148 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2149 *m_pDocument, nTab, nEmptyCol );
2150 else if ( cDelim != 0 )
2151 rStream.WriteUniOrByteChar( cDelim );
2153 endlub( rStream );
2155 for ( nEmptyCol = nStartCol; nEmptyCol < nCol; nEmptyCol++ )
2156 { // empty columns at beginning of row
2157 if ( bFixedWidth )
2158 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2159 *m_pDocument, nTab, nEmptyCol );
2160 else if ( cDelim != 0 )
2161 rStream.WriteUniOrByteChar( cDelim );
2163 nNextRow = nRow;
2165 else if ( nNextCol < nCol )
2166 { // empty columns in same row
2167 for ( nEmptyCol = nNextCol; nEmptyCol < nCol; nEmptyCol++ )
2168 { // columns in between
2169 if ( bFixedWidth )
2170 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2171 *m_pDocument, nTab, nEmptyCol );
2172 else if ( cDelim != 0 )
2173 rStream.WriteUniOrByteChar( cDelim );
2176 if ( nCol == nEndCol )
2178 bProgress = true;
2179 nNextCol = nStartCol;
2180 nNextRow = nRow + 1;
2182 else
2183 nNextCol = nCol + 1;
2185 CellType eType = pCell->getType();
2186 ScAddress aPos(nCol, nRow, nTab);
2187 if ( bTabProtect )
2189 const ScProtectionAttr* pProtAttr =
2190 m_pDocument->GetAttr( nCol, nRow, nTab, ATTR_PROTECTION );
2191 if ( pProtAttr->GetHideCell() ||
2192 ( eType == CELLTYPE_FORMULA && bShowFormulas &&
2193 pProtAttr->GetHideFormula() ) )
2194 eType = CELLTYPE_NONE; // hide
2196 bool bForceQuotes = false;
2197 bool bString;
2198 switch ( eType )
2200 case CELLTYPE_NONE:
2201 aString.clear();
2202 bString = false;
2203 break;
2204 case CELLTYPE_FORMULA :
2206 FormulaError nErrCode;
2207 if ( bShowFormulas )
2209 aString = pCell->getFormula()->GetFormula();
2210 bString = true;
2212 else if ((nErrCode = pCell->getFormula()->GetErrCode()) != FormulaError::NONE)
2214 aString = ScGlobal::GetErrorString( nErrCode );
2215 bString = true;
2217 else if (pCell->getFormula()->IsValue())
2219 sal_uInt32 nFormat = m_pDocument->GetNumberFormat(ScRange(aPos));
2220 if ( bFixedWidth || bSaveAsShown )
2222 const Color* pDummy;
2223 aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, &rContext, *m_pDocument);
2224 bString = bSaveAsShown && rContext.NFIsTextFormat( nFormat);
2226 else
2228 aString = ScCellFormat::GetInputString(*pCell, nFormat, &rContext, *m_pDocument);
2229 bString = bForceQuotes = !bSaveNumberAsSuch;
2232 else
2234 if ( bSaveAsShown )
2236 sal_uInt32 nFormat = m_pDocument->GetNumberFormat(ScRange(aPos));
2237 const Color* pDummy;
2238 aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, &rContext, *m_pDocument);
2240 else
2241 aString = pCell->getFormula()->GetString().getString();
2242 bString = true;
2245 break;
2246 case CELLTYPE_STRING :
2247 if ( bSaveAsShown )
2249 sal_uInt32 nFormat = m_pDocument->GetNumberFormat(ScRange(aPos));
2250 const Color* pDummy;
2251 aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, &rContext, *m_pDocument);
2253 else
2254 aString = pCell->getSharedString()->getString();
2255 bString = true;
2256 break;
2257 case CELLTYPE_EDIT :
2259 const EditTextObject* pObj = pCell->getEditText();
2260 EditEngine& rEngine = m_pDocument->GetEditEngine();
2261 rEngine.SetText( *pObj);
2262 aString = rEngine.GetText(); // including LF
2263 bString = true;
2265 break;
2266 case CELLTYPE_VALUE :
2268 sal_uInt32 nFormat = m_pDocument->GetNumberFormat( nCol, nRow, nTab );
2269 if ( bFixedWidth || bSaveAsShown )
2271 const Color* pDummy;
2272 aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, &rContext, *m_pDocument);
2273 bString = bSaveAsShown && rContext.NFIsTextFormat( nFormat);
2275 else
2277 aString = ScCellFormat::GetInputString(*pCell, nFormat, &rContext, *m_pDocument);
2278 bString = bForceQuotes = !bSaveNumberAsSuch;
2281 break;
2282 default:
2283 OSL_FAIL( "ScDocShell::AsciiSave: unknown CellType" );
2284 aString.clear();
2285 bString = false;
2288 if ( bFixedWidth )
2290 SvxCellHorJustify eHorJust =
2291 m_pDocument->GetAttr( nCol, nRow, nTab, ATTR_HOR_JUSTIFY )->GetValue();
2292 lcl_ScDocShell_GetFixedWidthString( aString, *m_pDocument, nTab, nCol,
2293 !bString, eHorJust );
2294 rStream.WriteUnicodeOrByteText( aString );
2296 else
2298 OUString aUniString = aString;// TODO: remove that later
2299 if (!bString && cStrDelim != 0 && !aUniString.isEmpty())
2301 sal_Unicode c = aUniString[0];
2302 bString = (c == cStrDelim || c == ' ' ||
2303 aUniString.endsWith(" ") ||
2304 aUniString.indexOf(cStrDelim) >= 0);
2305 if (!bString && cDelim != 0)
2306 bString = (aUniString.indexOf(cDelim) >= 0);
2308 if ( bString )
2310 if ( cStrDelim != 0 ) //@ BugId 55355
2312 if ( eCharSet == RTL_TEXTENCODING_UNICODE )
2314 bool bNeedQuotes = false;
2315 sal_Int32 nPos = getTextSepPos(aUniString, rAsciiOpt, cStrDelim, cDelim, bNeedQuotes);
2316 if (nPos >= 0)
2318 OUString strFrom(cStrDelim);
2319 OUString strTo = strFrom + strFrom;
2320 aUniString = aUniString.replaceAll(strFrom, strTo);
2323 if ( bNeedQuotes || bForceQuotes )
2324 rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
2325 rStream.WriteUnicodeOrByteText(aUniString, eCharSet);
2326 if ( bNeedQuotes || bForceQuotes )
2327 rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
2329 else
2331 // This is nasty. The Unicode to byte encoding
2332 // may convert typographical quotation marks to ASCII
2333 // quotation marks, which may interfere with the delimiter,
2334 // so we have to escape delimiters after the string has
2335 // been encoded. Since this may happen also with UTF-8
2336 // encoded typographical quotation marks if such was
2337 // specified as a delimiter we have to check for the full
2338 // encoded delimiter string, not just one character.
2339 // Now for RTL_TEXTENCODING_ISO_2022_... and similar brain
2340 // dead encodings where one code point (and especially a
2341 // low ASCII value) may represent different characters, we
2342 // have to convert forth and back and forth again. Same for
2343 // UTF-7 since it is a context sensitive encoding too.
2345 if ( bContextOrNotAsciiEncoding )
2347 // to byte encoding
2348 OString aStrEnc = OUStringToOString(aUniString, eCharSet);
2349 // back to Unicode
2350 OUString aStrDec = OStringToOUString(aStrEnc, eCharSet);
2352 // search on re-decoded string
2353 bool bNeedQuotes = false;
2354 sal_Int32 nPos = getTextSepPos(aStrDec, rAsciiOpt, aStrDelimDecoded, aDelimDecoded, bNeedQuotes);
2355 if (nPos >= 0)
2357 OUString strTo = aStrDelimDecoded + aStrDelimDecoded;
2358 aStrDec = aStrDec.replaceAll(aStrDelimDecoded, strTo);
2361 // write byte re-encoded
2362 if ( bNeedQuotes || bForceQuotes )
2363 rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
2364 rStream.WriteUnicodeOrByteText( aStrDec, eCharSet );
2365 if ( bNeedQuotes || bForceQuotes )
2366 rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
2368 else
2370 OString aStrEnc = OUStringToOString(aUniString, eCharSet);
2372 // search on encoded string
2373 bool bNeedQuotes = false;
2374 sal_Int32 nPos = getTextSepPos(aStrEnc, rAsciiOpt, aStrDelimEncoded, aDelimEncoded, bNeedQuotes);
2375 if (nPos >= 0)
2377 OString strTo = aStrDelimEncoded + aStrDelimEncoded;
2378 aStrEnc = aStrEnc.replaceAll(aStrDelimEncoded, strTo);
2381 // write byte encoded
2382 if ( bNeedQuotes || bForceQuotes )
2383 rStream.WriteBytes(
2384 aStrDelimEncoded.getStr(), aStrDelimEncoded.getLength());
2385 rStream.WriteBytes(aStrEnc.getStr(), aStrEnc.getLength());
2386 if ( bNeedQuotes || bForceQuotes )
2387 rStream.WriteBytes(
2388 aStrDelimEncoded.getStr(), aStrDelimEncoded.getLength());
2392 else
2393 rStream.WriteUnicodeOrByteText( aUniString );
2395 else
2396 rStream.WriteUnicodeOrByteText( aUniString );
2399 if( nCol < nEndCol )
2401 if(cDelim!=0) //@ BugId 55355
2402 rStream.WriteUniOrByteChar( cDelim );
2404 else
2405 endlub( rStream );
2407 if ( bProgress )
2408 aProgress.SetStateOnPercent( nRow );
2411 // write out empty if requested
2412 if ( nNextRow <= nEndRow )
2414 for ( nEmptyCol = nNextCol; nEmptyCol < nEndCol; nEmptyCol++ )
2415 { // remaining empty columns of last row
2416 if ( bFixedWidth )
2417 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2418 *m_pDocument, nTab, nEmptyCol );
2419 else if ( cDelim != 0 )
2420 rStream.WriteUniOrByteChar( cDelim );
2422 endlub( rStream );
2423 nNextRow++;
2425 for ( nEmptyRow = nNextRow; nEmptyRow <= nEndRow; nEmptyRow++ )
2426 { // entire empty rows
2427 for ( nEmptyCol = nStartCol; nEmptyCol < nEndCol; nEmptyCol++ )
2429 if ( bFixedWidth )
2430 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2431 *m_pDocument, nTab, nEmptyCol );
2432 else if ( cDelim != 0 )
2433 rStream.WriteUniOrByteChar( cDelim );
2435 endlub( rStream );
2438 rStream.SetStreamCharSet( eOldCharSet );
2439 rStream.SetEndian( nOldNumberFormatInt );
2442 bool ScDocShell::ConvertTo( SfxMedium &rMed )
2444 ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
2446 // #i6500# don't call DoEnterHandler here (doesn't work with AutoSave),
2447 // it's already in ExecuteSave (as for Save and SaveAs)
2449 if (m_pAutoStyleList)
2450 m_pAutoStyleList->ExecuteAllNow(); // Execute template timeouts now
2451 if (GetCreateMode()== SfxObjectCreateMode::STANDARD)
2452 SfxObjectShell::SetVisArea( tools::Rectangle() ); // Edited normally -> no VisArea
2454 OSL_ENSURE( rMed.GetFilter(), "Filter == 0" );
2456 bool bRet = false;
2457 OUString aFltName = rMed.GetFilter()->GetFilterName();
2459 if (aFltName == pFilterXML)
2461 //TODO/LATER: this shouldn't happen!
2462 OSL_FAIL("XML filter in ConvertFrom?!");
2463 bRet = SaveXML( &rMed, nullptr );
2465 else if (aFltName == pFilterExcel5 || aFltName == pFilterExcel95 ||
2466 aFltName == pFilterExcel97 || aFltName == pFilterEx5Temp ||
2467 aFltName == pFilterEx95Temp || aFltName == pFilterEx97Temp)
2469 weld::WaitObject aWait( GetActiveDialogParent() );
2471 bool bDoSave = true;
2472 if( ScTabViewShell* pViewShell = GetBestViewShell() )
2474 ScExtDocOptions* pExtDocOpt = m_pDocument->GetExtDocOptions();
2475 if( !pExtDocOpt )
2477 m_pDocument->SetExtDocOptions( std::make_unique<ScExtDocOptions>() );
2478 pExtDocOpt = m_pDocument->GetExtDocOptions();
2480 pViewShell->GetViewData().WriteExtOptions( *pExtDocOpt );
2482 /* #i104990# If the imported document contains a medium
2483 password, determine if we can save it, otherwise ask the users
2484 whether they want to save without it. */
2485 if( (rMed.GetFilter()->GetFilterFlags() & SfxFilterFlags::ENCRYPTION) == SfxFilterFlags::NONE )
2487 SfxItemSet& rItemSet = rMed.GetItemSet();
2488 if( rItemSet.GetItemState( SID_PASSWORD ) == SfxItemState::SET )
2490 bDoSave = ScWarnPassword::WarningOnPassword( rMed );
2491 // #i42858# remove password from medium (warn only one time)
2492 if( bDoSave )
2493 rItemSet.ClearItem( SID_PASSWORD );
2497 if( bDoSave )
2499 bool bNeedRetypePassDlg = ScPassHashHelper::needsPassHashRegen( *m_pDocument, PASSHASH_XL );
2500 bDoSave = !bNeedRetypePassDlg || pViewShell->ExecuteRetypePassDlg( PASSHASH_XL );
2504 if( bDoSave )
2506 ExportFormatExcel eFormat = ExpBiff5;
2507 if( aFltName == pFilterExcel97 || aFltName == pFilterEx97Temp )
2508 eFormat = ExpBiff8;
2509 ErrCode eError = ScFormatFilter::Get().ScExportExcel5( rMed, m_pDocument.get(), eFormat, RTL_TEXTENCODING_MS_1252 );
2511 if( eError && !GetErrorIgnoreWarning() )
2512 SetError(eError);
2514 // don't return false for warnings
2515 bRet = eError.IsWarning() || (eError == ERRCODE_NONE);
2517 else
2519 // export aborted, i.e. "Save without password" warning
2520 SetError(ERRCODE_ABORT);
2523 else if (aFltName == SC_TEXT_CSV_FILTER_NAME)
2525 OUString sItStr;
2526 if ( const SfxStringItem* pOptionsItem = rMed.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) )
2528 sItStr = pOptionsItem->GetValue();
2531 if ( sItStr.isEmpty() )
2533 // default for ascii export (from API without options):
2534 // UTF-8 encoding, comma, double quotes
2536 ScImportOptions aDefOptions(',', '"', RTL_TEXTENCODING_UTF8);
2537 sItStr = aDefOptions.BuildString();
2540 weld::WaitObject aWait( GetActiveDialogParent() );
2541 ScImportOptions aOptions( sItStr );
2543 if (aOptions.nSheetToExport)
2545 // Only from command line --convert-to
2546 bRet = true;
2548 // Verbose only from command line, not UI (in case we actually
2549 // implement that) nor macro filter options.
2550 bool bVerbose = false;
2551 const css::uno::Sequence<css::beans::PropertyValue> & rArgs = rMed.GetArgs();
2552 const auto pProp = std::find_if( rArgs.begin(), rArgs.end(),
2553 [](const css::beans::PropertyValue& rProp) { return rProp.Name == "ConversionRequestOrigin"; });
2554 if (pProp != rArgs.end())
2556 OUString aOrigin;
2557 pProp->Value >>= aOrigin;
2558 bVerbose = (aOrigin == "CommandLine");
2561 SCTAB nStartTab;
2562 SCTAB nCount = m_pDocument->GetTableCount();
2563 if (aOptions.nSheetToExport == -1)
2565 // All sheets.
2566 nStartTab = 0;
2568 else if (0 < aOptions.nSheetToExport && aOptions.nSheetToExport <= nCount)
2570 // One sheet, 1-based.
2571 nCount = aOptions.nSheetToExport;
2572 nStartTab = nCount - 1;
2574 else
2576 // Usage error, no export but log.
2577 if (bVerbose)
2579 if (aOptions.nSheetToExport < 0)
2580 std::cout << "Bad sheet number string given." << std::endl;
2581 else
2582 std::cout << "No sheet number " << aOptions.nSheetToExport
2583 << ", number of sheets is " << nCount << std::endl;
2585 nStartTab = 0;
2586 nCount = 0;
2587 SetError(SCERR_EXPORT_DATA);
2588 bRet = false;
2591 INetURLObject aURLObject(rMed.GetURLObject());
2592 OUString sExt = aURLObject.CutExtension();
2593 OUString sBaseName = aURLObject.GetLastName();
2594 aURLObject.CutLastName();
2596 for (SCTAB i = nStartTab; i < nCount; ++i)
2598 OUString sTabName;
2599 if (!m_pDocument->GetName(i, sTabName))
2600 sTabName = OUString::number(i);
2601 INetURLObject aSheetURLObject(aURLObject);
2602 OUString sFileName = sBaseName + "-" + sTabName;
2603 if (!sExt.isEmpty())
2604 sFileName = sFileName + "." + sExt;
2605 aSheetURLObject.Append(sFileName);
2607 // log similar to DispatchWatcher::executeDispatchRequests
2608 OUString aOutFile = aSheetURLObject.GetMainURL(INetURLObject::DecodeMechanism::NONE);
2609 if (bVerbose)
2611 OUString aDisplayedName;
2612 if (osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL(aOutFile, aDisplayedName))
2613 aDisplayedName = aOutFile;
2614 std::cout << "Writing sheet " << OUStringToOString(sTabName, osl_getThreadTextEncoding()) << " -> "
2615 << OUStringToOString(aDisplayedName, osl_getThreadTextEncoding())
2616 << std::endl;
2618 if (FStatHelper::IsDocument(aOutFile))
2619 std::cout << "Overwriting: " << OUStringToOString(aDisplayedName, osl_getThreadTextEncoding())
2620 << std::endl ;
2623 std::unique_ptr<SvStream> xStm = ::utl::UcbStreamHelper::CreateStream(aOutFile, StreamMode::TRUNC | StreamMode::WRITE);
2624 if (!xStm)
2626 SetError(ERRCODE_IO_CANTCREATE);
2627 bRet = false;
2628 break;
2630 AsciiSave(*xStm, aOptions, i);
2633 else
2635 SvStream* pStream = rMed.GetOutStream();
2636 if (pStream)
2638 AsciiSave(*pStream, aOptions, GetSaveTab());
2639 bRet = true;
2641 if (m_pDocument->GetTableCount() > 1)
2643 if (!rMed.GetErrorIgnoreWarning() && ScModule::get()->GetInputOptions().GetWarnActiveSheet())
2645 if (ScTabViewShell* pViewShell = GetBestViewShell())
2646 pViewShell->ExecuteOnlyActiveSheetSavedDlg();
2652 else if (aFltName == pFilterDBase)
2654 OUString sCharSet;
2655 if ( const SfxStringItem* pOptionsItem = rMed.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) )
2657 sCharSet = pOptionsItem->GetValue();
2660 if (sCharSet.isEmpty())
2662 // default for dBase export (from API without options):
2663 // IBM_850 encoding
2665 sCharSet = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_850 );
2668 weld::WaitObject aWait( GetActiveDialogParent() );
2669 // Hack so that Sba can overwrite the opened TempFile.
2670 rMed.CloseOutStream();
2671 bool bHasMemo = false;
2673 ErrCodeMsg eError = DBaseExport(
2674 rMed.GetPhysicalName(), ScGlobal::GetCharsetValue(sCharSet), bHasMemo);
2676 INetURLObject aTmpFile( rMed.GetPhysicalName(), INetProtocol::File );
2677 if ( bHasMemo )
2678 aTmpFile.setExtension(u"dbt");
2679 if ( eError != ERRCODE_NONE && !eError.IsWarning() )
2681 if (!GetErrorIgnoreWarning())
2682 SetError(eError);
2683 if ( bHasMemo && IsDocument( aTmpFile ) )
2684 KillFile( aTmpFile );
2686 else
2688 bRet = true;
2689 if ( bHasMemo )
2691 const SfxStringItem* pNameItem = rMed.GetItemSet().GetItem<SfxStringItem>( SID_FILE_NAME );
2692 assert(pNameItem && "SID_FILE_NAME is required");
2693 INetURLObject aDbtFile( pNameItem->GetValue(), INetProtocol::File );
2694 aDbtFile.setExtension(u"dbt");
2696 // tdf#40713: don't lose dbt file
2697 // if aDbtFile corresponds exactly to aTmpFile, we just have to return
2698 if (aDbtFile.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ) ==
2699 aTmpFile.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ))
2701 if (eError != ERRCODE_NONE && !GetErrorIgnoreWarning())
2702 SetError(eError);
2703 return bRet;
2706 if ( IsDocument( aDbtFile ) && !KillFile( aDbtFile ) )
2707 bRet = false;
2708 if ( bRet && !MoveFile( aTmpFile, aDbtFile ) )
2709 bRet = false;
2710 if ( !bRet )
2712 KillFile( aTmpFile );
2713 if (eError == ERRCODE_NONE || eError.IsWarning())
2714 eError = SCERR_EXPORT_DATA;
2717 if (eError != ERRCODE_NONE && !GetErrorIgnoreWarning())
2718 SetError(eError);
2721 else if (aFltName == pFilterDif)
2723 SvStream* pStream = rMed.GetOutStream();
2724 if (pStream)
2726 OUString sItStr;
2727 if ( const SfxStringItem* pOptionsItem = rMed.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) )
2729 sItStr = pOptionsItem->GetValue();
2732 if (sItStr.isEmpty())
2734 // default for DIF export (from API without options):
2735 // ISO8859-1/MS_1252 encoding
2737 sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_MS_1252 );
2740 weld::WaitObject aWait( GetActiveDialogParent() );
2741 ScFormatFilter::Get().ScExportDif( *pStream, m_pDocument.get(), ScAddress(0,0,0),
2742 ScGlobal::GetCharsetValue(sItStr) );
2743 bRet = true;
2745 if (m_pDocument->GetTableCount() > 1)
2746 if (!rMed.GetErrorIgnoreWarning() && ScModule::get()->GetInputOptions().GetWarnActiveSheet())
2747 rMed.SetError(SCWARN_EXPORT_ASCII);
2750 else if (aFltName == pFilterSylk)
2752 SvStream* pStream = rMed.GetOutStream();
2753 if ( pStream )
2755 weld::WaitObject aWait( GetActiveDialogParent() );
2757 SCCOL nEndCol;
2758 SCROW nEndRow;
2759 m_pDocument->GetCellArea( 0, nEndCol, nEndRow );
2760 ScRange aRange( 0,0,0, nEndCol,nEndRow,0 );
2762 ScImportExport aImExport( *m_pDocument, aRange );
2763 aImExport.SetFormulas( true );
2764 bRet = aImExport.ExportStream( *pStream, rMed.GetBaseURL( true ), SotClipboardFormatId::SYLK );
2767 else if (aFltName == pFilterHtml)
2769 SvStream* pStream = rMed.GetOutStream();
2770 if ( pStream )
2772 OUString sFilterOptions;
2774 if (const SfxStringItem* pOptionsItem = rMed.GetItemSet().GetItemIfSet(SID_FILE_FILTEROPTIONS))
2775 sFilterOptions = pOptionsItem->GetValue();
2777 weld::WaitObject aWait(GetActiveDialogParent());
2778 ScImportExport aImExport(*m_pDocument);
2779 aImExport.SetStreamPath(rMed.GetName());
2780 aImExport.SetFilterOptions(sFilterOptions);
2781 bRet = aImExport.ExportStream(*pStream, rMed.GetBaseURL(true), SotClipboardFormatId::HTML);
2782 if (bRet && !aImExport.GetNonConvertibleChars().isEmpty())
2784 SetError(ErrCodeMsg(
2785 SCWARN_EXPORT_NONCONVERTIBLE_CHARS,
2786 aImExport.GetNonConvertibleChars(),
2787 DialogMask::ButtonsOk | DialogMask::MessageInfo));
2791 else
2793 if (GetErrorIgnoreWarning())
2794 SetError(SCERR_IMPORT_NI);
2797 return bRet;
2800 bool ScDocShell::DoSaveCompleted( SfxMedium * pNewStor, bool bRegisterRecent )
2802 bool bRet = SfxObjectShell::DoSaveCompleted( pNewStor, bRegisterRecent );
2804 // SfxHintId::ScDocSaved for change ReadOnly -> Read/Write
2805 Broadcast( SfxHint( SfxHintId::ScDocSaved ) );
2806 return bRet;
2809 bool ScDocShell::QuerySlotExecutable( sal_uInt16 nSlotId )
2811 // #i112634# ask VBA event handlers whether to save or print the document
2813 using namespace ::com::sun::star::script::vba;
2815 sal_Int32 nVbaEventId = VBAEventId::NO_EVENT;
2816 uno::Sequence< uno::Any > aArgs;
2817 switch( nSlotId )
2819 case SID_SAVEDOC:
2820 case SID_SAVEASDOC:
2821 nVbaEventId = VBAEventId::WORKBOOK_BEFORESAVE;
2822 aArgs = { uno::Any(nSlotId == SID_SAVEASDOC) };
2823 break;
2824 case SID_PRINTDOC:
2825 case SID_PRINTDOCDIRECT:
2826 nVbaEventId = VBAEventId::WORKBOOK_BEFOREPRINT;
2827 break;
2830 bool bSlotExecutable = true;
2831 if( nVbaEventId != VBAEventId::NO_EVENT ) try
2833 uno::Reference< XVBAEventProcessor > xEventProcessor( m_pDocument->GetVbaEventProcessor(), uno::UNO_SET_THROW );
2834 xEventProcessor->processVbaEvent( nVbaEventId, aArgs );
2836 catch( util::VetoException& )
2838 bSlotExecutable = false;
2840 catch( uno::Exception& )
2843 return bSlotExecutable;
2846 bool ScDocShell::PrepareClose( bool bUI )
2848 if (ScModule::get()->GetCurRefDlgId() > 0)
2850 SfxViewFrame* pFrame = SfxViewFrame::GetFirst( this );
2851 if( pFrame )
2853 SfxViewShell* p = pFrame->GetViewShell();
2854 ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( p );
2855 if(pViewSh!=nullptr)
2857 vcl::Window *pWin=pViewSh->GetWindow();
2858 if(pWin!=nullptr) pWin->GrabFocus();
2862 return false;
2864 if ( m_pDocument->IsInLinkUpdate() || m_pDocument->IsInInterpreter() )
2866 ErrorMessage(STR_CLOSE_ERROR_LINK);
2867 return false;
2870 DoEnterHandler();
2872 // start 'Workbook_BeforeClose' VBA event handler for possible veto
2873 if( !IsInPrepareClose() )
2877 uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( m_pDocument->GetVbaEventProcessor(), uno::UNO_SET_THROW );
2878 uno::Sequence< uno::Any > aArgs;
2879 xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKBOOK_BEFORECLOSE, aArgs );
2881 catch( util::VetoException& )
2883 // if event processor throws VetoException, macro has vetoed close
2884 return false;
2886 catch( uno::Exception& )
2890 // end handler code
2892 bool bRet = SfxObjectShell::PrepareClose( bUI );
2893 if (bRet) // true == close
2894 m_pDocument->EnableIdle(false); // Do not mess around with it anymore!
2896 return bRet;
2899 OUString ScDocShell::GetOwnFilterName()
2901 return pFilterSc50;
2904 const OUString & ScDocShell::GetHtmlFilterName()
2906 return pFilterHtml;
2909 const OUString & ScDocShell::GetWebQueryFilterName()
2911 return pFilterHtmlWebQ;
2914 const OUString & ScDocShell::GetAsciiFilterName()
2916 return SC_TEXT_CSV_FILTER_NAME;
2919 const OUString & ScDocShell::GetLotusFilterName()
2921 return pFilterLotus;
2924 const OUString & ScDocShell::GetDBaseFilterName()
2926 return pFilterDBase;
2929 const OUString & ScDocShell::GetDifFilterName()
2931 return pFilterDif;
2934 bool ScDocShell::HasAutomaticTableName( std::u16string_view rFilter )
2936 // sal_True for those filters that keep the default table name
2937 // (which is language specific)
2939 return rFilter == SC_TEXT_CSV_FILTER_NAME
2940 || rFilter == pFilterLotus
2941 || rFilter == pFilterExcel4
2942 || rFilter == pFilterEx4Temp
2943 || rFilter == pFilterDBase
2944 || rFilter == pFilterDif
2945 || rFilter == pFilterSylk
2946 || rFilter == pFilterHtml
2947 || rFilter == pFilterRtf;
2950 std::unique_ptr<ScDocFunc> ScDocShell::CreateDocFunc()
2952 return std::make_unique<ScDocFuncDirect>( *this );
2955 ScDocShell::ScDocShell( const SfxModelFlags i_nSfxCreationFlags, const std::shared_ptr<ScDocument>& pDoc ) :
2956 SfxObjectShell( i_nSfxCreationFlags ),
2957 m_pDocument ( pDoc ? pDoc : std::make_shared<ScDocument>( SCDOCMODE_DOCUMENT, this )),
2958 m_aDdeTextFmt(u"TEXT"_ustr),
2959 m_nPrtToScreenFactor( 1.0 ),
2960 m_pImpl ( new DocShell_Impl ),
2961 m_bHeaderOn ( true ),
2962 m_bFooterOn ( true ),
2963 m_bIsEmpty ( true ),
2964 m_bIsInUndo ( false ),
2965 m_bDocumentModifiedPending( false ),
2966 m_bUpdateEnabled ( true ),
2967 m_bAreasChangedNeedBroadcast( false ),
2968 m_nDocumentLock ( 0 ),
2969 m_nCanUpdate (css::document::UpdateDocMode::ACCORDING_TO_CONFIG)
2971 SetPool(&ScModule::get()->GetPool());
2973 m_bIsInplace = (GetCreateMode() == SfxObjectCreateMode::EMBEDDED);
2974 // Will be reset if not in place
2976 m_pDocFunc = CreateDocFunc();
2978 // SetBaseModel needs exception handling
2979 ScModelObj::CreateAndSet( this );
2981 StartListening(*this);
2982 SfxStyleSheetPool* pStlPool = m_pDocument->GetStyleSheetPool();
2983 if (pStlPool)
2984 StartListening(*pStlPool);
2986 m_pDocument->GetDBCollection()->SetRefreshHandler(
2987 LINK( this, ScDocShell, RefreshDBDataHdl ) );
2989 // InitItems and CalcOutputFactor are called now in Load/ConvertFrom/InitNew
2992 ScDocShell::~ScDocShell()
2994 ResetDrawObjectShell(); // If the Drawing Layer still tries to access it, access it
2996 SfxStyleSheetPool* pStlPool = m_pDocument->GetStyleSheetPool();
2997 if (pStlPool)
2998 EndListening(*pStlPool);
2999 EndListening(*this);
3001 m_pAutoStyleList.reset();
3003 SfxApplication *pSfxApp = SfxGetpApp();
3004 if ( pSfxApp->GetDdeService() ) // Delete DDE for Document
3005 pSfxApp->RemoveDdeTopic( this );
3007 m_pDocFunc.reset();
3008 delete m_pDocument->mpUndoManager;
3009 m_pDocument->mpUndoManager = nullptr;
3010 m_pImpl.reset();
3012 m_pPaintLockData.reset();
3014 m_pSheetSaveData.reset();
3015 m_pFormatSaveData.reset();
3016 m_pOldAutoDBRange.reset();
3018 if (m_pModificator)
3020 OSL_FAIL("The Modificator should not exist");
3021 m_pModificator.reset();
3025 SfxUndoManager* ScDocShell::GetUndoManager()
3027 return m_pDocument->GetUndoManager();
3030 void ScDocShell::SetModified( bool bModified )
3032 if ( SfxObjectShell::IsEnableSetModified() )
3034 SfxObjectShell::SetModified( bModified );
3035 Broadcast( SfxHint( SfxHintId::DocChanged ) );
3039 void ScDocShell::SetDocumentModified()
3041 // BroadcastUno must also happen right away with pPaintLockData
3042 // FIXME: Also for SetDrawModified, if Drawing is connected
3043 // FIXME: Then own Hint?
3045 if ( m_pPaintLockData )
3047 // #i115009# broadcast BCA_BRDCST_ALWAYS, so a component can read recalculated results
3048 // of RecalcModeAlways formulas (like OFFSET) after modifying cells
3049 m_pDocument->Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS));
3050 m_pDocument->InvalidateTableArea(); // #i105279# needed here
3051 m_pDocument->BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
3053 m_pPaintLockData->SetModified(); // Later on ...
3054 return;
3057 SetDrawModified();
3059 if ( m_pDocument->IsAutoCalcShellDisabled() )
3060 SetDocumentModifiedPending( true );
3061 else
3063 SetDocumentModifiedPending( false );
3064 m_pDocument->InvalidateStyleSheetUsage();
3065 m_pDocument->InvalidateTableArea();
3066 m_pDocument->InvalidateLastTableOpParams();
3067 m_pDocument->Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS));
3068 if ( m_pDocument->IsForcedFormulaPending() && m_pDocument->GetAutoCalc() )
3069 m_pDocument->CalcFormulaTree( true );
3070 m_pDocument->RefreshDirtyTableColumnNames();
3071 PostDataChanged();
3073 // Detective AutoUpdate:
3074 // Update if formulas were modified (DetectiveDirty) or the list contains
3075 // "Trace Error" entries (Trace Error can look completely different
3076 // after changes to non-formula cells).
3078 ScDetOpList* pList = m_pDocument->GetDetOpList();
3079 if ( pList && ( m_pDocument->IsDetectiveDirty() || pList->HasAddError() ) &&
3080 pList->Count() && !IsInUndo() && ScModule::get()->GetAppOptions().GetDetectiveAuto() )
3082 GetDocFunc().DetectiveRefresh(true); // sal_True = caused by automatic update
3084 m_pDocument->SetDetectiveDirty(false); // always reset, also if not refreshed
3087 if (m_bAreasChangedNeedBroadcast)
3089 m_bAreasChangedNeedBroadcast = false;
3090 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged));
3093 // notify UNO objects after BCA_BRDCST_ALWAYS etc.
3094 m_pDocument->BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
3098 * SetDrawModified - without Formula update
3100 * Drawing also needs to be updated for the normal SetDocumentModified
3101 * e.g.: when deleting tables etc.
3103 void ScDocShell::SetDrawModified()
3105 bool bUpdate = !IsModified();
3107 SetModified();
3109 SfxBindings* pBindings = GetViewBindings();
3110 if (bUpdate && pBindings)
3112 pBindings->Invalidate( SID_SAVEDOC );
3113 pBindings->Invalidate( SID_DOC_MODIFIED );
3116 if (pBindings)
3118 // #i105960# Undo etc used to be volatile.
3119 // They always have to be invalidated, including drawing layer or row height changes
3120 // (but not while pPaintLockData is set).
3121 pBindings->Invalidate( SID_UNDO );
3122 pBindings->Invalidate( SID_REDO );
3123 pBindings->Invalidate( SID_REPEAT );
3126 if ( m_pDocument->IsChartListenerCollectionNeedsUpdate() )
3128 m_pDocument->UpdateChartListenerCollection();
3129 SfxGetpApp()->Broadcast(SfxHint( SfxHintId::ScDrawChanged )); // Navigator
3131 ScModule::get()->AnythingChanged();
3134 void ScDocShell::SetInUndo(bool bSet)
3136 m_bIsInUndo = bSet;
3139 void ScDocShell::GetDocStat( ScDocStat& rDocStat )
3141 SfxPrinter* pPrinter = GetPrinter();
3143 m_pDocument->GetDocStat( rDocStat );
3144 rDocStat.nPageCount = 0;
3146 if ( pPrinter )
3147 for ( SCTAB i=0; i<rDocStat.nTableCount; i++ )
3148 rDocStat.nPageCount = sal::static_int_cast<sal_uInt16>( rDocStat.nPageCount +
3149 static_cast<sal_uInt16>(ScPrintFunc( this, pPrinter, i ).GetTotalPages()) );
3152 std::shared_ptr<SfxDocumentInfoDialog> ScDocShell::CreateDocumentInfoDialog(weld::Window* pParent, const SfxItemSet &rSet)
3154 std::shared_ptr<SfxDocumentInfoDialog> xDlg = std::make_shared<SfxDocumentInfoDialog>(pParent, rSet);
3155 ScDocShell* pDocSh = dynamic_cast< ScDocShell *>( SfxObjectShell::Current() );
3157 // Only for statistics, if this Doc is shown; not from the Doc Manager
3158 if( pDocSh == this )
3160 ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
3161 ::CreateTabPage ScDocStatPageCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_STAT);
3162 OSL_ENSURE(ScDocStatPageCreate, "Tabpage create fail!");
3163 xDlg->AddFontTabPage();
3164 xDlg->AddTabPage(u"calcstats"_ustr, ScResId(STR_DOC_STAT), ScDocStatPageCreate);
3166 return xDlg;
3169 weld::Window* ScDocShell::GetActiveDialogParent()
3171 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
3172 if ( pViewSh )
3173 return pViewSh->GetDialogParent();
3174 return Application::GetDefDialogParent();
3177 ScSheetSaveData* ScDocShell::GetSheetSaveData()
3179 if (!m_pSheetSaveData)
3180 m_pSheetSaveData.reset( new ScSheetSaveData );
3182 return m_pSheetSaveData.get();
3185 ScFormatSaveData* ScDocShell::GetFormatSaveData()
3187 if (!m_pFormatSaveData)
3188 m_pFormatSaveData.reset( new ScFormatSaveData );
3190 return m_pFormatSaveData.get();
3193 namespace {
3195 void removeKeysIfExists(const Reference<ui::XAcceleratorConfiguration>& xScAccel, const vector<const awt::KeyEvent*>& rKeys)
3197 for (const awt::KeyEvent* p : rKeys)
3199 if (!p)
3200 continue;
3204 xScAccel->removeKeyEvent(*p);
3206 catch (const container::NoSuchElementException&) {}
3212 void ScDocShell::ResetKeyBindings( ScOptionsUtil::KeyBindingType eType )
3214 using namespace ::com::sun::star::ui;
3216 const Reference<uno::XComponentContext>& xContext = ::comphelper::getProcessComponentContext();
3217 if (!xContext.is())
3218 return;
3220 Reference<XModuleUIConfigurationManagerSupplier> xModuleCfgSupplier(
3221 theModuleUIConfigurationManagerSupplier::get(xContext) );
3223 // Grab the Calc configuration.
3224 Reference<XUIConfigurationManager> xConfigMgr =
3225 xModuleCfgSupplier->getUIConfigurationManager(
3226 u"com.sun.star.sheet.SpreadsheetDocument"_ustr);
3228 if (!xConfigMgr.is())
3229 return;
3231 // shortcut manager
3232 Reference<XAcceleratorConfiguration> xScAccel = xConfigMgr->getShortCutManager();
3234 if (!xScAccel.is())
3235 return;
3237 vector<const awt::KeyEvent*> aKeys;
3238 aKeys.reserve(9);
3240 // Backspace key
3241 awt::KeyEvent aBackspace;
3242 aBackspace.KeyCode = awt::Key::BACKSPACE;
3243 aBackspace.Modifiers = 0;
3244 aKeys.push_back(&aBackspace);
3246 // Delete key
3247 awt::KeyEvent aDelete;
3248 aDelete.KeyCode = awt::Key::DELETE;
3249 aDelete.Modifiers = 0;
3250 aKeys.push_back(&aDelete);
3252 // Ctrl-D
3253 awt::KeyEvent aCtrlD;
3254 aCtrlD.KeyCode = awt::Key::D;
3255 aCtrlD.Modifiers = awt::KeyModifier::MOD1;
3256 aKeys.push_back(&aCtrlD);
3258 // Alt-Down
3259 awt::KeyEvent aAltDown;
3260 aAltDown.KeyCode = awt::Key::DOWN;
3261 aAltDown.Modifiers = awt::KeyModifier::MOD2;
3262 aKeys.push_back(&aAltDown);
3264 // Ctrl-Space
3265 awt::KeyEvent aCtrlSpace;
3266 aCtrlSpace.KeyCode = awt::Key::SPACE;
3267 aCtrlSpace.Modifiers = awt::KeyModifier::MOD1;
3268 aKeys.push_back(&aCtrlSpace);
3270 // Ctrl-Shift-Space
3271 awt::KeyEvent aCtrlShiftSpace;
3272 aCtrlShiftSpace.KeyCode = awt::Key::SPACE;
3273 aCtrlShiftSpace.Modifiers = awt::KeyModifier::MOD1 | awt::KeyModifier::SHIFT;
3274 aKeys.push_back(&aCtrlShiftSpace);
3276 // F4
3277 awt::KeyEvent aF4;
3278 aF4.KeyCode = awt::Key::F4;
3279 aF4.Modifiers = 0;
3280 aKeys.push_back(&aF4);
3282 // CTRL+SHIFT+F4
3283 awt::KeyEvent aCtrlShiftF4;
3284 aCtrlShiftF4.KeyCode = awt::Key::F4;
3285 aCtrlShiftF4.Modifiers = awt::KeyModifier::MOD1 | awt::KeyModifier::SHIFT;
3286 aKeys.push_back(&aCtrlShiftF4);
3288 // SHIFT+F4
3289 awt::KeyEvent aShiftF4;
3290 aShiftF4.KeyCode = awt::Key::F4;
3291 aShiftF4.Modifiers = awt::KeyModifier::SHIFT;
3292 aKeys.push_back(&aShiftF4);
3294 // Remove all involved keys first, because swapping commands don't work
3295 // well without doing this.
3296 removeKeysIfExists(xScAccel, aKeys);
3297 xScAccel->store();
3299 switch (eType)
3301 case ScOptionsUtil::KEY_DEFAULT:
3302 xScAccel->setKeyEvent(aDelete, u".uno:ClearContents"_ustr);
3303 xScAccel->setKeyEvent(aBackspace, u".uno:Delete"_ustr);
3304 xScAccel->setKeyEvent(aCtrlD, u".uno:FillDown"_ustr);
3305 xScAccel->setKeyEvent(aAltDown, u".uno:DataSelect"_ustr);
3306 xScAccel->setKeyEvent(aCtrlSpace, u".uno:SelectColumn"_ustr);
3307 xScAccel->setKeyEvent(aCtrlShiftSpace, u".uno:SelectAll"_ustr);
3308 xScAccel->setKeyEvent(aF4, u".uno:ToggleRelative"_ustr);
3309 xScAccel->setKeyEvent(aCtrlShiftF4, u".uno:ViewDataSourceBrowser"_ustr);
3310 break;
3311 case ScOptionsUtil::KEY_OOO_LEGACY:
3312 xScAccel->setKeyEvent(aDelete, u".uno:Delete"_ustr);
3313 xScAccel->setKeyEvent(aBackspace, u".uno:ClearContents"_ustr);
3314 xScAccel->setKeyEvent(aCtrlD, u".uno:DataSelect"_ustr);
3315 xScAccel->setKeyEvent(aCtrlShiftSpace, u".uno:SelectColumn"_ustr);
3316 xScAccel->setKeyEvent(aF4, u".uno:ViewDataSourceBrowser"_ustr);
3317 xScAccel->setKeyEvent(aShiftF4, u".uno:ToggleRelative"_ustr);
3318 break;
3319 default:
3323 xScAccel->store();
3326 void ScDocShell::UseSheetSaveEntries()
3328 if (!m_pSheetSaveData)
3329 return;
3331 m_pSheetSaveData->UseSaveEntries(); // use positions from saved file for next saving
3333 bool bHasEntries = false;
3334 SCTAB nTabCount = m_pDocument->GetTableCount();
3335 SCTAB nTab;
3336 for (nTab = 0; nTab < nTabCount; ++nTab)
3337 if (m_pSheetSaveData->HasStreamPos(nTab))
3338 bHasEntries = true;
3340 if (!bHasEntries)
3342 // if no positions were set (for example, export to other format),
3343 // reset all "valid" flags
3344 for (nTab = 0; nTab < nTabCount; ++nTab)
3345 m_pDocument->SetStreamValid(nTab, false);
3349 // --- ScDocShellModificator ------------------------------------------
3351 ScDocShellModificator::ScDocShellModificator( ScDocShell& rDS )
3353 rDocShell( rDS ),
3354 mpProtector(new ScRefreshTimerProtector(rDS.GetDocument().GetRefreshTimerControlAddress()))
3356 ScDocument& rDoc = rDocShell.GetDocument();
3357 bAutoCalcShellDisabled = rDoc.IsAutoCalcShellDisabled();
3358 bIdleEnabled = rDoc.IsIdleEnabled();
3359 rDoc.SetAutoCalcShellDisabled( true );
3360 rDoc.EnableIdle(false);
3363 void ScDocShellModificator::ImplDestroy()
3365 ScDocument& rDoc = rDocShell.GetDocument();
3366 rDoc.SetAutoCalcShellDisabled( bAutoCalcShellDisabled );
3367 if ( !bAutoCalcShellDisabled && rDocShell.IsDocumentModifiedPending() )
3368 rDocShell.SetDocumentModified(); // last one shuts off the lights
3369 rDoc.EnableIdle(bIdleEnabled);
3372 ScDocShellModificator::~ScDocShellModificator()
3374 suppress_fun_call_w_exception(ImplDestroy());
3377 void ScDocShellModificator::SetDocumentModified()
3379 ScDocument& rDoc = rDocShell.GetDocument();
3380 rDoc.PrepareFormulaCalc();
3381 if ( !rDoc.IsImportingXML() )
3383 // temporarily restore AutoCalcShellDisabled
3384 bool bDisabled = rDoc.IsAutoCalcShellDisabled();
3385 rDoc.SetAutoCalcShellDisabled( bAutoCalcShellDisabled );
3386 rDocShell.SetDocumentModified();
3387 rDoc.SetAutoCalcShellDisabled( bDisabled );
3389 else
3391 // uno broadcast is necessary for api to work
3392 // -> must also be done during xml import
3393 rDoc.BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
3397 bool ScDocShell::IsChangeRecording() const
3399 ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
3400 return pChangeTrack != nullptr;
3403 bool ScDocShell::HasChangeRecordProtection() const
3405 bool bRes = false;
3406 ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
3407 if (pChangeTrack)
3408 bRes = pChangeTrack->IsProtected();
3409 return bRes;
3412 void ScDocShell::SetChangeRecording( bool bActivate, bool /*bLockAllViews*/ )
3414 bool bOldChangeRecording = IsChangeRecording();
3416 if (bActivate)
3418 m_pDocument->StartChangeTracking();
3419 ScChangeViewSettings aChangeViewSet;
3420 aChangeViewSet.SetShowChanges(true);
3421 m_pDocument->SetChangeViewSettings(aChangeViewSet);
3423 else
3425 m_pDocument->EndChangeTracking();
3426 PostPaintGridAll();
3429 if (bOldChangeRecording != IsChangeRecording())
3431 UpdateAcceptChangesDialog();
3432 // invalidate slots
3433 SfxBindings* pBindings = GetViewBindings();
3434 if (pBindings)
3435 pBindings->InvalidateAll(false);
3439 void ScDocShell::SetProtectionPassword( const OUString &rNewPassword )
3441 ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
3442 if (!pChangeTrack)
3443 return;
3445 bool bProtected = pChangeTrack->IsProtected();
3447 if (!rNewPassword.isEmpty())
3449 // when password protection is applied change tracking must always be active
3450 SetChangeRecording( true );
3452 css::uno::Sequence< sal_Int8 > aProtectionHash;
3453 SvPasswordHelper::GetHashPassword( aProtectionHash, rNewPassword );
3454 pChangeTrack->SetProtection( aProtectionHash );
3456 else
3458 pChangeTrack->SetProtection( css::uno::Sequence< sal_Int8 >() );
3461 if ( bProtected != pChangeTrack->IsProtected() )
3463 UpdateAcceptChangesDialog();
3464 SetDocumentModified();
3468 bool ScDocShell::GetProtectionHash( /*out*/ css::uno::Sequence< sal_Int8 > &rPasswordHash )
3470 bool bRes = false;
3471 ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
3472 if (pChangeTrack && pChangeTrack->IsProtected())
3474 rPasswordHash = pChangeTrack->GetProtection();
3475 bRes = true;
3477 return bRes;
3480 void ScDocShell::RegisterAutomationWorkbookObject(css::uno::Reference< ooo::vba::excel::XWorkbook > const& xWorkbook)
3482 mxAutomationWorkbookObject = xWorkbook;
3485 extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportSLK(SvStream &rStream)
3487 ScDLL::Init();
3488 ScDocument aDocument;
3489 ScDocOptions aDocOpt = aDocument.GetDocOptions();
3490 aDocOpt.SetLookUpColRowNames(false);
3491 aDocument.SetDocOptions(aDocOpt);
3492 aDocument.MakeTable(0);
3493 aDocument.EnableExecuteLink(false);
3494 aDocument.SetInsertingFromOtherDoc(true);
3495 aDocument.SetImportingXML(true);
3497 ScImportExport aImpEx(aDocument);
3498 return aImpEx.ImportStream(rStream, OUString(), SotClipboardFormatId::SYLK);
3501 extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportCalcHTML(SvStream &rStream)
3503 ScDLL::Init();
3504 ScDocument aDocument;
3505 ScDocOptions aDocOpt = aDocument.GetDocOptions();
3506 aDocOpt.SetLookUpColRowNames(false);
3507 aDocument.SetDocOptions(aDocOpt);
3508 aDocument.MakeTable(0);
3509 aDocument.EnableExecuteLink(false);
3510 aDocument.SetInsertingFromOtherDoc(true);
3511 aDocument.SetImportingXML(true);
3513 ScImportExport aImpEx(aDocument);
3514 return aImpEx.ImportStream(rStream, OUString(), SotClipboardFormatId::HTML);
3517 extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportDBF(SvStream &rStream)
3519 ScDLL::Init();
3521 // we need a real file for this filter
3523 // put it in an empty dir
3524 utl::TempFileNamed aTmpDir(nullptr, true);
3525 aTmpDir.EnableKillingFile();
3526 OUString sTmpDir = aTmpDir.GetURL();
3528 utl::TempFileNamed aTempInput(u"", true, u".dbf", &sTmpDir);
3529 aTempInput.EnableKillingFile();
3531 SvStream* pInputStream = aTempInput.GetStream(StreamMode::WRITE);
3532 sal_uInt8 aBuffer[8192];
3533 while (auto nRead = rStream.ReadBytes(aBuffer, SAL_N_ELEMENTS(aBuffer)))
3534 pInputStream->WriteBytes(aBuffer, nRead);
3535 aTempInput.CloseStream();
3537 SfxMedium aMedium(aTempInput.GetURL(), StreamMode::STD_READWRITE);
3539 ScDocShellRef xDocShell = new ScDocShell(SfxModelFlags::EMBEDDED_OBJECT |
3540 SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS |
3541 SfxModelFlags::DISABLE_DOCUMENT_RECOVERY);
3543 xDocShell->DoInitNew();
3545 ScDocument& rDoc = xDocShell->GetDocument();
3547 ScDocOptions aDocOpt = rDoc.GetDocOptions();
3548 aDocOpt.SetLookUpColRowNames(false);
3549 rDoc.SetDocOptions(aDocOpt);
3550 rDoc.MakeTable(0);
3551 rDoc.EnableExecuteLink(false);
3552 rDoc.SetInsertingFromOtherDoc(true);
3554 ScDocRowHeightUpdater::TabRanges aRecalcRanges(0, rDoc.MaxRow());
3555 std::map<SCCOL, ScColWidthParam> aColWidthParam;
3556 ErrCode eError = xDocShell->DBaseImport(aMedium.GetPhysicalName(), RTL_TEXTENCODING_IBM_850, aColWidthParam, aRecalcRanges.maRanges);
3558 xDocShell->DoClose();
3559 xDocShell.clear();
3561 return eError == ERRCODE_NONE;
3564 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */