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