calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / sc / source / ui / docshell / docsh.cxx
bloba0d45efd23a6b861fef52503150ff45d0ef7ab43
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 <svl/documentlockfile.hxx>
52 #include <svl/fstathelper.hxx>
53 #include <svl/sharecontrolfile.hxx>
54 #include <svl/urihelper.hxx>
55 #include <osl/file.hxx>
56 #include <chgtrack.hxx>
57 #include <chgviset.hxx>
58 #include <com/sun/star/awt/Key.hpp>
59 #include <com/sun/star/awt/KeyModifier.hpp>
60 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
61 #include <com/sun/star/document/UpdateDocMode.hpp>
62 #include <com/sun/star/script/vba/VBAEventId.hpp>
63 #include <com/sun/star/script/vba/VBAScriptEventId.hpp>
64 #include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
65 #include <com/sun/star/script/vba/XVBAScriptListener.hpp>
66 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
67 #include <com/sun/star/sheet/XSpreadsheetView.hpp>
68 #include <com/sun/star/task/XJob.hpp>
69 #include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
70 #include <com/sun/star/ui/XAcceleratorConfiguration.hpp>
71 #include <com/sun/star/util/VetoException.hpp>
72 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
73 #include <ooo/vba/excel/XWorkbook.hpp>
74 #include <comphelper/diagnose_ex.hxx>
76 #include <config_folders.h>
78 #include <scabstdlg.hxx>
79 #include <sot/formats.hxx>
80 #include <svx/compatflags.hxx>
81 #include <svx/dialogs.hrc>
82 #include <svx/svdpagv.hxx>
83 #include <svx/svdpage.hxx>
84 #include <docmodel/theme/Theme.hxx>
86 #include <formulacell.hxx>
87 #include <global.hxx>
88 #include <filter.hxx>
89 #include <scmod.hxx>
90 #include <tabvwsh.hxx>
91 #include <docfunc.hxx>
92 #include <imoptdlg.hxx>
93 #include <impex.hxx>
94 #include <scresid.hxx>
95 #include <strings.hrc>
96 #include <globstr.hrc>
97 #include <scerrors.hxx>
98 #include <brdcst.hxx>
99 #include <stlpool.hxx>
100 #include <autostyl.hxx>
101 #include <attrib.hxx>
102 #include <asciiopt.hxx>
103 #include <progress.hxx>
104 #include <pntlock.hxx>
105 #include <docuno.hxx>
106 #include <appoptio.hxx>
107 #include <formulaopt.hxx>
108 #include <scdll.hxx>
109 #include <detdata.hxx>
110 #include <printfun.hxx>
111 #include <dociter.hxx>
112 #include <cellform.hxx>
113 #include <chartlis.hxx>
114 #include <hints.hxx>
115 #include <xmlwrap.hxx>
116 #include <drwlayer.hxx>
117 #include <dbdata.hxx>
118 #include <scextopt.hxx>
119 #include <compiler.hxx>
120 #include <warnpassword.hxx>
121 #include <optsolver.hxx>
122 #include <sheetdata.hxx>
123 #include <table.hxx>
124 #include <tabprotection.hxx>
125 #include <docparam.hxx>
126 #include "docshimp.hxx"
127 #include <sizedev.hxx>
128 #include <undomanager.hxx>
129 #include <refreshtimerprotector.hxx>
131 #include <officecfg/Office/Calc.hxx>
132 #include <comphelper/processfactory.hxx>
133 #include <comphelper/string.hxx>
134 #include <unotools/configmgr.hxx>
135 #include <unotools/tempfile.hxx>
136 #include <unotools/ucbstreamhelper.hxx>
137 #include <uiitems.hxx>
138 #include <dpobject.hxx>
139 #include <markdata.hxx>
140 #include <docoptio.hxx>
141 #include <orcusfilters.hxx>
142 #include <datastream.hxx>
143 #include <documentlinkmgr.hxx>
144 #include <refupdatecontext.hxx>
146 #include <memory>
147 #include <vector>
149 #include <comphelper/lok.hxx>
150 #include <svtools/sfxecode.hxx>
151 #include <unotools/pathoptions.hxx>
153 using namespace com::sun::star;
154 using ::com::sun::star::uno::Reference;
155 using ::com::sun::star::lang::XMultiServiceFactory;
156 using std::shared_ptr;
157 using ::std::vector;
159 // Filter names (like in sclib.cxx)
161 constexpr OUStringLiteral pFilterSc50 = u"StarCalc 5.0";
162 const char pFilterXML[] = "StarOffice XML (Calc)";
163 constexpr OUStringLiteral pFilterLotus = u"Lotus";
164 const char pFilterQPro6[] = "Quattro Pro 6.0";
165 const char16_t pFilterExcel4[] = u"MS Excel 4.0";
166 const char16_t pFilterEx4Temp[] = u"MS Excel 4.0 Vorlage/Template";
167 const char pFilterExcel5[] = "MS Excel 5.0/95";
168 const char pFilterEx5Temp[] = "MS Excel 5.0/95 Vorlage/Template";
169 const char pFilterExcel95[] = "MS Excel 95";
170 const char pFilterEx95Temp[] = "MS Excel 95 Vorlage/Template";
171 const char pFilterExcel97[] = "MS Excel 97";
172 const char pFilterEx97Temp[] = "MS Excel 97 Vorlage/Template";
173 constexpr OUStringLiteral pFilterDBase = u"dBase";
174 constexpr OUStringLiteral pFilterDif = u"DIF";
175 const char16_t pFilterSylk[] = u"SYLK";
176 constexpr OUStringLiteral pFilterHtml = u"HTML (StarCalc)";
177 constexpr OUStringLiteral pFilterHtmlWebQ = u"calc_HTML_WebQuery";
178 const char16_t pFilterRtf[] = u"Rich Text Format (StarCalc)";
180 #define ShellClass_ScDocShell
181 #include <scslots.hxx>
183 SFX_IMPL_INTERFACE(ScDocShell,SfxObjectShell)
185 void ScDocShell::InitInterface_Impl()
189 // GlobalName of the current version:
190 SFX_IMPL_OBJECTFACTORY( ScDocShell, SvGlobalName(SO3_SC_CLASSID), "scalc" )
193 void ScDocShell::FillClass( SvGlobalName* pClassName,
194 SotClipboardFormatId* pFormat,
195 OUString* pFullTypeName,
196 sal_Int32 nFileFormat,
197 bool bTemplate /* = false */) const
199 if ( nFileFormat == SOFFICE_FILEFORMAT_60 )
201 *pClassName = SvGlobalName( SO3_SC_CLASSID_60 );
202 *pFormat = SotClipboardFormatId::STARCALC_60;
203 *pFullTypeName = ScResId( SCSTR_LONG_SCDOC_NAME_60 );
205 else if ( nFileFormat == SOFFICE_FILEFORMAT_8 )
207 *pClassName = SvGlobalName( SO3_SC_CLASSID_60 );
208 *pFormat = bTemplate ? SotClipboardFormatId::STARCALC_8_TEMPLATE : SotClipboardFormatId::STARCALC_8;
209 *pFullTypeName = ScResId( SCSTR_LONG_SCDOC_NAME_80 );
211 else
213 OSL_FAIL("Which version?");
217 std::set<Color> ScDocShell::GetDocColors()
219 return m_pDocument->GetDocColors();
222 std::shared_ptr<model::ColorSet> ScDocShell::GetThemeColors()
224 ScTabViewShell* pShell = GetBestViewShell();
225 if (!pShell)
226 return {};
228 SdrModel* pSdrModel = GetDocument().GetDrawLayer();
229 if (!pSdrModel)
230 return {};
232 auto const& pTheme = pSdrModel->getTheme();
233 if (!pTheme)
234 return {};
236 return pTheme->getColorSet();
239 void ScDocShell::DoEnterHandler()
241 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
242 if (pViewSh && pViewSh->GetViewData().GetDocShell() == this)
243 SC_MOD()->InputEnterHandler();
246 SCTAB ScDocShell::GetSaveTab()
248 SCTAB nTab = 0;
249 ScTabViewShell* pSh = GetBestViewShell();
250 if (pSh)
252 const ScMarkData& rMark = pSh->GetViewData().GetMarkData();
253 nTab = rMark.GetFirstSelected();
255 return nTab;
258 HiddenInformation ScDocShell::GetHiddenInformationState( HiddenInformation nStates )
260 // get global state like HiddenInformation::DOCUMENTVERSIONS
261 HiddenInformation nState = SfxObjectShell::GetHiddenInformationState( nStates );
263 if ( nStates & HiddenInformation::RECORDEDCHANGES )
265 if ( m_pDocument->GetChangeTrack() && m_pDocument->GetChangeTrack()->GetFirst() )
266 nState |= HiddenInformation::RECORDEDCHANGES;
268 if ( nStates & HiddenInformation::NOTES )
270 SCTAB nTableCount = m_pDocument->GetTableCount();
271 bool bFound = false;
272 for (SCTAB nTab = 0; nTab < nTableCount && !bFound; ++nTab)
274 if (m_pDocument->HasTabNotes(nTab)) //TODO:
275 bFound = true;
278 if (bFound)
279 nState |= HiddenInformation::NOTES;
282 return nState;
285 void ScDocShell::BeforeXMLLoading()
287 m_pDocument->EnableIdle(false);
289 // prevent unnecessary broadcasts and updates
290 OSL_ENSURE(m_pModificator == nullptr, "The Modificator should not exist");
291 m_pModificator.reset( new ScDocShellModificator( *this ) );
293 m_pDocument->SetImportingXML( true );
294 m_pDocument->EnableExecuteLink( false ); // #i101304# to be safe, prevent nested loading from external references
295 m_pDocument->EnableUndo( false );
296 // prevent unnecessary broadcasts and "half way listeners"
297 m_pDocument->SetInsertingFromOtherDoc( true );
300 void ScDocShell::AfterXMLLoading(bool bRet)
302 if (GetCreateMode() != SfxObjectCreateMode::ORGANIZER)
304 UpdateLinks();
305 // don't prevent establishing of listeners anymore
306 m_pDocument->SetInsertingFromOtherDoc( false );
307 if ( bRet )
309 ScChartListenerCollection* pChartListener = m_pDocument->GetChartListenerCollection();
310 if (pChartListener)
311 pChartListener->UpdateDirtyCharts();
313 // #95582#; set the table names of linked tables to the new path
314 SCTAB nTabCount = m_pDocument->GetTableCount();
315 for (SCTAB i = 0; i < nTabCount; ++i)
317 if (m_pDocument->IsLinked( i ))
319 OUString aName;
320 m_pDocument->GetName(i, aName);
321 OUString aLinkTabName = m_pDocument->GetLinkTab(i);
322 sal_Int32 nLinkTabNameLength = aLinkTabName.getLength();
323 sal_Int32 nNameLength = aName.getLength();
324 if (nLinkTabNameLength < nNameLength)
327 // remove the quotes on begin and end of the docname and restore the escaped quotes
328 const sal_Unicode* pNameBuffer = aName.getStr();
329 if ( *pNameBuffer == '\'' && // all docnames have to have a ' character on the first pos
330 ScGlobal::UnicodeStrChr( pNameBuffer, SC_COMPILER_FILE_TAB_SEP ) )
332 OUStringBuffer aDocURLBuffer;
333 bool bQuote = true; // Document name is always quoted
334 ++pNameBuffer;
335 while ( bQuote && *pNameBuffer )
337 if ( *pNameBuffer == '\'' && *(pNameBuffer-1) != '\\' )
338 bQuote = false;
339 else if( *pNameBuffer != '\\' || *(pNameBuffer+1) != '\'' )
340 aDocURLBuffer.append(*pNameBuffer); // If escaped quote: only quote in the name
341 ++pNameBuffer;
344 if( *pNameBuffer == SC_COMPILER_FILE_TAB_SEP ) // after the last quote of the docname should be the # char
346 sal_Int32 nIndex = nNameLength - nLinkTabNameLength;
347 INetURLObject aINetURLObject(aDocURLBuffer);
348 if(aName.match( aLinkTabName, nIndex) &&
349 (aName[nIndex - 1] == '#') && // before the table name should be the # char
350 !aINetURLObject.HasError()) // the docname should be a valid URL
352 aName = ScGlobal::GetDocTabName( m_pDocument->GetLinkDoc( i ), m_pDocument->GetLinkTab( i ) );
353 m_pDocument->RenameTab(i, aName, true/*bExternalDocument*/);
355 // else; nothing has to happen, because it is a user given name
357 // else; nothing has to happen, because it is a user given name
359 // else; nothing has to happen, because it is a user given name
361 // else; nothing has to happen, because it is a user given name
365 // #i94570# DataPilot table names have to be unique, or the tables can't be accessed by API.
366 // If no name (or an invalid name, skipped in ScXMLDataPilotTableContext::EndElement) was set, create a new name.
367 ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
368 if ( pDPCollection )
370 size_t nDPCount = pDPCollection->GetCount();
371 for (size_t nDP=0; nDP<nDPCount; ++nDP)
373 ScDPObject& rDPObj = (*pDPCollection)[nDP];
374 if (rDPObj.GetName().isEmpty())
375 rDPObj.SetName( pDPCollection->CreateNewName() );
380 else
381 m_pDocument->SetInsertingFromOtherDoc( false );
383 m_pDocument->SetImportingXML( false );
384 m_pDocument->EnableExecuteLink( true );
385 m_pDocument->EnableUndo( true );
386 m_bIsEmpty = false;
388 if (m_pModificator)
390 ScDocument::HardRecalcState eRecalcState = m_pDocument->GetHardRecalcState();
391 // Temporarily set hard-recalc to prevent calling
392 // ScFormulaCell::Notify() during destruction of the Modificator which
393 // will set the cells dirty.
394 if (eRecalcState == ScDocument::HardRecalcState::OFF)
395 m_pDocument->SetHardRecalcState(ScDocument::HardRecalcState::TEMPORARY);
396 m_pModificator.reset();
397 m_pDocument->SetHardRecalcState(eRecalcState);
399 else
401 OSL_FAIL("The Modificator should exist");
404 m_pDocument->EnableIdle(true);
407 namespace {
409 class LoadMediumGuard
411 public:
412 explicit LoadMediumGuard(ScDocument* pDoc) :
413 mpDoc(pDoc)
415 mpDoc->SetLoadingMedium(true);
418 ~LoadMediumGuard()
420 mpDoc->SetLoadingMedium(false);
422 private:
423 ScDocument* mpDoc;
426 void processDataStream( ScDocShell& rShell, const sc::ImportPostProcessData& rData )
428 if (!rData.mpDataStream)
429 return;
431 const sc::ImportPostProcessData::DataStream& r = *rData.mpDataStream;
432 if (!r.maRange.IsValid())
433 return;
435 // Break the streamed range into the top range and the height limit. A
436 // height limit of 0 means unlimited i.e. the streamed data will go all
437 // the way to the last row.
439 ScRange aTopRange = r.maRange;
440 aTopRange.aEnd.SetRow(aTopRange.aStart.Row());
441 sal_Int32 nLimit = r.maRange.aEnd.Row() - r.maRange.aStart.Row() + 1;
442 if (r.maRange.aEnd.Row() == rShell.GetDocument().MaxRow())
443 // Unlimited range.
444 nLimit = 0;
446 sc::DataStream::MoveType eMove =
447 r.meInsertPos == sc::ImportPostProcessData::DataStream::InsertTop ?
448 sc::DataStream::MOVE_DOWN : sc::DataStream::RANGE_DOWN;
450 sc::DataStream* pStrm = new sc::DataStream(&rShell, r.maURL, aTopRange, nLimit, eMove, 0);
451 pStrm->SetRefreshOnEmptyLine(r.mbRefreshOnEmpty);
452 sc::DocumentLinkManager& rMgr = rShell.GetDocument().GetDocLinkManager();
453 rMgr.setDataStream(pStrm);
456 class MessageWithCheck : public weld::MessageDialogController
458 private:
459 std::unique_ptr<weld::CheckButton> m_xWarningOnBox;
460 public:
461 MessageWithCheck(weld::Window *pParent, const OUString& rUIFile, const OString& rDialogId)
462 : MessageDialogController(pParent, rUIFile, rDialogId, "ask")
463 , m_xWarningOnBox(m_xBuilder->weld_check_button("ask"))
466 bool get_active() const { return m_xWarningOnBox->get_active(); }
467 void hide_ask() const { m_xWarningOnBox->set_visible(false); };
470 #if HAVE_FEATURE_SCRIPTING
471 class VBAScriptListener : public ::cppu::WeakImplHelper< css::script::vba::XVBAScriptListener >
473 private:
474 ScDocShell* m_pDocSh;
475 public:
476 VBAScriptListener(ScDocShell* pDocSh) : m_pDocSh(pDocSh)
480 // XVBAScriptListener
481 virtual void SAL_CALL notifyVBAScriptEvent( const ::css::script::vba::VBAScriptEvent& aEvent ) override
483 if (aEvent.Identifier == script::vba::VBAScriptEventId::SCRIPT_STOPPED &&
484 m_pDocSh->GetClipData().is())
486 m_pDocSh->SetClipData(uno::Reference<datatransfer::XTransferable2>());
490 // XEventListener
491 virtual void SAL_CALL disposing( const ::css::lang::EventObject& /*Source*/ ) override
495 #endif
499 bool ScDocShell::LoadXML( SfxMedium* pLoadMedium, const css::uno::Reference< css::embed::XStorage >& xStor )
501 LoadMediumGuard aLoadGuard(m_pDocument.get());
503 // MacroCallMode is no longer needed, state is kept in SfxObjectShell now
505 // no Seek(0) here - always loading from storage, GetInStream must not be called
507 BeforeXMLLoading();
509 ScXMLImportWrapper aImport(*this, pLoadMedium, xStor);
511 bool bRet = false;
512 ErrCode nError = ERRCODE_NONE;
513 m_pDocument->LockAdjustHeight();
514 if (GetCreateMode() == SfxObjectCreateMode::ORGANIZER)
515 bRet = aImport.Import(ImportFlags::Styles, nError);
516 else
517 bRet = aImport.Import(ImportFlags::All, nError);
519 if ( nError )
520 pLoadMedium->SetError(nError);
522 processDataStream(*this, aImport.GetImportPostProcessData());
524 //if the document was not generated by LibreOffice, do hard recalc in case some other document
525 //generator saved cached formula results that differ from LibreOffice's calculated results or
526 //did not use cached formula results.
527 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(GetModel(), uno::UNO_QUERY_THROW);
528 uno::Reference<document::XDocumentProperties> xDocProps = xDPS->getDocumentProperties();
530 ScRecalcOptions nRecalcMode =
531 static_cast<ScRecalcOptions>(officecfg::Office::Calc::Formula::Load::ODFRecalcMode::get());
533 bool bHardRecalc = false;
534 if (nRecalcMode == RECALC_ASK)
536 OUString sProductName(utl::ConfigManager::getProductName());
537 if (m_pDocument->IsUserInteractionEnabled() && xDocProps->getGenerator().indexOf(sProductName) == -1)
539 // Generator is not LibreOffice. Ask if the user wants to perform
540 // full re-calculation.
541 MessageWithCheck aQueryBox(GetActiveDialogParent(),
542 "modules/scalc/ui/recalcquerydialog.ui", "RecalcQueryDialog");
543 aQueryBox.set_primary_text(ScResId(STR_QUERY_FORMULA_RECALC_ONLOAD_ODS));
544 aQueryBox.set_default_response(RET_YES);
546 if ( officecfg::Office::Calc::Formula::Load::OOXMLRecalcMode::isReadOnly() )
547 aQueryBox.hide_ask();
549 bHardRecalc = aQueryBox.run() == RET_YES;
551 if (aQueryBox.get_active())
553 // Always perform selected action in the future.
554 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
555 officecfg::Office::Calc::Formula::Load::ODFRecalcMode::set(sal_Int32(0), batch);
556 ScFormulaOptions aOpt = SC_MOD()->GetFormulaOptions();
557 aOpt.SetODFRecalcOptions(bHardRecalc ? RECALC_ALWAYS : RECALC_NEVER);
558 /* XXX is this really supposed to set the ScModule options?
559 * Not the ScDocShell options? */
560 SC_MOD()->SetFormulaOptions(aOpt);
562 batch->commit();
566 else if (nRecalcMode == RECALC_ALWAYS)
567 bHardRecalc = true;
569 if (bHardRecalc)
570 DoHardRecalc();
571 else
573 // still need to recalc volatile formula cells.
574 m_pDocument->Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS));
577 AfterXMLLoading(bRet);
579 m_pDocument->UnlockAdjustHeight();
580 return bRet;
583 bool ScDocShell::SaveXML( SfxMedium* pSaveMedium, const css::uno::Reference< css::embed::XStorage >& xStor )
585 m_pDocument->EnableIdle(false);
587 ScXMLImportWrapper aImport(*this, pSaveMedium, xStor);
588 bool bRet(false);
589 if (GetCreateMode() != SfxObjectCreateMode::ORGANIZER)
590 bRet = aImport.Export(false);
591 else
592 bRet = aImport.Export(true);
594 m_pDocument->EnableIdle(true);
596 return bRet;
599 bool ScDocShell::Load( SfxMedium& rMedium )
601 LoadMediumGuard aLoadGuard(m_pDocument.get());
602 ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
604 // only the latin script language is loaded
605 // -> initialize the others from options (before loading)
606 InitOptions(true);
608 // If this is an ODF file being loaded, then by default, use legacy processing
609 // (if required, it will be overridden in *::ReadUserDataSequence())
610 if (IsOwnStorageFormat(rMedium))
612 if (ScDrawLayer* pDrawLayer = m_pDocument->GetDrawLayer())
614 pDrawLayer->SetCompatibilityFlag(SdrCompatibilityFlag::AnchoredTextOverflowLegacy,
615 true); // for tdf#99729
616 pDrawLayer->SetCompatibilityFlag(SdrCompatibilityFlag::LegacyFontwork,
617 true); // for tdf#148000
621 GetUndoManager()->Clear();
623 bool bRet = SfxObjectShell::Load(rMedium);
624 if (bRet)
626 SetInitialLinkUpdate(&rMedium);
629 // prepare a valid document for XML filter
630 // (for ConvertFrom, InitNew is called before)
631 m_pDocument->MakeTable(0);
632 m_pDocument->GetStyleSheetPool()->CreateStandardStyles();
633 m_pDocument->UpdStlShtPtrsFrmNms();
635 /* Create styles that are imported through Orcus */
637 OUString aURL("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/calc/styles.xml");
638 rtl::Bootstrap::expandMacros(aURL);
640 OUString aPath;
641 osl::FileBase::getSystemPathFromFileURL(aURL, aPath);
643 ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
645 if (pOrcus)
647 pOrcus->importODS_Styles(*m_pDocument, aPath);
648 m_pDocument->GetStyleSheetPool()->setAllParaStandard();
651 bRet = LoadXML( &rMedium, nullptr );
655 if (!bRet && !rMedium.GetError())
656 rMedium.SetError(SVSTREAM_FILEFORMAT_ERROR);
658 if (rMedium.GetError())
659 SetError(rMedium.GetError());
661 InitItems();
662 CalcOutputFactor();
664 // invalidate eventually temporary table areas
665 if ( bRet )
666 m_pDocument->InvalidateTableArea();
668 m_bIsEmpty = false;
669 FinishedLoading();
670 return bRet;
673 void ScDocShell::Notify( SfxBroadcaster&, const SfxHint& rHint )
675 const ScTablesHint* pScHint = dynamic_cast< const ScTablesHint* >( &rHint );
676 if (pScHint)
678 if (pScHint->GetTablesHintId() == SC_TAB_INSERTED)
680 uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents = m_pDocument->GetVbaEventProcessor();
681 if ( xVbaEvents.is() ) try
683 uno::Sequence< uno::Any > aArgs{ uno::Any(pScHint->GetTab1()) };
684 xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKBOOK_NEWSHEET, aArgs );
686 catch( uno::Exception& )
692 if ( auto pStyleSheetHint = dynamic_cast<const SfxStyleSheetHint*>(&rHint) ) // Template changed
693 NotifyStyle( *pStyleSheetHint );
694 else if ( auto pStlHint = dynamic_cast<const ScAutoStyleHint*>(&rHint) )
696 //! direct call for AutoStyles
698 // this is called synchronously from ScInterpreter::ScStyle,
699 // modifying the document must be asynchronous
700 // (handled by AddInitial)
702 const ScRange& aRange = pStlHint->GetRange();
703 const OUString& aName1 = pStlHint->GetStyle1();
704 const OUString& aName2 = pStlHint->GetStyle2();
705 sal_uInt32 nTimeout = pStlHint->GetTimeout();
707 if (!m_pAutoStyleList)
708 m_pAutoStyleList.reset( new ScAutoStyleList(this) );
709 m_pAutoStyleList->AddInitial( aRange, aName1, nTimeout, aName2 );
711 else if (rHint.GetId() == SfxHintId::ThisIsAnSfxEventHint)
713 switch (static_cast<const SfxEventHint&>(rHint).GetEventId())
715 case SfxEventHintId::LoadFinished:
717 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
718 // the readonly documents should not be opened in shared mode
719 if ( HasSharedXMLFlagSet() && !SC_MOD()->IsInSharedDocLoading() && !IsReadOnly() )
721 if ( SwitchToShared( true, false ) )
723 ScViewData* pViewData = GetViewData();
724 ScTabView* pTabView = ( pViewData ? pViewData->GetView() : nullptr );
725 if ( pTabView )
727 pTabView->UpdateLayerLocks();
730 else
732 // switching to shared mode has failed, the document should be opened readonly
733 // TODO/LATER: And error message should be shown here probably
734 SetReadOnlyUI();
737 #endif
739 break;
740 case SfxEventHintId::ViewCreated:
742 #if HAVE_FEATURE_SCRIPTING
743 uno::Reference<script::vba::XVBACompatibility> xVBACompat(GetBasicContainer(), uno::UNO_QUERY);
744 if ( !m_xVBAListener.is() && xVBACompat.is() )
746 m_xVBAListener.set(new VBAScriptListener(this));
747 xVBACompat->addVBAScriptListener(m_xVBAListener);
749 #endif
751 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
752 if ( IsDocShared() && !SC_MOD()->IsInSharedDocLoading()
753 && !comphelper::LibreOfficeKit::isActive() )
755 ScAppOptions aAppOptions = SC_MOD()->GetAppOptions();
756 if ( aAppOptions.GetShowSharedDocumentWarning() )
758 MessageWithCheck aWarningBox(ScDocShell::GetActiveDialogParent(),
759 "modules/scalc/ui/sharedwarningdialog.ui", "SharedWarningDialog");
760 aWarningBox.run();
762 bool bChecked = aWarningBox.get_active();
763 if (bChecked)
765 aAppOptions.SetShowSharedDocumentWarning(false);
766 SC_MOD()->SetAppOptions( aAppOptions );
770 #endif
773 uno::Reference< uno::XComponentContext > xContext(
774 comphelper::getProcessComponentContext() );
775 uno::Reference< lang::XMultiServiceFactory > xServiceManager(
776 xContext->getServiceManager(),
777 uno::UNO_QUERY_THROW );
778 uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xServiceManager, uno::UNO_QUERY_THROW );
779 uno::Reference< container::XEnumeration> xEnum = xEnumAccess->createContentEnumeration(
780 "com.sun.star.sheet.SpreadsheetDocumentJob" );
781 if ( xEnum.is() )
783 while ( xEnum->hasMoreElements() )
785 uno::Any aAny = xEnum->nextElement();
786 uno::Reference< lang::XSingleComponentFactory > xFactory;
787 aAny >>= xFactory;
788 if ( xFactory.is() )
790 uno::Reference< task::XJob > xJob( xFactory->createInstanceWithContext( xContext ), uno::UNO_QUERY_THROW );
791 ScViewData* pViewData = GetViewData();
792 SfxViewShell* pViewShell = ( pViewData ? pViewData->GetViewShell() : nullptr );
793 SfxViewFrame* pViewFrame = ( pViewShell ? pViewShell->GetViewFrame() : nullptr );
794 SfxFrame* pFrame = ( pViewFrame ? &pViewFrame->GetFrame() : nullptr );
795 uno::Reference< frame::XController > xController = ( pFrame ? pFrame->GetController() : nullptr );
796 uno::Reference< sheet::XSpreadsheetView > xSpreadsheetView( xController, uno::UNO_QUERY_THROW );
797 uno::Sequence< beans::NamedValue > aArgsForJob { { "SpreadsheetView", uno::Any( xSpreadsheetView ) } };
798 xJob->execute( aArgsForJob );
803 catch ( uno::Exception & )
807 break;
808 case SfxEventHintId::SaveDoc:
810 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
811 if ( IsDocShared() && !SC_MOD()->IsInSharedDocSaving() )
813 bool bSuccess = false;
814 bool bRetry = true;
815 while ( bRetry )
817 bRetry = false;
818 uno::Reference< frame::XModel > xModel;
821 // load shared file
822 xModel.set( LoadSharedDocument(), uno::UNO_SET_THROW );
823 uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY_THROW );
825 // check if shared flag is set in shared file
826 bool bShared = false;
827 ScModelObj* pDocObj = comphelper::getFromUnoTunnel<ScModelObj>( xModel );
828 ScDocShell* pSharedDocShell = ( pDocObj ? dynamic_cast< ScDocShell* >( pDocObj->GetObjectShell() ) : nullptr );
829 if ( pSharedDocShell )
831 bShared = pSharedDocShell->HasSharedXMLFlagSet();
834 // #i87870# check if shared status was disabled and enabled again
835 bool bOwnEntry = false;
836 bool bEntriesNotAccessible = false;
839 ::svt::ShareControlFile aControlFile( GetSharedFileURL() );
840 bOwnEntry = aControlFile.HasOwnEntry();
842 catch ( uno::Exception& )
844 bEntriesNotAccessible = true;
847 if ( bShared && bOwnEntry )
849 uno::Reference< frame::XStorable > xStorable( xModel, uno::UNO_QUERY_THROW );
851 if ( xStorable->isReadonly() )
853 xCloseable->close( true );
855 OUString aUserName( ScResId( STR_UNKNOWN_USER ) );
856 bool bNoLockAccess = false;
859 ::svt::DocumentLockFile aLockFile( GetSharedFileURL() );
860 LockFileEntry aData = aLockFile.GetLockData();
861 if ( !aData[LockFileComponent::OOOUSERNAME].isEmpty() )
863 aUserName = aData[LockFileComponent::OOOUSERNAME];
865 else if ( !aData[LockFileComponent::SYSUSERNAME].isEmpty() )
867 aUserName = aData[LockFileComponent::SYSUSERNAME];
870 catch ( uno::Exception& )
872 bNoLockAccess = true;
875 if ( bNoLockAccess )
877 // TODO/LATER: in future an error regarding impossibility to open file for writing could be shown
878 ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
880 else
882 OUString aMessage( ScResId( STR_FILE_LOCKED_SAVE_LATER ) );
883 aMessage = aMessage.replaceFirst( "%1", aUserName );
885 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
886 VclMessageType::Warning, VclButtonsType::NONE,
887 aMessage));
888 xWarn->add_button(GetStandardText(StandardButtonType::Retry), RET_RETRY);
889 xWarn->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
890 xWarn->set_default_response(RET_RETRY);
891 if (xWarn->run() == RET_RETRY)
893 bRetry = true;
897 else
899 // merge changes from shared file into temp file
900 bool bSaveToShared = false;
901 if ( pSharedDocShell )
903 bSaveToShared = MergeSharedDocument( pSharedDocShell );
906 // close shared file
907 xCloseable->close( true );
909 // TODO: keep file lock on shared file
911 // store to shared file
912 if ( bSaveToShared )
914 bool bChangedViewSettings = false;
915 ScChangeViewSettings* pChangeViewSet = m_pDocument->GetChangeViewSettings();
916 if ( pChangeViewSet && pChangeViewSet->ShowChanges() )
918 pChangeViewSet->SetShowChanges( false );
919 pChangeViewSet->SetShowAccepted( false );
920 m_pDocument->SetChangeViewSettings( *pChangeViewSet );
921 bChangedViewSettings = true;
924 uno::Reference< frame::XStorable > xStor( GetModel(), uno::UNO_QUERY_THROW );
925 // TODO/LATER: More entries from the MediaDescriptor might be interesting for the merge
926 uno::Sequence< beans::PropertyValue > aValues{
927 comphelper::makePropertyValue(
928 "FilterName",
929 GetMedium()->GetFilter()->GetFilterName())
932 const SfxStringItem* pPasswordItem = SfxItemSet::GetItem<SfxStringItem>(GetMedium()->GetItemSet(), SID_PASSWORD, false);
933 if ( pPasswordItem && !pPasswordItem->GetValue().isEmpty() )
935 aValues.realloc( 2 );
936 auto pValues = aValues.getArray();
937 pValues[1].Name = "Password";
938 pValues[1].Value <<= pPasswordItem->GetValue();
940 const SfxUnoAnyItem* pEncryptionItem = SfxItemSet::GetItem<SfxUnoAnyItem>(GetMedium()->GetItemSet(), SID_ENCRYPTIONDATA, false);
941 if (pEncryptionItem)
943 aValues.realloc(aValues.getLength() + 1);
944 auto pValues = aValues.getArray();
945 pValues[aValues.getLength() - 1].Name = "EncryptionData";
946 pValues[aValues.getLength() - 1].Value = pEncryptionItem->GetValue();
949 SC_MOD()->SetInSharedDocSaving( true );
950 xStor->storeToURL( GetSharedFileURL(), aValues );
951 SC_MOD()->SetInSharedDocSaving( false );
953 if ( bChangedViewSettings )
955 pChangeViewSet->SetShowChanges( true );
956 pChangeViewSet->SetShowAccepted( true );
957 m_pDocument->SetChangeViewSettings( *pChangeViewSet );
961 bSuccess = true;
962 GetUndoManager()->Clear();
965 else
967 xCloseable->close( true );
969 if ( bEntriesNotAccessible )
971 // TODO/LATER: in future an error regarding impossibility to write to share control file could be shown
972 ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
974 else
976 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
977 VclMessageType::Warning, VclButtonsType::Ok,
978 ScResId(STR_DOC_NOLONGERSHARED)));
979 xWarn->run();
981 SfxBindings* pBindings = GetViewBindings();
982 if ( pBindings )
984 pBindings->ExecuteSynchron( SID_SAVEASDOC );
989 catch ( uno::Exception& )
991 TOOLS_WARN_EXCEPTION( "sc", "SfxEventHintId::SaveDoc" );
992 SC_MOD()->SetInSharedDocSaving( false );
996 uno::Reference< util::XCloseable > xClose( xModel, uno::UNO_QUERY_THROW );
997 xClose->close( true );
999 catch ( uno::Exception& )
1005 if ( !bSuccess )
1006 SetError(ERRCODE_IO_ABORT); // this error code will produce no error message, but will break the further saving process
1008 #endif
1010 if (m_pSheetSaveData)
1011 m_pSheetSaveData->SetInSupportedSave(true);
1013 break;
1014 case SfxEventHintId::SaveAsDoc:
1016 if ( GetDocument().GetExternalRefManager()->containsUnsavedReferences() )
1018 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
1019 VclMessageType::Warning, VclButtonsType::YesNo,
1020 ScResId(STR_UNSAVED_EXT_REF)));
1021 if (RET_NO == xWarn->run())
1023 SetError(ERRCODE_IO_ABORT); // this error code will produce no error message, but will break the further saving process
1026 [[fallthrough]];
1028 case SfxEventHintId::SaveToDoc:
1029 // #i108978# If no event is sent before saving, there will also be no "...DONE" event,
1030 // and SAVE/SAVEAS can't be distinguished from SAVETO. So stream copying is only enabled
1031 // if there is a SAVE/SAVEAS/SAVETO event first.
1032 if (m_pSheetSaveData)
1033 m_pSheetSaveData->SetInSupportedSave(true);
1034 break;
1035 case SfxEventHintId::SaveDocDone:
1036 case SfxEventHintId::SaveAsDocDone:
1038 // new positions are used after "save" and "save as", but not "save to"
1039 UseSheetSaveEntries(); // use positions from saved file for next saving
1040 [[fallthrough]];
1042 case SfxEventHintId::SaveToDocDone:
1043 // only reset the flag, don't use the new positions
1044 if (m_pSheetSaveData)
1045 m_pSheetSaveData->SetInSupportedSave(false);
1046 break;
1047 default:
1050 break;
1053 else if (rHint.GetId() == SfxHintId::TitleChanged) // Without parameter
1055 m_pDocument->SetName( SfxShell::GetName() );
1056 // RegisterNewTargetNames doesn't exist any longer
1057 SfxGetpApp()->Broadcast(SfxHint( SfxHintId::ScDocNameChanged )); // Navigator
1059 else if (rHint.GetId() == SfxHintId::Deinitializing)
1062 #if HAVE_FEATURE_SCRIPTING
1063 uno::Reference<script::vba::XVBACompatibility> xVBACompat(GetBasicContainer(), uno::UNO_QUERY);
1064 if (m_xVBAListener.is() && xVBACompat.is())
1066 xVBACompat->removeVBAScriptListener(m_xVBAListener);
1068 #endif
1070 if (m_pDocument->IsClipboardSource())
1072 // Notes copied to the clipboard have a raw SdrCaptionObj pointer
1073 // copied from this document, forget it as it references this
1074 // document's drawing layer pages and what not, which otherwise when
1075 // pasting to another document after this document was destructed would
1076 // attempt to access non-existing data. Preserve the text data though.
1077 ScDocument* pClipDoc = ScModule::GetClipDoc();
1078 if (pClipDoc)
1079 pClipDoc->ClosingClipboardSource();
1083 if (rHint.GetId() != SfxHintId::ThisIsAnSfxEventHint)
1084 return;
1086 switch(static_cast<const SfxEventHint&>(rHint).GetEventId())
1088 case SfxEventHintId::CreateDoc:
1090 uno::Any aWorkbook;
1091 aWorkbook <<= mxAutomationWorkbookObject;
1092 uno::Sequence< uno::Any > aArgs{ aWorkbook };
1093 SC_MOD()->CallAutomationApplicationEventSinks( "NewWorkbook", aArgs );
1095 break;
1096 case SfxEventHintId::OpenDoc:
1098 uno::Any aWorkbook;
1099 aWorkbook <<= mxAutomationWorkbookObject;
1100 uno::Sequence< uno::Any > aArgs{ aWorkbook };
1101 SC_MOD()->CallAutomationApplicationEventSinks( "WorkbookOpen", aArgs );
1103 break;
1104 default:
1105 break;
1109 // Load contents for organizer
1110 bool ScDocShell::LoadFrom( SfxMedium& rMedium )
1112 LoadMediumGuard aLoadGuard(m_pDocument.get());
1113 ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
1115 weld::WaitObject aWait( GetActiveDialogParent() );
1117 bool bRet = false;
1119 SetInitialLinkUpdate(&rMedium);
1121 // until loading/saving only the styles in XML is implemented,
1122 // load the whole file
1123 bRet = LoadXML( &rMedium, nullptr );
1124 InitItems();
1126 SfxObjectShell::LoadFrom( rMedium );
1128 return bRet;
1131 static void lcl_parseHtmlFilterOption(const OUString& rOption, LanguageType& rLang, bool& rDateConvert)
1133 OUStringBuffer aBuf;
1134 std::vector< OUString > aTokens;
1135 sal_Int32 n = rOption.getLength();
1136 const sal_Unicode* p = rOption.getStr();
1137 for (sal_Int32 i = 0; i < n; ++i)
1139 const sal_Unicode c = p[i];
1140 if (c == ' ')
1142 if (!aBuf.isEmpty())
1143 aTokens.push_back( aBuf.makeStringAndClear() );
1145 else
1146 aBuf.append(c);
1149 if (!aBuf.isEmpty())
1150 aTokens.push_back( aBuf.makeStringAndClear() );
1152 rLang = LanguageType( 0 );
1153 rDateConvert = false;
1155 if (!aTokens.empty())
1156 rLang = static_cast<LanguageType>(aTokens[0].toInt32());
1157 if (aTokens.size() > 1)
1158 rDateConvert = static_cast<bool>(aTokens[1].toInt32());
1161 bool ScDocShell::ConvertFrom( SfxMedium& rMedium )
1163 LoadMediumGuard aLoadGuard(m_pDocument.get());
1165 bool bRet = false; // sal_False means user quit!
1166 // On error: Set error at stream
1168 ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
1170 GetUndoManager()->Clear();
1172 // Set optimal col width after import?
1173 bool bSetColWidths = false;
1174 bool bSetSimpleTextColWidths = false;
1175 std::map<SCCOL, ScColWidthParam> aColWidthParam;
1176 ScRange aColWidthRange;
1177 // Set optimal row height after import?
1178 bool bSetRowHeights = false;
1180 vector<ScDocRowHeightUpdater::TabRanges> aRecalcRowRangesArray;
1182 // All filters need the complete file in one piece (not asynchronously)
1183 // So make sure that we transfer the whole file with CreateFileStream
1184 rMedium.GetPhysicalName(); //! Call CreateFileStream directly, if available
1186 SetInitialLinkUpdate(&rMedium);
1188 std::shared_ptr<const SfxFilter> pFilter = rMedium.GetFilter();
1189 if (pFilter)
1191 OUString aFltName = pFilter->GetFilterName();
1193 bool bCalc3 = aFltName == "StarCalc 3.0";
1194 bool bCalc4 = aFltName == "StarCalc 4.0";
1195 if (!bCalc3 && !bCalc4)
1196 m_pDocument->SetInsertingFromOtherDoc( true );
1198 if (aFltName == pFilterXML)
1199 bRet = LoadXML( &rMedium, nullptr );
1200 else if (aFltName == pFilterLotus)
1202 OUString sItStr;
1203 SfxItemSet* pSet = rMedium.GetItemSet();
1204 const SfxStringItem* pOptionsItem;
1205 if ( pSet &&
1206 (pOptionsItem = pSet->GetItemIfSet( SID_FILE_FILTEROPTIONS, true )) )
1208 sItStr = pOptionsItem->GetValue();
1211 if (sItStr.isEmpty())
1213 // default for lotus import (from API without options):
1214 // IBM_437 encoding
1215 sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_437 );
1218 ErrCode eError = ScFormatFilter::Get().ScImportLotus123( rMedium, *m_pDocument,
1219 ScGlobal::GetCharsetValue(sItStr));
1220 if (eError != ERRCODE_NONE)
1222 if (!GetError())
1223 SetError(eError);
1225 if( eError.IsWarning() )
1226 bRet = true;
1228 else
1229 bRet = true;
1230 bSetColWidths = true;
1231 bSetRowHeights = true;
1233 else if ( aFltName == pFilterExcel4 || aFltName == pFilterExcel5 ||
1234 aFltName == pFilterExcel95 || aFltName == pFilterExcel97 ||
1235 aFltName == pFilterEx4Temp || aFltName == pFilterEx5Temp ||
1236 aFltName == pFilterEx95Temp || aFltName == pFilterEx97Temp )
1238 EXCIMPFORMAT eFormat = EIF_AUTO;
1239 if ( aFltName == pFilterExcel4 || aFltName == pFilterEx4Temp )
1240 eFormat = EIF_BIFF_LE4;
1241 else if ( aFltName == pFilterExcel5 || aFltName == pFilterExcel95 ||
1242 aFltName == pFilterEx5Temp || aFltName == pFilterEx95Temp )
1243 eFormat = EIF_BIFF5;
1244 else if ( aFltName == pFilterExcel97 || aFltName == pFilterEx97Temp )
1245 eFormat = EIF_BIFF8;
1247 MakeDrawLayer(); //! In the filter
1248 CalcOutputFactor(); // prepare update of row height
1249 ErrCode eError = ScFormatFilter::Get().ScImportExcel( rMedium, m_pDocument.get(), eFormat );
1250 m_pDocument->UpdateFontCharSet();
1251 if ( m_pDocument->IsChartListenerCollectionNeedsUpdate() )
1252 m_pDocument->UpdateChartListenerCollection(); //! For all imports?
1254 // all graphics objects must have names
1255 m_pDocument->EnsureGraphicNames();
1257 if (eError != ERRCODE_NONE)
1259 if (!GetError())
1260 SetError(eError);
1261 if( eError.IsWarning() )
1262 bRet = true;
1264 else
1265 bRet = true;
1267 else if (aFltName == "Gnumeric Spreadsheet")
1269 ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
1270 if (!pOrcus)
1271 return false;
1273 bRet = pOrcus->importGnumeric(*m_pDocument, rMedium);
1275 else if (aFltName == "MS Excel 2003 XML Orcus")
1277 ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
1278 if (!pOrcus)
1279 return false;
1281 bRet = pOrcus->importExcel2003XML(*m_pDocument, rMedium);
1283 else if (aFltName == SC_TEXT_CSV_FILTER_NAME)
1285 SfxItemSet* pSet = rMedium.GetItemSet();
1286 const SfxStringItem* pOptionsItem;
1287 ScAsciiOptions aOptions;
1288 bool bOptInit = false;
1290 if ( pSet &&
1291 (pOptionsItem = pSet->GetItemIfSet( SID_FILE_FILTEROPTIONS )) )
1293 aOptions.ReadFromString( pOptionsItem->GetValue() );
1294 bOptInit = true;
1297 if ( !bOptInit )
1299 // default for ascii import (from API without options):
1300 // UTF-8 encoding, comma, double quotes
1302 aOptions.SetCharSet(RTL_TEXTENCODING_UTF8);
1303 aOptions.SetFieldSeps( OUString(',') );
1304 aOptions.SetTextSep( '"' );
1307 ErrCode eError = ERRCODE_NONE;
1308 bool bOverflowRow, bOverflowCol, bOverflowCell;
1309 bOverflowRow = bOverflowCol = bOverflowCell = false;
1311 if( ! rMedium.IsStorage() )
1313 ScImportExport aImpEx( *m_pDocument );
1314 aImpEx.SetExtOptions( aOptions );
1316 SvStream* pInStream = rMedium.GetInStream();
1317 if (pInStream)
1319 pInStream->SetStreamCharSet( aOptions.GetCharSet() );
1320 pInStream->Seek( 0 );
1321 bRet = aImpEx.ImportStream( *pInStream, rMedium.GetBaseURL(), SotClipboardFormatId::STRING );
1322 eError = bRet ? ERRCODE_NONE : SCERR_IMPORT_CONNECT;
1323 m_pDocument->StartAllListeners();
1324 sc::SetFormulaDirtyContext aCxt;
1325 m_pDocument->SetAllFormulasDirty(aCxt);
1327 // for mobile case, we use a copy of the original document and give it a temporary name before editing
1328 // Therefore, the sheet name becomes ugly, long and nonsensical.
1329 #if !(defined ANDROID)
1330 // The same resulting name has to be handled in
1331 // ScExternalRefCache::initializeDoc() and related, hence
1332 // pass 'true' for RenameTab()'s bExternalDocument for a
1333 // composed name so ValidTabName() will not be checked,
1334 // which could veto the rename in case it contained
1335 // characters that Excel does not handle. If we wanted to
1336 // change that then it needed to be handled in all
1337 // corresponding places of the external references
1338 // manager/cache. Likely then we'd also need a method to
1339 // compose a name excluding such characters.
1340 m_pDocument->RenameTab( 0, INetURLObject( rMedium.GetName()).GetBase(), true/*bExternalDocument*/);
1341 #endif
1342 bOverflowRow = aImpEx.IsOverflowRow();
1343 bOverflowCol = aImpEx.IsOverflowCol();
1344 bOverflowCell = aImpEx.IsOverflowCell();
1346 else
1348 OSL_FAIL( "No Stream" );
1352 if (eError != ERRCODE_NONE)
1354 if (!GetError())
1355 SetError(eError);
1356 if( eError.IsWarning() )
1357 bRet = true;
1359 else if (!GetError() && (bOverflowRow || bOverflowCol || bOverflowCell))
1361 // precedence: row, column, cell
1362 ErrCode nWarn = (bOverflowRow ? SCWARN_IMPORT_ROW_OVERFLOW :
1363 (bOverflowCol ? SCWARN_IMPORT_COLUMN_OVERFLOW :
1364 SCWARN_IMPORT_CELL_OVERFLOW));
1365 SetError(nWarn);
1367 bSetColWidths = true;
1368 bSetSimpleTextColWidths = true;
1370 else if (aFltName == pFilterDBase)
1372 OUString sItStr;
1373 SfxItemSet* pSet = rMedium.GetItemSet();
1374 const SfxStringItem* pOptionsItem;
1375 if ( pSet &&
1376 (pOptionsItem = pSet->GetItemIfSet( SID_FILE_FILTEROPTIONS )) )
1378 sItStr = pOptionsItem->GetValue();
1381 if (sItStr.isEmpty())
1383 // default for dBase import (from API without options):
1384 // IBM_850 encoding
1386 sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_850 );
1389 ScDocRowHeightUpdater::TabRanges aRecalcRanges(0, m_pDocument->MaxRow());
1390 ErrCode eError = DBaseImport( rMedium.GetPhysicalName(),
1391 ScGlobal::GetCharsetValue(sItStr), aColWidthParam, aRecalcRanges.maRanges );
1392 aRecalcRowRangesArray.push_back(aRecalcRanges);
1394 if (eError != ERRCODE_NONE)
1396 if (!GetError())
1397 SetError(eError);
1398 if( eError.IsWarning() )
1399 bRet = true;
1401 else
1402 bRet = true;
1404 aColWidthRange.aStart.SetRow( 1 ); // Except for the column header
1405 bSetColWidths = true;
1406 bSetSimpleTextColWidths = true;
1408 else if (aFltName == pFilterDif)
1410 SvStream* pStream = rMedium.GetInStream();
1411 if (pStream)
1413 ErrCode eError;
1414 OUString sItStr;
1415 SfxItemSet* pSet = rMedium.GetItemSet();
1416 const SfxStringItem* pOptionsItem;
1417 if ( pSet &&
1418 (pOptionsItem = pSet->GetItemIfSet( SID_FILE_FILTEROPTIONS )) )
1420 sItStr = pOptionsItem->GetValue();
1423 if (sItStr.isEmpty())
1425 // default for DIF import (from API without options):
1426 // ISO8859-1/MS_1252 encoding
1428 sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_MS_1252 );
1431 eError = ScFormatFilter::Get().ScImportDif( *pStream, m_pDocument.get(), ScAddress(0,0,0),
1432 ScGlobal::GetCharsetValue(sItStr));
1433 if (eError != ERRCODE_NONE)
1435 if (!GetError())
1436 SetError(eError);
1438 if( eError.IsWarning() )
1439 bRet = true;
1441 else
1442 bRet = true;
1444 bSetColWidths = true;
1445 bSetSimpleTextColWidths = true;
1446 bSetRowHeights = true;
1448 else if (aFltName == pFilterSylk)
1450 ErrCode eError = SCERR_IMPORT_UNKNOWN;
1451 bool bOverflowRow, bOverflowCol, bOverflowCell;
1452 bOverflowRow = bOverflowCol = bOverflowCell = false;
1453 if( !rMedium.IsStorage() )
1455 ScImportExport aImpEx( *m_pDocument );
1457 SvStream* pInStream = rMedium.GetInStream();
1458 if (pInStream)
1460 pInStream->Seek( 0 );
1461 bRet = aImpEx.ImportStream( *pInStream, rMedium.GetBaseURL(), SotClipboardFormatId::SYLK );
1462 eError = bRet ? ERRCODE_NONE : SCERR_IMPORT_UNKNOWN;
1463 m_pDocument->StartAllListeners();
1464 sc::SetFormulaDirtyContext aCxt;
1465 m_pDocument->SetAllFormulasDirty(aCxt);
1467 bOverflowRow = aImpEx.IsOverflowRow();
1468 bOverflowCol = aImpEx.IsOverflowCol();
1469 bOverflowCell = aImpEx.IsOverflowCell();
1471 else
1473 OSL_FAIL( "No Stream" );
1477 if (eError != ERRCODE_NONE)
1479 if (!GetError())
1480 SetError(eError);
1481 if( eError.IsWarning() )
1482 bRet = true;
1484 else if (!GetError() && (bOverflowRow || bOverflowCol || bOverflowCell))
1486 // precedence: row, column, cell
1487 ErrCode nWarn = (bOverflowRow ? SCWARN_IMPORT_ROW_OVERFLOW :
1488 (bOverflowCol ? SCWARN_IMPORT_COLUMN_OVERFLOW :
1489 SCWARN_IMPORT_CELL_OVERFLOW));
1490 SetError(nWarn);
1492 bSetColWidths = true;
1493 bSetSimpleTextColWidths = true;
1494 bSetRowHeights = true;
1496 else if (aFltName == pFilterQPro6)
1498 ErrCode eError = ScFormatFilter::Get().ScImportQuattroPro(rMedium.GetInStream(), *m_pDocument);
1499 if (eError != ERRCODE_NONE)
1501 if (!GetError())
1502 SetError(eError);
1503 if( eError.IsWarning() )
1504 bRet = true;
1506 else
1507 bRet = true;
1508 // TODO: Filter should set column widths. Not doing it here, it may
1509 // result in very narrow or wide columns, depending on content.
1510 // Setting row heights makes cells with font size attribution or
1511 // wrapping enabled look nicer...
1512 bSetRowHeights = true;
1514 else if (aFltName == pFilterRtf)
1516 ErrCode eError = SCERR_IMPORT_UNKNOWN;
1517 if( !rMedium.IsStorage() )
1519 SvStream* pInStream = rMedium.GetInStream();
1520 if (pInStream)
1522 pInStream->Seek( 0 );
1523 ScRange aRange;
1524 eError = ScFormatFilter::Get().ScImportRTF( *pInStream, rMedium.GetBaseURL(), m_pDocument.get(), aRange );
1525 if (eError != ERRCODE_NONE)
1527 if (!GetError())
1528 SetError(eError);
1530 if( eError.IsWarning() )
1531 bRet = true;
1533 else
1534 bRet = true;
1535 m_pDocument->StartAllListeners();
1536 sc::SetFormulaDirtyContext aCxt;
1537 m_pDocument->SetAllFormulasDirty(aCxt);
1538 bSetColWidths = true;
1539 bSetRowHeights = true;
1541 else
1543 OSL_FAIL( "No Stream" );
1547 if (eError != ERRCODE_NONE)
1549 if (!GetError())
1550 SetError(eError);
1551 if( eError.IsWarning() )
1552 bRet = true;
1555 else if (aFltName == pFilterHtml || aFltName == pFilterHtmlWebQ)
1557 ErrCode eError = SCERR_IMPORT_UNKNOWN;
1558 bool bWebQuery = aFltName == pFilterHtmlWebQ;
1559 if( !rMedium.IsStorage() )
1561 SvStream* pInStream = rMedium.GetInStream();
1562 if (pInStream)
1564 LanguageType eLang = LANGUAGE_SYSTEM;
1565 bool bDateConvert = false;
1566 SfxItemSet* pSet = rMedium.GetItemSet();
1567 const SfxStringItem* pOptionsItem;
1568 if ( pSet &&
1569 (pOptionsItem = pSet->GetItemIfSet( SID_FILE_FILTEROPTIONS )) )
1571 OUString aFilterOption = pOptionsItem->GetValue();
1572 lcl_parseHtmlFilterOption(aFilterOption, eLang, bDateConvert);
1575 pInStream->Seek( 0 );
1576 ScRange aRange;
1577 // HTML does its own ColWidth/RowHeight
1578 CalcOutputFactor();
1579 SvNumberFormatter aNumFormatter( comphelper::getProcessComponentContext(), eLang);
1580 eError = ScFormatFilter::Get().ScImportHTML( *pInStream, rMedium.GetBaseURL(), m_pDocument.get(), aRange,
1581 GetOutputFactor(), !bWebQuery, &aNumFormatter, bDateConvert );
1582 if (eError != ERRCODE_NONE)
1584 if (!GetError())
1585 SetError(eError);
1587 if( eError.IsWarning() )
1588 bRet = true;
1590 else
1591 bRet = true;
1592 m_pDocument->StartAllListeners();
1594 sc::SetFormulaDirtyContext aCxt;
1595 m_pDocument->SetAllFormulasDirty(aCxt);
1597 else
1599 OSL_FAIL( "No Stream" );
1603 if (eError != ERRCODE_NONE)
1605 if (!GetError())
1606 SetError(eError);
1607 if( eError.IsWarning() )
1608 bRet = true;
1611 else
1613 if (!GetError())
1615 SAL_WARN("sc.filter", "No match for filter '" << aFltName << "' in ConvertFrom");
1616 SetError(SCERR_IMPORT_NI);
1620 if (!bCalc3)
1621 m_pDocument->SetInsertingFromOtherDoc( false );
1623 else
1625 OSL_FAIL("No Filter in ConvertFrom");
1628 InitItems();
1629 CalcOutputFactor();
1630 if ( bRet && (bSetColWidths || bSetRowHeights) )
1631 { // Adjust column width/row height; base 100% zoom
1632 Fraction aZoom( 1, 1 );
1633 double nPPTX = ScGlobal::nScreenPPTX * static_cast<double>(aZoom) / GetOutputFactor(); // Factor is printer display ratio
1634 double nPPTY = ScGlobal::nScreenPPTY * static_cast<double>(aZoom);
1635 ScopedVclPtrInstance< VirtualDevice > pVirtDev;
1636 // all sheets (for Excel import)
1637 SCTAB nTabCount = m_pDocument->GetTableCount();
1638 for (SCTAB nTab=0; nTab<nTabCount; nTab++)
1640 SCCOL nEndCol;
1641 SCROW nEndRow;
1642 m_pDocument->GetCellArea( nTab, nEndCol, nEndRow );
1643 aColWidthRange.aEnd.SetCol( nEndCol );
1644 aColWidthRange.aEnd.SetRow( nEndRow );
1645 ScMarkData aMark(m_pDocument->GetSheetLimits());
1646 aMark.SetMarkArea( aColWidthRange );
1647 aMark.MarkToMulti();
1649 // Order is important: First width, then height
1650 if ( bSetColWidths )
1652 for ( SCCOL nCol=0; nCol <= nEndCol; nCol++ )
1654 if (!bSetSimpleTextColWidths)
1655 aColWidthParam[nCol].mbSimpleText = false;
1657 sal_uInt16 nWidth = m_pDocument->GetOptimalColWidth(
1658 nCol, nTab, pVirtDev, nPPTX, nPPTY, aZoom, aZoom, false, &aMark,
1659 &aColWidthParam[nCol] );
1660 m_pDocument->SetColWidth( nCol, nTab,
1661 nWidth + static_cast<sal_uInt16>(ScGlobal::nLastColWidthExtra) );
1666 if (bSetRowHeights)
1668 // Update all rows in all tables.
1669 ScSizeDeviceProvider aProv(this);
1670 ScDocRowHeightUpdater aUpdater(*m_pDocument, aProv.GetDevice(), aProv.GetPPTX(), aProv.GetPPTY(), nullptr);
1671 aUpdater.update();
1673 else if (!aRecalcRowRangesArray.empty())
1675 // Update only specified row ranges for better performance.
1676 ScSizeDeviceProvider aProv(this);
1677 ScDocRowHeightUpdater aUpdater(*m_pDocument, aProv.GetDevice(), aProv.GetPPTX(), aProv.GetPPTY(), &aRecalcRowRangesArray);
1678 aUpdater.update();
1681 FinishedLoading();
1683 // invalidate eventually temporary table areas
1684 if ( bRet )
1685 m_pDocument->InvalidateTableArea();
1687 m_bIsEmpty = false;
1689 return bRet;
1692 bool ScDocShell::LoadExternal( SfxMedium& rMed )
1694 std::shared_ptr<const SfxFilter> pFilter = rMed.GetFilter();
1695 if (!pFilter)
1696 return false;
1698 if (pFilter->GetProviderName() == "orcus")
1700 ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
1701 if (!pOrcus)
1702 return false;
1704 const OUString& rFilterName = pFilter->GetName();
1705 if (rFilterName == "gnumeric")
1707 if (!pOrcus->importGnumeric(*m_pDocument, rMed))
1708 return false;
1710 else if (rFilterName == "csv")
1712 if (!pOrcus->importCSV(*m_pDocument, rMed))
1713 return false;
1715 else if (rFilterName == "xlsx")
1717 if (!pOrcus->importXLSX(*m_pDocument, rMed))
1718 return false;
1720 else if (rFilterName == "ods")
1722 if (!pOrcus->importODS(*m_pDocument, rMed))
1723 return false;
1726 FinishedLoading();
1727 return true;
1730 return false;
1733 ScDocShell::PrepareSaveGuard::PrepareSaveGuard( ScDocShell& rDocShell )
1734 : mrDocShell( rDocShell)
1736 // DoEnterHandler not here (because of AutoSave), is in ExecuteSave.
1738 ScChartListenerCollection* pCharts = mrDocShell.m_pDocument->GetChartListenerCollection();
1739 if (pCharts)
1740 pCharts->UpdateDirtyCharts(); // Charts to be updated.
1741 mrDocShell.m_pDocument->StopTemporaryChartLock();
1742 if (mrDocShell.m_pAutoStyleList)
1743 mrDocShell.m_pAutoStyleList->ExecuteAllNow(); // Execute template timeouts now.
1744 if (mrDocShell.m_pDocument->HasExternalRefManager())
1746 ScExternalRefManager* pRefMgr = mrDocShell.m_pDocument->GetExternalRefManager();
1747 if (pRefMgr && pRefMgr->hasExternalData())
1749 pRefMgr->setAllCacheTableReferencedStati( false);
1750 mrDocShell.m_pDocument->MarkUsedExternalReferences(); // Mark tables of external references to be written.
1753 if (mrDocShell.GetCreateMode()== SfxObjectCreateMode::STANDARD)
1754 mrDocShell.SfxObjectShell::SetVisArea( tools::Rectangle() ); // "Normally" worked on => no VisArea.
1757 ScDocShell::PrepareSaveGuard::~PrepareSaveGuard() COVERITY_NOEXCEPT_FALSE
1759 if (mrDocShell.m_pDocument->HasExternalRefManager())
1761 ScExternalRefManager* pRefMgr = mrDocShell.m_pDocument->GetExternalRefManager();
1762 if (pRefMgr && pRefMgr->hasExternalData())
1764 // Prevent accidental data loss due to lack of knowledge.
1765 pRefMgr->setAllCacheTableReferencedStati( true);
1770 bool ScDocShell::Save()
1772 ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
1774 PrepareSaveGuard aPrepareGuard( *this);
1776 if (const auto pFrame1 = SfxViewFrame::GetFirst(this))
1778 if (auto pSysWin = pFrame1->GetWindow().GetSystemWindow())
1780 pSysWin->SetAccessibleName(OUString());
1783 // wait cursor is handled with progress bar
1784 bool bRet = SfxObjectShell::Save();
1785 if( bRet )
1786 bRet = SaveXML( GetMedium(), nullptr );
1787 return bRet;
1790 namespace {
1793 * Remove the file name from the full path, to keep only the directory path.
1795 void popFileName(OUString& rPath)
1797 if (!rPath.isEmpty())
1799 INetURLObject aURLObj(rPath);
1800 aURLObj.removeSegment();
1801 rPath = aURLObj.GetMainURL(INetURLObject::DecodeMechanism::NONE);
1807 void ScDocShell::TerminateEditing()
1809 // Commit any cell changes before saving.
1810 SC_MOD()->InputEnterHandler();
1813 bool ScDocShell::SaveAs( SfxMedium& rMedium )
1815 OUString aCurPath; // empty for new document that hasn't been saved.
1816 const SfxMedium* pCurMedium = GetMedium();
1817 if (pCurMedium)
1819 aCurPath = pCurMedium->GetName();
1820 popFileName(aCurPath);
1823 if (!aCurPath.isEmpty())
1825 // current document has a path -> not a brand-new document.
1826 OUString aNewPath = rMedium.GetName();
1827 popFileName(aNewPath);
1828 OUString aRel = URIHelper::simpleNormalizedMakeRelative(aCurPath, aNewPath);
1829 if (!aRel.isEmpty())
1831 // Directory path will change before and after the save.
1832 m_pDocument->InvalidateStreamOnSave();
1836 ScTabViewShell* pViewShell = GetBestViewShell();
1837 bool bNeedsRehash = ScPassHashHelper::needsPassHashRegen(*m_pDocument, PASSHASH_SHA1);
1838 if (bNeedsRehash)
1839 // legacy xls hash double-hashed by SHA1 is also supported.
1840 bNeedsRehash = ScPassHashHelper::needsPassHashRegen(*m_pDocument, PASSHASH_XL, PASSHASH_SHA1);
1841 if (bNeedsRehash)
1842 { // SHA256 explicitly supported in ODF 1.2, implicitly in ODF 1.1
1843 bNeedsRehash = ScPassHashHelper::needsPassHashRegen(*m_pDocument, PASSHASH_SHA256);
1846 // skip saving recovery file instead of showing re-type password dialog window
1847 if ( bNeedsRehash && rMedium.GetFilter()->GetFilterName() == "calc8" &&
1848 // it seems, utl::MediaDescriptor::PROP_AUTOSAVEEVENT is true at Save As, too,
1849 // so check the backup path
1850 rMedium.GetName().startsWith( SvtPathOptions().GetBackupPath() ) )
1852 SAL_WARN("sc.filter", "Should re-type password for own format, won't export recovery file");
1853 rMedium.SetError(ERRCODE_SFX_WRONGPASSWORD);
1854 return false;
1857 if (pViewShell && bNeedsRehash)
1859 if (!pViewShell->ExecuteRetypePassDlg(PASSHASH_SHA1))
1860 // password re-type cancelled. Don't save the document.
1861 return false;
1864 ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
1866 PrepareSaveGuard aPrepareGuard( *this);
1868 // wait cursor is handled with progress bar
1869 bool bRet = SfxObjectShell::SaveAs( rMedium );
1870 if (bRet)
1871 bRet = SaveXML( &rMedium, nullptr );
1873 return bRet;
1876 namespace {
1878 // Xcl-like column width measured in characters of standard font.
1879 sal_Int32 lcl_ScDocShell_GetColWidthInChars( sal_uInt16 nWidth )
1881 double f = nWidth;
1882 f *= 1328.0 / 25.0;
1883 f += 90.0;
1884 f *= 1.0 / 23.0;
1885 f /= 256.0;
1887 return sal_Int32( f );
1890 void lcl_ScDocShell_GetFixedWidthString( OUString& rStr, const ScDocument& rDoc,
1891 SCTAB nTab, SCCOL nCol, bool bValue, SvxCellHorJustify eHorJust )
1893 OUString aString = rStr;
1894 sal_Int32 nLen = lcl_ScDocShell_GetColWidthInChars(
1895 rDoc.GetColWidth( nCol, nTab ) );
1896 //If the text won't fit in the column
1897 if ( nLen < aString.getLength() )
1899 OUStringBuffer aReplacement;
1900 if (bValue)
1901 aReplacement.append("###");
1902 else
1903 aReplacement.append(aString);
1904 //truncate to the number of characters that should fit, even in the
1905 //bValue case nLen might be < len ###
1906 aString = comphelper::string::truncateToLength(aReplacement, nLen).makeStringAndClear();
1908 if ( nLen > aString.getLength() )
1910 if ( bValue && eHorJust == SvxCellHorJustify::Standard )
1911 eHorJust = SvxCellHorJustify::Right;
1912 OUStringBuffer aTmp(nLen);
1913 switch ( eHorJust )
1915 case SvxCellHorJustify::Right:
1916 comphelper::string::padToLength( aTmp, nLen - aString.getLength(), ' ' );
1917 aString = aTmp.append(aString);
1918 break;
1919 case SvxCellHorJustify::Center:
1920 comphelper::string::padToLength( aTmp, (nLen - aString.getLength()) / 2, ' ' );
1921 [[fallthrough]];
1922 default:
1923 aTmp.append(aString);
1924 comphelper::string::padToLength( aTmp, nLen, ' ' );
1926 aString = aTmp.makeStringAndClear();
1928 rStr = aString;
1931 void lcl_ScDocShell_WriteEmptyFixedWidthString( SvStream& rStream,
1932 const ScDocument& rDoc, SCTAB nTab, SCCOL nCol )
1934 OUString aString;
1935 lcl_ScDocShell_GetFixedWidthString( aString, rDoc, nTab, nCol, false,
1936 SvxCellHorJustify::Standard );
1937 rStream.WriteUnicodeOrByteText( aString );
1940 template<typename StrT, typename SepCharT>
1941 sal_Int32 getTextSepPos(
1942 const StrT& rStr, const ScImportOptions& rAsciiOpt, const SepCharT& rTextSep, const SepCharT& rFieldSep, bool& rNeedQuotes)
1944 // #i116636# quotes are needed if text delimiter (quote), field delimiter,
1945 // or LF or CR is in the cell text.
1946 sal_Int32 nPos = rStr.indexOf(rTextSep);
1947 rNeedQuotes = rAsciiOpt.bQuoteAllText || (nPos >= 0) ||
1948 (rStr.indexOf(rFieldSep) >= 0) ||
1949 (rStr.indexOf('\n') >= 0) ||
1950 (rStr.indexOf('\r') >= 0);
1951 return nPos;
1956 void ScDocShell::AsciiSave( SvStream& rStream, const ScImportOptions& rAsciiOpt, SCTAB nTab )
1958 sal_Unicode cDelim = rAsciiOpt.nFieldSepCode;
1959 sal_Unicode cStrDelim = rAsciiOpt.nTextSepCode;
1960 rtl_TextEncoding eCharSet = rAsciiOpt.eCharSet;
1961 bool bFixedWidth = rAsciiOpt.bFixedWidth;
1962 bool bSaveNumberAsSuch = rAsciiOpt.bSaveNumberAsSuch;
1963 bool bSaveAsShown = rAsciiOpt.bSaveAsShown;
1964 bool bShowFormulas = rAsciiOpt.bSaveFormulas;
1966 rtl_TextEncoding eOldCharSet = rStream.GetStreamCharSet();
1967 rStream.SetStreamCharSet( eCharSet );
1968 SvStreamEndian nOldNumberFormatInt = rStream.GetEndian();
1969 OString aStrDelimEncoded; // only used if not Unicode
1970 OUString aStrDelimDecoded; // only used if context encoding
1971 OString aDelimEncoded;
1972 OUString aDelimDecoded;
1973 bool bContextOrNotAsciiEncoding;
1974 if ( eCharSet == RTL_TEXTENCODING_UNICODE )
1976 rStream.StartWritingUnicodeText();
1977 bContextOrNotAsciiEncoding = false;
1979 else
1981 aStrDelimEncoded = OString(&cStrDelim, 1, eCharSet);
1982 aDelimEncoded = OString(&cDelim, 1, eCharSet);
1983 rtl_TextEncodingInfo aInfo;
1984 aInfo.StructSize = sizeof(aInfo);
1985 if ( rtl_getTextEncodingInfo( eCharSet, &aInfo ) )
1987 bContextOrNotAsciiEncoding =
1988 (((aInfo.Flags & RTL_TEXTENCODING_INFO_CONTEXT) != 0) ||
1989 ((aInfo.Flags & RTL_TEXTENCODING_INFO_ASCII) == 0));
1990 if ( bContextOrNotAsciiEncoding )
1992 aStrDelimDecoded = OStringToOUString(aStrDelimEncoded, eCharSet);
1993 aDelimDecoded = OStringToOUString(aDelimEncoded, eCharSet);
1996 else
1997 bContextOrNotAsciiEncoding = false;
2000 SCCOL nStartCol = 0;
2001 SCROW nStartRow = 0;
2002 SCCOL nEndCol;
2003 SCROW nEndRow;
2004 m_pDocument->GetCellArea( nTab, nEndCol, nEndRow );
2006 ScProgress aProgress( this, ScResId( STR_SAVE_DOC ), nEndRow, true );
2008 OUString aString;
2010 bool bTabProtect = m_pDocument->IsTabProtected( nTab );
2012 SCCOL nCol;
2013 SCROW nRow;
2015 // Treat the top left cell separator "sep=" special.
2016 // Here nStartRow == 0 && nStartCol == 0
2017 if (!bFixedWidth && cDelim != 0)
2019 // First row iterator.
2020 ScHorizontalCellIterator aIter( *m_pDocument, nTab, nStartCol, nStartRow, nEndCol, nStartRow);
2021 ScRefCellValue* pCell;
2022 // Must be first column and all following cells on this row must be
2023 // empty to fiddle with "sep=".
2024 if ((pCell = aIter.GetNext( nCol, nRow)) != nullptr && nCol == nStartCol && !aIter.GetNext( nCol, nRow))
2026 if (pCell->getType() == CELLTYPE_STRING)
2028 aString = pCell->getSharedString()->getString();
2029 if (aString.getLength() <= 5 && aString.startsWithIgnoreAsciiCase("sep="))
2031 // Cell content is /^sep=.?$/ so write current separator.
2032 // Force the quote character to '"' regardless what is set
2033 // for export because that is the only one recognized on
2034 // import.
2035 aString = "sep=" + OUStringChar(cDelim);
2036 if (cStrDelim != 0)
2037 rStream.WriteUniOrByteChar( '"', eCharSet);
2038 if (eCharSet == RTL_TEXTENCODING_UNICODE)
2040 write_uInt16s_FromOUString( rStream, aString);
2042 else
2044 OString aStrEnc = OUStringToOString( aString, eCharSet);
2045 // write byte encoded
2046 rStream.WriteBytes( aStrEnc.getStr(), aStrEnc.getLength());
2048 if (cStrDelim != 0)
2049 rStream.WriteUniOrByteChar( '"', eCharSet);
2050 endlub( rStream );
2051 ++nStartRow;
2057 SCCOL nNextCol = nStartCol;
2058 SCROW nNextRow = nStartRow;
2059 SCCOL nEmptyCol;
2060 SCROW nEmptyRow;
2061 SvNumberFormatter& rFormatter = *m_pDocument->GetFormatTable();
2063 ScHorizontalCellIterator aIter( *m_pDocument, nTab, nStartCol, nStartRow,
2064 nEndCol, nEndRow );
2065 ScRefCellValue* pCell;
2066 while ( ( pCell = aIter.GetNext( nCol, nRow ) ) != nullptr )
2068 bool bProgress = false; // only upon line change
2069 if ( nNextRow < nRow )
2070 { // empty rows or/and empty columns up to end of row
2071 bProgress = true;
2072 for ( nEmptyCol = nNextCol; nEmptyCol < nEndCol; nEmptyCol++ )
2073 { // remaining columns of last row
2074 if ( bFixedWidth )
2075 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2076 *m_pDocument, nTab, nEmptyCol );
2077 else if ( cDelim != 0 )
2078 rStream.WriteUniOrByteChar( cDelim );
2080 endlub( rStream );
2081 nNextRow++;
2082 for ( nEmptyRow = nNextRow; nEmptyRow < nRow; nEmptyRow++ )
2083 { // completely empty rows
2084 for ( nEmptyCol = nStartCol; nEmptyCol < nEndCol; nEmptyCol++ )
2086 if ( bFixedWidth )
2087 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2088 *m_pDocument, nTab, nEmptyCol );
2089 else if ( cDelim != 0 )
2090 rStream.WriteUniOrByteChar( cDelim );
2092 endlub( rStream );
2094 for ( nEmptyCol = nStartCol; nEmptyCol < nCol; nEmptyCol++ )
2095 { // empty columns at beginning of row
2096 if ( bFixedWidth )
2097 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2098 *m_pDocument, nTab, nEmptyCol );
2099 else if ( cDelim != 0 )
2100 rStream.WriteUniOrByteChar( cDelim );
2102 nNextRow = nRow;
2104 else if ( nNextCol < nCol )
2105 { // empty columns in same row
2106 for ( nEmptyCol = nNextCol; nEmptyCol < nCol; nEmptyCol++ )
2107 { // columns in between
2108 if ( bFixedWidth )
2109 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2110 *m_pDocument, nTab, nEmptyCol );
2111 else if ( cDelim != 0 )
2112 rStream.WriteUniOrByteChar( cDelim );
2115 if ( nCol == nEndCol )
2117 bProgress = true;
2118 nNextCol = nStartCol;
2119 nNextRow = nRow + 1;
2121 else
2122 nNextCol = nCol + 1;
2124 CellType eType = pCell->getType();
2125 ScAddress aPos(nCol, nRow, nTab);
2126 if ( bTabProtect )
2128 const ScProtectionAttr* pProtAttr =
2129 m_pDocument->GetAttr( nCol, nRow, nTab, ATTR_PROTECTION );
2130 if ( pProtAttr->GetHideCell() ||
2131 ( eType == CELLTYPE_FORMULA && bShowFormulas &&
2132 pProtAttr->GetHideFormula() ) )
2133 eType = CELLTYPE_NONE; // hide
2135 bool bForceQuotes = false;
2136 bool bString;
2137 switch ( eType )
2139 case CELLTYPE_NONE:
2140 aString.clear();
2141 bString = false;
2142 break;
2143 case CELLTYPE_FORMULA :
2145 FormulaError nErrCode;
2146 if ( bShowFormulas )
2148 aString = pCell->getFormula()->GetFormula();
2149 bString = true;
2151 else if ((nErrCode = pCell->getFormula()->GetErrCode()) != FormulaError::NONE)
2153 aString = ScGlobal::GetErrorString( nErrCode );
2154 bString = true;
2156 else if (pCell->getFormula()->IsValue())
2158 sal_uInt32 nFormat = m_pDocument->GetNumberFormat(aPos);
2159 if ( bFixedWidth || bSaveAsShown )
2161 const Color* pDummy;
2162 aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, rFormatter, *m_pDocument);
2163 bString = bSaveAsShown && rFormatter.IsTextFormat( nFormat);
2165 else
2167 aString = ScCellFormat::GetInputString(*pCell, nFormat, rFormatter, *m_pDocument);
2168 bString = bForceQuotes = !bSaveNumberAsSuch;
2171 else
2173 if ( bSaveAsShown )
2175 sal_uInt32 nFormat = m_pDocument->GetNumberFormat(aPos);
2176 const Color* pDummy;
2177 aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, rFormatter, *m_pDocument);
2179 else
2180 aString = pCell->getFormula()->GetString().getString();
2181 bString = true;
2184 break;
2185 case CELLTYPE_STRING :
2186 if ( bSaveAsShown )
2188 sal_uInt32 nFormat = m_pDocument->GetNumberFormat(aPos);
2189 const Color* pDummy;
2190 aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, rFormatter, *m_pDocument);
2192 else
2193 aString = pCell->getSharedString()->getString();
2194 bString = true;
2195 break;
2196 case CELLTYPE_EDIT :
2198 const EditTextObject* pObj = pCell->getEditText();
2199 EditEngine& rEngine = m_pDocument->GetEditEngine();
2200 rEngine.SetText( *pObj);
2201 aString = rEngine.GetText(); // including LF
2202 bString = true;
2204 break;
2205 case CELLTYPE_VALUE :
2207 sal_uInt32 nFormat = m_pDocument->GetNumberFormat( nCol, nRow, nTab );
2208 if ( bFixedWidth || bSaveAsShown )
2210 const Color* pDummy;
2211 aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, rFormatter, *m_pDocument);
2212 bString = bSaveAsShown && rFormatter.IsTextFormat( nFormat);
2214 else
2216 aString = ScCellFormat::GetInputString(*pCell, nFormat, rFormatter, *m_pDocument);
2217 bString = bForceQuotes = !bSaveNumberAsSuch;
2220 break;
2221 default:
2222 OSL_FAIL( "ScDocShell::AsciiSave: unknown CellType" );
2223 aString.clear();
2224 bString = false;
2227 if ( bFixedWidth )
2229 SvxCellHorJustify eHorJust =
2230 m_pDocument->GetAttr( nCol, nRow, nTab, ATTR_HOR_JUSTIFY )->GetValue();
2231 lcl_ScDocShell_GetFixedWidthString( aString, *m_pDocument, nTab, nCol,
2232 !bString, eHorJust );
2233 rStream.WriteUnicodeOrByteText( aString );
2235 else
2237 OUString aUniString = aString;// TODO: remove that later
2238 if (!bString && cStrDelim != 0 && !aUniString.isEmpty())
2240 sal_Unicode c = aUniString[0];
2241 bString = (c == cStrDelim || c == ' ' ||
2242 aUniString.endsWith(" ") ||
2243 aUniString.indexOf(cStrDelim) >= 0);
2244 if (!bString && cDelim != 0)
2245 bString = (aUniString.indexOf(cDelim) >= 0);
2247 if ( bString )
2249 if ( cStrDelim != 0 ) //@ BugId 55355
2251 if ( eCharSet == RTL_TEXTENCODING_UNICODE )
2253 bool bNeedQuotes = false;
2254 sal_Int32 nPos = getTextSepPos(aUniString, rAsciiOpt, cStrDelim, cDelim, bNeedQuotes);
2255 if (nPos >= 0)
2257 OUString strFrom(cStrDelim);
2258 OUString strTo = strFrom + strFrom;
2259 aUniString = aUniString.replaceAll(strFrom, strTo);
2262 if ( bNeedQuotes || bForceQuotes )
2263 rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
2264 write_uInt16s_FromOUString(rStream, aUniString);
2265 if ( bNeedQuotes || bForceQuotes )
2266 rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
2268 else
2270 // This is nasty. The Unicode to byte encoding
2271 // may convert typographical quotation marks to ASCII
2272 // quotation marks, which may interfere with the delimiter,
2273 // so we have to escape delimiters after the string has
2274 // been encoded. Since this may happen also with UTF-8
2275 // encoded typographical quotation marks if such was
2276 // specified as a delimiter we have to check for the full
2277 // encoded delimiter string, not just one character.
2278 // Now for RTL_TEXTENCODING_ISO_2022_... and similar brain
2279 // dead encodings where one code point (and especially a
2280 // low ASCII value) may represent different characters, we
2281 // have to convert forth and back and forth again. Same for
2282 // UTF-7 since it is a context sensitive encoding too.
2284 if ( bContextOrNotAsciiEncoding )
2286 // to byte encoding
2287 OString aStrEnc = OUStringToOString(aUniString, eCharSet);
2288 // back to Unicode
2289 OUString aStrDec = OStringToOUString(aStrEnc, eCharSet);
2291 // search on re-decoded string
2292 bool bNeedQuotes = false;
2293 sal_Int32 nPos = getTextSepPos(aStrDec, rAsciiOpt, aStrDelimDecoded, aDelimDecoded, bNeedQuotes);
2294 if (nPos >= 0)
2296 OUString strTo = aStrDelimDecoded + aStrDelimDecoded;
2297 aStrDec = aStrDec.replaceAll(aStrDelimDecoded, strTo);
2300 // write byte re-encoded
2301 if ( bNeedQuotes || bForceQuotes )
2302 rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
2303 rStream.WriteUnicodeOrByteText( aStrDec, eCharSet );
2304 if ( bNeedQuotes || bForceQuotes )
2305 rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
2307 else
2309 OString aStrEnc = OUStringToOString(aUniString, eCharSet);
2311 // search on encoded string
2312 bool bNeedQuotes = false;
2313 sal_Int32 nPos = getTextSepPos(aStrEnc, rAsciiOpt, aStrDelimEncoded, aDelimEncoded, bNeedQuotes);
2314 if (nPos >= 0)
2316 OString strTo = aStrDelimEncoded + aStrDelimEncoded;
2317 aStrEnc = aStrEnc.replaceAll(aStrDelimEncoded, strTo);
2320 // write byte encoded
2321 if ( bNeedQuotes || bForceQuotes )
2322 rStream.WriteBytes(
2323 aStrDelimEncoded.getStr(), aStrDelimEncoded.getLength());
2324 rStream.WriteBytes(aStrEnc.getStr(), aStrEnc.getLength());
2325 if ( bNeedQuotes || bForceQuotes )
2326 rStream.WriteBytes(
2327 aStrDelimEncoded.getStr(), aStrDelimEncoded.getLength());
2331 else
2332 rStream.WriteUnicodeOrByteText( aUniString );
2334 else
2335 rStream.WriteUnicodeOrByteText( aUniString );
2338 if( nCol < nEndCol )
2340 if(cDelim!=0) //@ BugId 55355
2341 rStream.WriteUniOrByteChar( cDelim );
2343 else
2344 endlub( rStream );
2346 if ( bProgress )
2347 aProgress.SetStateOnPercent( nRow );
2350 // write out empty if requested
2351 if ( nNextRow <= nEndRow )
2353 for ( nEmptyCol = nNextCol; nEmptyCol < nEndCol; nEmptyCol++ )
2354 { // remaining empty columns of last row
2355 if ( bFixedWidth )
2356 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2357 *m_pDocument, nTab, nEmptyCol );
2358 else if ( cDelim != 0 )
2359 rStream.WriteUniOrByteChar( cDelim );
2361 endlub( rStream );
2362 nNextRow++;
2364 for ( nEmptyRow = nNextRow; nEmptyRow <= nEndRow; nEmptyRow++ )
2365 { // entire empty rows
2366 for ( nEmptyCol = nStartCol; nEmptyCol < nEndCol; nEmptyCol++ )
2368 if ( bFixedWidth )
2369 lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
2370 *m_pDocument, nTab, nEmptyCol );
2371 else if ( cDelim != 0 )
2372 rStream.WriteUniOrByteChar( cDelim );
2374 endlub( rStream );
2377 rStream.SetStreamCharSet( eOldCharSet );
2378 rStream.SetEndian( nOldNumberFormatInt );
2381 bool ScDocShell::ConvertTo( SfxMedium &rMed )
2383 ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
2385 // #i6500# don't call DoEnterHandler here (doesn't work with AutoSave),
2386 // it's already in ExecuteSave (as for Save and SaveAs)
2388 if (m_pAutoStyleList)
2389 m_pAutoStyleList->ExecuteAllNow(); // Execute template timeouts now
2390 if (GetCreateMode()== SfxObjectCreateMode::STANDARD)
2391 SfxObjectShell::SetVisArea( tools::Rectangle() ); // Edited normally -> no VisArea
2393 OSL_ENSURE( rMed.GetFilter(), "Filter == 0" );
2395 bool bRet = false;
2396 OUString aFltName = rMed.GetFilter()->GetFilterName();
2398 if (aFltName == pFilterXML)
2400 //TODO/LATER: this shouldn't happen!
2401 OSL_FAIL("XML filter in ConvertFrom?!");
2402 bRet = SaveXML( &rMed, nullptr );
2404 else if (aFltName == pFilterExcel5 || aFltName == pFilterExcel95 ||
2405 aFltName == pFilterExcel97 || aFltName == pFilterEx5Temp ||
2406 aFltName == pFilterEx95Temp || aFltName == pFilterEx97Temp)
2408 weld::WaitObject aWait( GetActiveDialogParent() );
2410 bool bDoSave = true;
2411 if( ScTabViewShell* pViewShell = GetBestViewShell() )
2413 ScExtDocOptions* pExtDocOpt = m_pDocument->GetExtDocOptions();
2414 if( !pExtDocOpt )
2416 m_pDocument->SetExtDocOptions( std::make_unique<ScExtDocOptions>() );
2417 pExtDocOpt = m_pDocument->GetExtDocOptions();
2419 pViewShell->GetViewData().WriteExtOptions( *pExtDocOpt );
2421 /* #i104990# If the imported document contains a medium
2422 password, determine if we can save it, otherwise ask the users
2423 whether they want to save without it. */
2424 if( (rMed.GetFilter()->GetFilterFlags() & SfxFilterFlags::ENCRYPTION) == SfxFilterFlags::NONE )
2426 SfxItemSet* pItemSet = rMed.GetItemSet();
2427 if( pItemSet && pItemSet->GetItemState( SID_PASSWORD ) == SfxItemState::SET )
2429 bDoSave = ScWarnPassword::WarningOnPassword( rMed );
2430 // #i42858# remove password from medium (warn only one time)
2431 if( bDoSave )
2432 pItemSet->ClearItem( SID_PASSWORD );
2436 if( bDoSave )
2438 bool bNeedRetypePassDlg = ScPassHashHelper::needsPassHashRegen( *m_pDocument, PASSHASH_XL );
2439 bDoSave = !bNeedRetypePassDlg || pViewShell->ExecuteRetypePassDlg( PASSHASH_XL );
2443 if( bDoSave )
2445 ExportFormatExcel eFormat = ExpBiff5;
2446 if( aFltName == pFilterExcel97 || aFltName == pFilterEx97Temp )
2447 eFormat = ExpBiff8;
2448 ErrCode eError = ScFormatFilter::Get().ScExportExcel5( rMed, m_pDocument.get(), eFormat, RTL_TEXTENCODING_MS_1252 );
2450 if( eError && !GetError() )
2451 SetError(eError);
2453 // don't return false for warnings
2454 bRet = eError.IsWarning() || (eError == ERRCODE_NONE);
2456 else
2458 // export aborted, i.e. "Save without password" warning
2459 SetError(ERRCODE_ABORT);
2462 else if (aFltName == SC_TEXT_CSV_FILTER_NAME)
2464 OUString sItStr;
2465 SfxItemSet* pSet = rMed.GetItemSet();
2466 const SfxStringItem* pOptionsItem;
2467 if ( pSet &&
2468 (pOptionsItem = pSet->GetItemIfSet( SID_FILE_FILTEROPTIONS )) )
2470 sItStr = pOptionsItem->GetValue();
2473 if ( sItStr.isEmpty() )
2475 // default for ascii export (from API without options):
2476 // UTF-8 encoding, comma, double quotes
2478 ScImportOptions aDefOptions(',', '"', RTL_TEXTENCODING_UTF8);
2479 sItStr = aDefOptions.BuildString();
2482 weld::WaitObject aWait( GetActiveDialogParent() );
2483 ScImportOptions aOptions( sItStr );
2485 if (aOptions.nSheetToExport)
2487 // Only from command line --convert-to
2488 bRet = true;
2490 // Verbose only from command line, not UI (in case we actually
2491 // implement that) nor macro filter options.
2492 bool bVerbose = false;
2493 const css::uno::Sequence<css::beans::PropertyValue> & rArgs = rMed.GetArgs();
2494 const auto pProp = std::find_if( rArgs.begin(), rArgs.end(),
2495 [](const css::beans::PropertyValue& rProp) { return rProp.Name == "ConversionRequestOrigin"; });
2496 if (pProp != rArgs.end())
2498 OUString aOrigin;
2499 pProp->Value >>= aOrigin;
2500 bVerbose = (aOrigin == "CommandLine");
2503 SCTAB nStartTab;
2504 SCTAB nCount = m_pDocument->GetTableCount();
2505 if (aOptions.nSheetToExport == -1)
2507 // All sheets.
2508 nStartTab = 0;
2510 else if (0 < aOptions.nSheetToExport && aOptions.nSheetToExport <= nCount)
2512 // One sheet, 1-based.
2513 nCount = aOptions.nSheetToExport;
2514 nStartTab = nCount - 1;
2516 else
2518 // Usage error, no export but log.
2519 if (bVerbose)
2521 if (aOptions.nSheetToExport < 0)
2522 std::cout << "Bad sheet number string given." << std::endl;
2523 else
2524 std::cout << "No sheet number " << aOptions.nSheetToExport
2525 << ", number of sheets is " << nCount << std::endl;
2527 nStartTab = 0;
2528 nCount = 0;
2529 SetError(SCERR_EXPORT_DATA);
2530 bRet = false;
2533 INetURLObject aURLObject(rMed.GetURLObject());
2534 OUString sExt = aURLObject.CutExtension();
2535 OUString sBaseName = aURLObject.GetLastName();
2536 aURLObject.CutLastName();
2538 for (SCTAB i = nStartTab; i < nCount; ++i)
2540 OUString sTabName;
2541 if (!m_pDocument->GetName(i, sTabName))
2542 sTabName = OUString::number(i);
2543 INetURLObject aSheetURLObject(aURLObject);
2544 OUString sFileName = sBaseName + "-" + sTabName;
2545 if (!sExt.isEmpty())
2546 sFileName = sFileName + "." + sExt;
2547 aSheetURLObject.Append(sFileName);
2549 // log similar to DispatchWatcher::executeDispatchRequests
2550 OUString aOutFile = aSheetURLObject.GetMainURL(INetURLObject::DecodeMechanism::NONE);
2551 if (bVerbose)
2553 OUString aDisplayedName;
2554 if (osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL(aOutFile, aDisplayedName))
2555 aDisplayedName = aOutFile;
2556 std::cout << "Writing sheet " << OUStringToOString(sTabName, osl_getThreadTextEncoding()) << " -> "
2557 << OUStringToOString(aDisplayedName, osl_getThreadTextEncoding())
2558 << std::endl;
2560 if (FStatHelper::IsDocument(aOutFile))
2561 std::cout << "Overwriting: " << OUStringToOString(aDisplayedName, osl_getThreadTextEncoding())
2562 << std::endl ;
2565 std::unique_ptr<SvStream> xStm = ::utl::UcbStreamHelper::CreateStream(aOutFile, StreamMode::TRUNC | StreamMode::WRITE);
2566 if (!xStm)
2568 SetError(ERRCODE_IO_CANTCREATE);
2569 bRet = false;
2570 break;
2572 AsciiSave(*xStm, aOptions, i);
2575 else
2577 SvStream* pStream = rMed.GetOutStream();
2578 if (pStream)
2580 AsciiSave(*pStream, aOptions, GetSaveTab());
2581 bRet = true;
2583 if (m_pDocument->GetTableCount() > 1)
2584 if (!rMed.GetError())
2585 rMed.SetError(SCWARN_EXPORT_ASCII);
2589 else if (aFltName == pFilterDBase)
2591 OUString sCharSet;
2592 SfxItemSet* pSet = rMed.GetItemSet();
2593 const SfxStringItem* pOptionsItem;
2594 if ( pSet &&
2595 (pOptionsItem = pSet->GetItemIfSet( SID_FILE_FILTEROPTIONS )) )
2597 sCharSet = pOptionsItem->GetValue();
2600 if (sCharSet.isEmpty())
2602 // default for dBase export (from API without options):
2603 // IBM_850 encoding
2605 sCharSet = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_850 );
2608 weld::WaitObject aWait( GetActiveDialogParent() );
2609 // Hack so that Sba can overwrite the opened TempFile.
2610 rMed.CloseOutStream();
2611 bool bHasMemo = false;
2613 ErrCode eError = DBaseExport(
2614 rMed.GetPhysicalName(), ScGlobal::GetCharsetValue(sCharSet), bHasMemo);
2616 INetURLObject aTmpFile( rMed.GetPhysicalName(), INetProtocol::File );
2617 if ( bHasMemo )
2618 aTmpFile.setExtension(u"dbt");
2619 if ( eError != ERRCODE_NONE && !eError.IsWarning() )
2621 if (!GetError())
2622 SetError(eError);
2623 if ( bHasMemo && IsDocument( aTmpFile ) )
2624 KillFile( aTmpFile );
2626 else
2628 bRet = true;
2629 if ( bHasMemo )
2631 const SfxStringItem* pNameItem = rMed.GetItemSet()->GetItem<SfxStringItem>( SID_FILE_NAME );
2632 assert(pNameItem && "SID_FILE_NAME is required");
2633 INetURLObject aDbtFile( pNameItem->GetValue(), INetProtocol::File );
2634 aDbtFile.setExtension(u"dbt");
2636 // tdf#40713: don't lose dbt file
2637 // if aDbtFile corresponds exactly to aTmpFile, we just have to return
2638 if (aDbtFile.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ) ==
2639 aTmpFile.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ))
2641 if (eError != ERRCODE_NONE && !GetError())
2642 SetError(eError);
2643 return bRet;
2646 if ( IsDocument( aDbtFile ) && !KillFile( aDbtFile ) )
2647 bRet = false;
2648 if ( bRet && !MoveFile( aTmpFile, aDbtFile ) )
2649 bRet = false;
2650 if ( !bRet )
2652 KillFile( aTmpFile );
2653 if (eError == ERRCODE_NONE || eError.IsWarning())
2654 eError = SCERR_EXPORT_DATA;
2657 if (eError != ERRCODE_NONE && !GetError())
2658 SetError(eError);
2661 else if (aFltName == pFilterDif)
2663 SvStream* pStream = rMed.GetOutStream();
2664 if (pStream)
2666 OUString sItStr;
2667 SfxItemSet* pSet = rMed.GetItemSet();
2668 const SfxStringItem* pOptionsItem;
2669 if ( pSet &&
2670 (pOptionsItem = pSet->GetItemIfSet( SID_FILE_FILTEROPTIONS )) )
2672 sItStr = pOptionsItem->GetValue();
2675 if (sItStr.isEmpty())
2677 // default for DIF export (from API without options):
2678 // ISO8859-1/MS_1252 encoding
2680 sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_MS_1252 );
2683 weld::WaitObject aWait( GetActiveDialogParent() );
2684 ScFormatFilter::Get().ScExportDif( *pStream, m_pDocument.get(), ScAddress(0,0,0),
2685 ScGlobal::GetCharsetValue(sItStr) );
2686 bRet = true;
2688 if (m_pDocument->GetTableCount() > 1)
2689 if (!rMed.GetError())
2690 rMed.SetError(SCWARN_EXPORT_ASCII);
2693 else if (aFltName == pFilterSylk)
2695 SvStream* pStream = rMed.GetOutStream();
2696 if ( pStream )
2698 weld::WaitObject aWait( GetActiveDialogParent() );
2700 SCCOL nEndCol;
2701 SCROW nEndRow;
2702 m_pDocument->GetCellArea( 0, nEndCol, nEndRow );
2703 ScRange aRange( 0,0,0, nEndCol,nEndRow,0 );
2705 ScImportExport aImExport( *m_pDocument, aRange );
2706 aImExport.SetFormulas( true );
2707 bRet = aImExport.ExportStream( *pStream, rMed.GetBaseURL( true ), SotClipboardFormatId::SYLK );
2710 else if (aFltName == pFilterHtml)
2712 SvStream* pStream = rMed.GetOutStream();
2713 if ( pStream )
2715 SfxItemSet* pSet = rMed.GetItemSet();
2716 OUString sFilterOptions;
2718 if (const SfxStringItem* pOptionsItem = pSet->GetItemIfSet(SID_FILE_FILTEROPTIONS))
2719 sFilterOptions = pOptionsItem->GetValue();
2721 weld::WaitObject aWait(GetActiveDialogParent());
2722 ScImportExport aImExport(*m_pDocument);
2723 aImExport.SetStreamPath(rMed.GetName());
2724 aImExport.SetFilterOptions(sFilterOptions);
2725 bRet = aImExport.ExportStream(*pStream, rMed.GetBaseURL(true), SotClipboardFormatId::HTML);
2726 if (bRet && !aImExport.GetNonConvertibleChars().isEmpty())
2728 SetError(*new StringErrorInfo(
2729 SCWARN_EXPORT_NONCONVERTIBLE_CHARS,
2730 aImExport.GetNonConvertibleChars(),
2731 DialogMask::ButtonsOk | DialogMask::MessageInfo));
2735 else
2737 if (GetError())
2738 SetError(SCERR_IMPORT_NI);
2740 return bRet;
2743 bool ScDocShell::DoSaveCompleted( SfxMedium * pNewStor, bool bRegisterRecent )
2745 bool bRet = SfxObjectShell::DoSaveCompleted( pNewStor, bRegisterRecent );
2747 // SfxHintId::ScDocSaved for change ReadOnly -> Read/Write
2748 Broadcast( SfxHint( SfxHintId::ScDocSaved ) );
2749 return bRet;
2752 bool ScDocShell::QuerySlotExecutable( sal_uInt16 nSlotId )
2754 // #i112634# ask VBA event handlers whether to save or print the document
2756 using namespace ::com::sun::star::script::vba;
2758 sal_Int32 nVbaEventId = VBAEventId::NO_EVENT;
2759 uno::Sequence< uno::Any > aArgs;
2760 switch( nSlotId )
2762 case SID_SAVEDOC:
2763 case SID_SAVEASDOC:
2764 nVbaEventId = VBAEventId::WORKBOOK_BEFORESAVE;
2765 aArgs = { uno::Any(nSlotId == SID_SAVEASDOC) };
2766 break;
2767 case SID_PRINTDOC:
2768 case SID_PRINTDOCDIRECT:
2769 nVbaEventId = VBAEventId::WORKBOOK_BEFOREPRINT;
2770 break;
2773 bool bSlotExecutable = true;
2774 if( nVbaEventId != VBAEventId::NO_EVENT ) try
2776 uno::Reference< XVBAEventProcessor > xEventProcessor( m_pDocument->GetVbaEventProcessor(), uno::UNO_SET_THROW );
2777 xEventProcessor->processVbaEvent( nVbaEventId, aArgs );
2779 catch( util::VetoException& )
2781 bSlotExecutable = false;
2783 catch( uno::Exception& )
2786 return bSlotExecutable;
2789 bool ScDocShell::PrepareClose( bool bUI )
2791 if(SC_MOD()->GetCurRefDlgId()>0)
2793 SfxViewFrame* pFrame = SfxViewFrame::GetFirst( this );
2794 if( pFrame )
2796 SfxViewShell* p = pFrame->GetViewShell();
2797 ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( p );
2798 if(pViewSh!=nullptr)
2800 vcl::Window *pWin=pViewSh->GetWindow();
2801 if(pWin!=nullptr) pWin->GrabFocus();
2805 return false;
2807 if ( m_pDocument->IsInLinkUpdate() || m_pDocument->IsInInterpreter() )
2809 ErrorMessage(STR_CLOSE_ERROR_LINK);
2810 return false;
2813 DoEnterHandler();
2815 // start 'Workbook_BeforeClose' VBA event handler for possible veto
2816 if( !IsInPrepareClose() )
2820 uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( m_pDocument->GetVbaEventProcessor(), uno::UNO_SET_THROW );
2821 uno::Sequence< uno::Any > aArgs;
2822 xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKBOOK_BEFORECLOSE, aArgs );
2824 catch( util::VetoException& )
2826 // if event processor throws VetoException, macro has vetoed close
2827 return false;
2829 catch( uno::Exception& )
2833 // end handler code
2835 bool bRet = SfxObjectShell::PrepareClose( bUI );
2836 if (bRet) // true == close
2837 m_pDocument->EnableIdle(false); // Do not mess around with it anymore!
2839 return bRet;
2842 OUString ScDocShell::GetOwnFilterName()
2844 return pFilterSc50;
2847 OUString ScDocShell::GetHtmlFilterName()
2849 return pFilterHtml;
2852 OUString ScDocShell::GetWebQueryFilterName()
2854 return pFilterHtmlWebQ;
2857 OUString ScDocShell::GetAsciiFilterName()
2859 return SC_TEXT_CSV_FILTER_NAME;
2862 OUString ScDocShell::GetLotusFilterName()
2864 return pFilterLotus;
2867 OUString ScDocShell::GetDBaseFilterName()
2869 return pFilterDBase;
2872 OUString ScDocShell::GetDifFilterName()
2874 return pFilterDif;
2877 bool ScDocShell::HasAutomaticTableName( std::u16string_view rFilter )
2879 // sal_True for those filters that keep the default table name
2880 // (which is language specific)
2882 return rFilter == SC_TEXT_CSV_FILTER_NAME
2883 || rFilter == pFilterLotus
2884 || rFilter == pFilterExcel4
2885 || rFilter == pFilterEx4Temp
2886 || rFilter == pFilterDBase
2887 || rFilter == pFilterDif
2888 || rFilter == pFilterSylk
2889 || rFilter == pFilterHtml
2890 || rFilter == pFilterRtf;
2893 std::unique_ptr<ScDocFunc> ScDocShell::CreateDocFunc()
2895 return std::make_unique<ScDocFuncDirect>( *this );
2898 ScDocShell::ScDocShell( const SfxModelFlags i_nSfxCreationFlags, const std::shared_ptr<ScDocument>& pDoc ) :
2899 SfxObjectShell( i_nSfxCreationFlags ),
2900 m_pDocument ( pDoc ? pDoc : std::make_shared<ScDocument>( SCDOCMODE_DOCUMENT, this )),
2901 m_aDdeTextFmt(OUString("TEXT")),
2902 m_nPrtToScreenFactor( 1.0 ),
2903 m_pImpl ( new DocShell_Impl ),
2904 m_bHeaderOn ( true ),
2905 m_bFooterOn ( true ),
2906 m_bIsEmpty ( true ),
2907 m_bIsInUndo ( false ),
2908 m_bDocumentModifiedPending( false ),
2909 m_bUpdateEnabled ( true ),
2910 m_bAreasChangedNeedBroadcast( false ),
2911 m_nDocumentLock ( 0 ),
2912 m_nCanUpdate (css::document::UpdateDocMode::ACCORDING_TO_CONFIG)
2914 SetPool( &SC_MOD()->GetPool() );
2916 m_bIsInplace = (GetCreateMode() == SfxObjectCreateMode::EMBEDDED);
2917 // Will be reset if not in place
2919 m_pDocFunc = CreateDocFunc();
2921 // SetBaseModel needs exception handling
2922 ScModelObj::CreateAndSet( this );
2924 StartListening(*this);
2925 SfxStyleSheetPool* pStlPool = m_pDocument->GetStyleSheetPool();
2926 if (pStlPool)
2927 StartListening(*pStlPool);
2929 m_pDocument->GetDBCollection()->SetRefreshHandler(
2930 LINK( this, ScDocShell, RefreshDBDataHdl ) );
2932 // InitItems and CalcOutputFactor are called now in Load/ConvertFrom/InitNew
2935 ScDocShell::~ScDocShell()
2937 ResetDrawObjectShell(); // If the Drawing Layer still tries to access it, access it
2939 SfxStyleSheetPool* pStlPool = m_pDocument->GetStyleSheetPool();
2940 if (pStlPool)
2941 EndListening(*pStlPool);
2942 EndListening(*this);
2944 m_pAutoStyleList.reset();
2946 SfxApplication *pSfxApp = SfxGetpApp();
2947 if ( pSfxApp->GetDdeService() ) // Delete DDE for Document
2948 pSfxApp->RemoveDdeTopic( this );
2950 m_pDocFunc.reset();
2951 delete m_pDocument->mpUndoManager;
2952 m_pDocument->mpUndoManager = nullptr;
2953 m_pImpl.reset();
2955 m_pPaintLockData.reset();
2957 m_pSolverSaveData.reset();
2958 m_pSheetSaveData.reset();
2959 m_pFormatSaveData.reset();
2960 m_pOldAutoDBRange.reset();
2962 if (m_pModificator)
2964 OSL_FAIL("The Modificator should not exist");
2965 m_pModificator.reset();
2969 SfxUndoManager* ScDocShell::GetUndoManager()
2971 return m_pDocument->GetUndoManager();
2974 void ScDocShell::SetModified( bool bModified )
2976 if ( SfxObjectShell::IsEnableSetModified() )
2978 SfxObjectShell::SetModified( bModified );
2979 Broadcast( SfxHint( SfxHintId::DocChanged ) );
2983 void ScDocShell::SetDocumentModified()
2985 // BroadcastUno must also happen right away with pPaintLockData
2986 // FIXME: Also for SetDrawModified, if Drawing is connected
2987 // FIXME: Then own Hint?
2989 if ( m_pPaintLockData )
2991 // #i115009# broadcast BCA_BRDCST_ALWAYS, so a component can read recalculated results
2992 // of RecalcModeAlways formulas (like OFFSET) after modifying cells
2993 m_pDocument->Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS));
2994 m_pDocument->InvalidateTableArea(); // #i105279# needed here
2995 m_pDocument->BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
2997 m_pPaintLockData->SetModified(); // Later on ...
2998 return;
3001 SetDrawModified();
3003 if ( m_pDocument->IsAutoCalcShellDisabled() )
3004 SetDocumentModifiedPending( true );
3005 else
3007 SetDocumentModifiedPending( false );
3008 m_pDocument->InvalidateStyleSheetUsage();
3009 m_pDocument->InvalidateTableArea();
3010 m_pDocument->InvalidateLastTableOpParams();
3011 m_pDocument->Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS));
3012 if ( m_pDocument->IsForcedFormulaPending() && m_pDocument->GetAutoCalc() )
3013 m_pDocument->CalcFormulaTree( true );
3014 m_pDocument->RefreshDirtyTableColumnNames();
3015 PostDataChanged();
3017 // Detective AutoUpdate:
3018 // Update if formulas were modified (DetectiveDirty) or the list contains
3019 // "Trace Error" entries (Trace Error can look completely different
3020 // after changes to non-formula cells).
3022 ScDetOpList* pList = m_pDocument->GetDetOpList();
3023 if ( pList && ( m_pDocument->IsDetectiveDirty() || pList->HasAddError() ) &&
3024 pList->Count() && !IsInUndo() && SC_MOD()->GetAppOptions().GetDetectiveAuto() )
3026 GetDocFunc().DetectiveRefresh(true); // sal_True = caused by automatic update
3028 m_pDocument->SetDetectiveDirty(false); // always reset, also if not refreshed
3031 if (m_bAreasChangedNeedBroadcast)
3033 m_bAreasChangedNeedBroadcast = false;
3034 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged));
3037 // notify UNO objects after BCA_BRDCST_ALWAYS etc.
3038 m_pDocument->BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
3042 * SetDrawModified - without Formula update
3044 * Drawing also needs to be updated for the normal SetDocumentModified
3045 * e.g.: when deleting tables etc.
3047 void ScDocShell::SetDrawModified()
3049 bool bUpdate = !IsModified();
3051 SetModified();
3053 SfxBindings* pBindings = GetViewBindings();
3054 if (bUpdate && pBindings)
3056 pBindings->Invalidate( SID_SAVEDOC );
3057 pBindings->Invalidate( SID_DOC_MODIFIED );
3060 if (pBindings)
3062 // #i105960# Undo etc used to be volatile.
3063 // They always have to be invalidated, including drawing layer or row height changes
3064 // (but not while pPaintLockData is set).
3065 pBindings->Invalidate( SID_UNDO );
3066 pBindings->Invalidate( SID_REDO );
3067 pBindings->Invalidate( SID_REPEAT );
3070 if ( m_pDocument->IsChartListenerCollectionNeedsUpdate() )
3072 m_pDocument->UpdateChartListenerCollection();
3073 SfxGetpApp()->Broadcast(SfxHint( SfxHintId::ScDrawChanged )); // Navigator
3075 SC_MOD()->AnythingChanged();
3078 void ScDocShell::SetInUndo(bool bSet)
3080 m_bIsInUndo = bSet;
3083 void ScDocShell::GetDocStat( ScDocStat& rDocStat )
3085 SfxPrinter* pPrinter = GetPrinter();
3087 m_pDocument->GetDocStat( rDocStat );
3088 rDocStat.nPageCount = 0;
3090 if ( pPrinter )
3091 for ( SCTAB i=0; i<rDocStat.nTableCount; i++ )
3092 rDocStat.nPageCount = sal::static_int_cast<sal_uInt16>( rDocStat.nPageCount +
3093 static_cast<sal_uInt16>(ScPrintFunc( this, pPrinter, i ).GetTotalPages()) );
3096 std::shared_ptr<SfxDocumentInfoDialog> ScDocShell::CreateDocumentInfoDialog(weld::Window* pParent, const SfxItemSet &rSet)
3098 std::shared_ptr<SfxDocumentInfoDialog> xDlg = std::make_shared<SfxDocumentInfoDialog>(pParent, rSet);
3099 ScDocShell* pDocSh = dynamic_cast< ScDocShell *>( SfxObjectShell::Current() );
3101 // Only for statistics, if this Doc is shown; not from the Doc Manager
3102 if( pDocSh == this )
3104 ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
3105 ::CreateTabPage ScDocStatPageCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_STAT);
3106 OSL_ENSURE(ScDocStatPageCreate, "Tabpage create fail!");
3107 xDlg->AddFontTabPage();
3108 xDlg->AddTabPage("calcstats", ScResId(STR_DOC_STAT), ScDocStatPageCreate);
3110 return xDlg;
3113 weld::Window* ScDocShell::GetActiveDialogParent()
3115 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
3116 if ( pViewSh )
3117 return pViewSh->GetDialogParent();
3118 return Application::GetDefDialogParent();
3121 void ScDocShell::SetSolverSaveData( std::unique_ptr<ScOptSolverSave> pData )
3123 m_pSolverSaveData = std::move(pData);
3126 ScSheetSaveData* ScDocShell::GetSheetSaveData()
3128 if (!m_pSheetSaveData)
3129 m_pSheetSaveData.reset( new ScSheetSaveData );
3131 return m_pSheetSaveData.get();
3134 ScFormatSaveData* ScDocShell::GetFormatSaveData()
3136 if (!m_pFormatSaveData)
3137 m_pFormatSaveData.reset( new ScFormatSaveData );
3139 return m_pFormatSaveData.get();
3142 namespace {
3144 void removeKeysIfExists(const Reference<ui::XAcceleratorConfiguration>& xScAccel, const vector<const awt::KeyEvent*>& rKeys)
3146 for (const awt::KeyEvent* p : rKeys)
3148 if (!p)
3149 continue;
3153 xScAccel->removeKeyEvent(*p);
3155 catch (const container::NoSuchElementException&) {}
3161 void ScDocShell::ResetKeyBindings( ScOptionsUtil::KeyBindingType eType )
3163 using namespace ::com::sun::star::ui;
3165 Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
3166 if (!xContext.is())
3167 return;
3169 Reference<XModuleUIConfigurationManagerSupplier> xModuleCfgSupplier(
3170 theModuleUIConfigurationManagerSupplier::get(xContext) );
3172 // Grab the Calc configuration.
3173 Reference<XUIConfigurationManager> xConfigMgr =
3174 xModuleCfgSupplier->getUIConfigurationManager(
3175 "com.sun.star.sheet.SpreadsheetDocument");
3177 if (!xConfigMgr.is())
3178 return;
3180 // shortcut manager
3181 Reference<XAcceleratorConfiguration> xScAccel = xConfigMgr->getShortCutManager();
3183 if (!xScAccel.is())
3184 return;
3186 vector<const awt::KeyEvent*> aKeys;
3187 aKeys.reserve(9);
3189 // Backspace key
3190 awt::KeyEvent aBackspace;
3191 aBackspace.KeyCode = awt::Key::BACKSPACE;
3192 aBackspace.Modifiers = 0;
3193 aKeys.push_back(&aBackspace);
3195 // Delete key
3196 awt::KeyEvent aDelete;
3197 aDelete.KeyCode = awt::Key::DELETE;
3198 aDelete.Modifiers = 0;
3199 aKeys.push_back(&aDelete);
3201 // Ctrl-D
3202 awt::KeyEvent aCtrlD;
3203 aCtrlD.KeyCode = awt::Key::D;
3204 aCtrlD.Modifiers = awt::KeyModifier::MOD1;
3205 aKeys.push_back(&aCtrlD);
3207 // Alt-Down
3208 awt::KeyEvent aAltDown;
3209 aAltDown.KeyCode = awt::Key::DOWN;
3210 aAltDown.Modifiers = awt::KeyModifier::MOD2;
3211 aKeys.push_back(&aAltDown);
3213 // Ctrl-Space
3214 awt::KeyEvent aCtrlSpace;
3215 aCtrlSpace.KeyCode = awt::Key::SPACE;
3216 aCtrlSpace.Modifiers = awt::KeyModifier::MOD1;
3217 aKeys.push_back(&aCtrlSpace);
3219 // Ctrl-Shift-Space
3220 awt::KeyEvent aCtrlShiftSpace;
3221 aCtrlShiftSpace.KeyCode = awt::Key::SPACE;
3222 aCtrlShiftSpace.Modifiers = awt::KeyModifier::MOD1 | awt::KeyModifier::SHIFT;
3223 aKeys.push_back(&aCtrlShiftSpace);
3225 // F4
3226 awt::KeyEvent aF4;
3227 aF4.KeyCode = awt::Key::F4;
3228 aF4.Modifiers = 0;
3229 aKeys.push_back(&aF4);
3231 // CTRL+SHIFT+F4
3232 awt::KeyEvent aCtrlShiftF4;
3233 aCtrlShiftF4.KeyCode = awt::Key::F4;
3234 aCtrlShiftF4.Modifiers = awt::KeyModifier::MOD1 | awt::KeyModifier::SHIFT;
3235 aKeys.push_back(&aCtrlShiftF4);
3237 // SHIFT+F4
3238 awt::KeyEvent aShiftF4;
3239 aShiftF4.KeyCode = awt::Key::F4;
3240 aShiftF4.Modifiers = awt::KeyModifier::SHIFT;
3241 aKeys.push_back(&aShiftF4);
3243 // Remove all involved keys first, because swapping commands don't work
3244 // well without doing this.
3245 removeKeysIfExists(xScAccel, aKeys);
3246 xScAccel->store();
3248 switch (eType)
3250 case ScOptionsUtil::KEY_DEFAULT:
3251 xScAccel->setKeyEvent(aDelete, ".uno:ClearContents");
3252 xScAccel->setKeyEvent(aBackspace, ".uno:Delete");
3253 xScAccel->setKeyEvent(aCtrlD, ".uno:FillDown");
3254 xScAccel->setKeyEvent(aAltDown, ".uno:DataSelect");
3255 xScAccel->setKeyEvent(aCtrlSpace, ".uno:SelectColumn");
3256 xScAccel->setKeyEvent(aCtrlShiftSpace, ".uno:SelectAll");
3257 xScAccel->setKeyEvent(aF4, ".uno:ToggleRelative");
3258 xScAccel->setKeyEvent(aCtrlShiftF4, ".uno:ViewDataSourceBrowser");
3259 break;
3260 case ScOptionsUtil::KEY_OOO_LEGACY:
3261 xScAccel->setKeyEvent(aDelete, ".uno:Delete");
3262 xScAccel->setKeyEvent(aBackspace, ".uno:ClearContents");
3263 xScAccel->setKeyEvent(aCtrlD, ".uno:DataSelect");
3264 xScAccel->setKeyEvent(aCtrlShiftSpace, ".uno:SelectColumn");
3265 xScAccel->setKeyEvent(aF4, ".uno:ViewDataSourceBrowser");
3266 xScAccel->setKeyEvent(aShiftF4, ".uno:ToggleRelative");
3267 break;
3268 default:
3272 xScAccel->store();
3275 void ScDocShell::UseSheetSaveEntries()
3277 if (!m_pSheetSaveData)
3278 return;
3280 m_pSheetSaveData->UseSaveEntries(); // use positions from saved file for next saving
3282 bool bHasEntries = false;
3283 SCTAB nTabCount = m_pDocument->GetTableCount();
3284 SCTAB nTab;
3285 for (nTab = 0; nTab < nTabCount; ++nTab)
3286 if (m_pSheetSaveData->HasStreamPos(nTab))
3287 bHasEntries = true;
3289 if (!bHasEntries)
3291 // if no positions were set (for example, export to other format),
3292 // reset all "valid" flags
3293 for (nTab = 0; nTab < nTabCount; ++nTab)
3294 m_pDocument->SetStreamValid(nTab, false);
3298 // --- ScDocShellModificator ------------------------------------------
3300 ScDocShellModificator::ScDocShellModificator( ScDocShell& rDS )
3302 rDocShell( rDS ),
3303 mpProtector(new ScRefreshTimerProtector(rDS.GetDocument().GetRefreshTimerControlAddress()))
3305 ScDocument& rDoc = rDocShell.GetDocument();
3306 bAutoCalcShellDisabled = rDoc.IsAutoCalcShellDisabled();
3307 bIdleEnabled = rDoc.IsIdleEnabled();
3308 rDoc.SetAutoCalcShellDisabled( true );
3309 rDoc.EnableIdle(false);
3312 ScDocShellModificator::~ScDocShellModificator() COVERITY_NOEXCEPT_FALSE
3314 ScDocument& rDoc = rDocShell.GetDocument();
3315 rDoc.SetAutoCalcShellDisabled( bAutoCalcShellDisabled );
3316 if ( !bAutoCalcShellDisabled && rDocShell.IsDocumentModifiedPending() )
3317 rDocShell.SetDocumentModified(); // last one shuts off the lights
3318 rDoc.EnableIdle(bIdleEnabled);
3321 void ScDocShellModificator::SetDocumentModified()
3323 ScDocument& rDoc = rDocShell.GetDocument();
3324 rDoc.PrepareFormulaCalc();
3325 if ( !rDoc.IsImportingXML() )
3327 // temporarily restore AutoCalcShellDisabled
3328 bool bDisabled = rDoc.IsAutoCalcShellDisabled();
3329 rDoc.SetAutoCalcShellDisabled( bAutoCalcShellDisabled );
3330 rDocShell.SetDocumentModified();
3331 rDoc.SetAutoCalcShellDisabled( bDisabled );
3333 else
3335 // uno broadcast is necessary for api to work
3336 // -> must also be done during xml import
3337 rDoc.BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
3341 bool ScDocShell::IsChangeRecording() const
3343 ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
3344 return pChangeTrack != nullptr;
3347 bool ScDocShell::HasChangeRecordProtection() const
3349 bool bRes = false;
3350 ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
3351 if (pChangeTrack)
3352 bRes = pChangeTrack->IsProtected();
3353 return bRes;
3356 void ScDocShell::SetChangeRecording( bool bActivate, bool /*bLockAllViews*/ )
3358 bool bOldChangeRecording = IsChangeRecording();
3360 if (bActivate)
3362 m_pDocument->StartChangeTracking();
3363 ScChangeViewSettings aChangeViewSet;
3364 aChangeViewSet.SetShowChanges(true);
3365 m_pDocument->SetChangeViewSettings(aChangeViewSet);
3367 else
3369 m_pDocument->EndChangeTracking();
3370 PostPaintGridAll();
3373 if (bOldChangeRecording != IsChangeRecording())
3375 UpdateAcceptChangesDialog();
3376 // invalidate slots
3377 SfxBindings* pBindings = GetViewBindings();
3378 if (pBindings)
3379 pBindings->InvalidateAll(false);
3383 void ScDocShell::SetProtectionPassword( const OUString &rNewPassword )
3385 ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
3386 if (!pChangeTrack)
3387 return;
3389 bool bProtected = pChangeTrack->IsProtected();
3391 if (!rNewPassword.isEmpty())
3393 // when password protection is applied change tracking must always be active
3394 SetChangeRecording( true );
3396 css::uno::Sequence< sal_Int8 > aProtectionHash;
3397 SvPasswordHelper::GetHashPassword( aProtectionHash, rNewPassword );
3398 pChangeTrack->SetProtection( aProtectionHash );
3400 else
3402 pChangeTrack->SetProtection( css::uno::Sequence< sal_Int8 >() );
3405 if ( bProtected != pChangeTrack->IsProtected() )
3407 UpdateAcceptChangesDialog();
3408 SetDocumentModified();
3412 bool ScDocShell::GetProtectionHash( /*out*/ css::uno::Sequence< sal_Int8 > &rPasswordHash )
3414 bool bRes = false;
3415 ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
3416 if (pChangeTrack && pChangeTrack->IsProtected())
3418 rPasswordHash = pChangeTrack->GetProtection();
3419 bRes = true;
3421 return bRes;
3424 void ScDocShell::RegisterAutomationWorkbookObject(css::uno::Reference< ooo::vba::excel::XWorkbook > const& xWorkbook)
3426 mxAutomationWorkbookObject = xWorkbook;
3429 extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportSLK(SvStream &rStream)
3431 ScDLL::Init();
3432 ScDocument aDocument;
3433 ScDocOptions aDocOpt = aDocument.GetDocOptions();
3434 aDocOpt.SetLookUpColRowNames(false);
3435 aDocument.SetDocOptions(aDocOpt);
3436 aDocument.MakeTable(0);
3437 aDocument.EnableExecuteLink(false);
3438 aDocument.SetInsertingFromOtherDoc(true);
3439 aDocument.SetImportingXML(true);
3441 ScImportExport aImpEx(aDocument);
3442 return aImpEx.ImportStream(rStream, OUString(), SotClipboardFormatId::SYLK);
3445 extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportDBF(SvStream &rStream)
3447 ScDLL::Init();
3449 // we need a real file for this filter
3451 // put it in an empty dir
3452 utl::TempFileNamed aTmpDir(nullptr, true);
3453 aTmpDir.EnableKillingFile();
3454 OUString sTmpDir = aTmpDir.GetURL();
3456 utl::TempFileNamed aTempInput(u"", true, u".dbf", &sTmpDir);
3457 aTempInput.EnableKillingFile();
3459 SvStream* pInputStream = aTempInput.GetStream(StreamMode::WRITE);
3460 sal_uInt8 aBuffer[8192];
3461 while (auto nRead = rStream.ReadBytes(aBuffer, SAL_N_ELEMENTS(aBuffer)))
3462 pInputStream->WriteBytes(aBuffer, nRead);
3463 aTempInput.CloseStream();
3465 SfxMedium aMedium(aTempInput.GetURL(), StreamMode::STD_READWRITE);
3467 ScDocShellRef xDocShell = new ScDocShell(SfxModelFlags::EMBEDDED_OBJECT |
3468 SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS |
3469 SfxModelFlags::DISABLE_DOCUMENT_RECOVERY);
3471 xDocShell->DoInitNew();
3473 ScDocument& rDoc = xDocShell->GetDocument();
3475 ScDocOptions aDocOpt = rDoc.GetDocOptions();
3476 aDocOpt.SetLookUpColRowNames(false);
3477 rDoc.SetDocOptions(aDocOpt);
3478 rDoc.MakeTable(0);
3479 rDoc.EnableExecuteLink(false);
3480 rDoc.SetInsertingFromOtherDoc(true);
3482 ScDocRowHeightUpdater::TabRanges aRecalcRanges(0, rDoc.MaxRow());
3483 std::map<SCCOL, ScColWidthParam> aColWidthParam;
3484 ErrCode eError = xDocShell->DBaseImport(aMedium.GetPhysicalName(), RTL_TEXTENCODING_IBM_850, aColWidthParam, aRecalcRanges.maRanges);
3486 xDocShell->DoClose();
3487 xDocShell.clear();
3489 return eError == ERRCODE_NONE;
3492 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */