/src/libreoffice/sc/source/ui/docshell/docsh.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
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/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
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 . |
18 | | */ |
19 | | |
20 | | #include <sal/config.h> |
21 | | |
22 | | #include <docsh.hxx> |
23 | | |
24 | | #include <config_features.h> |
25 | | #include <scitems.hxx> |
26 | | #include <sc.hrc> |
27 | | #include <vcl/errinf.hxx> |
28 | | #include <editeng/justifyitem.hxx> |
29 | | #include <comphelper/fileformat.h> |
30 | | #include <comphelper/classids.hxx> |
31 | | #include <comphelper/propertyvalue.hxx> |
32 | | #include <comphelper/sequenceashashmap.hxx> |
33 | | #include <formula/errorcodes.hxx> |
34 | | #include <vcl/stdtext.hxx> |
35 | | #include <vcl/syswin.hxx> |
36 | | #include <vcl/svapp.hxx> |
37 | | #include <vcl/virdev.hxx> |
38 | | #include <vcl/weld/MessageDialog.hxx> |
39 | | #include <vcl/weld/weld.hxx> |
40 | | #include <rtl/bootstrap.hxx> |
41 | | #include <rtl/tencinfo.h> |
42 | | #include <sal/log.hxx> |
43 | | #include <svl/PasswordHelper.hxx> |
44 | | #include <sfx2/app.hxx> |
45 | | #include <sfx2/bindings.hxx> |
46 | | #include <sfx2/dinfdlg.hxx> |
47 | | #include <sfx2/docfile.hxx> |
48 | | #include <sfx2/event.hxx> |
49 | | #include <sfx2/docfilt.hxx> |
50 | | #include <sfx2/lokhelper.hxx> |
51 | | #include <sfx2/objface.hxx> |
52 | | #include <sfx2/viewfrm.hxx> |
53 | | #include <sfx2/infobar.hxx> |
54 | | #include <svl/documentlockfile.hxx> |
55 | | #include <svl/fstathelper.hxx> |
56 | | #include <svl/sharecontrolfile.hxx> |
57 | | #include <svl/urihelper.hxx> |
58 | | #include <osl/file.hxx> |
59 | | #include <chgtrack.hxx> |
60 | | #include <chgviset.hxx> |
61 | | #include <com/sun/star/awt/Key.hpp> |
62 | | #include <com/sun/star/awt/KeyModifier.hpp> |
63 | | #include <com/sun/star/container/XContentEnumerationAccess.hpp> |
64 | | #include <com/sun/star/document/UpdateDocMode.hpp> |
65 | | #include <com/sun/star/script/vba/VBAEventId.hpp> |
66 | | #include <com/sun/star/script/vba/VBAScriptEventId.hpp> |
67 | | #include <com/sun/star/script/vba/XVBAEventProcessor.hpp> |
68 | | #include <com/sun/star/script/vba/XVBAScriptListener.hpp> |
69 | | #include <com/sun/star/script/vba/XVBACompatibility.hpp> |
70 | | #include <com/sun/star/sheet/XSpreadsheetView.hpp> |
71 | | #include <com/sun/star/task/XJob.hpp> |
72 | | #include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp> |
73 | | #include <com/sun/star/ui/XAcceleratorConfiguration.hpp> |
74 | | #include <com/sun/star/util/VetoException.hpp> |
75 | | #include <com/sun/star/lang/XSingleComponentFactory.hpp> |
76 | | #include <ooo/vba/excel/XWorkbook.hpp> |
77 | | #include <comphelper/diagnose_ex.hxx> |
78 | | |
79 | | #include <config_folders.h> |
80 | | |
81 | | #include <scabstdlg.hxx> |
82 | | #include <sot/formats.hxx> |
83 | | #include <svx/compatflags.hxx> |
84 | | #include <svx/dialogs.hrc> |
85 | | #include <svx/svdpagv.hxx> |
86 | | #include <svx/svdpage.hxx> |
87 | | #include <docmodel/theme/Theme.hxx> |
88 | | |
89 | | #include <inputopt.hxx> |
90 | | #include <formulacell.hxx> |
91 | | #include <global.hxx> |
92 | | #include <filter.hxx> |
93 | | #include <scmod.hxx> |
94 | | #include <tabvwsh.hxx> |
95 | | #include <docfunc.hxx> |
96 | | #include <imoptdlg.hxx> |
97 | | #include <impex.hxx> |
98 | | #include <scresid.hxx> |
99 | | #include <strings.hrc> |
100 | | #include <globstr.hrc> |
101 | | #include <scerrors.hxx> |
102 | | #include <brdcst.hxx> |
103 | | #include <stlpool.hxx> |
104 | | #include <autostyl.hxx> |
105 | | #include <attrib.hxx> |
106 | | #include <asciiopt.hxx> |
107 | | #include <progress.hxx> |
108 | | #include <pntlock.hxx> |
109 | | #include <docuno.hxx> |
110 | | #include <appoptio.hxx> |
111 | | #include <formulaopt.hxx> |
112 | | #include <scdll.hxx> |
113 | | #include <detdata.hxx> |
114 | | #include <printfun.hxx> |
115 | | #include <dociter.hxx> |
116 | | #include <cellform.hxx> |
117 | | #include <chartlis.hxx> |
118 | | #include <hints.hxx> |
119 | | #include <xmlwrap.hxx> |
120 | | #include <drwlayer.hxx> |
121 | | #include <dbdata.hxx> |
122 | | #include <scextopt.hxx> |
123 | | #include <compiler.hxx> |
124 | | #include <warnpassword.hxx> |
125 | | #include <sheetdata.hxx> |
126 | | #include <table.hxx> |
127 | | #include <tabprotection.hxx> |
128 | | #include <docparam.hxx> |
129 | | #include "docshimp.hxx" |
130 | | #include <sizedev.hxx> |
131 | | #include <undomanager.hxx> |
132 | | #include <refreshtimerprotector.hxx> |
133 | | |
134 | | #include <officecfg/Office/Calc.hxx> |
135 | | #include <comphelper/processfactory.hxx> |
136 | | #include <comphelper/string.hxx> |
137 | | #include <unotools/configmgr.hxx> |
138 | | #include <unotools/mediadescriptor.hxx> |
139 | | #include <unotools/tempfile.hxx> |
140 | | #include <unotools/ucbstreamhelper.hxx> |
141 | | #include <uiitems.hxx> |
142 | | #include <dpobject.hxx> |
143 | | #include <markdata.hxx> |
144 | | #include <docoptio.hxx> |
145 | | #include <orcusfilters.hxx> |
146 | | #include <datastream.hxx> |
147 | | #include <documentlinkmgr.hxx> |
148 | | #include <refupdatecontext.hxx> |
149 | | #include <DocumentModelAccessor.hxx> |
150 | | |
151 | | #include <memory> |
152 | | #include <vector> |
153 | | |
154 | | #include <comphelper/lok.hxx> |
155 | | #include <svtools/sfxecode.hxx> |
156 | | #include <unotools/pathoptions.hxx> |
157 | | |
158 | | #include <vcl/tabs.hrc> |
159 | | |
160 | | using namespace com::sun::star; |
161 | | using ::com::sun::star::uno::Reference; |
162 | | using ::com::sun::star::lang::XMultiServiceFactory; |
163 | | |
164 | | #define ShellClass_ScDocShell |
165 | | #include <scslots.hxx> |
166 | | |
167 | | SFX_IMPL_INTERFACE(ScDocShell,SfxObjectShell) |
168 | | |
169 | | void ScDocShell::InitInterface_Impl() |
170 | 11 | { |
171 | 11 | } |
172 | | |
173 | | // GlobalName of the current version: |
174 | | SFX_IMPL_OBJECTFACTORY( ScDocShell, SvGlobalName(SO3_SC_CLASSID), u"scalc"_ustr ) |
175 | | |
176 | | |
177 | | void ScDocShell::FillClass( SvGlobalName* pClassName, |
178 | | SotClipboardFormatId* pFormat, |
179 | | OUString* pFullTypeName, |
180 | | sal_Int32 nFileFormat, |
181 | | bool bTemplate /* = false */) const |
182 | 51.3k | { |
183 | 51.3k | if ( nFileFormat == SOFFICE_FILEFORMAT_60 ) |
184 | 0 | { |
185 | 0 | *pClassName = SvGlobalName( SO3_SC_CLASSID_60 ); |
186 | 0 | *pFormat = SotClipboardFormatId::STARCALC_60; |
187 | 0 | *pFullTypeName = ScResId( SCSTR_LONG_SCDOC_NAME_60 ); |
188 | 0 | } |
189 | 51.3k | else if ( nFileFormat == SOFFICE_FILEFORMAT_8 ) |
190 | 51.3k | { |
191 | 51.3k | *pClassName = SvGlobalName( SO3_SC_CLASSID_60 ); |
192 | 51.3k | *pFormat = bTemplate ? SotClipboardFormatId::STARCALC_8_TEMPLATE : SotClipboardFormatId::STARCALC_8; |
193 | 51.3k | *pFullTypeName = ScResId( SCSTR_LONG_SCDOC_NAME_80 ); |
194 | 51.3k | } |
195 | 0 | else |
196 | 0 | { |
197 | 0 | OSL_FAIL("Which version?"); |
198 | 0 | } |
199 | 51.3k | } |
200 | | |
201 | | std::set<Color> ScDocShell::GetDocColors() |
202 | 0 | { |
203 | 0 | return m_pDocument->GetDocColors(); |
204 | 0 | } |
205 | | |
206 | | std::shared_ptr<sfx::IDocumentModelAccessor> ScDocShell::GetDocumentModelAccessor() const |
207 | 0 | { |
208 | 0 | std::shared_ptr<sfx::IDocumentModelAccessor> pReturn; |
209 | 0 | pReturn.reset(new sc::DocumentModelAccessor(m_pDocument)); |
210 | 0 | return pReturn; |
211 | 0 | } |
212 | | |
213 | | std::shared_ptr<model::ColorSet> ScDocShell::GetThemeColors() |
214 | 0 | { |
215 | 0 | ScTabViewShell* pShell = GetBestViewShell(); |
216 | 0 | if (!pShell) |
217 | 0 | return {}; |
218 | | |
219 | 0 | SdrModel* pSdrModel = GetDocument().GetDrawLayer(); |
220 | 0 | if (!pSdrModel) |
221 | 0 | return {}; |
222 | | |
223 | 0 | auto const& pTheme = pSdrModel->getTheme(); |
224 | 0 | if (!pTheme) |
225 | 0 | return {}; |
226 | | |
227 | 0 | return pTheme->getColorSet(); |
228 | 0 | } |
229 | | |
230 | | void ScDocShell::DoEnterHandler() |
231 | 0 | { |
232 | 0 | ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); |
233 | 0 | if (pViewSh && pViewSh->GetViewData().GetDocShell() == this) |
234 | 0 | ScModule::get()->InputEnterHandler(); |
235 | 0 | } |
236 | | |
237 | | SCTAB ScDocShell::GetSaveTab() |
238 | 0 | { |
239 | 0 | SCTAB nTab = 0; |
240 | 0 | ScTabViewShell* pSh = GetBestViewShell(); |
241 | 0 | if (pSh) |
242 | 0 | { |
243 | 0 | const ScMarkData& rMark = pSh->GetViewData().GetMarkData(); |
244 | 0 | nTab = rMark.GetFirstSelected(); |
245 | 0 | } |
246 | 0 | return nTab; |
247 | 0 | } |
248 | | |
249 | | HiddenInformation ScDocShell::GetHiddenInformationState( HiddenInformation nStates ) |
250 | 0 | { |
251 | | // get global state like HiddenInformation::DOCUMENTVERSIONS |
252 | 0 | HiddenInformation nState = SfxObjectShell::GetHiddenInformationState( nStates ); |
253 | |
|
254 | 0 | if ( nStates & HiddenInformation::RECORDEDCHANGES ) |
255 | 0 | { |
256 | 0 | if ( m_pDocument->GetChangeTrack() && m_pDocument->GetChangeTrack()->GetFirst() ) |
257 | 0 | nState |= HiddenInformation::RECORDEDCHANGES; |
258 | 0 | } |
259 | 0 | if ( nStates & HiddenInformation::NOTES ) |
260 | 0 | { |
261 | 0 | SCTAB nTableCount = m_pDocument->GetTableCount(); |
262 | 0 | bool bFound = false; |
263 | 0 | for (SCTAB nTab = 0; nTab < nTableCount && !bFound; ++nTab) |
264 | 0 | { |
265 | 0 | if (m_pDocument->HasTabNotes(nTab)) //TODO: |
266 | 0 | bFound = true; |
267 | 0 | } |
268 | |
|
269 | 0 | if (bFound) |
270 | 0 | nState |= HiddenInformation::NOTES; |
271 | 0 | } |
272 | |
|
273 | 0 | return nState; |
274 | 0 | } |
275 | | |
276 | | void ScDocShell::BeforeXMLLoading() |
277 | 32.5k | { |
278 | 32.5k | m_pDocument->EnableIdle(false); |
279 | | |
280 | | // prevent unnecessary broadcasts and updates |
281 | 32.5k | OSL_ENSURE(m_pModificator == nullptr, "The Modificator should not exist"); |
282 | 32.5k | m_pModificator.reset( new ScDocShellModificator( *this ) ); |
283 | | |
284 | 32.5k | m_pDocument->SetImportingXML( true ); |
285 | 32.5k | m_pDocument->EnableExecuteLink( false ); // #i101304# to be safe, prevent nested loading from external references |
286 | 32.5k | m_pDocument->EnableUndo( false ); |
287 | | // prevent unnecessary broadcasts and "half way listeners" |
288 | 32.5k | m_pDocument->SetInsertingFromOtherDoc( true ); |
289 | 32.5k | } |
290 | | |
291 | | void ScDocShell::AfterXMLLoading(bool bRet) |
292 | 8.40k | { |
293 | 8.40k | if (GetCreateMode() != SfxObjectCreateMode::ORGANIZER) |
294 | 8.40k | { |
295 | 8.40k | UpdateLinks(); |
296 | | // don't prevent establishing of listeners anymore |
297 | 8.40k | m_pDocument->SetInsertingFromOtherDoc( false ); |
298 | 8.40k | if ( bRet ) |
299 | 8.40k | { |
300 | 8.40k | ScChartListenerCollection* pChartListener = m_pDocument->GetChartListenerCollection(); |
301 | 8.40k | if (pChartListener) |
302 | 8.40k | pChartListener->UpdateDirtyCharts(); |
303 | | |
304 | | // #95582#; set the table names of linked tables to the new path |
305 | 8.40k | SCTAB nTabCount = m_pDocument->GetTableCount(); |
306 | 18.2k | for (SCTAB i = 0; i < nTabCount; ++i) |
307 | 9.89k | { |
308 | 9.89k | if (m_pDocument->IsLinked( i )) |
309 | 0 | { |
310 | 0 | OUString aName; |
311 | 0 | m_pDocument->GetName(i, aName); |
312 | 0 | OUString aLinkTabName = m_pDocument->GetLinkTab(i); |
313 | 0 | sal_Int32 nLinkTabNameLength = aLinkTabName.getLength(); |
314 | 0 | sal_Int32 nNameLength = aName.getLength(); |
315 | 0 | if (nLinkTabNameLength < nNameLength) |
316 | 0 | { |
317 | | |
318 | | // remove the quotes on begin and end of the docname and restore the escaped quotes |
319 | 0 | const sal_Unicode* pNameBuffer = aName.getStr(); |
320 | 0 | if ( *pNameBuffer == '\'' && // all docnames have to have a ' character on the first pos |
321 | 0 | ScGlobal::UnicodeStrChr( pNameBuffer, SC_COMPILER_FILE_TAB_SEP ) ) |
322 | 0 | { |
323 | 0 | OUStringBuffer aDocURLBuffer; |
324 | 0 | bool bQuote = true; // Document name is always quoted |
325 | 0 | ++pNameBuffer; |
326 | 0 | while ( bQuote && *pNameBuffer ) |
327 | 0 | { |
328 | 0 | if ( *pNameBuffer == '\'' && *(pNameBuffer-1) != '\\' ) |
329 | 0 | bQuote = false; |
330 | 0 | else if( *pNameBuffer != '\\' || *(pNameBuffer+1) != '\'' ) |
331 | 0 | aDocURLBuffer.append(*pNameBuffer); // If escaped quote: only quote in the name |
332 | 0 | ++pNameBuffer; |
333 | 0 | } |
334 | |
|
335 | 0 | if( *pNameBuffer == SC_COMPILER_FILE_TAB_SEP ) // after the last quote of the docname should be the # char |
336 | 0 | { |
337 | 0 | sal_Int32 nIndex = nNameLength - nLinkTabNameLength; |
338 | 0 | INetURLObject aINetURLObject(aDocURLBuffer); |
339 | 0 | if(aName.match( aLinkTabName, nIndex) && |
340 | 0 | (aName[nIndex - 1] == '#') && // before the table name should be the # char |
341 | 0 | !aINetURLObject.HasError()) // the docname should be a valid URL |
342 | 0 | { |
343 | 0 | aName = ScGlobal::GetDocTabName( m_pDocument->GetLinkDoc( i ), m_pDocument->GetLinkTab( i ) ); |
344 | 0 | m_pDocument->RenameTab(i, aName, true/*bExternalDocument*/); |
345 | 0 | } |
346 | | // else; nothing has to happen, because it is a user given name |
347 | 0 | } |
348 | | // else; nothing has to happen, because it is a user given name |
349 | 0 | } |
350 | | // else; nothing has to happen, because it is a user given name |
351 | 0 | } |
352 | | // else; nothing has to happen, because it is a user given name |
353 | 0 | } |
354 | 9.89k | } |
355 | | |
356 | | // #i94570# DataPilot table names have to be unique, or the tables can't be accessed by API. |
357 | | // If no name (or an invalid name, skipped in ScXMLDataPilotTableContext::EndElement) was set, create a new name. |
358 | 8.40k | ScDPCollection* pDPCollection = m_pDocument->GetDPCollection(); |
359 | 8.40k | if ( pDPCollection ) |
360 | 8.40k | { |
361 | 8.40k | size_t nDPCount = pDPCollection->GetCount(); |
362 | 8.40k | for (size_t nDP=0; nDP<nDPCount; ++nDP) |
363 | 0 | { |
364 | 0 | ScDPObject& rDPObj = (*pDPCollection)[nDP]; |
365 | 0 | if (rDPObj.GetName().isEmpty()) |
366 | 0 | rDPObj.SetName( pDPCollection->CreateNewName() ); |
367 | 0 | } |
368 | 8.40k | } |
369 | 8.40k | } |
370 | 8.40k | } |
371 | 0 | else |
372 | 0 | m_pDocument->SetInsertingFromOtherDoc( false ); |
373 | | |
374 | 8.40k | m_pDocument->SetImportingXML( false ); |
375 | 8.40k | m_pDocument->EnableExecuteLink( true ); |
376 | 8.40k | m_pDocument->EnableUndo( true ); |
377 | 8.40k | m_bIsEmpty = false; |
378 | | |
379 | 8.40k | if (m_pModificator) |
380 | 8.40k | { |
381 | 8.40k | ScDocument::HardRecalcState eRecalcState = m_pDocument->GetHardRecalcState(); |
382 | | // Temporarily set hard-recalc to prevent calling |
383 | | // ScFormulaCell::Notify() during destruction of the Modificator which |
384 | | // will set the cells dirty. |
385 | 8.40k | if (eRecalcState == ScDocument::HardRecalcState::OFF) |
386 | 8.40k | m_pDocument->SetHardRecalcState(ScDocument::HardRecalcState::TEMPORARY); |
387 | 8.40k | m_pModificator.reset(); |
388 | 8.40k | m_pDocument->SetHardRecalcState(eRecalcState); |
389 | 8.40k | } |
390 | 0 | else |
391 | 0 | { |
392 | 0 | OSL_FAIL("The Modificator should exist"); |
393 | 0 | } |
394 | | |
395 | 8.40k | m_pDocument->EnableIdle(true); |
396 | 8.40k | } |
397 | | |
398 | | namespace { |
399 | | |
400 | | class LoadMediumGuard |
401 | | { |
402 | | public: |
403 | | explicit LoadMediumGuard(ScDocument* pDoc) : |
404 | 0 | mpDoc(pDoc) |
405 | 0 | { |
406 | 0 | mpDoc->SetLoadingMedium(true); |
407 | 0 | } |
408 | | |
409 | | ~LoadMediumGuard() |
410 | 0 | { |
411 | 0 | mpDoc->SetLoadingMedium(false); |
412 | 0 | } |
413 | | private: |
414 | | ScDocument* mpDoc; |
415 | | }; |
416 | | |
417 | | void processDataStream( ScDocShell& rShell, const sc::ImportPostProcessData& rData ) |
418 | 0 | { |
419 | 0 | if (!rData.mpDataStream) |
420 | 0 | return; |
421 | | |
422 | 0 | const sc::ImportPostProcessData::DataStream& r = *rData.mpDataStream; |
423 | 0 | if (!r.maRange.IsValid()) |
424 | 0 | return; |
425 | | |
426 | | // Break the streamed range into the top range and the height limit. A |
427 | | // height limit of 0 means unlimited i.e. the streamed data will go all |
428 | | // the way to the last row. |
429 | | |
430 | 0 | ScRange aTopRange = r.maRange; |
431 | 0 | aTopRange.aEnd.SetRow(aTopRange.aStart.Row()); |
432 | 0 | sal_Int32 nLimit = r.maRange.aEnd.Row() - r.maRange.aStart.Row() + 1; |
433 | 0 | if (r.maRange.aEnd.Row() == rShell.GetDocument().MaxRow()) |
434 | | // Unlimited range. |
435 | 0 | nLimit = 0; |
436 | |
|
437 | 0 | sc::DataStream::MoveType eMove = |
438 | 0 | r.meInsertPos == sc::ImportPostProcessData::DataStream::InsertTop ? |
439 | 0 | sc::DataStream::MOVE_DOWN : sc::DataStream::RANGE_DOWN; |
440 | |
|
441 | 0 | sc::DataStream* pStrm = new sc::DataStream(&rShell, r.maURL, aTopRange, nLimit, eMove); |
442 | 0 | pStrm->SetRefreshOnEmptyLine(r.mbRefreshOnEmpty); |
443 | 0 | sc::DocumentLinkManager& rMgr = rShell.GetDocument().GetDocLinkManager(); |
444 | 0 | rMgr.setDataStream(pStrm); |
445 | 0 | } |
446 | | |
447 | | class MessageWithCheck : public weld::MessageDialogController |
448 | | { |
449 | | private: |
450 | | std::unique_ptr<weld::CheckButton> m_xWarningOnBox; |
451 | | public: |
452 | | MessageWithCheck(weld::Window *pParent, const OUString& rUIFile, const OUString& rDialogId) |
453 | 0 | : MessageDialogController(pParent, rUIFile, rDialogId, u"ask"_ustr) |
454 | 0 | , m_xWarningOnBox(m_xBuilder->weld_check_button(u"ask"_ustr)) |
455 | 0 | { |
456 | 0 | } |
457 | 0 | bool get_active() const { return m_xWarningOnBox->get_active(); } |
458 | 0 | void hide_ask() const { m_xWarningOnBox->set_visible(false); }; |
459 | | }; |
460 | | |
461 | | #if HAVE_FEATURE_SCRIPTING |
462 | | class VBAScriptListener : public ::cppu::WeakImplHelper< css::script::vba::XVBAScriptListener > |
463 | | { |
464 | | private: |
465 | | ScDocShell* m_pDocSh; |
466 | | public: |
467 | | VBAScriptListener(ScDocShell* pDocSh) : m_pDocSh(pDocSh) |
468 | | { |
469 | | } |
470 | | |
471 | | // XVBAScriptListener |
472 | | virtual void SAL_CALL notifyVBAScriptEvent( const ::css::script::vba::VBAScriptEvent& aEvent ) override |
473 | | { |
474 | | if (aEvent.Identifier == script::vba::VBAScriptEventId::SCRIPT_STOPPED && |
475 | | m_pDocSh->GetClipData().is()) |
476 | | { |
477 | | m_pDocSh->SetClipData(uno::Reference<datatransfer::XTransferable2>()); |
478 | | } |
479 | | } |
480 | | |
481 | | // XEventListener |
482 | | virtual void SAL_CALL disposing( const ::css::lang::EventObject& /*Source*/ ) override |
483 | | { |
484 | | } |
485 | | }; |
486 | | #endif |
487 | | |
488 | | } |
489 | | |
490 | | bool ScDocShell::GetRecalcRowHeightsMode() |
491 | 10.8k | { |
492 | 10.8k | const ScRecalcOptions nRecalcMode = static_cast<ScRecalcOptions>( |
493 | 10.8k | officecfg::Office::Calc::Formula::Load::RecalcOptimalRowHeightMode::get()); |
494 | | |
495 | 10.8k | bool bHardRecalc = false; |
496 | 10.8k | switch (nRecalcMode) |
497 | 10.8k | { |
498 | 0 | case RECALC_ASK: |
499 | 0 | { |
500 | 0 | if (m_pDocument->IsUserInteractionEnabled()) |
501 | 0 | { |
502 | | // Ask if the user wants to perform full re-calculation. |
503 | 0 | MessageWithCheck aQueryBox(ScDocShell::GetActiveDialogParent(), |
504 | 0 | u"modules/scalc/ui/recalcquerydialog.ui"_ustr, |
505 | 0 | u"RecalcQueryDialog"_ustr); |
506 | 0 | aQueryBox.set_primary_text(ScResId(STR_QUERY_OPT_ROW_HEIGHT_RECALC_ONLOAD)); |
507 | 0 | aQueryBox.set_default_response(RET_YES); |
508 | |
|
509 | 0 | if (officecfg::Office::Calc::Formula::Load::RecalcOptimalRowHeightMode::isReadOnly()) |
510 | 0 | aQueryBox.hide_ask(); |
511 | |
|
512 | 0 | bHardRecalc = aQueryBox.run() == RET_YES; |
513 | |
|
514 | 0 | if (aQueryBox.get_active()) |
515 | 0 | { |
516 | | // Always perform selected action in the future. |
517 | 0 | std::shared_ptr<comphelper::ConfigurationChanges> batch( |
518 | 0 | comphelper::ConfigurationChanges::create()); |
519 | 0 | officecfg::Office::Calc::Formula::Load::RecalcOptimalRowHeightMode::set( |
520 | 0 | bHardRecalc ? static_cast<sal_Int32>(RECALC_ALWAYS) |
521 | 0 | : static_cast<sal_Int32>(RECALC_NEVER), |
522 | 0 | batch); |
523 | |
|
524 | 0 | ScModule* mod = ScModule::get(); |
525 | 0 | ScFormulaOptions aOpt = mod->GetFormulaOptions(); |
526 | 0 | aOpt.SetReCalcOptiRowHeights(bHardRecalc ? RECALC_ALWAYS : RECALC_NEVER); |
527 | 0 | mod->SetFormulaOptions(aOpt); |
528 | |
|
529 | 0 | batch->commit(); |
530 | 0 | } |
531 | 0 | } |
532 | 0 | } |
533 | 0 | break; |
534 | 10.8k | case RECALC_ALWAYS: |
535 | 10.8k | bHardRecalc = true; |
536 | 10.8k | break; |
537 | 0 | case RECALC_NEVER: |
538 | 0 | bHardRecalc = false; |
539 | 0 | break; |
540 | 0 | default: |
541 | 0 | SAL_WARN("sc", "unknown optimal row height recalc option!"); |
542 | 10.8k | } |
543 | | |
544 | 10.8k | return bHardRecalc; |
545 | 10.8k | } |
546 | | |
547 | | bool ScDocShell::ImportFrom(SfxMedium& rMedium, |
548 | | const css::uno::Reference<css::text::XTextRange>& xInsertPosition) |
549 | 0 | { |
550 | 0 | LoadMediumGuard aLoadGuard(m_pDocument.get()); |
551 | 0 | return SfxObjectShell::ImportFrom(rMedium, xInsertPosition); |
552 | 0 | } |
553 | | |
554 | | bool ScDocShell::LoadXML( SfxMedium* pLoadMedium, const css::uno::Reference< css::embed::XStorage >& xStor ) |
555 | 0 | { |
556 | 0 | LoadMediumGuard aLoadGuard(m_pDocument.get()); |
557 | | |
558 | | // MacroCallMode is no longer needed, state is kept in SfxObjectShell now |
559 | | |
560 | | // no Seek(0) here - always loading from storage, GetInStream must not be called |
561 | |
|
562 | 0 | BeforeXMLLoading(); |
563 | |
|
564 | 0 | ScXMLImportWrapper aImport(*this, pLoadMedium, xStor); |
565 | |
|
566 | 0 | bool bRet = false; |
567 | 0 | ErrCodeMsg nError = ERRCODE_NONE; |
568 | 0 | m_pDocument->LockAdjustHeight(); |
569 | 0 | if (GetCreateMode() == SfxObjectCreateMode::ORGANIZER) |
570 | 0 | bRet = aImport.Import(ImportFlags::Styles, nError); |
571 | 0 | else |
572 | 0 | bRet = aImport.Import(ImportFlags::All, nError); |
573 | |
|
574 | 0 | if ( nError ) |
575 | 0 | pLoadMedium->SetError(nError); |
576 | |
|
577 | 0 | processDataStream(*this, aImport.GetImportPostProcessData()); |
578 | | |
579 | | //if the document was not generated by LibreOffice, do hard recalc in case some other document |
580 | | //generator saved cached formula results that differ from LibreOffice's calculated results or |
581 | | //did not use cached formula results. |
582 | 0 | uno::Reference<document::XDocumentProperties> xDocProps = GetModel()->getDocumentProperties(); |
583 | |
|
584 | 0 | ScRecalcOptions nRecalcMode = |
585 | 0 | static_cast<ScRecalcOptions>(officecfg::Office::Calc::Formula::Load::ODFRecalcMode::get()); |
586 | |
|
587 | 0 | bool bHardRecalc = false; |
588 | 0 | if (nRecalcMode == RECALC_ASK) |
589 | 0 | { |
590 | 0 | OUString sProductName(utl::ConfigManager::getProductName()); |
591 | 0 | if (m_pDocument->IsUserInteractionEnabled() && xDocProps->getGenerator().indexOf(sProductName) == -1) |
592 | 0 | { |
593 | | // Generator is not LibreOffice. Ask if the user wants to perform |
594 | | // full re-calculation. |
595 | 0 | MessageWithCheck aQueryBox(GetActiveDialogParent(), |
596 | 0 | u"modules/scalc/ui/recalcquerydialog.ui"_ustr, u"RecalcQueryDialog"_ustr); |
597 | 0 | aQueryBox.set_primary_text(ScResId(STR_QUERY_FORMULA_RECALC_ONLOAD_ODS)); |
598 | 0 | aQueryBox.set_default_response(RET_YES); |
599 | |
|
600 | 0 | if ( officecfg::Office::Calc::Formula::Load::OOXMLRecalcMode::isReadOnly() ) |
601 | 0 | aQueryBox.hide_ask(); |
602 | |
|
603 | 0 | bHardRecalc = aQueryBox.run() == RET_YES; |
604 | |
|
605 | 0 | if (aQueryBox.get_active()) |
606 | 0 | { |
607 | | // Always perform selected action in the future. |
608 | 0 | std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create()); |
609 | 0 | officecfg::Office::Calc::Formula::Load::ODFRecalcMode::set(sal_Int32(0), batch); |
610 | 0 | ScModule* mod = ScModule::get(); |
611 | 0 | ScFormulaOptions aOpt = mod->GetFormulaOptions(); |
612 | 0 | aOpt.SetODFRecalcOptions(bHardRecalc ? RECALC_ALWAYS : RECALC_NEVER); |
613 | | /* XXX is this really supposed to set the ScModule options? |
614 | | * Not the ScDocShell options? */ |
615 | 0 | mod->SetFormulaOptions(aOpt); |
616 | |
|
617 | 0 | batch->commit(); |
618 | 0 | } |
619 | 0 | } |
620 | 0 | } |
621 | 0 | else if (nRecalcMode == RECALC_ALWAYS) |
622 | 0 | bHardRecalc = true; |
623 | |
|
624 | 0 | if (bHardRecalc) |
625 | 0 | DoHardRecalc(); |
626 | 0 | else |
627 | 0 | { |
628 | | // still need to recalc volatile formula cells. |
629 | 0 | m_pDocument->Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS)); |
630 | 0 | } |
631 | |
|
632 | 0 | AfterXMLLoading(bRet); |
633 | |
|
634 | 0 | m_pDocument->UnlockAdjustHeight(); |
635 | 0 | return bRet; |
636 | 0 | } |
637 | | |
638 | | bool ScDocShell::SaveXML( SfxMedium* pSaveMedium, const css::uno::Reference< css::embed::XStorage >& xStor ) |
639 | 0 | { |
640 | 0 | m_pDocument->EnableIdle(false); |
641 | |
|
642 | 0 | ScXMLImportWrapper aImport(*this, pSaveMedium, xStor); |
643 | 0 | bool bRet(false); |
644 | 0 | if (GetCreateMode() != SfxObjectCreateMode::ORGANIZER) |
645 | 0 | bRet = aImport.Export(false); |
646 | 0 | else |
647 | 0 | bRet = aImport.Export(true); |
648 | |
|
649 | 0 | m_pDocument->EnableIdle(true); |
650 | |
|
651 | 0 | return bRet; |
652 | 0 | } |
653 | | |
654 | | bool ScDocShell::Load( SfxMedium& rMedium ) |
655 | 0 | { |
656 | 0 | LoadMediumGuard aLoadGuard(m_pDocument.get()); |
657 | 0 | ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() ); |
658 | | |
659 | | // only the latin script language is loaded |
660 | | // -> initialize the others from options (before loading) |
661 | 0 | InitOptions(true); |
662 | | |
663 | | // If this is an ODF file being loaded, then by default, use legacy processing |
664 | | // (if required, it will be overridden in *::ReadUserDataSequence()) |
665 | 0 | if (IsOwnStorageFormat(rMedium)) |
666 | 0 | { |
667 | 0 | if (ScDrawLayer* pDrawLayer = m_pDocument->GetDrawLayer()) |
668 | 0 | { |
669 | 0 | pDrawLayer->SetCompatibilityFlag(SdrCompatibilityFlag::AnchoredTextOverflowLegacy, |
670 | 0 | true); // for tdf#99729 |
671 | 0 | pDrawLayer->SetCompatibilityFlag(SdrCompatibilityFlag::LegacyFontwork, |
672 | 0 | true); // for tdf#148000 |
673 | 0 | } |
674 | 0 | } |
675 | |
|
676 | 0 | GetUndoManager()->Clear(); |
677 | |
|
678 | 0 | bool bRet = SfxObjectShell::Load(rMedium); |
679 | 0 | if (bRet) |
680 | 0 | { |
681 | 0 | SetInitialLinkUpdate(&rMedium); |
682 | |
|
683 | 0 | { |
684 | | // prepare a valid document for XML filter |
685 | | // (for ConvertFrom, InitNew is called before) |
686 | 0 | m_pDocument->MakeTable(0); |
687 | 0 | m_pDocument->GetStyleSheetPool()->CreateStandardStyles(); |
688 | 0 | m_pDocument->getCellAttributeHelper().UpdateAllStyleSheets(*m_pDocument); |
689 | | |
690 | | /* Create styles that are imported through Orcus */ |
691 | |
|
692 | 0 | OUString aURL(u"$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/calc/styles.xml"_ustr); |
693 | 0 | rtl::Bootstrap::expandMacros(aURL); |
694 | |
|
695 | 0 | OUString aPath; |
696 | 0 | osl::FileBase::getSystemPathFromFileURL(aURL, aPath); |
697 | |
|
698 | 0 | ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters(); |
699 | |
|
700 | 0 | if (pOrcus) |
701 | 0 | { |
702 | 0 | pOrcus->importODS_Styles(*m_pDocument, aPath); |
703 | 0 | m_pDocument->GetStyleSheetPool()->setAllParaStandard(); |
704 | 0 | } |
705 | |
|
706 | 0 | bRet = LoadXML( &rMedium, nullptr ); |
707 | 0 | } |
708 | 0 | } |
709 | |
|
710 | 0 | if (!bRet && !rMedium.GetErrorIgnoreWarning()) |
711 | 0 | rMedium.SetError(SVSTREAM_FILEFORMAT_ERROR); |
712 | |
|
713 | 0 | if (rMedium.GetErrorIgnoreWarning()) |
714 | 0 | SetError(rMedium.GetErrorIgnoreWarning()); |
715 | |
|
716 | 0 | InitItems(); |
717 | 0 | CalcOutputFactor(); |
718 | | |
719 | | // invalidate eventually temporary table areas |
720 | 0 | if ( bRet ) |
721 | 0 | m_pDocument->InvalidateTableArea(); |
722 | |
|
723 | 0 | m_bIsEmpty = false; |
724 | 0 | FinishedLoading(); |
725 | 0 | return bRet; |
726 | 0 | } |
727 | | |
728 | | void ScDocShell::Notify( SfxBroadcaster&, const SfxHint& rHint ) |
729 | 487k | { |
730 | 487k | if (rHint.GetId() == SfxHintId::ScTables) |
731 | 4.88k | { |
732 | 4.88k | const ScTablesHint* pScHint = static_cast< const ScTablesHint* >( &rHint ); |
733 | 4.88k | if (pScHint->GetTablesHintId() == SC_TAB_INSERTED) |
734 | 4.88k | { |
735 | 4.88k | uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents = m_pDocument->GetVbaEventProcessor(); |
736 | 4.88k | if ( xVbaEvents.is() ) try |
737 | 0 | { |
738 | 0 | uno::Sequence< uno::Any > aArgs{ uno::Any(pScHint->GetTab1()) }; |
739 | 0 | xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKBOOK_NEWSHEET, aArgs ); |
740 | 0 | } |
741 | 0 | catch( uno::Exception& ) |
742 | 0 | { |
743 | 0 | } |
744 | 4.88k | } |
745 | 4.88k | } |
746 | | |
747 | 487k | if ( auto pStyleSheetHint = dynamic_cast<const SfxStyleSheetHint*>(&rHint) ) // Template changed |
748 | 65.1k | NotifyStyle( *pStyleSheetHint ); |
749 | 422k | else if ( rHint.GetId() == SfxHintId::ScAutoStyle ) |
750 | 0 | { |
751 | 0 | auto pStlHint = static_cast<const ScAutoStyleHint*>(&rHint); |
752 | | //! direct call for AutoStyles |
753 | | |
754 | | // this is called synchronously from ScInterpreter::ScStyle, |
755 | | // modifying the document must be asynchronous |
756 | | // (handled by AddInitial) |
757 | |
|
758 | 0 | const ScRange& aRange = pStlHint->GetRange(); |
759 | 0 | const OUString& aName1 = pStlHint->GetStyle1(); |
760 | 0 | const OUString& aName2 = pStlHint->GetStyle2(); |
761 | 0 | sal_uInt32 nTimeout = pStlHint->GetTimeout(); |
762 | |
|
763 | 0 | if (!m_pAutoStyleList) |
764 | 0 | m_pAutoStyleList.reset( new ScAutoStyleList(this) ); |
765 | 0 | m_pAutoStyleList->AddInitial( aRange, aName1, nTimeout, aName2 ); |
766 | 0 | } |
767 | 422k | else if (rHint.GetId() == SfxHintId::ThisIsAnSfxEventHint) |
768 | 4.14k | { |
769 | 4.14k | switch (static_cast<const SfxEventHint&>(rHint).GetEventId()) |
770 | 4.14k | { |
771 | 0 | case SfxEventHintId::LoadFinished: |
772 | 0 | { |
773 | | #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT |
774 | | // the readonly documents should not be opened in shared mode |
775 | | if ( HasSharedXMLFlagSet() && !ScModule::get()->IsInSharedDocLoading() && !IsReadOnly() ) |
776 | | { |
777 | | if ( SwitchToShared( true, false ) ) |
778 | | { |
779 | | ScViewData* pViewData = GetViewData(); |
780 | | ScTabView* pTabView = ( pViewData ? pViewData->GetView() : nullptr ); |
781 | | if ( pTabView ) |
782 | | { |
783 | | pTabView->UpdateLayerLocks(); |
784 | | } |
785 | | } |
786 | | else |
787 | | { |
788 | | // switching to shared mode has failed, the document should be opened readonly |
789 | | // TODO/LATER: And error message should be shown here probably |
790 | | SetReadOnlyUI(); |
791 | | } |
792 | | } |
793 | | #endif |
794 | 0 | } |
795 | 0 | break; |
796 | 0 | case SfxEventHintId::ViewCreated: |
797 | 0 | { |
798 | | #if HAVE_FEATURE_SCRIPTING |
799 | | uno::Reference<script::vba::XVBACompatibility> xVBACompat(GetBasicContainer(), uno::UNO_QUERY); |
800 | | if ( !m_xVBAListener.is() && xVBACompat.is() ) |
801 | | { |
802 | | m_xVBAListener.set(new VBAScriptListener(this)); |
803 | | xVBACompat->addVBAScriptListener(m_xVBAListener); |
804 | | } |
805 | | #endif |
806 | |
|
807 | | #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT |
808 | | if (ScModule* mod = ScModule::get(); IsDocShared() && !mod->IsInSharedDocLoading() |
809 | | && !comphelper::LibreOfficeKit::isActive() ) |
810 | | { |
811 | | ScAppOptions aAppOptions = mod->GetAppOptions(); |
812 | | if ( aAppOptions.GetShowSharedDocumentWarning() ) |
813 | | { |
814 | | MessageWithCheck aWarningBox(ScDocShell::GetActiveDialogParent(), |
815 | | u"modules/scalc/ui/sharedwarningdialog.ui"_ustr, u"SharedWarningDialog"_ustr); |
816 | | aWarningBox.run(); |
817 | | |
818 | | bool bChecked = aWarningBox.get_active(); |
819 | | if (bChecked) |
820 | | { |
821 | | aAppOptions.SetShowSharedDocumentWarning(false); |
822 | | mod->SetAppOptions(aAppOptions); |
823 | | } |
824 | | } |
825 | | } |
826 | | #endif |
827 | |
|
828 | 0 | ScViewData* pViewData = GetViewData(); |
829 | 0 | if (!pViewData) |
830 | 0 | break; |
831 | 0 | SfxViewShell* pViewShell = pViewData->GetViewShell(); |
832 | 0 | if (!pViewShell) |
833 | 0 | break; |
834 | 0 | SfxViewFrame* pViewFrame = &pViewShell->GetViewFrame(); |
835 | 0 | if (!pViewFrame) |
836 | 0 | break; |
837 | 0 | SfxFrame* pFrame = &pViewFrame->GetFrame(); |
838 | |
|
839 | 0 | try |
840 | 0 | { |
841 | 0 | const uno::Reference< uno::XComponentContext >& xContext( |
842 | 0 | comphelper::getProcessComponentContext() ); |
843 | 0 | uno::Reference< lang::XMultiServiceFactory > xServiceManager( |
844 | 0 | xContext->getServiceManager(), |
845 | 0 | uno::UNO_QUERY_THROW ); |
846 | 0 | uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xServiceManager, uno::UNO_QUERY_THROW ); |
847 | 0 | uno::Reference< container::XEnumeration> xEnum = xEnumAccess->createContentEnumeration( |
848 | 0 | u"com.sun.star.sheet.SpreadsheetDocumentJob"_ustr ); |
849 | 0 | if ( xEnum.is() ) |
850 | 0 | { |
851 | 0 | while ( xEnum->hasMoreElements() ) |
852 | 0 | { |
853 | 0 | uno::Any aAny = xEnum->nextElement(); |
854 | 0 | uno::Reference< lang::XSingleComponentFactory > xFactory; |
855 | 0 | aAny >>= xFactory; |
856 | 0 | if ( xFactory.is() ) |
857 | 0 | { |
858 | 0 | uno::Reference< task::XJob > xJob( xFactory->createInstanceWithContext( xContext ), uno::UNO_QUERY_THROW ); |
859 | 0 | uno::Reference< frame::XController > xController = pFrame->GetController(); |
860 | 0 | uno::Reference< sheet::XSpreadsheetView > xSpreadsheetView( xController, uno::UNO_QUERY_THROW ); |
861 | 0 | uno::Sequence< beans::NamedValue > aArgsForJob { { u"SpreadsheetView"_ustr, uno::Any( xSpreadsheetView ) } }; |
862 | 0 | xJob->execute( aArgsForJob ); |
863 | 0 | } |
864 | 0 | } |
865 | 0 | } |
866 | 0 | } |
867 | 0 | catch ( uno::Exception & ) |
868 | 0 | { |
869 | 0 | } |
870 | | |
871 | | // Show delayed infobar entries |
872 | 0 | for (auto const& r : m_pImpl->mpDelayedInfobarEntry) |
873 | 0 | { |
874 | 0 | pViewFrame->AppendInfoBar(r.msId, r.msPrimaryMessage, r.msSecondaryMessage, r.maInfobarType, r.mbShowCloseButton); |
875 | 0 | } |
876 | 0 | m_pImpl->mpDelayedInfobarEntry.clear(); |
877 | 0 | } |
878 | 0 | break; |
879 | 0 | case SfxEventHintId::SaveDoc: |
880 | 0 | { |
881 | | #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT |
882 | | if (ScModule* mod = ScModule::get(); IsDocShared() && !mod->IsInSharedDocSaving()) |
883 | | { |
884 | | bool bSuccess = false; |
885 | | bool bRetry = true; |
886 | | while ( bRetry ) |
887 | | { |
888 | | bRetry = false; |
889 | | uno::Reference< frame::XModel > xModel; |
890 | | try |
891 | | { |
892 | | // load shared file |
893 | | xModel.set( LoadSharedDocument(), uno::UNO_SET_THROW ); |
894 | | uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY_THROW ); |
895 | | |
896 | | // check if shared flag is set in shared file |
897 | | bool bShared = false; |
898 | | ScModelObj* pDocObj = comphelper::getFromUnoTunnel<ScModelObj>( xModel ); |
899 | | ScDocShell* pSharedDocShell = ( pDocObj ? dynamic_cast< ScDocShell* >( pDocObj->GetObjectShell() ) : nullptr ); |
900 | | if ( pSharedDocShell ) |
901 | | { |
902 | | bShared = pSharedDocShell->HasSharedXMLFlagSet(); |
903 | | } |
904 | | |
905 | | // #i87870# check if shared status was disabled and enabled again |
906 | | bool bOwnEntry = false; |
907 | | bool bEntriesNotAccessible = false; |
908 | | try |
909 | | { |
910 | | ::svt::ShareControlFile aControlFile( GetSharedFileURL() ); |
911 | | bOwnEntry = aControlFile.HasOwnEntry(); |
912 | | } |
913 | | catch ( uno::Exception& ) |
914 | | { |
915 | | bEntriesNotAccessible = true; |
916 | | } |
917 | | |
918 | | if ( bShared && bOwnEntry ) |
919 | | { |
920 | | uno::Reference< frame::XStorable > xStorable( xModel, uno::UNO_QUERY_THROW ); |
921 | | |
922 | | if ( xStorable->isReadonly() ) |
923 | | { |
924 | | xCloseable->close( true ); |
925 | | |
926 | | OUString aUserName( ScResId( STR_UNKNOWN_USER ) ); |
927 | | bool bNoLockAccess = false; |
928 | | try |
929 | | { |
930 | | ::svt::DocumentLockFile aLockFile( GetSharedFileURL() ); |
931 | | LockFileEntry aData = aLockFile.GetLockData(); |
932 | | if ( !aData[LockFileComponent::OOOUSERNAME].isEmpty() ) |
933 | | { |
934 | | aUserName = aData[LockFileComponent::OOOUSERNAME]; |
935 | | } |
936 | | else if ( !aData[LockFileComponent::SYSUSERNAME].isEmpty() ) |
937 | | { |
938 | | aUserName = aData[LockFileComponent::SYSUSERNAME]; |
939 | | } |
940 | | } |
941 | | catch ( uno::Exception& ) |
942 | | { |
943 | | bNoLockAccess = true; |
944 | | } |
945 | | |
946 | | if ( bNoLockAccess ) |
947 | | { |
948 | | // TODO/LATER: in future an error regarding impossibility to open file for writing could be shown |
949 | | ErrorHandler::HandleError( ERRCODE_IO_GENERAL ); |
950 | | } |
951 | | else |
952 | | { |
953 | | OUString aMessage( ScResId( STR_FILE_LOCKED_SAVE_LATER ) ); |
954 | | aMessage = aMessage.replaceFirst( "%1", aUserName ); |
955 | | |
956 | | std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(), |
957 | | VclMessageType::Warning, VclButtonsType::NONE, |
958 | | aMessage)); |
959 | | xWarn->add_button(GetStandardText(StandardButtonType::Retry), RET_RETRY); |
960 | | xWarn->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL); |
961 | | xWarn->set_default_response(RET_RETRY); |
962 | | if (xWarn->run() == RET_RETRY) |
963 | | { |
964 | | bRetry = true; |
965 | | } |
966 | | } |
967 | | } |
968 | | else |
969 | | { |
970 | | // merge changes from shared file into temp file |
971 | | bool bSaveToShared = false; |
972 | | if ( pSharedDocShell ) |
973 | | { |
974 | | bSaveToShared = MergeSharedDocument( pSharedDocShell ); |
975 | | } |
976 | | |
977 | | // close shared file |
978 | | xCloseable->close( true ); |
979 | | |
980 | | // TODO: keep file lock on shared file |
981 | | |
982 | | // store to shared file |
983 | | if ( bSaveToShared ) |
984 | | { |
985 | | bool bChangedViewSettings = false; |
986 | | ScChangeViewSettings* pChangeViewSet = m_pDocument->GetChangeViewSettings(); |
987 | | if ( pChangeViewSet && pChangeViewSet->ShowChanges() ) |
988 | | { |
989 | | pChangeViewSet->SetShowChanges( false ); |
990 | | pChangeViewSet->SetShowAccepted( false ); |
991 | | m_pDocument->SetChangeViewSettings( *pChangeViewSet ); |
992 | | bChangedViewSettings = true; |
993 | | } |
994 | | |
995 | | // TODO/LATER: More entries from the MediaDescriptor might be interesting for the merge |
996 | | uno::Sequence< beans::PropertyValue > aValues{ |
997 | | comphelper::makePropertyValue( |
998 | | u"FilterName"_ustr, |
999 | | GetMedium()->GetFilter()->GetFilterName()) |
1000 | | }; |
1001 | | |
1002 | | const SfxStringItem* pPasswordItem = GetMedium()->GetItemSet().GetItem(SID_PASSWORD, false); |
1003 | | if ( pPasswordItem && !pPasswordItem->GetValue().isEmpty() ) |
1004 | | { |
1005 | | aValues.realloc( 2 ); |
1006 | | auto pValues = aValues.getArray(); |
1007 | | pValues[1].Name = "Password"; |
1008 | | pValues[1].Value <<= pPasswordItem->GetValue(); |
1009 | | } |
1010 | | const SfxUnoAnyItem* pEncryptionItem = GetMedium()->GetItemSet().GetItem(SID_ENCRYPTIONDATA, false); |
1011 | | if (pEncryptionItem) |
1012 | | { |
1013 | | aValues.realloc(aValues.getLength() + 1); |
1014 | | auto pValues = aValues.getArray(); |
1015 | | pValues[aValues.getLength() - 1].Name = "EncryptionData"; |
1016 | | pValues[aValues.getLength() - 1].Value = pEncryptionItem->GetValue(); |
1017 | | } |
1018 | | |
1019 | | mod->SetInSharedDocSaving(true); |
1020 | | GetModel()->storeToURL( GetSharedFileURL(), aValues ); |
1021 | | mod->SetInSharedDocSaving(false); |
1022 | | |
1023 | | if ( bChangedViewSettings ) |
1024 | | { |
1025 | | pChangeViewSet->SetShowChanges( true ); |
1026 | | pChangeViewSet->SetShowAccepted( true ); |
1027 | | m_pDocument->SetChangeViewSettings( *pChangeViewSet ); |
1028 | | } |
1029 | | } |
1030 | | |
1031 | | bSuccess = true; |
1032 | | GetUndoManager()->Clear(); |
1033 | | } |
1034 | | } |
1035 | | else |
1036 | | { |
1037 | | xCloseable->close( true ); |
1038 | | |
1039 | | if ( bEntriesNotAccessible ) |
1040 | | { |
1041 | | // TODO/LATER: in future an error regarding impossibility to write to share control file could be shown |
1042 | | ErrorHandler::HandleError( ERRCODE_IO_GENERAL ); |
1043 | | } |
1044 | | else |
1045 | | { |
1046 | | std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(), |
1047 | | VclMessageType::Warning, VclButtonsType::Ok, |
1048 | | ScResId(STR_DOC_NOLONGERSHARED))); |
1049 | | xWarn->run(); |
1050 | | |
1051 | | SfxBindings* pBindings = GetViewBindings(); |
1052 | | if ( pBindings ) |
1053 | | { |
1054 | | pBindings->ExecuteSynchron( SID_SAVEASDOC ); |
1055 | | } |
1056 | | } |
1057 | | } |
1058 | | } |
1059 | | catch ( uno::Exception& ) |
1060 | | { |
1061 | | TOOLS_WARN_EXCEPTION( "sc", "SfxEventHintId::SaveDoc" ); |
1062 | | mod->SetInSharedDocSaving(false); |
1063 | | |
1064 | | try |
1065 | | { |
1066 | | uno::Reference< util::XCloseable > xClose( xModel, uno::UNO_QUERY_THROW ); |
1067 | | xClose->close( true ); |
1068 | | } |
1069 | | catch ( uno::Exception& ) |
1070 | | { |
1071 | | } |
1072 | | } |
1073 | | } |
1074 | | |
1075 | | if ( !bSuccess ) |
1076 | | SetError(ERRCODE_IO_ABORT); // this error code will produce no error message, but will break the further saving process |
1077 | | } |
1078 | | #endif |
1079 | |
|
1080 | 0 | if (m_pSheetSaveData) |
1081 | 0 | m_pSheetSaveData->SetInSupportedSave(true); |
1082 | 0 | } |
1083 | 0 | break; |
1084 | 0 | case SfxEventHintId::SaveAsDoc: |
1085 | 0 | { |
1086 | 0 | if ( GetDocument().GetExternalRefManager()->containsUnsavedReferences() ) |
1087 | 0 | { |
1088 | 0 | std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(), |
1089 | 0 | VclMessageType::Warning, VclButtonsType::YesNo, |
1090 | 0 | ScResId(STR_UNSAVED_EXT_REF))); |
1091 | 0 | if (RET_NO == xWarn->run()) |
1092 | 0 | { |
1093 | 0 | SetError(ERRCODE_IO_ABORT); // this error code will produce no error message, but will break the further saving process |
1094 | 0 | } |
1095 | 0 | } |
1096 | 0 | [[fallthrough]]; |
1097 | 0 | } |
1098 | 0 | case SfxEventHintId::SaveToDoc: |
1099 | | // #i108978# If no event is sent before saving, there will also be no "...DONE" event, |
1100 | | // and SAVE/SAVEAS can't be distinguished from SAVETO. So stream copying is only enabled |
1101 | | // if there is a SAVE/SAVEAS/SAVETO event first. |
1102 | 0 | if (m_pSheetSaveData) |
1103 | 0 | m_pSheetSaveData->SetInSupportedSave(true); |
1104 | 0 | break; |
1105 | 0 | case SfxEventHintId::SaveDocDone: |
1106 | 0 | case SfxEventHintId::SaveAsDocDone: |
1107 | 0 | { |
1108 | | // new positions are used after "save" and "save as", but not "save to" |
1109 | 0 | UseSheetSaveEntries(); // use positions from saved file for next saving |
1110 | 0 | [[fallthrough]]; |
1111 | 0 | } |
1112 | 0 | case SfxEventHintId::SaveToDocDone: |
1113 | | // only reset the flag, don't use the new positions |
1114 | 0 | if (m_pSheetSaveData) |
1115 | 0 | m_pSheetSaveData->SetInSupportedSave(false); |
1116 | 0 | break; |
1117 | 4.14k | default: |
1118 | 4.14k | { |
1119 | 4.14k | } |
1120 | 4.14k | break; |
1121 | 4.14k | } |
1122 | 4.14k | } |
1123 | 418k | else if (rHint.GetId() == SfxHintId::TitleChanged) // Without parameter |
1124 | 62.5k | { |
1125 | 62.5k | m_pDocument->SetName( SfxShell::GetName() ); |
1126 | | // RegisterNewTargetNames doesn't exist any longer |
1127 | 62.5k | SfxGetpApp()->Broadcast(SfxHint( SfxHintId::ScDocNameChanged )); // Navigator |
1128 | 62.5k | } |
1129 | 356k | else if (rHint.GetId() == SfxHintId::Deinitializing) |
1130 | 62.5k | { |
1131 | | |
1132 | | #if HAVE_FEATURE_SCRIPTING |
1133 | | uno::Reference<script::vba::XVBACompatibility> xVBACompat(GetBasicContainer(), uno::UNO_QUERY); |
1134 | | if (m_xVBAListener.is() && xVBACompat.is()) |
1135 | | { |
1136 | | xVBACompat->removeVBAScriptListener(m_xVBAListener); |
1137 | | } |
1138 | | #endif |
1139 | | |
1140 | 62.5k | if (m_pDocument->IsClipboardSource()) |
1141 | 0 | { |
1142 | | // Notes copied to the clipboard have a raw SdrCaptionObj pointer |
1143 | | // copied from this document, forget it as it references this |
1144 | | // document's drawing layer pages and what not, which otherwise when |
1145 | | // pasting to another document after this document was destructed would |
1146 | | // attempt to access non-existing data. Preserve the text data though. |
1147 | 0 | ScDocument* pClipDoc = ScModule::GetClipDoc(); |
1148 | 0 | if (pClipDoc) |
1149 | 0 | pClipDoc->ClosingClipboardSource(); |
1150 | 0 | } |
1151 | 62.5k | } |
1152 | | |
1153 | 487k | if (rHint.GetId() != SfxHintId::ThisIsAnSfxEventHint) |
1154 | 483k | return; |
1155 | | |
1156 | 4.14k | switch(static_cast<const SfxEventHint&>(rHint).GetEventId()) |
1157 | 4.14k | { |
1158 | 0 | case SfxEventHintId::CreateDoc: |
1159 | 0 | { |
1160 | 0 | uno::Any aWorkbook; |
1161 | 0 | aWorkbook <<= mxAutomationWorkbookObject; |
1162 | 0 | uno::Sequence< uno::Any > aArgs{ aWorkbook }; |
1163 | 0 | ScModule::get()->CallAutomationApplicationEventSinks(u"NewWorkbook"_ustr, aArgs); |
1164 | 0 | } |
1165 | 0 | break; |
1166 | 0 | case SfxEventHintId::OpenDoc: |
1167 | 0 | { |
1168 | 0 | uno::Any aWorkbook; |
1169 | 0 | aWorkbook <<= mxAutomationWorkbookObject; |
1170 | 0 | uno::Sequence< uno::Any > aArgs{ aWorkbook }; |
1171 | 0 | ScModule::get()->CallAutomationApplicationEventSinks(u"WorkbookOpen"_ustr, aArgs); |
1172 | 0 | } |
1173 | 0 | break; |
1174 | 4.14k | default: |
1175 | 4.14k | break; |
1176 | 4.14k | } |
1177 | 4.14k | } |
1178 | | |
1179 | | // Load contents for organizer |
1180 | | bool ScDocShell::LoadFrom( SfxMedium& rMedium ) |
1181 | 0 | { |
1182 | 0 | LoadMediumGuard aLoadGuard(m_pDocument.get()); |
1183 | 0 | ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() ); |
1184 | |
|
1185 | 0 | weld::WaitObject aWait( GetActiveDialogParent() ); |
1186 | |
|
1187 | 0 | bool bRet = false; |
1188 | |
|
1189 | 0 | SetInitialLinkUpdate(&rMedium); |
1190 | | |
1191 | | // until loading/saving only the styles in XML is implemented, |
1192 | | // load the whole file |
1193 | 0 | bRet = LoadXML( &rMedium, nullptr ); |
1194 | 0 | InitItems(); |
1195 | |
|
1196 | 0 | SfxObjectShell::LoadFrom( rMedium ); |
1197 | |
|
1198 | 0 | return bRet; |
1199 | 0 | } |
1200 | | |
1201 | | static void lcl_parseHtmlFilterOption(const OUString& rOption, LanguageType& rLang, bool& rDateConvert, bool& rScientificConvert) |
1202 | 0 | { |
1203 | 0 | OUStringBuffer aBuf; |
1204 | 0 | std::vector< OUString > aTokens; |
1205 | 0 | sal_Int32 n = rOption.getLength(); |
1206 | 0 | const sal_Unicode* p = rOption.getStr(); |
1207 | 0 | for (sal_Int32 i = 0; i < n; ++i) |
1208 | 0 | { |
1209 | 0 | const sal_Unicode c = p[i]; |
1210 | 0 | if (c == ' ') |
1211 | 0 | { |
1212 | 0 | if (!aBuf.isEmpty()) |
1213 | 0 | aTokens.push_back( aBuf.makeStringAndClear() ); |
1214 | 0 | } |
1215 | 0 | else |
1216 | 0 | aBuf.append(c); |
1217 | 0 | } |
1218 | |
|
1219 | 0 | if (!aBuf.isEmpty()) |
1220 | 0 | aTokens.push_back( aBuf.makeStringAndClear() ); |
1221 | |
|
1222 | 0 | rLang = LanguageType( 0 ); |
1223 | 0 | rDateConvert = false; |
1224 | |
|
1225 | 0 | if (!aTokens.empty()) |
1226 | 0 | rLang = static_cast<LanguageType>(aTokens[0].toInt32()); |
1227 | 0 | if (aTokens.size() > 1) |
1228 | 0 | rDateConvert = static_cast<bool>(aTokens[1].toInt32()); |
1229 | 0 | if (aTokens.size() > 2) |
1230 | 0 | rScientificConvert = static_cast<bool>(aTokens[2].toInt32()); |
1231 | 0 | } |
1232 | | |
1233 | | void ScDocShell::AddDelayedInfobarEntry(const OUString& sId, const OUString& sPrimaryMessage, |
1234 | | const OUString& sSecondaryMessage, InfobarType aInfobarType, |
1235 | | bool bShowCloseButton) |
1236 | 0 | { |
1237 | 0 | m_pImpl->mpDelayedInfobarEntry.push_back( |
1238 | 0 | { sId, sPrimaryMessage, sSecondaryMessage, aInfobarType, bShowCloseButton }); |
1239 | 0 | } |
1240 | | |
1241 | | bool ScDocShell::ConvertFrom( SfxMedium& rMedium ) |
1242 | 0 | { |
1243 | 0 | LoadMediumGuard aLoadGuard(m_pDocument.get()); |
1244 | |
|
1245 | 0 | bool bRet = false; // sal_False means user quit! |
1246 | | // On error: Set error at stream |
1247 | |
|
1248 | 0 | ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() ); |
1249 | |
|
1250 | 0 | GetUndoManager()->Clear(); |
1251 | | |
1252 | | // Set optimal col width after import? |
1253 | 0 | bool bSetColWidths = false; |
1254 | 0 | bool bSetSimpleTextColWidths = false; |
1255 | 0 | std::map<SCCOL, ScColWidthParam> aColWidthParam; |
1256 | 0 | ScRange aColWidthRange; |
1257 | | // Set optimal row height after import? |
1258 | 0 | bool bSetRowHeights = false; |
1259 | |
|
1260 | 0 | std::vector<ScDocRowHeightUpdater::TabRanges> aRecalcRowRangesArray; |
1261 | | |
1262 | | // All filters need the complete file in one piece (not asynchronously) |
1263 | | // So make sure that we transfer the whole file with CreateFileStream |
1264 | 0 | rMedium.GetPhysicalName(); //! Call CreateFileStream directly, if available |
1265 | |
|
1266 | 0 | SetInitialLinkUpdate(&rMedium); |
1267 | |
|
1268 | 0 | std::shared_ptr<const SfxFilter> pFilter = rMedium.GetFilter(); |
1269 | 0 | if (pFilter) |
1270 | 0 | { |
1271 | 0 | OUString aFltName = pFilter->GetFilterName(); |
1272 | |
|
1273 | 0 | bool bCalc3 = aFltName == "StarCalc 3.0"; |
1274 | 0 | bool bCalc4 = aFltName == "StarCalc 4.0"; |
1275 | 0 | if (!bCalc3 && !bCalc4) |
1276 | 0 | m_pDocument->SetInsertingFromOtherDoc( true ); |
1277 | |
|
1278 | 0 | if (aFltName == SC_SOXML_FILTER_NAME) |
1279 | 0 | bRet = LoadXML( &rMedium, nullptr ); |
1280 | 0 | else if (aFltName == SC_LOTUS_FILTER_NAME) |
1281 | 0 | { |
1282 | 0 | OUString sItStr; |
1283 | 0 | if ( const SfxStringItem* pOptionsItem = rMedium.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS, true ) ) |
1284 | 0 | { |
1285 | 0 | sItStr = pOptionsItem->GetValue(); |
1286 | 0 | } |
1287 | |
|
1288 | 0 | if (sItStr.isEmpty()) |
1289 | 0 | { |
1290 | | // default for lotus import (from API without options): |
1291 | | // IBM_437 encoding |
1292 | 0 | sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_437 ); |
1293 | 0 | } |
1294 | |
|
1295 | 0 | ErrCode eError = ScFormatFilter::Get().ScImportLotus123( rMedium, *m_pDocument, |
1296 | 0 | ScGlobal::GetCharsetValue(sItStr)); |
1297 | 0 | if (eError != ERRCODE_NONE) |
1298 | 0 | { |
1299 | 0 | if (!GetErrorIgnoreWarning()) |
1300 | 0 | SetError(eError); |
1301 | |
|
1302 | 0 | if( eError.IsWarning() ) |
1303 | 0 | bRet = true; |
1304 | 0 | } |
1305 | 0 | else |
1306 | 0 | bRet = true; |
1307 | 0 | bSetColWidths = true; |
1308 | 0 | bSetRowHeights = true; |
1309 | 0 | } |
1310 | 0 | else if ( aFltName == SC_XL4_FILTER_NAME || aFltName == SC_XL5_FILTER_NAME || |
1311 | 0 | aFltName == SC_XL95_FILTER_NAME || aFltName == SC_XL97_FILTER_NAME || |
1312 | 0 | aFltName == SC_XL4TMPL_FILTER_NAME || aFltName == SC_XL5TMPL_FILTER_NAME || |
1313 | 0 | aFltName == SC_XL95TMPL_FILTER_NAME || aFltName == SC_XL97TMPL_FILTER_NAME ) |
1314 | 0 | { |
1315 | 0 | EXCIMPFORMAT eFormat = EIF_AUTO; |
1316 | 0 | if (aFltName == SC_XL4_FILTER_NAME || aFltName == SC_XL4TMPL_FILTER_NAME) |
1317 | 0 | eFormat = EIF_BIFF_LE4; |
1318 | 0 | else if ( aFltName == SC_XL5_FILTER_NAME || aFltName == SC_XL95_FILTER_NAME || |
1319 | 0 | aFltName == SC_XL5TMPL_FILTER_NAME || aFltName == SC_XL95TMPL_FILTER_NAME ) |
1320 | 0 | eFormat = EIF_BIFF5; |
1321 | 0 | else if (aFltName == SC_XL97_FILTER_NAME || aFltName == SC_XL97TMPL_FILTER_NAME) |
1322 | 0 | eFormat = EIF_BIFF8; |
1323 | |
|
1324 | 0 | MakeDrawLayer(); //! In the filter |
1325 | 0 | CalcOutputFactor(); // prepare update of row height |
1326 | 0 | ErrCode eError = ScFormatFilter::Get().ScImportExcel( rMedium, m_pDocument.get(), eFormat ); |
1327 | 0 | m_pDocument->UpdateFontCharSet(); |
1328 | 0 | if ( m_pDocument->IsChartListenerCollectionNeedsUpdate() ) |
1329 | 0 | m_pDocument->UpdateChartListenerCollection(); //! For all imports? |
1330 | | |
1331 | | // all graphics objects must have names |
1332 | 0 | m_pDocument->EnsureGraphicNames(); |
1333 | |
|
1334 | 0 | if (eError == SCWARN_IMPORT_UNKNOWN_ENCRYPTION) |
1335 | 0 | { |
1336 | 0 | AddDelayedInfobarEntry(u"UnknownEncryption"_ustr, ScResId(STR_CONTENT_WITH_UNKNOWN_ENCRYPTION), u""_ustr, InfobarType::INFO, true); |
1337 | 0 | eError = ERRCODE_NONE; |
1338 | 0 | } |
1339 | |
|
1340 | 0 | if (eError != ERRCODE_NONE) |
1341 | 0 | { |
1342 | 0 | if (!GetErrorIgnoreWarning()) |
1343 | 0 | SetError(eError); |
1344 | 0 | if( eError.IsWarning() ) |
1345 | 0 | bRet = true; |
1346 | 0 | } |
1347 | 0 | else |
1348 | 0 | bRet = true; |
1349 | 0 | } |
1350 | 0 | else if (aFltName == SC_TEXT_CSV_FILTER_NAME) |
1351 | 0 | { |
1352 | 0 | ScAsciiOptions aOptions; |
1353 | 0 | bool bOptInit = false; |
1354 | |
|
1355 | 0 | if ( const SfxStringItem* pOptionsItem = rMedium.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) ) |
1356 | 0 | { |
1357 | 0 | aOptions.ReadFromString( pOptionsItem->GetValue(), rMedium.GetInStream() ); |
1358 | 0 | bOptInit = true; |
1359 | 0 | } |
1360 | |
|
1361 | 0 | if ( !bOptInit ) |
1362 | 0 | { |
1363 | | // default for ascii import (from API without options): |
1364 | | // UTF-8 encoding, comma, double quotes |
1365 | |
|
1366 | 0 | aOptions.SetCharSet(RTL_TEXTENCODING_UTF8); |
1367 | 0 | aOptions.SetFieldSeps( OUString(',') ); |
1368 | 0 | aOptions.SetTextSep( '"' ); |
1369 | 0 | } |
1370 | |
|
1371 | 0 | ErrCode eError = ERRCODE_NONE; |
1372 | 0 | bool bOverflowRow, bOverflowCol, bOverflowCell; |
1373 | 0 | bOverflowRow = bOverflowCol = bOverflowCell = false; |
1374 | |
|
1375 | 0 | if( ! rMedium.IsStorage() ) |
1376 | 0 | { |
1377 | 0 | ScImportExport aImpEx( *m_pDocument ); |
1378 | 0 | aImpEx.SetExtOptions( aOptions ); |
1379 | |
|
1380 | 0 | SvStream* pInStream = rMedium.GetInStream(); |
1381 | 0 | if (pInStream) |
1382 | 0 | { |
1383 | 0 | pInStream->SetStreamCharSet( aOptions.GetCharSet() ); |
1384 | 0 | pInStream->Seek( 0 ); |
1385 | 0 | bRet = aImpEx.ImportStream( *pInStream, rMedium.GetBaseURL(), SotClipboardFormatId::STRING ); |
1386 | 0 | eError = bRet ? ERRCODE_NONE : SCERR_IMPORT_CONNECT; |
1387 | 0 | m_pDocument->StartAllListeners(); |
1388 | 0 | sc::SetFormulaDirtyContext aCxt; |
1389 | 0 | m_pDocument->SetAllFormulasDirty(aCxt); |
1390 | | |
1391 | | // tdf#82254 - check whether to include a byte-order-mark in the output |
1392 | 0 | if (const bool bIncludeBOM = aImpEx.GetIncludeBOM()) |
1393 | 0 | { |
1394 | 0 | aOptions.SetIncludeBOM(bIncludeBOM); |
1395 | 0 | rMedium.GetItemSet().Put( |
1396 | 0 | SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions.WriteToString())); |
1397 | 0 | } |
1398 | | |
1399 | | // for mobile case, we use a copy of the original document and give it a temporary name before editing |
1400 | | // Therefore, the sheet name becomes ugly, long and nonsensical. |
1401 | 0 | #if !(defined ANDROID) |
1402 | | // The same resulting name has to be handled in |
1403 | | // ScExternalRefCache::initializeDoc() and related, hence |
1404 | | // pass 'true' for RenameTab()'s bExternalDocument for a |
1405 | | // composed name so ValidTabName() will not be checked, |
1406 | | // which could veto the rename in case it contained |
1407 | | // characters that Excel does not handle. If we wanted to |
1408 | | // change that then it needed to be handled in all |
1409 | | // corresponding places of the external references |
1410 | | // manager/cache. Likely then we'd also need a method to |
1411 | | // compose a name excluding such characters. |
1412 | 0 | m_pDocument->RenameTab( 0, INetURLObject( rMedium.GetName()).GetBase(), true/*bExternalDocument*/); |
1413 | 0 | #endif |
1414 | 0 | bOverflowRow = aImpEx.IsOverflowRow(); |
1415 | 0 | bOverflowCol = aImpEx.IsOverflowCol(); |
1416 | 0 | bOverflowCell = aImpEx.IsOverflowCell(); |
1417 | 0 | } |
1418 | 0 | else |
1419 | 0 | { |
1420 | 0 | OSL_FAIL( "No Stream" ); |
1421 | 0 | } |
1422 | 0 | } |
1423 | |
|
1424 | 0 | if (eError != ERRCODE_NONE) |
1425 | 0 | { |
1426 | 0 | if (!GetErrorIgnoreWarning()) |
1427 | 0 | SetError(eError); |
1428 | 0 | if( eError.IsWarning() ) |
1429 | 0 | bRet = true; |
1430 | 0 | } |
1431 | 0 | else if (!GetErrorIgnoreWarning() && (bOverflowRow || bOverflowCol || bOverflowCell)) |
1432 | 0 | { |
1433 | | // precedence: row, column, cell |
1434 | 0 | ErrCode nWarn = (bOverflowRow ? SCWARN_IMPORT_ROW_OVERFLOW : |
1435 | 0 | (bOverflowCol ? SCWARN_IMPORT_COLUMN_OVERFLOW : |
1436 | 0 | SCWARN_IMPORT_CELL_OVERFLOW)); |
1437 | 0 | SetError(nWarn); |
1438 | 0 | } |
1439 | 0 | bSetColWidths = true; |
1440 | 0 | bSetSimpleTextColWidths = true; |
1441 | 0 | } |
1442 | 0 | else if (aFltName == SC_DBASE_FILTER_NAME) |
1443 | 0 | { |
1444 | 0 | OUString sItStr; |
1445 | 0 | if ( const SfxStringItem* pOptionsItem = rMedium.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) ) |
1446 | 0 | { |
1447 | 0 | sItStr = pOptionsItem->GetValue(); |
1448 | 0 | } |
1449 | |
|
1450 | 0 | if (sItStr.isEmpty()) |
1451 | 0 | { |
1452 | | // default for dBase import (from API without options): |
1453 | | // IBM_850 encoding |
1454 | |
|
1455 | 0 | sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_850 ); |
1456 | 0 | } |
1457 | |
|
1458 | 0 | ScDocRowHeightUpdater::TabRanges aRecalcRanges(0, m_pDocument->MaxRow()); |
1459 | 0 | ErrCode eError = DBaseImport( rMedium.GetPhysicalName(), |
1460 | 0 | ScGlobal::GetCharsetValue(sItStr), aColWidthParam, aRecalcRanges.maRanges ); |
1461 | 0 | aRecalcRowRangesArray.push_back(std::move(aRecalcRanges)); |
1462 | |
|
1463 | 0 | if (eError != ERRCODE_NONE) |
1464 | 0 | { |
1465 | 0 | if (!GetErrorIgnoreWarning()) |
1466 | 0 | SetError(eError); |
1467 | 0 | if( eError.IsWarning() ) |
1468 | 0 | bRet = true; |
1469 | 0 | } |
1470 | 0 | else |
1471 | 0 | bRet = true; |
1472 | |
|
1473 | 0 | aColWidthRange.aStart.SetRow( 1 ); // Except for the column header |
1474 | 0 | bSetColWidths = true; |
1475 | 0 | bSetSimpleTextColWidths = true; |
1476 | 0 | } |
1477 | 0 | else if (aFltName == SC_DIF_FILTER_NAME) |
1478 | 0 | { |
1479 | 0 | SvStream* pStream = rMedium.GetInStream(); |
1480 | 0 | if (pStream) |
1481 | 0 | { |
1482 | 0 | ErrCode eError; |
1483 | 0 | OUString sItStr; |
1484 | 0 | if ( const SfxStringItem* pOptionsItem = rMedium.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) ) |
1485 | 0 | { |
1486 | 0 | sItStr = pOptionsItem->GetValue(); |
1487 | 0 | } |
1488 | |
|
1489 | 0 | if (sItStr.isEmpty()) |
1490 | 0 | { |
1491 | | // default for DIF import (from API without options): |
1492 | | // ISO8859-1/MS_1252 encoding |
1493 | |
|
1494 | 0 | sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_MS_1252 ); |
1495 | 0 | } |
1496 | |
|
1497 | 0 | eError = ScFormatFilter::Get().ScImportDif( *pStream, m_pDocument.get(), ScAddress(0,0,0), |
1498 | 0 | ScGlobal::GetCharsetValue(sItStr)); |
1499 | 0 | if (eError != ERRCODE_NONE) |
1500 | 0 | { |
1501 | 0 | if (!GetErrorIgnoreWarning()) |
1502 | 0 | SetError(eError); |
1503 | |
|
1504 | 0 | if( eError.IsWarning() ) |
1505 | 0 | bRet = true; |
1506 | 0 | } |
1507 | 0 | else |
1508 | 0 | bRet = true; |
1509 | 0 | } |
1510 | 0 | bSetColWidths = true; |
1511 | 0 | bSetSimpleTextColWidths = true; |
1512 | 0 | bSetRowHeights = true; |
1513 | 0 | } |
1514 | 0 | else if (aFltName == SC_SYLK_FILTER_NAME) |
1515 | 0 | { |
1516 | 0 | ErrCode eError = SCERR_IMPORT_UNKNOWN; |
1517 | 0 | bool bOverflowRow, bOverflowCol, bOverflowCell; |
1518 | 0 | bOverflowRow = bOverflowCol = bOverflowCell = false; |
1519 | 0 | if( !rMedium.IsStorage() ) |
1520 | 0 | { |
1521 | 0 | ScImportExport aImpEx( *m_pDocument ); |
1522 | |
|
1523 | 0 | SvStream* pInStream = rMedium.GetInStream(); |
1524 | 0 | if (pInStream) |
1525 | 0 | { |
1526 | 0 | pInStream->Seek( 0 ); |
1527 | 0 | bRet = aImpEx.ImportStream( *pInStream, rMedium.GetBaseURL(), SotClipboardFormatId::SYLK ); |
1528 | 0 | eError = bRet ? ERRCODE_NONE : SCERR_IMPORT_UNKNOWN; |
1529 | 0 | m_pDocument->StartAllListeners(); |
1530 | 0 | sc::SetFormulaDirtyContext aCxt; |
1531 | 0 | m_pDocument->SetAllFormulasDirty(aCxt); |
1532 | |
|
1533 | 0 | bOverflowRow = aImpEx.IsOverflowRow(); |
1534 | 0 | bOverflowCol = aImpEx.IsOverflowCol(); |
1535 | 0 | bOverflowCell = aImpEx.IsOverflowCell(); |
1536 | 0 | } |
1537 | 0 | else |
1538 | 0 | { |
1539 | 0 | OSL_FAIL( "No Stream" ); |
1540 | 0 | } |
1541 | 0 | } |
1542 | |
|
1543 | 0 | if (eError != ERRCODE_NONE) |
1544 | 0 | { |
1545 | 0 | if (!GetErrorIgnoreWarning()) |
1546 | 0 | SetError(eError); |
1547 | 0 | if( eError.IsWarning() ) |
1548 | 0 | bRet = true; |
1549 | 0 | } |
1550 | 0 | else if (!GetErrorIgnoreWarning() && (bOverflowRow || bOverflowCol || bOverflowCell)) |
1551 | 0 | { |
1552 | | // precedence: row, column, cell |
1553 | 0 | ErrCode nWarn = (bOverflowRow ? SCWARN_IMPORT_ROW_OVERFLOW : |
1554 | 0 | (bOverflowCol ? SCWARN_IMPORT_COLUMN_OVERFLOW : |
1555 | 0 | SCWARN_IMPORT_CELL_OVERFLOW)); |
1556 | 0 | SetError(nWarn); |
1557 | 0 | } |
1558 | 0 | bSetColWidths = true; |
1559 | 0 | bSetSimpleTextColWidths = true; |
1560 | 0 | bSetRowHeights = true; |
1561 | 0 | } |
1562 | 0 | else if (aFltName == SC_QPRO6_FILTER_NAME) |
1563 | 0 | { |
1564 | 0 | ErrCode eError = ScFormatFilter::Get().ScImportQuattroPro(rMedium.GetInStream(), *m_pDocument); |
1565 | 0 | if (eError != ERRCODE_NONE) |
1566 | 0 | { |
1567 | 0 | if (!GetErrorIgnoreWarning()) |
1568 | 0 | SetError(eError); |
1569 | 0 | if( eError.IsWarning() ) |
1570 | 0 | bRet = true; |
1571 | 0 | } |
1572 | 0 | else |
1573 | 0 | bRet = true; |
1574 | | // TODO: Filter should set column widths. Not doing it here, it may |
1575 | | // result in very narrow or wide columns, depending on content. |
1576 | | // Setting row heights makes cells with font size attribution or |
1577 | | // wrapping enabled look nicer... |
1578 | 0 | bSetRowHeights = true; |
1579 | 0 | } |
1580 | 0 | else if (aFltName == SC_RTF_FILTER_NAME) |
1581 | 0 | { |
1582 | 0 | ErrCode eError = SCERR_IMPORT_UNKNOWN; |
1583 | 0 | if( !rMedium.IsStorage() ) |
1584 | 0 | { |
1585 | 0 | SvStream* pInStream = rMedium.GetInStream(); |
1586 | 0 | if (pInStream) |
1587 | 0 | { |
1588 | 0 | pInStream->Seek( 0 ); |
1589 | 0 | ScRange aRange; |
1590 | 0 | eError = ScFormatFilter::Get().ScImportRTF( *pInStream, rMedium.GetBaseURL(), *m_pDocument, aRange ); |
1591 | 0 | if (eError != ERRCODE_NONE) |
1592 | 0 | { |
1593 | 0 | if (!GetErrorIgnoreWarning()) |
1594 | 0 | SetError(eError); |
1595 | |
|
1596 | 0 | if( eError.IsWarning() ) |
1597 | 0 | bRet = true; |
1598 | 0 | } |
1599 | 0 | else |
1600 | 0 | bRet = true; |
1601 | 0 | m_pDocument->StartAllListeners(); |
1602 | 0 | sc::SetFormulaDirtyContext aCxt; |
1603 | 0 | m_pDocument->SetAllFormulasDirty(aCxt); |
1604 | 0 | bSetColWidths = true; |
1605 | 0 | bSetRowHeights = true; |
1606 | 0 | } |
1607 | 0 | else |
1608 | 0 | { |
1609 | 0 | OSL_FAIL( "No Stream" ); |
1610 | 0 | } |
1611 | 0 | } |
1612 | |
|
1613 | 0 | if (eError != ERRCODE_NONE) |
1614 | 0 | { |
1615 | 0 | if (!GetErrorIgnoreWarning()) |
1616 | 0 | SetError(eError); |
1617 | 0 | if( eError.IsWarning() ) |
1618 | 0 | bRet = true; |
1619 | 0 | } |
1620 | 0 | } |
1621 | 0 | else if (aFltName == SC_HTML_FILTER_NAME || aFltName == SC_HTML_WEBQ_FILTER_NAME) |
1622 | 0 | { |
1623 | 0 | ErrCode eError = SCERR_IMPORT_UNKNOWN; |
1624 | 0 | bool bWebQuery = aFltName == SC_HTML_WEBQ_FILTER_NAME; |
1625 | 0 | if( !rMedium.IsStorage() ) |
1626 | 0 | { |
1627 | 0 | SvStream* pInStream = rMedium.GetInStream(); |
1628 | 0 | if (pInStream) |
1629 | 0 | { |
1630 | 0 | LanguageType eLang = LANGUAGE_SYSTEM; |
1631 | 0 | bool bDateConvert = false; |
1632 | 0 | bool bScientificConvert = true; |
1633 | 0 | if ( const SfxStringItem* pOptionsItem = rMedium.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) ) |
1634 | 0 | { |
1635 | 0 | OUString aFilterOption = pOptionsItem->GetValue(); |
1636 | 0 | lcl_parseHtmlFilterOption(aFilterOption, eLang, bDateConvert, bScientificConvert); |
1637 | 0 | } |
1638 | |
|
1639 | 0 | pInStream->Seek( 0 ); |
1640 | 0 | ScRange aRange; |
1641 | | // HTML does its own ColWidth/RowHeight |
1642 | 0 | CalcOutputFactor(); |
1643 | 0 | SvNumberFormatter aNumFormatter( comphelper::getProcessComponentContext(), eLang); |
1644 | 0 | eError = ScFormatFilter::Get().ScImportHTML( *pInStream, rMedium.GetBaseURL(), *m_pDocument, aRange, |
1645 | 0 | GetOutputFactor(), !bWebQuery, &aNumFormatter, bDateConvert, bScientificConvert ); |
1646 | 0 | if (eError != ERRCODE_NONE) |
1647 | 0 | { |
1648 | 0 | if (!GetErrorIgnoreWarning()) |
1649 | 0 | SetError(eError); |
1650 | |
|
1651 | 0 | if( eError.IsWarning() ) |
1652 | 0 | bRet = true; |
1653 | 0 | } |
1654 | 0 | else |
1655 | 0 | bRet = true; |
1656 | 0 | m_pDocument->StartAllListeners(); |
1657 | |
|
1658 | 0 | sc::SetFormulaDirtyContext aCxt; |
1659 | 0 | m_pDocument->SetAllFormulasDirty(aCxt); |
1660 | 0 | } |
1661 | 0 | else |
1662 | 0 | { |
1663 | 0 | OSL_FAIL( "No Stream" ); |
1664 | 0 | } |
1665 | 0 | } |
1666 | |
|
1667 | 0 | if (eError != ERRCODE_NONE) |
1668 | 0 | { |
1669 | 0 | if (!GetErrorIgnoreWarning()) |
1670 | 0 | SetError(eError); |
1671 | 0 | if( eError.IsWarning() ) |
1672 | 0 | bRet = true; |
1673 | 0 | } |
1674 | 0 | } |
1675 | 0 | else |
1676 | 0 | { |
1677 | 0 | ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters(); |
1678 | 0 | if (!pOrcus) |
1679 | 0 | return false; |
1680 | | |
1681 | 0 | switch (pOrcus->importByName(*m_pDocument, rMedium, aFltName)) |
1682 | 0 | { |
1683 | 0 | case ScOrcusFilters::ImportResult::Success: |
1684 | 0 | bRet = true; |
1685 | 0 | break; |
1686 | 0 | case ScOrcusFilters::ImportResult::Failure: |
1687 | 0 | bRet = false; |
1688 | 0 | break; |
1689 | 0 | case ScOrcusFilters::ImportResult::NotSupported: |
1690 | 0 | { |
1691 | 0 | if (!GetErrorIgnoreWarning()) |
1692 | 0 | { |
1693 | 0 | SAL_WARN("sc.filter", "No match for filter '" << aFltName << "' in ConvertFrom"); |
1694 | 0 | SetError(SCERR_IMPORT_NI); |
1695 | 0 | } |
1696 | 0 | break; |
1697 | 0 | } |
1698 | 0 | } |
1699 | 0 | } |
1700 | | |
1701 | 0 | if (!bCalc3) |
1702 | 0 | m_pDocument->SetInsertingFromOtherDoc( false ); |
1703 | 0 | } |
1704 | 0 | else |
1705 | 0 | { |
1706 | 0 | OSL_FAIL("No Filter in ConvertFrom"); |
1707 | 0 | } |
1708 | | |
1709 | 0 | InitItems(); |
1710 | 0 | CalcOutputFactor(); |
1711 | 0 | if ( bRet && (bSetColWidths || bSetRowHeights) ) |
1712 | 0 | { // Adjust column width/row height; base 100% zoom |
1713 | 0 | Fraction aZoom( 1, 1 ); |
1714 | 0 | double nPPTX = ScGlobal::nScreenPPTX * static_cast<double>(aZoom) / GetOutputFactor(); // Factor is printer display ratio |
1715 | 0 | double nPPTY = ScGlobal::nScreenPPTY * static_cast<double>(aZoom); |
1716 | 0 | ScopedVclPtrInstance< VirtualDevice > pVirtDev; |
1717 | | // all sheets (for Excel import) |
1718 | 0 | SCTAB nTabCount = m_pDocument->GetTableCount(); |
1719 | 0 | for (SCTAB nTab=0; nTab<nTabCount; nTab++) |
1720 | 0 | { |
1721 | 0 | SCCOL nEndCol; |
1722 | 0 | SCROW nEndRow; |
1723 | 0 | m_pDocument->GetCellArea( nTab, nEndCol, nEndRow ); |
1724 | 0 | aColWidthRange.aEnd.SetCol( nEndCol ); |
1725 | 0 | aColWidthRange.aEnd.SetRow( nEndRow ); |
1726 | 0 | ScMarkData aMark(m_pDocument->GetSheetLimits()); |
1727 | 0 | aMark.SetMarkArea( aColWidthRange ); |
1728 | 0 | aMark.MarkToMulti(); |
1729 | | |
1730 | | // Order is important: First width, then height |
1731 | 0 | if ( bSetColWidths ) |
1732 | 0 | { |
1733 | 0 | for ( SCCOL nCol=0; nCol <= nEndCol; nCol++ ) |
1734 | 0 | { |
1735 | 0 | if (!bSetSimpleTextColWidths) |
1736 | 0 | aColWidthParam[nCol].mbSimpleText = false; |
1737 | |
|
1738 | 0 | sal_uInt16 nWidth = m_pDocument->GetOptimalColWidth( |
1739 | 0 | nCol, nTab, pVirtDev, nPPTX, nPPTY, aZoom, aZoom, false, &aMark, |
1740 | 0 | &aColWidthParam[nCol] ); |
1741 | 0 | m_pDocument->SetColWidth( nCol, nTab, |
1742 | 0 | nWidth + static_cast<sal_uInt16>(ScGlobal::nLastColWidthExtra) ); |
1743 | 0 | } |
1744 | 0 | } |
1745 | 0 | } |
1746 | |
|
1747 | 0 | if (bSetRowHeights) |
1748 | 0 | { |
1749 | | // Update all rows in all tables. |
1750 | 0 | ScSizeDeviceProvider aProv(*this); |
1751 | 0 | ScDocRowHeightUpdater aUpdater(*m_pDocument, aProv.GetDevice(), aProv.GetPPTX(), aProv.GetPPTY(), nullptr); |
1752 | 0 | aUpdater.update(); |
1753 | 0 | } |
1754 | 0 | else if (!aRecalcRowRangesArray.empty()) |
1755 | 0 | { |
1756 | | // Update only specified row ranges for better performance. |
1757 | 0 | ScSizeDeviceProvider aProv(*this); |
1758 | 0 | ScDocRowHeightUpdater aUpdater(*m_pDocument, aProv.GetDevice(), aProv.GetPPTX(), aProv.GetPPTY(), &aRecalcRowRangesArray); |
1759 | 0 | aUpdater.update(); |
1760 | 0 | } |
1761 | 0 | } |
1762 | 0 | FinishedLoading(); |
1763 | | |
1764 | | // invalidate eventually temporary table areas |
1765 | 0 | if ( bRet ) |
1766 | 0 | m_pDocument->InvalidateTableArea(); |
1767 | |
|
1768 | 0 | m_bIsEmpty = false; |
1769 | |
|
1770 | 0 | return bRet; |
1771 | 0 | } |
1772 | | |
1773 | | bool ScDocShell::LoadExternal( SfxMedium& rMed ) |
1774 | 0 | { |
1775 | 0 | std::shared_ptr<const SfxFilter> pFilter = rMed.GetFilter(); |
1776 | 0 | if (!pFilter) |
1777 | 0 | return false; |
1778 | | |
1779 | 0 | if (pFilter->GetProviderName() == "orcus") |
1780 | 0 | { |
1781 | 0 | ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters(); |
1782 | 0 | if (!pOrcus) |
1783 | 0 | return false; |
1784 | | |
1785 | 0 | auto res = pOrcus->importByName(*m_pDocument, rMed, pFilter->GetName()); |
1786 | 0 | if (res != ScOrcusFilters::ImportResult::Success) |
1787 | 0 | return false; |
1788 | | |
1789 | 0 | FinishedLoading(); |
1790 | 0 | return true; |
1791 | 0 | } |
1792 | | |
1793 | 0 | return false; |
1794 | 0 | } |
1795 | | |
1796 | | ScDocShell::PrepareSaveGuard::PrepareSaveGuard( ScDocShell& rDocShell ) |
1797 | 0 | : mrDocShell( rDocShell) |
1798 | 0 | { |
1799 | | // DoEnterHandler not here (because of AutoSave), is in ExecuteSave. |
1800 | |
|
1801 | 0 | ScChartListenerCollection* pCharts = mrDocShell.m_pDocument->GetChartListenerCollection(); |
1802 | 0 | if (pCharts) |
1803 | 0 | pCharts->UpdateDirtyCharts(); // Charts to be updated. |
1804 | 0 | mrDocShell.m_pDocument->StopTemporaryChartLock(); |
1805 | 0 | if (mrDocShell.m_pAutoStyleList) |
1806 | 0 | mrDocShell.m_pAutoStyleList->ExecuteAllNow(); // Execute template timeouts now. |
1807 | 0 | if (mrDocShell.m_pDocument->HasExternalRefManager()) |
1808 | 0 | { |
1809 | 0 | ScExternalRefManager* pRefMgr = mrDocShell.m_pDocument->GetExternalRefManager(); |
1810 | 0 | if (pRefMgr && pRefMgr->hasExternalData()) |
1811 | 0 | { |
1812 | 0 | pRefMgr->setAllCacheTableReferencedStati( false); |
1813 | 0 | mrDocShell.m_pDocument->MarkUsedExternalReferences(); // Mark tables of external references to be written. |
1814 | 0 | } |
1815 | 0 | } |
1816 | 0 | if (mrDocShell.GetCreateMode()== SfxObjectCreateMode::STANDARD) |
1817 | 0 | mrDocShell.SfxObjectShell::SetVisArea( tools::Rectangle() ); // "Normally" worked on => no VisArea. |
1818 | 0 | } |
1819 | | |
1820 | | ScDocShell::PrepareSaveGuard::~PrepareSaveGuard() |
1821 | 0 | { |
1822 | 0 | if (mrDocShell.m_pDocument->HasExternalRefManager()) |
1823 | 0 | { |
1824 | 0 | ScExternalRefManager* pRefMgr = mrDocShell.m_pDocument->GetExternalRefManager(); |
1825 | 0 | if (pRefMgr && pRefMgr->hasExternalData()) |
1826 | 0 | { |
1827 | | // Prevent accidental data loss due to lack of knowledge. |
1828 | 0 | pRefMgr->setAllCacheTableReferencedStati( true); |
1829 | 0 | } |
1830 | 0 | } |
1831 | 0 | } |
1832 | | |
1833 | | bool ScDocShell::Save() |
1834 | 0 | { |
1835 | 0 | ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() ); |
1836 | |
|
1837 | 0 | PrepareSaveGuard aPrepareGuard( *this); |
1838 | |
|
1839 | 0 | if (const auto pFrame1 = SfxViewFrame::GetFirst(this)) |
1840 | 0 | { |
1841 | 0 | if (auto pSysWin = pFrame1->GetWindow().GetSystemWindow()) |
1842 | 0 | { |
1843 | 0 | pSysWin->SetAccessibleName(OUString()); |
1844 | 0 | } |
1845 | 0 | } |
1846 | | // wait cursor is handled with progress bar |
1847 | 0 | bool bRet = SfxObjectShell::Save(); |
1848 | 0 | if( bRet ) |
1849 | 0 | bRet = SaveXML( GetMedium(), nullptr ); |
1850 | 0 | return bRet; |
1851 | 0 | } |
1852 | | |
1853 | | namespace { |
1854 | | |
1855 | | /** |
1856 | | * Remove the file name from the full path, to keep only the directory path. |
1857 | | */ |
1858 | | void popFileName(OUString& rPath) |
1859 | 0 | { |
1860 | 0 | if (!rPath.isEmpty()) |
1861 | 0 | { |
1862 | 0 | INetURLObject aURLObj(rPath); |
1863 | 0 | aURLObj.removeSegment(); |
1864 | 0 | rPath = aURLObj.GetMainURL(INetURLObject::DecodeMechanism::NONE); |
1865 | 0 | } |
1866 | 0 | } |
1867 | | |
1868 | | } |
1869 | | |
1870 | | void ScDocShell::TerminateEditing() |
1871 | 0 | { |
1872 | | // Commit any cell changes before saving. |
1873 | 0 | ScModule::get()->InputEnterHandler(); |
1874 | 0 | } |
1875 | | |
1876 | | bool ScDocShell::SaveAs( SfxMedium& rMedium ) |
1877 | 0 | { |
1878 | 0 | OUString aCurPath; // empty for new document that hasn't been saved. |
1879 | 0 | const SfxMedium* pCurMedium = GetMedium(); |
1880 | 0 | if (pCurMedium) |
1881 | 0 | { |
1882 | 0 | aCurPath = pCurMedium->GetName(); |
1883 | 0 | popFileName(aCurPath); |
1884 | 0 | } |
1885 | |
|
1886 | 0 | if (!aCurPath.isEmpty()) |
1887 | 0 | { |
1888 | | // current document has a path -> not a brand-new document. |
1889 | 0 | OUString aNewPath = rMedium.GetName(); |
1890 | 0 | popFileName(aNewPath); |
1891 | 0 | OUString aRel = URIHelper::simpleNormalizedMakeRelative(aCurPath, aNewPath); |
1892 | 0 | if (!aRel.isEmpty()) |
1893 | 0 | { |
1894 | | // Directory path will change before and after the save. |
1895 | 0 | m_pDocument->InvalidateStreamOnSave(); |
1896 | 0 | } |
1897 | 0 | } |
1898 | |
|
1899 | 0 | ScTabViewShell* pViewShell = GetBestViewShell(); |
1900 | 0 | bool bNeedsRehash = ScPassHashHelper::needsPassHashRegen(*m_pDocument, PASSHASH_SHA1); |
1901 | 0 | if (bNeedsRehash) |
1902 | | // legacy xls hash double-hashed by SHA1 is also supported. |
1903 | 0 | bNeedsRehash = ScPassHashHelper::needsPassHashRegen(*m_pDocument, PASSHASH_XL, PASSHASH_SHA1); |
1904 | 0 | if (bNeedsRehash) |
1905 | 0 | { // SHA256 explicitly supported in ODF 1.2, implicitly in ODF 1.1 |
1906 | 0 | bNeedsRehash = ScPassHashHelper::needsPassHashRegen(*m_pDocument, PASSHASH_SHA256); |
1907 | 0 | } |
1908 | |
|
1909 | 0 | if (pViewShell && bNeedsRehash) |
1910 | 0 | { |
1911 | 0 | if (rMedium.GetArgs().getValue(utl::MediaDescriptor::PROP_AUTOSAVEEVENT) == true) |
1912 | 0 | { |
1913 | | // skip saving recovery file instead of showing re-type password dialog window |
1914 | 0 | SAL_WARN("sc.filter", |
1915 | 0 | "Should re-type password for own format, won't export recovery file"); |
1916 | 0 | rMedium.SetError(ERRCODE_SFX_WRONGPASSWORD); |
1917 | 0 | return false; |
1918 | 0 | } |
1919 | | |
1920 | 0 | if (!pViewShell->ExecuteRetypePassDlg(PASSHASH_SHA1)) |
1921 | | // password re-type cancelled. Don't save the document. |
1922 | 0 | return false; |
1923 | 0 | } |
1924 | | |
1925 | 0 | ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() ); |
1926 | |
|
1927 | 0 | PrepareSaveGuard aPrepareGuard( *this); |
1928 | | |
1929 | | // wait cursor is handled with progress bar |
1930 | 0 | bool bRet = SfxObjectShell::SaveAs( rMedium ); |
1931 | 0 | if (bRet) |
1932 | 0 | bRet = SaveXML( &rMedium, nullptr ); |
1933 | |
|
1934 | 0 | return bRet; |
1935 | 0 | } |
1936 | | |
1937 | | namespace { |
1938 | | |
1939 | | // Xcl-like column width measured in characters of standard font. |
1940 | | sal_Int32 lcl_ScDocShell_GetColWidthInChars( sal_uInt16 nWidth ) |
1941 | 0 | { |
1942 | 0 | double f = nWidth; |
1943 | 0 | f *= 1328.0 / 25.0; |
1944 | 0 | f += 90.0; |
1945 | 0 | f *= 1.0 / 23.0; |
1946 | 0 | f /= 256.0; |
1947 | |
|
1948 | 0 | return sal_Int32( f ); |
1949 | 0 | } |
1950 | | |
1951 | | void lcl_ScDocShell_GetFixedWidthString( OUString& rStr, const ScDocument& rDoc, |
1952 | | SCTAB nTab, SCCOL nCol, bool bValue, SvxCellHorJustify eHorJust ) |
1953 | 0 | { |
1954 | 0 | OUString aString = rStr; |
1955 | 0 | sal_Int32 nLen = lcl_ScDocShell_GetColWidthInChars( |
1956 | 0 | rDoc.GetColWidth( nCol, nTab ) ); |
1957 | | //If the text won't fit in the column |
1958 | 0 | if ( nLen < aString.getLength() ) |
1959 | 0 | { |
1960 | 0 | OUStringBuffer aReplacement; |
1961 | 0 | if (bValue) |
1962 | 0 | aReplacement.append("###"); |
1963 | 0 | else |
1964 | 0 | aReplacement.append(aString); |
1965 | | //truncate to the number of characters that should fit, even in the |
1966 | | //bValue case nLen might be < len ### |
1967 | 0 | aString = comphelper::string::truncateToLength(aReplacement, nLen).makeStringAndClear(); |
1968 | 0 | } |
1969 | 0 | if ( nLen > aString.getLength() ) |
1970 | 0 | { |
1971 | 0 | if ( bValue && eHorJust == SvxCellHorJustify::Standard ) |
1972 | 0 | eHorJust = SvxCellHorJustify::Right; |
1973 | 0 | OUStringBuffer aTmp(nLen); |
1974 | 0 | switch ( eHorJust ) |
1975 | 0 | { |
1976 | 0 | case SvxCellHorJustify::Right: |
1977 | 0 | comphelper::string::padToLength( aTmp, nLen - aString.getLength(), ' ' ); |
1978 | 0 | aString = aTmp.append(aString); |
1979 | 0 | break; |
1980 | 0 | case SvxCellHorJustify::Center: |
1981 | 0 | comphelper::string::padToLength( aTmp, (nLen - aString.getLength()) / 2, ' ' ); |
1982 | 0 | [[fallthrough]]; |
1983 | 0 | default: |
1984 | 0 | aTmp.append(aString); |
1985 | 0 | comphelper::string::padToLength( aTmp, nLen, ' ' ); |
1986 | 0 | } |
1987 | 0 | aString = aTmp.makeStringAndClear(); |
1988 | 0 | } |
1989 | 0 | rStr = aString; |
1990 | 0 | } |
1991 | | |
1992 | | void lcl_ScDocShell_WriteEmptyFixedWidthString( SvStream& rStream, |
1993 | | const ScDocument& rDoc, SCTAB nTab, SCCOL nCol ) |
1994 | 0 | { |
1995 | 0 | OUString aString; |
1996 | 0 | lcl_ScDocShell_GetFixedWidthString( aString, rDoc, nTab, nCol, false, |
1997 | 0 | SvxCellHorJustify::Standard ); |
1998 | 0 | rStream.WriteUnicodeOrByteText( aString ); |
1999 | 0 | } |
2000 | | |
2001 | | template<typename StrT, typename SepCharT> |
2002 | | sal_Int32 getTextSepPos( |
2003 | | const StrT& rStr, const ScImportOptions& rAsciiOpt, const SepCharT& rTextSep, const SepCharT& rFieldSep, bool& rNeedQuotes) |
2004 | 0 | { |
2005 | | // #i116636# quotes are needed if text delimiter (quote), field delimiter, |
2006 | | // or LF or CR is in the cell text. |
2007 | 0 | sal_Int32 nPos = rStr.indexOf(rTextSep); |
2008 | 0 | rNeedQuotes = rAsciiOpt.bQuoteAllText || (nPos >= 0) || |
2009 | 0 | (rStr.indexOf(rFieldSep) >= 0) || |
2010 | 0 | (rStr.indexOf('\n') >= 0) || |
2011 | 0 | (rStr.indexOf('\r') >= 0); |
2012 | 0 | return nPos; |
2013 | 0 | } Unexecuted instantiation: docsh.cxx:int (anonymous namespace)::getTextSepPos<rtl::OUString, char16_t>(rtl::OUString const&, ScImportOptions const&, char16_t const&, char16_t const&, bool&) Unexecuted instantiation: docsh.cxx:int (anonymous namespace)::getTextSepPos<rtl::OUString, rtl::OUString>(rtl::OUString const&, ScImportOptions const&, rtl::OUString const&, rtl::OUString const&, bool&) Unexecuted instantiation: docsh.cxx:int (anonymous namespace)::getTextSepPos<rtl::OString, rtl::OString>(rtl::OString const&, ScImportOptions const&, rtl::OString const&, rtl::OString const&, bool&) |
2014 | | |
2015 | | } |
2016 | | |
2017 | | void ScDocShell::AsciiSave( SvStream& rStream, const ScImportOptions& rAsciiOpt, SCTAB nTab ) |
2018 | 0 | { |
2019 | 0 | sal_Unicode cDelim = rAsciiOpt.nFieldSepCode; |
2020 | 0 | sal_Unicode cStrDelim = rAsciiOpt.nTextSepCode; |
2021 | 0 | rtl_TextEncoding eCharSet = rAsciiOpt.eCharSet; |
2022 | 0 | bool bFixedWidth = rAsciiOpt.bFixedWidth; |
2023 | 0 | bool bSaveNumberAsSuch = rAsciiOpt.bSaveNumberAsSuch; |
2024 | 0 | bool bSaveAsShown = rAsciiOpt.bSaveAsShown; |
2025 | 0 | bool bShowFormulas = rAsciiOpt.bSaveFormulas; |
2026 | 0 | bool bIncludeBOM = rAsciiOpt.bIncludeBOM; |
2027 | |
|
2028 | 0 | rtl_TextEncoding eOldCharSet = rStream.GetStreamCharSet(); |
2029 | 0 | rStream.SetStreamCharSet( eCharSet ); |
2030 | 0 | SvStreamEndian nOldNumberFormatInt = rStream.GetEndian(); |
2031 | 0 | OString aStrDelimEncoded; // only used if not Unicode |
2032 | 0 | OUString aStrDelimDecoded; // only used if context encoding |
2033 | 0 | OString aDelimEncoded; |
2034 | 0 | OUString aDelimDecoded; |
2035 | 0 | bool bContextOrNotAsciiEncoding; |
2036 | 0 | if ( eCharSet == RTL_TEXTENCODING_UNICODE ) |
2037 | 0 | { |
2038 | 0 | rStream.StartWritingUnicodeText(); |
2039 | 0 | bContextOrNotAsciiEncoding = false; |
2040 | 0 | } |
2041 | 0 | else |
2042 | 0 | { |
2043 | | // tdf#82254 - check whether to include a byte-order-mark in the output |
2044 | 0 | if (bIncludeBOM && eCharSet == RTL_TEXTENCODING_UTF8) |
2045 | 0 | rStream.WriteUChar(0xEF).WriteUChar(0xBB).WriteUChar(0xBF); |
2046 | 0 | aStrDelimEncoded = OString(&cStrDelim, 1, eCharSet); |
2047 | 0 | aDelimEncoded = OString(&cDelim, 1, eCharSet); |
2048 | 0 | rtl_TextEncodingInfo aInfo; |
2049 | 0 | aInfo.StructSize = sizeof(aInfo); |
2050 | 0 | if ( rtl_getTextEncodingInfo( eCharSet, &aInfo ) ) |
2051 | 0 | { |
2052 | 0 | bContextOrNotAsciiEncoding = |
2053 | 0 | (((aInfo.Flags & RTL_TEXTENCODING_INFO_CONTEXT) != 0) || |
2054 | 0 | ((aInfo.Flags & RTL_TEXTENCODING_INFO_ASCII) == 0)); |
2055 | 0 | if ( bContextOrNotAsciiEncoding ) |
2056 | 0 | { |
2057 | 0 | aStrDelimDecoded = OStringToOUString(aStrDelimEncoded, eCharSet); |
2058 | 0 | aDelimDecoded = OStringToOUString(aDelimEncoded, eCharSet); |
2059 | 0 | } |
2060 | 0 | } |
2061 | 0 | else |
2062 | 0 | bContextOrNotAsciiEncoding = false; |
2063 | 0 | } |
2064 | |
|
2065 | 0 | SCCOL nStartCol = 0; |
2066 | 0 | SCROW nStartRow = 0; |
2067 | 0 | SCCOL nEndCol; |
2068 | 0 | SCROW nEndRow; |
2069 | 0 | m_pDocument->GetCellArea( nTab, nEndCol, nEndRow ); |
2070 | |
|
2071 | 0 | ScProgress aProgress( this, ScResId( STR_SAVE_DOC ), nEndRow, true ); |
2072 | |
|
2073 | 0 | OUString aString; |
2074 | |
|
2075 | 0 | bool bTabProtect = m_pDocument->IsTabProtected( nTab ); |
2076 | |
|
2077 | 0 | SCCOL nCol; |
2078 | 0 | SCROW nRow; |
2079 | | |
2080 | | // Treat the top left cell separator "sep=" special. |
2081 | | // Here nStartRow == 0 && nStartCol == 0 |
2082 | 0 | if (!bFixedWidth && cDelim != 0) |
2083 | 0 | { |
2084 | | // First row iterator. |
2085 | 0 | ScHorizontalCellIterator aIter( *m_pDocument, nTab, nStartCol, nStartRow, nEndCol, nStartRow); |
2086 | 0 | ScRefCellValue* pCell; |
2087 | | // Must be first column and all following cells on this row must be |
2088 | | // empty to fiddle with "sep=". |
2089 | 0 | if ((pCell = aIter.GetNext( nCol, nRow)) != nullptr && nCol == nStartCol && !aIter.GetNext( nCol, nRow)) |
2090 | 0 | { |
2091 | 0 | if (pCell->getType() == CELLTYPE_STRING) |
2092 | 0 | { |
2093 | 0 | aString = pCell->getSharedString()->getString(); |
2094 | 0 | if (aString.getLength() <= 5 && aString.startsWithIgnoreAsciiCase("sep=")) |
2095 | 0 | { |
2096 | | // Cell content is /^sep=.?$/ so write current separator. |
2097 | | // Force the quote character to '"' regardless what is set |
2098 | | // for export because that is the only one recognized on |
2099 | | // import. |
2100 | 0 | aString = "sep=" + OUStringChar(cDelim); |
2101 | 0 | if (cStrDelim != 0) |
2102 | 0 | rStream.WriteUniOrByteChar( '"', eCharSet); |
2103 | 0 | rStream.WriteUnicodeOrByteText(aString, eCharSet); |
2104 | 0 | if (cStrDelim != 0) |
2105 | 0 | rStream.WriteUniOrByteChar( '"', eCharSet); |
2106 | 0 | endlub( rStream ); |
2107 | 0 | ++nStartRow; |
2108 | 0 | } |
2109 | 0 | } |
2110 | 0 | } |
2111 | 0 | } |
2112 | |
|
2113 | 0 | SCCOL nNextCol = nStartCol; |
2114 | 0 | SCROW nNextRow = nStartRow; |
2115 | 0 | SCCOL nEmptyCol; |
2116 | 0 | SCROW nEmptyRow; |
2117 | 0 | ScInterpreterContext& rContext = m_pDocument->GetNonThreadedContext(); |
2118 | |
|
2119 | 0 | ScHorizontalCellIterator aIter( *m_pDocument, nTab, nStartCol, nStartRow, |
2120 | 0 | nEndCol, nEndRow ); |
2121 | 0 | ScRefCellValue* pCell; |
2122 | 0 | while ( ( pCell = aIter.GetNext( nCol, nRow ) ) != nullptr ) |
2123 | 0 | { |
2124 | 0 | bool bProgress = false; // only upon line change |
2125 | 0 | if ( nNextRow < nRow ) |
2126 | 0 | { // empty rows or/and empty columns up to end of row |
2127 | 0 | bProgress = true; |
2128 | 0 | for ( nEmptyCol = nNextCol; nEmptyCol < nEndCol; nEmptyCol++ ) |
2129 | 0 | { // remaining columns of last row |
2130 | 0 | if ( bFixedWidth ) |
2131 | 0 | lcl_ScDocShell_WriteEmptyFixedWidthString( rStream, |
2132 | 0 | *m_pDocument, nTab, nEmptyCol ); |
2133 | 0 | else if ( cDelim != 0 ) |
2134 | 0 | rStream.WriteUniOrByteChar( cDelim ); |
2135 | 0 | } |
2136 | 0 | endlub( rStream ); |
2137 | 0 | nNextRow++; |
2138 | 0 | for ( nEmptyRow = nNextRow; nEmptyRow < nRow; nEmptyRow++ ) |
2139 | 0 | { // completely empty rows |
2140 | 0 | for ( nEmptyCol = nStartCol; nEmptyCol < nEndCol; nEmptyCol++ ) |
2141 | 0 | { |
2142 | 0 | if ( bFixedWidth ) |
2143 | 0 | lcl_ScDocShell_WriteEmptyFixedWidthString( rStream, |
2144 | 0 | *m_pDocument, nTab, nEmptyCol ); |
2145 | 0 | else if ( cDelim != 0 ) |
2146 | 0 | rStream.WriteUniOrByteChar( cDelim ); |
2147 | 0 | } |
2148 | 0 | endlub( rStream ); |
2149 | 0 | } |
2150 | 0 | for ( nEmptyCol = nStartCol; nEmptyCol < nCol; nEmptyCol++ ) |
2151 | 0 | { // empty columns at beginning of row |
2152 | 0 | if ( bFixedWidth ) |
2153 | 0 | lcl_ScDocShell_WriteEmptyFixedWidthString( rStream, |
2154 | 0 | *m_pDocument, nTab, nEmptyCol ); |
2155 | 0 | else if ( cDelim != 0 ) |
2156 | 0 | rStream.WriteUniOrByteChar( cDelim ); |
2157 | 0 | } |
2158 | 0 | nNextRow = nRow; |
2159 | 0 | } |
2160 | 0 | else if ( nNextCol < nCol ) |
2161 | 0 | { // empty columns in same row |
2162 | 0 | for ( nEmptyCol = nNextCol; nEmptyCol < nCol; nEmptyCol++ ) |
2163 | 0 | { // columns in between |
2164 | 0 | if ( bFixedWidth ) |
2165 | 0 | lcl_ScDocShell_WriteEmptyFixedWidthString( rStream, |
2166 | 0 | *m_pDocument, nTab, nEmptyCol ); |
2167 | 0 | else if ( cDelim != 0 ) |
2168 | 0 | rStream.WriteUniOrByteChar( cDelim ); |
2169 | 0 | } |
2170 | 0 | } |
2171 | 0 | if ( nCol == nEndCol ) |
2172 | 0 | { |
2173 | 0 | bProgress = true; |
2174 | 0 | nNextCol = nStartCol; |
2175 | 0 | nNextRow = nRow + 1; |
2176 | 0 | } |
2177 | 0 | else |
2178 | 0 | nNextCol = nCol + 1; |
2179 | |
|
2180 | 0 | CellType eType = pCell->getType(); |
2181 | 0 | ScAddress aPos(nCol, nRow, nTab); |
2182 | 0 | if ( bTabProtect ) |
2183 | 0 | { |
2184 | 0 | const ScProtectionAttr& rProtAttr = |
2185 | 0 | m_pDocument->GetAttr( nCol, nRow, nTab, ATTR_PROTECTION ); |
2186 | 0 | if ( rProtAttr.GetHideCell() || |
2187 | 0 | ( eType == CELLTYPE_FORMULA && bShowFormulas && |
2188 | 0 | rProtAttr.GetHideFormula() ) ) |
2189 | 0 | eType = CELLTYPE_NONE; // hide |
2190 | 0 | } |
2191 | 0 | bool bForceQuotes = false; |
2192 | 0 | bool bString; |
2193 | 0 | switch ( eType ) |
2194 | 0 | { |
2195 | 0 | case CELLTYPE_NONE: |
2196 | 0 | aString.clear(); |
2197 | 0 | bString = false; |
2198 | 0 | break; |
2199 | 0 | case CELLTYPE_FORMULA : |
2200 | 0 | { |
2201 | 0 | FormulaError nErrCode; |
2202 | 0 | if ( bShowFormulas ) |
2203 | 0 | { |
2204 | 0 | aString = pCell->getFormula()->GetFormula(); |
2205 | 0 | bString = true; |
2206 | 0 | } |
2207 | 0 | else if ((nErrCode = pCell->getFormula()->GetErrCode()) != FormulaError::NONE) |
2208 | 0 | { |
2209 | 0 | aString = ScGlobal::GetErrorString( nErrCode ); |
2210 | 0 | bString = true; |
2211 | 0 | } |
2212 | 0 | else if (pCell->getFormula()->IsValue()) |
2213 | 0 | { |
2214 | 0 | sal_uInt32 nFormat = m_pDocument->GetNumberFormat(ScRange(aPos)); |
2215 | 0 | if ( bFixedWidth || bSaveAsShown ) |
2216 | 0 | { |
2217 | 0 | const Color* pDummy; |
2218 | 0 | aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, &rContext, *m_pDocument); |
2219 | 0 | bString = bSaveAsShown && rContext.NFIsTextFormat( nFormat); |
2220 | 0 | } |
2221 | 0 | else |
2222 | 0 | { |
2223 | 0 | aString = ScCellFormat::GetInputString(*pCell, nFormat, &rContext, *m_pDocument); |
2224 | 0 | bString = bForceQuotes = !bSaveNumberAsSuch; |
2225 | 0 | } |
2226 | 0 | } |
2227 | 0 | else |
2228 | 0 | { |
2229 | 0 | if ( bSaveAsShown ) |
2230 | 0 | { |
2231 | 0 | sal_uInt32 nFormat = m_pDocument->GetNumberFormat(ScRange(aPos)); |
2232 | 0 | const Color* pDummy; |
2233 | 0 | aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, &rContext, *m_pDocument); |
2234 | 0 | } |
2235 | 0 | else |
2236 | 0 | aString = pCell->getFormula()->GetString().getString(); |
2237 | 0 | bString = true; |
2238 | 0 | } |
2239 | 0 | } |
2240 | 0 | break; |
2241 | 0 | case CELLTYPE_STRING : |
2242 | 0 | if ( bSaveAsShown ) |
2243 | 0 | { |
2244 | 0 | sal_uInt32 nFormat = m_pDocument->GetNumberFormat(ScRange(aPos)); |
2245 | 0 | const Color* pDummy; |
2246 | 0 | aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, &rContext, *m_pDocument); |
2247 | 0 | } |
2248 | 0 | else |
2249 | 0 | aString = pCell->getSharedString()->getString(); |
2250 | 0 | bString = true; |
2251 | 0 | break; |
2252 | 0 | case CELLTYPE_EDIT : |
2253 | 0 | { |
2254 | 0 | const EditTextObject* pObj = pCell->getEditText(); |
2255 | 0 | EditEngine& rEngine = m_pDocument->GetEditEngine(); |
2256 | 0 | rEngine.SetText( *pObj); |
2257 | 0 | aString = rEngine.GetText(); // including LF |
2258 | 0 | bString = true; |
2259 | 0 | } |
2260 | 0 | break; |
2261 | 0 | case CELLTYPE_VALUE : |
2262 | 0 | { |
2263 | 0 | sal_uInt32 nFormat = m_pDocument->GetNumberFormat( nCol, nRow, nTab ); |
2264 | 0 | if ( bFixedWidth || bSaveAsShown ) |
2265 | 0 | { |
2266 | 0 | const Color* pDummy; |
2267 | 0 | aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, &rContext, *m_pDocument); |
2268 | 0 | bString = bSaveAsShown && rContext.NFIsTextFormat( nFormat); |
2269 | 0 | } |
2270 | 0 | else |
2271 | 0 | { |
2272 | 0 | aString = ScCellFormat::GetInputString(*pCell, nFormat, &rContext, *m_pDocument); |
2273 | 0 | bString = bForceQuotes = !bSaveNumberAsSuch; |
2274 | 0 | } |
2275 | 0 | } |
2276 | 0 | break; |
2277 | 0 | default: |
2278 | 0 | OSL_FAIL( "ScDocShell::AsciiSave: unknown CellType" ); |
2279 | 0 | aString.clear(); |
2280 | 0 | bString = false; |
2281 | 0 | } |
2282 | | |
2283 | 0 | if ( bFixedWidth ) |
2284 | 0 | { |
2285 | 0 | SvxCellHorJustify eHorJust = |
2286 | 0 | m_pDocument->GetAttr( nCol, nRow, nTab, ATTR_HOR_JUSTIFY ).GetValue(); |
2287 | 0 | lcl_ScDocShell_GetFixedWidthString( aString, *m_pDocument, nTab, nCol, |
2288 | 0 | !bString, eHorJust ); |
2289 | 0 | rStream.WriteUnicodeOrByteText( aString ); |
2290 | 0 | } |
2291 | 0 | else |
2292 | 0 | { |
2293 | 0 | OUString aUniString = aString;// TODO: remove that later |
2294 | 0 | if (!bString && cStrDelim != 0 && !aUniString.isEmpty()) |
2295 | 0 | { |
2296 | 0 | sal_Unicode c = aUniString[0]; |
2297 | 0 | bString = (c == cStrDelim || c == ' ' || |
2298 | 0 | aUniString.endsWith(" ") || |
2299 | 0 | aUniString.indexOf(cStrDelim) >= 0); |
2300 | 0 | if (!bString && cDelim != 0) |
2301 | 0 | bString = (aUniString.indexOf(cDelim) >= 0); |
2302 | 0 | } |
2303 | 0 | if ( bString ) |
2304 | 0 | { |
2305 | 0 | if ( cStrDelim != 0 ) //@ BugId 55355 |
2306 | 0 | { |
2307 | 0 | if ( eCharSet == RTL_TEXTENCODING_UNICODE ) |
2308 | 0 | { |
2309 | 0 | bool bNeedQuotes = false; |
2310 | 0 | sal_Int32 nPos = getTextSepPos(aUniString, rAsciiOpt, cStrDelim, cDelim, bNeedQuotes); |
2311 | 0 | if (nPos >= 0) |
2312 | 0 | { |
2313 | 0 | OUString strFrom(cStrDelim); |
2314 | 0 | OUString strTo = strFrom + strFrom; |
2315 | 0 | aUniString = aUniString.replaceAll(strFrom, strTo); |
2316 | 0 | } |
2317 | |
|
2318 | 0 | if ( bNeedQuotes || bForceQuotes ) |
2319 | 0 | rStream.WriteUniOrByteChar( cStrDelim, eCharSet ); |
2320 | 0 | rStream.WriteUnicodeOrByteText(aUniString, eCharSet); |
2321 | 0 | if ( bNeedQuotes || bForceQuotes ) |
2322 | 0 | rStream.WriteUniOrByteChar( cStrDelim, eCharSet ); |
2323 | 0 | } |
2324 | 0 | else |
2325 | 0 | { |
2326 | | // This is nasty. The Unicode to byte encoding |
2327 | | // may convert typographical quotation marks to ASCII |
2328 | | // quotation marks, which may interfere with the delimiter, |
2329 | | // so we have to escape delimiters after the string has |
2330 | | // been encoded. Since this may happen also with UTF-8 |
2331 | | // encoded typographical quotation marks if such was |
2332 | | // specified as a delimiter we have to check for the full |
2333 | | // encoded delimiter string, not just one character. |
2334 | | // Now for RTL_TEXTENCODING_ISO_2022_... and similar brain |
2335 | | // dead encodings where one code point (and especially a |
2336 | | // low ASCII value) may represent different characters, we |
2337 | | // have to convert forth and back and forth again. Same for |
2338 | | // UTF-7 since it is a context sensitive encoding too. |
2339 | |
|
2340 | 0 | if ( bContextOrNotAsciiEncoding ) |
2341 | 0 | { |
2342 | | // to byte encoding |
2343 | 0 | OString aStrEnc = OUStringToOString(aUniString, eCharSet); |
2344 | | // back to Unicode |
2345 | 0 | OUString aStrDec = OStringToOUString(aStrEnc, eCharSet); |
2346 | | |
2347 | | // search on re-decoded string |
2348 | 0 | bool bNeedQuotes = false; |
2349 | 0 | sal_Int32 nPos = getTextSepPos(aStrDec, rAsciiOpt, aStrDelimDecoded, aDelimDecoded, bNeedQuotes); |
2350 | 0 | if (nPos >= 0) |
2351 | 0 | { |
2352 | 0 | OUString strTo = aStrDelimDecoded + aStrDelimDecoded; |
2353 | 0 | aStrDec = aStrDec.replaceAll(aStrDelimDecoded, strTo); |
2354 | 0 | } |
2355 | | |
2356 | | // write byte re-encoded |
2357 | 0 | if ( bNeedQuotes || bForceQuotes ) |
2358 | 0 | rStream.WriteUniOrByteChar( cStrDelim, eCharSet ); |
2359 | 0 | rStream.WriteUnicodeOrByteText( aStrDec, eCharSet ); |
2360 | 0 | if ( bNeedQuotes || bForceQuotes ) |
2361 | 0 | rStream.WriteUniOrByteChar( cStrDelim, eCharSet ); |
2362 | 0 | } |
2363 | 0 | else |
2364 | 0 | { |
2365 | 0 | OString aStrEnc = OUStringToOString(aUniString, eCharSet); |
2366 | | |
2367 | | // search on encoded string |
2368 | 0 | bool bNeedQuotes = false; |
2369 | 0 | sal_Int32 nPos = getTextSepPos(aStrEnc, rAsciiOpt, aStrDelimEncoded, aDelimEncoded, bNeedQuotes); |
2370 | 0 | if (nPos >= 0) |
2371 | 0 | { |
2372 | 0 | OString strTo = aStrDelimEncoded + aStrDelimEncoded; |
2373 | 0 | aStrEnc = aStrEnc.replaceAll(aStrDelimEncoded, strTo); |
2374 | 0 | } |
2375 | | |
2376 | | // write byte encoded |
2377 | 0 | if ( bNeedQuotes || bForceQuotes ) |
2378 | 0 | rStream.WriteBytes( |
2379 | 0 | aStrDelimEncoded.getStr(), aStrDelimEncoded.getLength()); |
2380 | 0 | rStream.WriteBytes(aStrEnc.getStr(), aStrEnc.getLength()); |
2381 | 0 | if ( bNeedQuotes || bForceQuotes ) |
2382 | 0 | rStream.WriteBytes( |
2383 | 0 | aStrDelimEncoded.getStr(), aStrDelimEncoded.getLength()); |
2384 | 0 | } |
2385 | 0 | } |
2386 | 0 | } |
2387 | 0 | else |
2388 | 0 | rStream.WriteUnicodeOrByteText( aUniString ); |
2389 | 0 | } |
2390 | 0 | else |
2391 | 0 | rStream.WriteUnicodeOrByteText( aUniString ); |
2392 | 0 | } |
2393 | |
|
2394 | 0 | if( nCol < nEndCol ) |
2395 | 0 | { |
2396 | 0 | if(cDelim!=0) //@ BugId 55355 |
2397 | 0 | rStream.WriteUniOrByteChar( cDelim ); |
2398 | 0 | } |
2399 | 0 | else |
2400 | 0 | endlub( rStream ); |
2401 | |
|
2402 | 0 | if ( bProgress ) |
2403 | 0 | aProgress.SetStateOnPercent( nRow ); |
2404 | 0 | } |
2405 | | |
2406 | | // write out empty if requested |
2407 | 0 | if ( nNextRow <= nEndRow ) |
2408 | 0 | { |
2409 | 0 | for ( nEmptyCol = nNextCol; nEmptyCol < nEndCol; nEmptyCol++ ) |
2410 | 0 | { // remaining empty columns of last row |
2411 | 0 | if ( bFixedWidth ) |
2412 | 0 | lcl_ScDocShell_WriteEmptyFixedWidthString( rStream, |
2413 | 0 | *m_pDocument, nTab, nEmptyCol ); |
2414 | 0 | else if ( cDelim != 0 ) |
2415 | 0 | rStream.WriteUniOrByteChar( cDelim ); |
2416 | 0 | } |
2417 | 0 | endlub( rStream ); |
2418 | 0 | nNextRow++; |
2419 | 0 | } |
2420 | 0 | for ( nEmptyRow = nNextRow; nEmptyRow <= nEndRow; nEmptyRow++ ) |
2421 | 0 | { // entire empty rows |
2422 | 0 | for ( nEmptyCol = nStartCol; nEmptyCol < nEndCol; nEmptyCol++ ) |
2423 | 0 | { |
2424 | 0 | if ( bFixedWidth ) |
2425 | 0 | lcl_ScDocShell_WriteEmptyFixedWidthString( rStream, |
2426 | 0 | *m_pDocument, nTab, nEmptyCol ); |
2427 | 0 | else if ( cDelim != 0 ) |
2428 | 0 | rStream.WriteUniOrByteChar( cDelim ); |
2429 | 0 | } |
2430 | 0 | endlub( rStream ); |
2431 | 0 | } |
2432 | |
|
2433 | 0 | rStream.SetStreamCharSet( eOldCharSet ); |
2434 | 0 | rStream.SetEndian( nOldNumberFormatInt ); |
2435 | 0 | } |
2436 | | |
2437 | | bool ScDocShell::ConvertTo( SfxMedium &rMed ) |
2438 | 0 | { |
2439 | 0 | ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() ); |
2440 | | |
2441 | | // #i6500# don't call DoEnterHandler here (doesn't work with AutoSave), |
2442 | | // it's already in ExecuteSave (as for Save and SaveAs) |
2443 | |
|
2444 | 0 | if (m_pAutoStyleList) |
2445 | 0 | m_pAutoStyleList->ExecuteAllNow(); // Execute template timeouts now |
2446 | 0 | if (GetCreateMode()== SfxObjectCreateMode::STANDARD) |
2447 | 0 | SfxObjectShell::SetVisArea( tools::Rectangle() ); // Edited normally -> no VisArea |
2448 | |
|
2449 | 0 | OSL_ENSURE( rMed.GetFilter(), "Filter == 0" ); |
2450 | |
|
2451 | 0 | bool bRet = false; |
2452 | 0 | OUString aFltName = rMed.GetFilter()->GetFilterName(); |
2453 | |
|
2454 | 0 | if (aFltName == SC_SOXML_FILTER_NAME) |
2455 | 0 | { |
2456 | | //TODO/LATER: this shouldn't happen! |
2457 | 0 | OSL_FAIL("XML filter in ConvertFrom?!"); |
2458 | 0 | bRet = SaveXML( &rMed, nullptr ); |
2459 | 0 | } |
2460 | 0 | else if (aFltName == SC_XL5_FILTER_NAME || aFltName == SC_XL95_FILTER_NAME || |
2461 | 0 | aFltName == SC_XL97_FILTER_NAME || aFltName == SC_XL5TMPL_FILTER_NAME || |
2462 | 0 | aFltName == SC_XL95TMPL_FILTER_NAME || aFltName == SC_XL97TMPL_FILTER_NAME) |
2463 | 0 | { |
2464 | 0 | weld::WaitObject aWait( GetActiveDialogParent() ); |
2465 | |
|
2466 | 0 | bool bDoSave = true; |
2467 | 0 | if( ScTabViewShell* pViewShell = GetBestViewShell() ) |
2468 | 0 | { |
2469 | 0 | ScExtDocOptions* pExtDocOpt = m_pDocument->GetExtDocOptions(); |
2470 | 0 | if( !pExtDocOpt ) |
2471 | 0 | { |
2472 | 0 | m_pDocument->SetExtDocOptions( std::make_unique<ScExtDocOptions>() ); |
2473 | 0 | pExtDocOpt = m_pDocument->GetExtDocOptions(); |
2474 | 0 | } |
2475 | 0 | pViewShell->GetViewData().WriteExtOptions( *pExtDocOpt ); |
2476 | | |
2477 | | /* #i104990# If the imported document contains a medium |
2478 | | password, determine if we can save it, otherwise ask the users |
2479 | | whether they want to save without it. */ |
2480 | 0 | if( (rMed.GetFilter()->GetFilterFlags() & SfxFilterFlags::ENCRYPTION) == SfxFilterFlags::NONE ) |
2481 | 0 | { |
2482 | 0 | SfxItemSet& rItemSet = rMed.GetItemSet(); |
2483 | 0 | if( rItemSet.GetItemState( SID_PASSWORD ) == SfxItemState::SET ) |
2484 | 0 | { |
2485 | 0 | bDoSave = ScWarnPassword::WarningOnPassword( rMed ); |
2486 | | // #i42858# remove password from medium (warn only one time) |
2487 | 0 | if( bDoSave ) |
2488 | 0 | rItemSet.ClearItem( SID_PASSWORD ); |
2489 | 0 | } |
2490 | 0 | } |
2491 | |
|
2492 | 0 | if( bDoSave ) |
2493 | 0 | { |
2494 | 0 | bool bNeedRetypePassDlg = ScPassHashHelper::needsPassHashRegen( *m_pDocument, PASSHASH_XL ); |
2495 | 0 | bDoSave = !bNeedRetypePassDlg || pViewShell->ExecuteRetypePassDlg( PASSHASH_XL ); |
2496 | 0 | } |
2497 | 0 | } |
2498 | |
|
2499 | 0 | if( bDoSave ) |
2500 | 0 | { |
2501 | 0 | ExportFormatExcel eFormat = ExpBiff5; |
2502 | 0 | if (aFltName == SC_XL97_FILTER_NAME || aFltName == SC_XL97TMPL_FILTER_NAME) |
2503 | 0 | eFormat = ExpBiff8; |
2504 | 0 | ErrCode eError = ScFormatFilter::Get().ScExportExcel5( rMed, m_pDocument.get(), eFormat, RTL_TEXTENCODING_MS_1252 ); |
2505 | |
|
2506 | 0 | if( eError && !GetErrorIgnoreWarning() ) |
2507 | 0 | SetError(eError); |
2508 | | |
2509 | | // don't return false for warnings |
2510 | 0 | bRet = eError.IsWarning() || (eError == ERRCODE_NONE); |
2511 | 0 | } |
2512 | 0 | else |
2513 | 0 | { |
2514 | | // export aborted, i.e. "Save without password" warning |
2515 | 0 | SetError(ERRCODE_ABORT); |
2516 | 0 | } |
2517 | 0 | } |
2518 | 0 | else if (aFltName == SC_TEXT_CSV_FILTER_NAME) |
2519 | 0 | { |
2520 | 0 | OUString sItStr; |
2521 | 0 | if ( const SfxStringItem* pOptionsItem = rMed.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) ) |
2522 | 0 | { |
2523 | 0 | sItStr = pOptionsItem->GetValue(); |
2524 | 0 | } |
2525 | |
|
2526 | 0 | if ( sItStr.isEmpty() ) |
2527 | 0 | { |
2528 | | // default for ascii export (from API without options): |
2529 | | // UTF-8 encoding, comma, double quotes |
2530 | |
|
2531 | 0 | ScImportOptions aDefOptions(',', '"', RTL_TEXTENCODING_UTF8); |
2532 | 0 | sItStr = aDefOptions.BuildString(); |
2533 | 0 | } |
2534 | |
|
2535 | 0 | weld::WaitObject aWait( GetActiveDialogParent() ); |
2536 | 0 | ScImportOptions aOptions( sItStr ); |
2537 | |
|
2538 | 0 | if (aOptions.nSheetToExport) |
2539 | 0 | { |
2540 | | // Only from command line --convert-to |
2541 | 0 | bRet = true; |
2542 | | |
2543 | | // Verbose only from command line, not UI (in case we actually |
2544 | | // implement that) nor macro filter options. |
2545 | 0 | bool bVerbose |
2546 | 0 | = rMed.GetArgs().getValue(u"ConversionRequestOrigin"_ustr) == u"CommandLine"_ustr; |
2547 | |
|
2548 | 0 | SCTAB nStartTab; |
2549 | 0 | SCTAB nCount = m_pDocument->GetTableCount(); |
2550 | 0 | if (aOptions.nSheetToExport == -1) |
2551 | 0 | { |
2552 | | // All sheets. |
2553 | 0 | nStartTab = 0; |
2554 | 0 | } |
2555 | 0 | else if (0 < aOptions.nSheetToExport && aOptions.nSheetToExport <= nCount) |
2556 | 0 | { |
2557 | | // One sheet, 1-based. |
2558 | 0 | nCount = aOptions.nSheetToExport; |
2559 | 0 | nStartTab = nCount - 1; |
2560 | 0 | } |
2561 | 0 | else |
2562 | 0 | { |
2563 | | // Usage error, no export but log. |
2564 | 0 | if (bVerbose) |
2565 | 0 | { |
2566 | 0 | if (aOptions.nSheetToExport < 0) |
2567 | 0 | std::cout << "Bad sheet number string given." << std::endl; |
2568 | 0 | else |
2569 | 0 | std::cout << "No sheet number " << aOptions.nSheetToExport |
2570 | 0 | << ", number of sheets is " << nCount << std::endl; |
2571 | 0 | } |
2572 | 0 | nStartTab = 0; |
2573 | 0 | nCount = 0; |
2574 | 0 | SetError(SCERR_EXPORT_DATA); |
2575 | 0 | bRet = false; |
2576 | 0 | } |
2577 | |
|
2578 | 0 | INetURLObject aURLObject(rMed.GetURLObject()); |
2579 | 0 | OUString sExt = aURLObject.CutExtension(); |
2580 | 0 | OUString sBaseName = aURLObject.GetLastName(); |
2581 | 0 | aURLObject.CutLastName(); |
2582 | |
|
2583 | 0 | for (SCTAB i = nStartTab; i < nCount; ++i) |
2584 | 0 | { |
2585 | 0 | OUString sTabName; |
2586 | 0 | if (!m_pDocument->GetName(i, sTabName)) |
2587 | 0 | sTabName = OUString::number(i); |
2588 | 0 | INetURLObject aSheetURLObject(aURLObject); |
2589 | 0 | OUString sFileName = sBaseName + "-" + sTabName; |
2590 | 0 | if (!sExt.isEmpty()) |
2591 | 0 | sFileName = sFileName + "." + sExt; |
2592 | 0 | aSheetURLObject.Append(sFileName); |
2593 | | |
2594 | | // log similar to DispatchWatcher::executeDispatchRequests |
2595 | 0 | OUString aOutFile = aSheetURLObject.GetMainURL(INetURLObject::DecodeMechanism::NONE); |
2596 | 0 | if (bVerbose) |
2597 | 0 | { |
2598 | 0 | OUString aDisplayedName; |
2599 | 0 | if (osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL(aOutFile, aDisplayedName)) |
2600 | 0 | aDisplayedName = aOutFile; |
2601 | 0 | std::cout << "Writing sheet " << OUStringToOString(sTabName, osl_getThreadTextEncoding()) << " -> " |
2602 | 0 | << OUStringToOString(aDisplayedName, osl_getThreadTextEncoding()) |
2603 | 0 | << std::endl; |
2604 | |
|
2605 | 0 | if (FStatHelper::IsDocument(aOutFile)) |
2606 | 0 | std::cout << "Overwriting: " << OUStringToOString(aDisplayedName, osl_getThreadTextEncoding()) |
2607 | 0 | << std::endl ; |
2608 | 0 | } |
2609 | |
|
2610 | 0 | std::unique_ptr<SvStream> xStm = ::utl::UcbStreamHelper::CreateStream(aOutFile, StreamMode::TRUNC | StreamMode::WRITE); |
2611 | 0 | if (!xStm) |
2612 | 0 | { |
2613 | 0 | SetError(ERRCODE_IO_CANTCREATE); |
2614 | 0 | bRet = false; |
2615 | 0 | break; |
2616 | 0 | } |
2617 | 0 | AsciiSave(*xStm, aOptions, i); |
2618 | 0 | } |
2619 | 0 | } |
2620 | 0 | else |
2621 | 0 | { |
2622 | 0 | SvStream* pStream = rMed.GetOutStream(); |
2623 | 0 | if (pStream) |
2624 | 0 | { |
2625 | 0 | AsciiSave(*pStream, aOptions, GetSaveTab()); |
2626 | 0 | bRet = true; |
2627 | |
|
2628 | 0 | if (m_pDocument->GetTableCount() > 1) |
2629 | 0 | { |
2630 | 0 | if (!rMed.GetErrorIgnoreWarning() && ScModule::get()->GetInputOptions().GetWarnActiveSheet()) |
2631 | 0 | { |
2632 | 0 | if (ScTabViewShell* pViewShell = GetBestViewShell()) |
2633 | 0 | pViewShell->ExecuteOnlyActiveSheetSavedDlg(); |
2634 | 0 | } |
2635 | 0 | } |
2636 | 0 | } |
2637 | 0 | } |
2638 | 0 | } |
2639 | 0 | else if (aFltName == SC_DBASE_FILTER_NAME) |
2640 | 0 | { |
2641 | 0 | OUString sCharSet; |
2642 | 0 | if ( const SfxStringItem* pOptionsItem = rMed.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) ) |
2643 | 0 | { |
2644 | 0 | sCharSet = pOptionsItem->GetValue(); |
2645 | 0 | } |
2646 | |
|
2647 | 0 | if (sCharSet.isEmpty()) |
2648 | 0 | { |
2649 | | // default for dBase export (from API without options): |
2650 | | // IBM_850 encoding |
2651 | |
|
2652 | 0 | sCharSet = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_850 ); |
2653 | 0 | } |
2654 | |
|
2655 | 0 | weld::WaitObject aWait( GetActiveDialogParent() ); |
2656 | | // Hack so that Sba can overwrite the opened TempFile. |
2657 | 0 | rMed.CloseOutStream(); |
2658 | 0 | bool bHasMemo = false; |
2659 | |
|
2660 | 0 | ErrCodeMsg eError = DBaseExport( |
2661 | 0 | rMed.GetPhysicalName(), ScGlobal::GetCharsetValue(sCharSet), bHasMemo); |
2662 | |
|
2663 | 0 | INetURLObject aTmpFile( rMed.GetPhysicalName(), INetProtocol::File ); |
2664 | 0 | if ( bHasMemo ) |
2665 | 0 | aTmpFile.setExtension(u"dbt"); |
2666 | 0 | if ( eError != ERRCODE_NONE && !eError.IsWarning() ) |
2667 | 0 | { |
2668 | 0 | if (!GetErrorIgnoreWarning()) |
2669 | 0 | SetError(eError); |
2670 | 0 | if ( bHasMemo && IsDocument( aTmpFile ) ) |
2671 | 0 | KillFile( aTmpFile ); |
2672 | 0 | } |
2673 | 0 | else |
2674 | 0 | { |
2675 | 0 | bRet = true; |
2676 | 0 | if ( bHasMemo ) |
2677 | 0 | { |
2678 | 0 | const SfxStringItem* pNameItem = rMed.GetItemSet().GetItem<SfxStringItem>( SID_FILE_NAME ); |
2679 | 0 | assert(pNameItem && "SID_FILE_NAME is required"); |
2680 | 0 | INetURLObject aDbtFile( pNameItem->GetValue(), INetProtocol::File ); |
2681 | 0 | aDbtFile.setExtension(u"dbt"); |
2682 | | |
2683 | | // tdf#40713: don't lose dbt file |
2684 | | // if aDbtFile corresponds exactly to aTmpFile, we just have to return |
2685 | 0 | if (aDbtFile.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ) == |
2686 | 0 | aTmpFile.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous )) |
2687 | 0 | { |
2688 | 0 | if (eError != ERRCODE_NONE && !GetErrorIgnoreWarning()) |
2689 | 0 | SetError(eError); |
2690 | 0 | return bRet; |
2691 | 0 | } |
2692 | | |
2693 | 0 | if ( IsDocument( aDbtFile ) && !KillFile( aDbtFile ) ) |
2694 | 0 | bRet = false; |
2695 | 0 | if ( bRet && !MoveFile( aTmpFile, aDbtFile ) ) |
2696 | 0 | bRet = false; |
2697 | 0 | if ( !bRet ) |
2698 | 0 | { |
2699 | 0 | KillFile( aTmpFile ); |
2700 | 0 | if (eError == ERRCODE_NONE || eError.IsWarning()) |
2701 | 0 | eError = SCERR_EXPORT_DATA; |
2702 | 0 | } |
2703 | 0 | } |
2704 | 0 | if (eError != ERRCODE_NONE && !GetErrorIgnoreWarning()) |
2705 | 0 | SetError(eError); |
2706 | 0 | } |
2707 | 0 | } |
2708 | 0 | else if (aFltName == SC_DIF_FILTER_NAME) |
2709 | 0 | { |
2710 | 0 | SvStream* pStream = rMed.GetOutStream(); |
2711 | 0 | if (pStream) |
2712 | 0 | { |
2713 | 0 | OUString sItStr; |
2714 | 0 | if ( const SfxStringItem* pOptionsItem = rMed.GetItemSet().GetItemIfSet( SID_FILE_FILTEROPTIONS ) ) |
2715 | 0 | { |
2716 | 0 | sItStr = pOptionsItem->GetValue(); |
2717 | 0 | } |
2718 | |
|
2719 | 0 | if (sItStr.isEmpty()) |
2720 | 0 | { |
2721 | | // default for DIF export (from API without options): |
2722 | | // ISO8859-1/MS_1252 encoding |
2723 | |
|
2724 | 0 | sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_MS_1252 ); |
2725 | 0 | } |
2726 | |
|
2727 | 0 | weld::WaitObject aWait( GetActiveDialogParent() ); |
2728 | 0 | ScFormatFilter::Get().ScExportDif( *pStream, *m_pDocument, ScAddress(0,0,0), |
2729 | 0 | ScGlobal::GetCharsetValue(sItStr) ); |
2730 | 0 | bRet = true; |
2731 | |
|
2732 | 0 | if (m_pDocument->GetTableCount() > 1) |
2733 | 0 | if (!rMed.GetErrorIgnoreWarning() && ScModule::get()->GetInputOptions().GetWarnActiveSheet()) |
2734 | 0 | rMed.SetError(SCWARN_EXPORT_ASCII); |
2735 | 0 | } |
2736 | 0 | } |
2737 | 0 | else if (aFltName == SC_SYLK_FILTER_NAME) |
2738 | 0 | { |
2739 | 0 | SvStream* pStream = rMed.GetOutStream(); |
2740 | 0 | if ( pStream ) |
2741 | 0 | { |
2742 | 0 | weld::WaitObject aWait( GetActiveDialogParent() ); |
2743 | |
|
2744 | 0 | SCCOL nEndCol; |
2745 | 0 | SCROW nEndRow; |
2746 | 0 | m_pDocument->GetCellArea( 0, nEndCol, nEndRow ); |
2747 | 0 | ScRange aRange( 0,0,0, nEndCol,nEndRow,0 ); |
2748 | |
|
2749 | 0 | ScImportExport aImExport( *m_pDocument, aRange ); |
2750 | 0 | aImExport.SetFormulas( true ); |
2751 | 0 | bRet = aImExport.ExportStream( *pStream, rMed.GetBaseURL( true ), SotClipboardFormatId::SYLK ); |
2752 | 0 | } |
2753 | 0 | } |
2754 | 0 | else if (aFltName == SC_HTML_FILTER_NAME) |
2755 | 0 | { |
2756 | 0 | SvStream* pStream = rMed.GetOutStream(); |
2757 | 0 | if ( pStream ) |
2758 | 0 | { |
2759 | 0 | OUString sFilterOptions; |
2760 | |
|
2761 | 0 | if (const SfxStringItem* pOptionsItem = rMed.GetItemSet().GetItemIfSet(SID_FILE_FILTEROPTIONS)) |
2762 | 0 | sFilterOptions = pOptionsItem->GetValue(); |
2763 | |
|
2764 | 0 | weld::WaitObject aWait(GetActiveDialogParent()); |
2765 | 0 | ScImportExport aImExport(*m_pDocument); |
2766 | 0 | aImExport.SetStreamPath(rMed.GetName()); |
2767 | 0 | aImExport.SetFilterOptions(sFilterOptions); |
2768 | 0 | bRet = aImExport.ExportStream(*pStream, rMed.GetBaseURL(true), SotClipboardFormatId::HTML); |
2769 | 0 | if (bRet && !aImExport.GetNonConvertibleChars().isEmpty()) |
2770 | 0 | { |
2771 | 0 | SetError(ErrCodeMsg( |
2772 | 0 | SCWARN_EXPORT_NONCONVERTIBLE_CHARS, |
2773 | 0 | aImExport.GetNonConvertibleChars(), |
2774 | 0 | DialogMask::ButtonsOk | DialogMask::MessageInfo)); |
2775 | 0 | } |
2776 | 0 | } |
2777 | 0 | } |
2778 | 0 | else |
2779 | 0 | { |
2780 | 0 | if (GetErrorIgnoreWarning()) |
2781 | 0 | SetError(SCERR_IMPORT_NI); |
2782 | 0 | } |
2783 | | |
2784 | 0 | return bRet; |
2785 | 0 | } |
2786 | | |
2787 | | bool ScDocShell::DoSaveCompleted( SfxMedium * pNewStor, bool bRegisterRecent ) |
2788 | 0 | { |
2789 | 0 | bool bRet = SfxObjectShell::DoSaveCompleted( pNewStor, bRegisterRecent ); |
2790 | | |
2791 | | // SfxHintId::ScDocSaved for change ReadOnly -> Read/Write |
2792 | 0 | Broadcast( SfxHint( SfxHintId::ScDocSaved ) ); |
2793 | 0 | return bRet; |
2794 | 0 | } |
2795 | | |
2796 | | bool ScDocShell::QuerySlotExecutable( sal_uInt16 nSlotId ) |
2797 | 0 | { |
2798 | | // #i112634# ask VBA event handlers whether to save or print the document |
2799 | |
|
2800 | 0 | using namespace ::com::sun::star::script::vba; |
2801 | |
|
2802 | 0 | sal_Int32 nVbaEventId = VBAEventId::NO_EVENT; |
2803 | 0 | uno::Sequence< uno::Any > aArgs; |
2804 | 0 | switch( nSlotId ) |
2805 | 0 | { |
2806 | 0 | case SID_SAVEDOC: |
2807 | 0 | case SID_SAVEASDOC: |
2808 | 0 | nVbaEventId = VBAEventId::WORKBOOK_BEFORESAVE; |
2809 | 0 | aArgs = { uno::Any(nSlotId == SID_SAVEASDOC) }; |
2810 | 0 | break; |
2811 | 0 | case SID_PRINTDOC: |
2812 | 0 | case SID_PRINTDOCDIRECT: |
2813 | 0 | nVbaEventId = VBAEventId::WORKBOOK_BEFOREPRINT; |
2814 | 0 | break; |
2815 | 0 | } |
2816 | | |
2817 | 0 | bool bSlotExecutable = true; |
2818 | 0 | if( nVbaEventId != VBAEventId::NO_EVENT ) try |
2819 | 0 | { |
2820 | 0 | uno::Reference< XVBAEventProcessor > xEventProcessor( m_pDocument->GetVbaEventProcessor(), uno::UNO_SET_THROW ); |
2821 | 0 | xEventProcessor->processVbaEvent( nVbaEventId, aArgs ); |
2822 | 0 | } |
2823 | 0 | catch( util::VetoException& ) |
2824 | 0 | { |
2825 | 0 | bSlotExecutable = false; |
2826 | 0 | } |
2827 | 0 | catch( uno::Exception& ) |
2828 | 0 | { |
2829 | 0 | } |
2830 | 0 | return bSlotExecutable; |
2831 | 0 | } |
2832 | | |
2833 | | bool ScDocShell::PrepareClose( bool bUI ) |
2834 | 0 | { |
2835 | 0 | if (ScModule::get()->GetCurRefDlgId() > 0) |
2836 | 0 | { |
2837 | 0 | SfxViewFrame* pFrame = SfxViewFrame::GetFirst( this ); |
2838 | 0 | if( pFrame ) |
2839 | 0 | { |
2840 | 0 | SfxViewShell* p = pFrame->GetViewShell(); |
2841 | 0 | ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( p ); |
2842 | 0 | if(pViewSh!=nullptr) |
2843 | 0 | { |
2844 | 0 | vcl::Window *pWin=pViewSh->GetWindow(); |
2845 | 0 | if(pWin!=nullptr) pWin->GrabFocus(); |
2846 | 0 | } |
2847 | 0 | } |
2848 | |
|
2849 | 0 | return false; |
2850 | 0 | } |
2851 | 0 | if ( m_pDocument->IsInLinkUpdate() || m_pDocument->IsInInterpreter() ) |
2852 | 0 | { |
2853 | 0 | ErrorMessage(STR_CLOSE_ERROR_LINK); |
2854 | 0 | return false; |
2855 | 0 | } |
2856 | | |
2857 | 0 | DoEnterHandler(); |
2858 | | |
2859 | | // start 'Workbook_BeforeClose' VBA event handler for possible veto |
2860 | 0 | if( !IsInPrepareClose() ) |
2861 | 0 | { |
2862 | 0 | try |
2863 | 0 | { |
2864 | 0 | uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( m_pDocument->GetVbaEventProcessor(), uno::UNO_SET_THROW ); |
2865 | 0 | uno::Sequence< uno::Any > aArgs; |
2866 | 0 | xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKBOOK_BEFORECLOSE, aArgs ); |
2867 | 0 | } |
2868 | 0 | catch( util::VetoException& ) |
2869 | 0 | { |
2870 | | // if event processor throws VetoException, macro has vetoed close |
2871 | 0 | return false; |
2872 | 0 | } |
2873 | 0 | catch( uno::Exception& ) |
2874 | 0 | { |
2875 | 0 | } |
2876 | 0 | } |
2877 | | // end handler code |
2878 | | |
2879 | 0 | bool bRet = SfxObjectShell::PrepareClose( bUI ); |
2880 | 0 | if (bRet) // true == close |
2881 | 0 | m_pDocument->EnableIdle(false); // Do not mess around with it anymore! |
2882 | |
|
2883 | 0 | return bRet; |
2884 | 0 | } |
2885 | | |
2886 | | bool ScDocShell::HasAutomaticTableName( std::u16string_view rFilter ) |
2887 | 0 | { |
2888 | | // sal_True for those filters that keep the default table name |
2889 | | // (which is language specific) |
2890 | |
|
2891 | 0 | return rFilter == SC_TEXT_CSV_FILTER_NAME |
2892 | 0 | || rFilter == SC_LOTUS_FILTER_NAME |
2893 | 0 | || rFilter == SC_XL4_FILTER_NAME |
2894 | 0 | || rFilter == SC_XL4TMPL_FILTER_NAME |
2895 | 0 | || rFilter == SC_DBASE_FILTER_NAME |
2896 | 0 | || rFilter == SC_DIF_FILTER_NAME |
2897 | 0 | || rFilter == SC_SYLK_FILTER_NAME |
2898 | 0 | || rFilter == SC_HTML_FILTER_NAME |
2899 | 0 | || rFilter == SC_RTF_FILTER_NAME; |
2900 | 0 | } |
2901 | | |
2902 | | std::unique_ptr<ScDocFunc> ScDocShell::CreateDocFunc() |
2903 | 62.5k | { |
2904 | 62.5k | return std::make_unique<ScDocFuncDirect>( *this ); |
2905 | 62.5k | } |
2906 | | |
2907 | | ScDocShell::ScDocShell(const SfxModelFlags i_nSfxCreationFlags, ScDocumentMode docMode) |
2908 | 0 | : ScDocShell(i_nSfxCreationFlags, std::make_shared<ScDocument>(docMode, this)) |
2909 | 0 | { |
2910 | 0 | } |
2911 | | |
2912 | | ScDocShell::ScDocShell( const SfxModelFlags i_nSfxCreationFlags, const std::shared_ptr<ScDocument>& pDoc ) : |
2913 | 62.5k | SfxObjectShell( i_nSfxCreationFlags ), |
2914 | 62.5k | m_pDocument ( pDoc ? pDoc : std::make_shared<ScDocument>( SCDOCMODE_DOCUMENT, this )), |
2915 | 62.5k | m_aDdeTextFmt(u"TEXT"_ustr), |
2916 | 62.5k | m_nPrtToScreenFactor( 1.0 ), |
2917 | 62.5k | m_pImpl ( new DocShell_Impl ), |
2918 | 62.5k | m_bHeaderOn ( true ), |
2919 | 62.5k | m_bFooterOn ( true ), |
2920 | 62.5k | m_bIsEmpty ( true ), |
2921 | 62.5k | m_bIsInUndo ( false ), |
2922 | 62.5k | m_bDocumentModifiedPending( false ), |
2923 | 62.5k | m_bUpdateEnabled ( true ), |
2924 | 62.5k | m_bAreasChangedNeedBroadcast( false ), |
2925 | 62.5k | m_nDocumentLock ( 0 ), |
2926 | 62.5k | m_nCanUpdate (css::document::UpdateDocMode::ACCORDING_TO_CONFIG) |
2927 | 62.5k | { |
2928 | 62.5k | SetPool(&ScModule::get()->GetPool()); |
2929 | | |
2930 | 62.5k | m_bIsInplace = (GetCreateMode() == SfxObjectCreateMode::EMBEDDED); |
2931 | | // Will be reset if not in place |
2932 | | |
2933 | 62.5k | m_pDocFunc = CreateDocFunc(); |
2934 | | |
2935 | | // SetBaseModel needs exception handling |
2936 | 62.5k | ScModelObj::CreateAndSet( this ); |
2937 | | |
2938 | 62.5k | StartListening(*this); |
2939 | 62.5k | SfxStyleSheetPool* pStlPool = m_pDocument->GetStyleSheetPool(); |
2940 | 62.5k | if (pStlPool) |
2941 | 62.5k | StartListening(*pStlPool); |
2942 | | |
2943 | 62.5k | m_pDocument->GetDBCollection()->SetRefreshHandler( |
2944 | 62.5k | LINK( this, ScDocShell, RefreshDBDataHdl ) ); |
2945 | | |
2946 | | // InitItems and CalcOutputFactor are called now in Load/ConvertFrom/InitNew |
2947 | 62.5k | } |
2948 | | |
2949 | | ScDocShell::~ScDocShell() |
2950 | 62.4k | { |
2951 | 62.4k | ResetDrawObjectShell(); // If the Drawing Layer still tries to access it, access it |
2952 | | |
2953 | 62.4k | SfxStyleSheetPool* pStlPool = m_pDocument->GetStyleSheetPool(); |
2954 | 62.4k | if (pStlPool) |
2955 | 62.4k | EndListening(*pStlPool); |
2956 | 62.4k | EndListening(*this); |
2957 | | |
2958 | 62.4k | m_pAutoStyleList.reset(); |
2959 | | |
2960 | 62.4k | SfxApplication *pSfxApp = SfxGetpApp(); |
2961 | 62.4k | if ( pSfxApp->GetDdeService() ) // Delete DDE for Document |
2962 | 0 | pSfxApp->RemoveDdeTopic( this ); |
2963 | | |
2964 | 62.4k | m_pDocFunc.reset(); |
2965 | 62.4k | delete m_pDocument->mpUndoManager; |
2966 | 62.4k | m_pDocument->mpUndoManager = nullptr; |
2967 | 62.4k | m_pImpl.reset(); |
2968 | | |
2969 | 62.4k | m_pPaintLockData.reset(); |
2970 | | |
2971 | 62.4k | m_pSheetSaveData.reset(); |
2972 | 62.4k | m_pFormatSaveData.reset(); |
2973 | 62.4k | m_pOldAutoDBRange.reset(); |
2974 | | |
2975 | 62.4k | if (m_pModificator) |
2976 | 24.1k | { |
2977 | 24.1k | OSL_FAIL("The Modificator should not exist"); |
2978 | 24.1k | m_pModificator.reset(); |
2979 | 24.1k | } |
2980 | 62.4k | } |
2981 | | |
2982 | | SfxUndoManager* ScDocShell::GetUndoManager() |
2983 | 70 | { |
2984 | 70 | return m_pDocument->GetUndoManager(); |
2985 | 70 | } |
2986 | | |
2987 | | void ScDocShell::SetModified( bool bModified ) |
2988 | 82.4k | { |
2989 | 82.4k | if ( SfxObjectShell::IsEnableSetModified() ) |
2990 | 82.4k | { |
2991 | 82.4k | SfxObjectShell::SetModified( bModified ); |
2992 | 82.4k | Broadcast( SfxHint( SfxHintId::DocChanged ) ); |
2993 | 82.4k | } |
2994 | 82.4k | } |
2995 | | |
2996 | | void ScDocShell::SetDocumentModified() |
2997 | 219k | { |
2998 | | // BroadcastUno must also happen right away with pPaintLockData |
2999 | | // FIXME: Also for SetDrawModified, if Drawing is connected |
3000 | | // FIXME: Then own Hint? |
3001 | | |
3002 | 219k | if ( m_pPaintLockData ) |
3003 | 207k | { |
3004 | | // #i115009# broadcast BCA_BRDCST_ALWAYS, so a component can read recalculated results |
3005 | | // of RecalcModeAlways formulas (like OFFSET) after modifying cells |
3006 | 207k | m_pDocument->Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS)); |
3007 | 207k | m_pDocument->InvalidateTableArea(); // #i105279# needed here |
3008 | 207k | m_pDocument->BroadcastUno( SfxHint( SfxHintId::DataChanged ) ); |
3009 | | |
3010 | 207k | m_pPaintLockData->SetModified(); // Later on ... |
3011 | 207k | return; |
3012 | 207k | } |
3013 | | |
3014 | 11.9k | SetDrawModified(); |
3015 | | |
3016 | 11.9k | if ( m_pDocument->IsAutoCalcShellDisabled() ) |
3017 | 0 | SetDocumentModifiedPending( true ); |
3018 | 11.9k | else |
3019 | 11.9k | { |
3020 | 11.9k | SetDocumentModifiedPending( false ); |
3021 | 11.9k | m_pDocument->InvalidateStyleSheetUsage(); |
3022 | 11.9k | m_pDocument->InvalidateTableArea(); |
3023 | 11.9k | m_pDocument->InvalidateLastTableOpParams(); |
3024 | 11.9k | m_pDocument->Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS)); |
3025 | 11.9k | if ( m_pDocument->IsForcedFormulaPending() && m_pDocument->GetAutoCalc() ) |
3026 | 0 | m_pDocument->CalcFormulaTree( true ); |
3027 | 11.9k | m_pDocument->RefreshDirtyTableColumnNames(); |
3028 | 11.9k | PostDataChanged(); |
3029 | | |
3030 | | // Detective AutoUpdate: |
3031 | | // Update if formulas were modified (DetectiveDirty) or the list contains |
3032 | | // "Trace Error" entries (Trace Error can look completely different |
3033 | | // after changes to non-formula cells). |
3034 | | |
3035 | 11.9k | ScDetOpList* pList = m_pDocument->GetDetOpList(); |
3036 | 11.9k | if ( pList && ( m_pDocument->IsDetectiveDirty() || pList->HasAddError() ) && |
3037 | 0 | pList->Count() && !IsInUndo() && ScModule::get()->GetAppOptions().GetDetectiveAuto() ) |
3038 | 0 | { |
3039 | 0 | GetDocFunc().DetectiveRefresh(true); // sal_True = caused by automatic update |
3040 | 0 | } |
3041 | 11.9k | m_pDocument->SetDetectiveDirty(false); // always reset, also if not refreshed |
3042 | 11.9k | } |
3043 | | |
3044 | 11.9k | if (m_bAreasChangedNeedBroadcast) |
3045 | 0 | { |
3046 | 0 | m_bAreasChangedNeedBroadcast = false; |
3047 | 0 | SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged)); |
3048 | 0 | } |
3049 | | |
3050 | | // notify UNO objects after BCA_BRDCST_ALWAYS etc. |
3051 | 11.9k | m_pDocument->BroadcastUno( SfxHint( SfxHintId::DataChanged ) ); |
3052 | 11.9k | } |
3053 | | |
3054 | | /** |
3055 | | * SetDrawModified - without Formula update |
3056 | | * |
3057 | | * Drawing also needs to be updated for the normal SetDocumentModified |
3058 | | * e.g.: when deleting tables etc. |
3059 | | */ |
3060 | | void ScDocShell::SetDrawModified() |
3061 | 11.9k | { |
3062 | 11.9k | bool bUpdate = !IsModified(); |
3063 | | |
3064 | 11.9k | SetModified(); |
3065 | | |
3066 | 11.9k | SfxBindings* pBindings = GetViewBindings(); |
3067 | 11.9k | if (bUpdate && pBindings) |
3068 | 0 | { |
3069 | 0 | pBindings->Invalidate( SID_SAVEDOC ); |
3070 | 0 | pBindings->Invalidate( SID_DOC_MODIFIED ); |
3071 | 0 | } |
3072 | | |
3073 | 11.9k | if (pBindings) |
3074 | 0 | { |
3075 | | // #i105960# Undo etc used to be volatile. |
3076 | | // They always have to be invalidated, including drawing layer or row height changes |
3077 | | // (but not while pPaintLockData is set). |
3078 | 0 | pBindings->Invalidate( SID_UNDO ); |
3079 | 0 | pBindings->Invalidate( SID_REDO ); |
3080 | 0 | pBindings->Invalidate( SID_REPEAT ); |
3081 | 0 | } |
3082 | | |
3083 | 11.9k | if ( m_pDocument->IsChartListenerCollectionNeedsUpdate() ) |
3084 | 4.09k | { |
3085 | 4.09k | m_pDocument->UpdateChartListenerCollection(); |
3086 | 4.09k | SfxGetpApp()->Broadcast(SfxHint( SfxHintId::ScDrawChanged )); // Navigator |
3087 | 4.09k | } |
3088 | 11.9k | ScModule::get()->AnythingChanged(); |
3089 | 11.9k | } |
3090 | | |
3091 | | void ScDocShell::SetInUndo(bool bSet) |
3092 | 0 | { |
3093 | 0 | m_bIsInUndo = bSet; |
3094 | 0 | } |
3095 | | |
3096 | | void ScDocShell::GetDocStat( ScDocStat& rDocStat ) |
3097 | 0 | { |
3098 | 0 | SfxPrinter* pPrinter = GetPrinter(); |
3099 | |
|
3100 | 0 | m_pDocument->GetDocStat( rDocStat ); |
3101 | 0 | rDocStat.nPageCount = 0; |
3102 | |
|
3103 | 0 | if ( pPrinter ) |
3104 | 0 | for ( SCTAB i=0; i<rDocStat.nTableCount; i++ ) |
3105 | 0 | rDocStat.nPageCount = sal::static_int_cast<sal_uInt16>( rDocStat.nPageCount + |
3106 | 0 | static_cast<sal_uInt16>(ScPrintFunc( *this, pPrinter, i ).GetTotalPages()) ); |
3107 | 0 | } |
3108 | | |
3109 | | std::shared_ptr<SfxDocumentInfoDialog> ScDocShell::CreateDocumentInfoDialog(weld::Window* pParent, const SfxItemSet &rSet) |
3110 | 0 | { |
3111 | 0 | std::shared_ptr<SfxDocumentInfoDialog> xDlg = std::make_shared<SfxDocumentInfoDialog>(pParent, rSet); |
3112 | 0 | ScDocShell* pDocSh = dynamic_cast< ScDocShell *>( SfxObjectShell::Current() ); |
3113 | | |
3114 | | // Only for statistics, if this Doc is shown; not from the Doc Manager |
3115 | 0 | if( pDocSh == this ) |
3116 | 0 | { |
3117 | 0 | ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create(); |
3118 | 0 | ::CreateTabPage ScDocStatPageCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_STAT); |
3119 | 0 | OSL_ENSURE(ScDocStatPageCreate, "Tabpage create fail!"); |
3120 | 0 | xDlg->AddFontTabPage(); |
3121 | 0 | xDlg->AddTabPage(u"calcstats"_ustr, TabResId(RID_TAB_STATISTICS.aLabel), |
3122 | 0 | ScDocStatPageCreate, RID_L + RID_TAB_STATISTICS.sIconName); |
3123 | 0 | } |
3124 | 0 | return xDlg; |
3125 | 0 | } |
3126 | | |
3127 | | weld::Window* ScDocShell::GetActiveDialogParent() |
3128 | 12.2k | { |
3129 | 12.2k | ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); |
3130 | 12.2k | if ( pViewSh ) |
3131 | 0 | return pViewSh->GetDialogParent(); |
3132 | 12.2k | return Application::GetDefDialogParent(); |
3133 | 12.2k | } |
3134 | | |
3135 | | ScSheetSaveData* ScDocShell::GetSheetSaveData() |
3136 | 111k | { |
3137 | 111k | if (!m_pSheetSaveData) |
3138 | 32.5k | m_pSheetSaveData.reset( new ScSheetSaveData ); |
3139 | | |
3140 | 111k | return m_pSheetSaveData.get(); |
3141 | 111k | } |
3142 | | |
3143 | | ScFormatSaveData* ScDocShell::GetFormatSaveData() |
3144 | 174 | { |
3145 | 174 | if (!m_pFormatSaveData) |
3146 | 101 | m_pFormatSaveData.reset( new ScFormatSaveData ); |
3147 | | |
3148 | 174 | return m_pFormatSaveData.get(); |
3149 | 174 | } |
3150 | | |
3151 | | namespace { |
3152 | | |
3153 | | void removeKeysIfExists(const Reference<ui::XAcceleratorConfiguration>& xScAccel, const std::vector<const awt::KeyEvent*>& rKeys) |
3154 | 0 | { |
3155 | 0 | for (const awt::KeyEvent* p : rKeys) |
3156 | 0 | { |
3157 | 0 | if (!p) |
3158 | 0 | continue; |
3159 | | |
3160 | 0 | try |
3161 | 0 | { |
3162 | 0 | xScAccel->removeKeyEvent(*p); |
3163 | 0 | } |
3164 | 0 | catch (const container::NoSuchElementException&) {} |
3165 | 0 | } |
3166 | 0 | } |
3167 | | |
3168 | | } |
3169 | | |
3170 | | void ScDocShell::ResetKeyBindings( ScOptionsUtil::KeyBindingType eType ) |
3171 | 0 | { |
3172 | 0 | using namespace ::com::sun::star::ui; |
3173 | |
|
3174 | 0 | const Reference<uno::XComponentContext>& xContext = ::comphelper::getProcessComponentContext(); |
3175 | 0 | if (!xContext.is()) |
3176 | 0 | return; |
3177 | | |
3178 | 0 | Reference<XModuleUIConfigurationManagerSupplier> xModuleCfgSupplier( |
3179 | 0 | theModuleUIConfigurationManagerSupplier::get(xContext) ); |
3180 | | |
3181 | | // Grab the Calc configuration. |
3182 | 0 | Reference<XUIConfigurationManager> xConfigMgr = |
3183 | 0 | xModuleCfgSupplier->getUIConfigurationManager( |
3184 | 0 | u"com.sun.star.sheet.SpreadsheetDocument"_ustr); |
3185 | |
|
3186 | 0 | if (!xConfigMgr.is()) |
3187 | 0 | return; |
3188 | | |
3189 | | // shortcut manager |
3190 | 0 | Reference<XAcceleratorConfiguration> xScAccel = xConfigMgr->getShortCutManager(); |
3191 | |
|
3192 | 0 | if (!xScAccel.is()) |
3193 | 0 | return; |
3194 | | |
3195 | 0 | std::vector<const awt::KeyEvent*> aKeys; |
3196 | 0 | aKeys.reserve(9); |
3197 | | |
3198 | | // Backspace key |
3199 | 0 | awt::KeyEvent aBackspace; |
3200 | 0 | aBackspace.KeyCode = awt::Key::BACKSPACE; |
3201 | 0 | aBackspace.Modifiers = 0; |
3202 | 0 | aKeys.push_back(&aBackspace); |
3203 | | |
3204 | | // Delete key |
3205 | 0 | awt::KeyEvent aDelete; |
3206 | 0 | aDelete.KeyCode = awt::Key::DELETE; |
3207 | 0 | aDelete.Modifiers = 0; |
3208 | 0 | aKeys.push_back(&aDelete); |
3209 | | |
3210 | | // Ctrl-D |
3211 | 0 | awt::KeyEvent aCtrlD; |
3212 | 0 | aCtrlD.KeyCode = awt::Key::D; |
3213 | 0 | aCtrlD.Modifiers = awt::KeyModifier::MOD1; |
3214 | 0 | aKeys.push_back(&aCtrlD); |
3215 | | |
3216 | | // Alt-Down |
3217 | 0 | awt::KeyEvent aAltDown; |
3218 | 0 | aAltDown.KeyCode = awt::Key::DOWN; |
3219 | 0 | aAltDown.Modifiers = awt::KeyModifier::MOD2; |
3220 | 0 | aKeys.push_back(&aAltDown); |
3221 | | |
3222 | | // Ctrl-Space |
3223 | 0 | awt::KeyEvent aCtrlSpace; |
3224 | 0 | aCtrlSpace.KeyCode = awt::Key::SPACE; |
3225 | 0 | aCtrlSpace.Modifiers = awt::KeyModifier::MOD1; |
3226 | 0 | aKeys.push_back(&aCtrlSpace); |
3227 | | |
3228 | | // Ctrl-Shift-Space |
3229 | 0 | awt::KeyEvent aCtrlShiftSpace; |
3230 | 0 | aCtrlShiftSpace.KeyCode = awt::Key::SPACE; |
3231 | 0 | aCtrlShiftSpace.Modifiers = awt::KeyModifier::MOD1 | awt::KeyModifier::SHIFT; |
3232 | 0 | aKeys.push_back(&aCtrlShiftSpace); |
3233 | | |
3234 | | // F4 |
3235 | 0 | awt::KeyEvent aF4; |
3236 | 0 | aF4.KeyCode = awt::Key::F4; |
3237 | 0 | aF4.Modifiers = 0; |
3238 | 0 | aKeys.push_back(&aF4); |
3239 | | |
3240 | | // CTRL+SHIFT+F4 |
3241 | 0 | awt::KeyEvent aCtrlShiftF4; |
3242 | 0 | aCtrlShiftF4.KeyCode = awt::Key::F4; |
3243 | 0 | aCtrlShiftF4.Modifiers = awt::KeyModifier::MOD1 | awt::KeyModifier::SHIFT; |
3244 | 0 | aKeys.push_back(&aCtrlShiftF4); |
3245 | | |
3246 | | // SHIFT+F4 |
3247 | 0 | awt::KeyEvent aShiftF4; |
3248 | 0 | aShiftF4.KeyCode = awt::Key::F4; |
3249 | 0 | aShiftF4.Modifiers = awt::KeyModifier::SHIFT; |
3250 | 0 | aKeys.push_back(&aShiftF4); |
3251 | | |
3252 | | // Remove all involved keys first, because swapping commands don't work |
3253 | | // well without doing this. |
3254 | 0 | removeKeysIfExists(xScAccel, aKeys); |
3255 | 0 | xScAccel->store(); |
3256 | |
|
3257 | 0 | switch (eType) |
3258 | 0 | { |
3259 | 0 | case ScOptionsUtil::KEY_DEFAULT: |
3260 | 0 | xScAccel->setKeyEvent(aDelete, u".uno:ClearContents"_ustr); |
3261 | 0 | xScAccel->setKeyEvent(aBackspace, u".uno:Delete"_ustr); |
3262 | 0 | xScAccel->setKeyEvent(aCtrlD, u".uno:FillDown"_ustr); |
3263 | 0 | xScAccel->setKeyEvent(aAltDown, u".uno:DataSelect"_ustr); |
3264 | 0 | xScAccel->setKeyEvent(aCtrlSpace, u".uno:SelectColumn"_ustr); |
3265 | 0 | xScAccel->setKeyEvent(aCtrlShiftSpace, u".uno:SelectAll"_ustr); |
3266 | 0 | xScAccel->setKeyEvent(aF4, u".uno:ToggleRelative"_ustr); |
3267 | 0 | xScAccel->setKeyEvent(aCtrlShiftF4, u".uno:ViewDataSourceBrowser"_ustr); |
3268 | 0 | break; |
3269 | 0 | case ScOptionsUtil::KEY_OOO_LEGACY: |
3270 | 0 | xScAccel->setKeyEvent(aDelete, u".uno:Delete"_ustr); |
3271 | 0 | xScAccel->setKeyEvent(aBackspace, u".uno:ClearContents"_ustr); |
3272 | 0 | xScAccel->setKeyEvent(aCtrlD, u".uno:DataSelect"_ustr); |
3273 | 0 | xScAccel->setKeyEvent(aCtrlShiftSpace, u".uno:SelectColumn"_ustr); |
3274 | 0 | xScAccel->setKeyEvent(aF4, u".uno:ViewDataSourceBrowser"_ustr); |
3275 | 0 | xScAccel->setKeyEvent(aShiftF4, u".uno:ToggleRelative"_ustr); |
3276 | 0 | break; |
3277 | 0 | default: |
3278 | 0 | ; |
3279 | 0 | } |
3280 | | |
3281 | 0 | xScAccel->store(); |
3282 | 0 | } |
3283 | | |
3284 | | void ScDocShell::UseSheetSaveEntries() |
3285 | 0 | { |
3286 | 0 | if (!m_pSheetSaveData) |
3287 | 0 | return; |
3288 | | |
3289 | 0 | m_pSheetSaveData->UseSaveEntries(); // use positions from saved file for next saving |
3290 | |
|
3291 | 0 | bool bHasEntries = false; |
3292 | 0 | SCTAB nTabCount = m_pDocument->GetTableCount(); |
3293 | 0 | SCTAB nTab; |
3294 | 0 | for (nTab = 0; nTab < nTabCount; ++nTab) |
3295 | 0 | if (m_pSheetSaveData->HasStreamPos(nTab)) |
3296 | 0 | bHasEntries = true; |
3297 | |
|
3298 | 0 | if (!bHasEntries) |
3299 | 0 | { |
3300 | | // if no positions were set (for example, export to other format), |
3301 | | // reset all "valid" flags |
3302 | 0 | for (nTab = 0; nTab < nTabCount; ++nTab) |
3303 | 0 | m_pDocument->SetStreamValid(nTab, false); |
3304 | 0 | } |
3305 | 0 | } |
3306 | | |
3307 | | // --- ScDocShellModificator ------------------------------------------ |
3308 | | |
3309 | | ScDocShellModificator::ScDocShellModificator( ScDocShell& rDS ) |
3310 | | : |
3311 | 392k | rDocShell( rDS ), |
3312 | 392k | mpProtector(new ScRefreshTimerProtector(rDS.GetDocument().GetRefreshTimerControlAddress())) |
3313 | 392k | { |
3314 | 392k | ScDocument& rDoc = rDocShell.GetDocument(); |
3315 | 392k | bAutoCalcShellDisabled = rDoc.IsAutoCalcShellDisabled(); |
3316 | 392k | bIdleEnabled = rDoc.IsIdleEnabled(); |
3317 | 392k | rDoc.SetAutoCalcShellDisabled( true ); |
3318 | 392k | rDoc.EnableIdle(false); |
3319 | 392k | } |
3320 | | |
3321 | | void ScDocShellModificator::ImplDestroy() |
3322 | 392k | { |
3323 | 392k | ScDocument& rDoc = rDocShell.GetDocument(); |
3324 | 392k | rDoc.SetAutoCalcShellDisabled( bAutoCalcShellDisabled ); |
3325 | 392k | if ( !bAutoCalcShellDisabled && rDocShell.IsDocumentModifiedPending() ) |
3326 | 0 | rDocShell.SetDocumentModified(); // last one shuts off the lights |
3327 | 392k | rDoc.EnableIdle(bIdleEnabled); |
3328 | 392k | } |
3329 | | |
3330 | | ScDocShellModificator::~ScDocShellModificator() |
3331 | 392k | { |
3332 | 392k | suppress_fun_call_w_exception(ImplDestroy()); |
3333 | 392k | } |
3334 | | |
3335 | | void ScDocShellModificator::SetDocumentModified() |
3336 | 335k | { |
3337 | 335k | ScDocument& rDoc = rDocShell.GetDocument(); |
3338 | 335k | rDoc.PrepareFormulaCalc(); |
3339 | 335k | if ( !rDoc.IsImportingXML() ) |
3340 | 180k | { |
3341 | | // temporarily restore AutoCalcShellDisabled |
3342 | 180k | bool bDisabled = rDoc.IsAutoCalcShellDisabled(); |
3343 | 180k | rDoc.SetAutoCalcShellDisabled( bAutoCalcShellDisabled ); |
3344 | 180k | rDocShell.SetDocumentModified(); |
3345 | 180k | rDoc.SetAutoCalcShellDisabled( bDisabled ); |
3346 | 180k | } |
3347 | 155k | else |
3348 | 155k | { |
3349 | | // uno broadcast is necessary for api to work |
3350 | | // -> must also be done during xml import |
3351 | 155k | rDoc.BroadcastUno( SfxHint( SfxHintId::DataChanged ) ); |
3352 | 155k | } |
3353 | 335k | } |
3354 | | |
3355 | | bool ScDocShell::IsChangeRecording(SfxViewShell* /*pViewShell*/, bool /*bRecordAllViews*/) const |
3356 | 0 | { |
3357 | 0 | ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack(); |
3358 | 0 | return pChangeTrack != nullptr; |
3359 | 0 | } |
3360 | | |
3361 | | bool ScDocShell::HasChangeRecordProtection() const |
3362 | 0 | { |
3363 | 0 | bool bRes = false; |
3364 | 0 | ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack(); |
3365 | 0 | if (pChangeTrack) |
3366 | 0 | bRes = pChangeTrack->IsProtected(); |
3367 | 0 | return bRes; |
3368 | 0 | } |
3369 | | |
3370 | | void ScDocShell::SetChangeRecording( bool bActivate, bool /*bLockAllViews*/, SfxRedlineRecordingMode /*eRedlineRecordingMode*/) |
3371 | 0 | { |
3372 | 0 | bool bOldChangeRecording = IsChangeRecording(); |
3373 | |
|
3374 | 0 | if (bActivate) |
3375 | 0 | { |
3376 | 0 | m_pDocument->StartChangeTracking(); |
3377 | 0 | ScChangeViewSettings aChangeViewSet; |
3378 | 0 | aChangeViewSet.SetShowChanges(true); |
3379 | 0 | m_pDocument->SetChangeViewSettings(aChangeViewSet); |
3380 | 0 | } |
3381 | 0 | else |
3382 | 0 | { |
3383 | 0 | m_pDocument->EndChangeTracking(); |
3384 | 0 | PostPaintGridAll(); |
3385 | 0 | } |
3386 | |
|
3387 | 0 | if (bOldChangeRecording != IsChangeRecording()) |
3388 | 0 | { |
3389 | 0 | UpdateAcceptChangesDialog(); |
3390 | | // invalidate slots |
3391 | 0 | SfxBindings* pBindings = GetViewBindings(); |
3392 | 0 | if (pBindings) |
3393 | 0 | pBindings->InvalidateAll(false); |
3394 | 0 | } |
3395 | 0 | } |
3396 | | |
3397 | | void ScDocShell::SetProtectionPassword( const OUString &rNewPassword ) |
3398 | 0 | { |
3399 | 0 | ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack(); |
3400 | 0 | if (!pChangeTrack) |
3401 | 0 | return; |
3402 | | |
3403 | 0 | bool bProtected = pChangeTrack->IsProtected(); |
3404 | |
|
3405 | 0 | if (!rNewPassword.isEmpty()) |
3406 | 0 | { |
3407 | | // when password protection is applied change tracking must always be active |
3408 | 0 | SetChangeRecording( true ); |
3409 | |
|
3410 | 0 | css::uno::Sequence< sal_Int8 > aProtectionHash; |
3411 | 0 | SvPasswordHelper::GetHashPassword( aProtectionHash, rNewPassword ); |
3412 | 0 | pChangeTrack->SetProtection( aProtectionHash ); |
3413 | 0 | } |
3414 | 0 | else |
3415 | 0 | { |
3416 | 0 | pChangeTrack->SetProtection( css::uno::Sequence< sal_Int8 >() ); |
3417 | 0 | } |
3418 | |
|
3419 | 0 | if ( bProtected != pChangeTrack->IsProtected() ) |
3420 | 0 | { |
3421 | 0 | UpdateAcceptChangesDialog(); |
3422 | 0 | SetDocumentModified(); |
3423 | 0 | } |
3424 | 0 | } |
3425 | | |
3426 | | bool ScDocShell::GetProtectionHash( /*out*/ css::uno::Sequence< sal_Int8 > &rPasswordHash ) |
3427 | 0 | { |
3428 | 0 | bool bRes = false; |
3429 | 0 | ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack(); |
3430 | 0 | if (pChangeTrack && pChangeTrack->IsProtected()) |
3431 | 0 | { |
3432 | 0 | rPasswordHash = pChangeTrack->GetProtection(); |
3433 | 0 | bRes = true; |
3434 | 0 | } |
3435 | 0 | return bRes; |
3436 | 0 | } |
3437 | | |
3438 | | void ScDocShell::RegisterAutomationWorkbookObject(css::uno::Reference< ooo::vba::excel::XWorkbook > const& xWorkbook) |
3439 | 0 | { |
3440 | 0 | mxAutomationWorkbookObject = xWorkbook; |
3441 | 0 | } |
3442 | | |
3443 | | extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportSLK(SvStream &rStream) |
3444 | 27.9k | { |
3445 | 27.9k | ScDLL::Init(); |
3446 | 27.9k | ScDocument aDocument; |
3447 | 27.9k | ScDocOptions aDocOpt = aDocument.GetDocOptions(); |
3448 | 27.9k | aDocOpt.SetLookUpColRowNames(false); |
3449 | 27.9k | aDocument.SetDocOptions(aDocOpt); |
3450 | 27.9k | aDocument.MakeTable(0); |
3451 | 27.9k | aDocument.EnableExecuteLink(false); |
3452 | 27.9k | aDocument.SetInsertingFromOtherDoc(true); |
3453 | 27.9k | aDocument.SetImportingXML(true); |
3454 | | |
3455 | 27.9k | ScImportExport aImpEx(aDocument); |
3456 | 27.9k | return aImpEx.ImportStream(rStream, OUString(), SotClipboardFormatId::SYLK); |
3457 | 27.9k | } |
3458 | | |
3459 | | extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportCalcHTML(SvStream &rStream) |
3460 | 26.3k | { |
3461 | 26.3k | ScDLL::Init(); |
3462 | 26.3k | ScDocument aDocument; |
3463 | 26.3k | ScDocOptions aDocOpt = aDocument.GetDocOptions(); |
3464 | 26.3k | aDocOpt.SetLookUpColRowNames(false); |
3465 | 26.3k | aDocument.SetDocOptions(aDocOpt); |
3466 | 26.3k | aDocument.MakeTable(0); |
3467 | 26.3k | aDocument.EnableExecuteLink(false); |
3468 | 26.3k | aDocument.SetInsertingFromOtherDoc(true); |
3469 | 26.3k | aDocument.SetImportingXML(true); |
3470 | | |
3471 | 26.3k | ScImportExport aImpEx(aDocument); |
3472 | 26.3k | return aImpEx.ImportStream(rStream, OUString(), SotClipboardFormatId::HTML); |
3473 | 26.3k | } |
3474 | | |
3475 | | extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportDBF(SvStream &rStream) |
3476 | 9.73k | { |
3477 | 9.73k | ScDLL::Init(); |
3478 | | |
3479 | | // we need a real file for this filter |
3480 | | |
3481 | | // put it in an empty dir |
3482 | 9.73k | utl::TempFileNamed aTmpDir(nullptr, true); |
3483 | 9.73k | aTmpDir.EnableKillingFile(); |
3484 | 9.73k | OUString sTmpDir = aTmpDir.GetURL(); |
3485 | | |
3486 | 9.73k | utl::TempFileNamed aTempInput(u"", true, u".dbf", &sTmpDir); |
3487 | 9.73k | aTempInput.EnableKillingFile(); |
3488 | | |
3489 | 9.73k | SvStream* pInputStream = aTempInput.GetStream(StreamMode::WRITE); |
3490 | 9.73k | sal_uInt8 aBuffer[8192]; |
3491 | 20.7k | while (auto nRead = rStream.ReadBytes(aBuffer, SAL_N_ELEMENTS(aBuffer))) |
3492 | 10.9k | pInputStream->WriteBytes(aBuffer, nRead); |
3493 | 9.73k | aTempInput.CloseStream(); |
3494 | | |
3495 | 9.73k | SfxMedium aMedium(aTempInput.GetURL(), StreamMode::STD_READWRITE); |
3496 | | |
3497 | 9.73k | ScDocShellRef xDocShell = new ScDocShell(SfxModelFlags::EMBEDDED_OBJECT | |
3498 | 9.73k | SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS | |
3499 | 9.73k | SfxModelFlags::DISABLE_DOCUMENT_RECOVERY); |
3500 | | |
3501 | 9.73k | xDocShell->DoInitNew(); |
3502 | | |
3503 | 9.73k | ScDocument& rDoc = xDocShell->GetDocument(); |
3504 | | |
3505 | 9.73k | ScDocOptions aDocOpt = rDoc.GetDocOptions(); |
3506 | 9.73k | aDocOpt.SetLookUpColRowNames(false); |
3507 | 9.73k | rDoc.SetDocOptions(aDocOpt); |
3508 | 9.73k | rDoc.MakeTable(0); |
3509 | 9.73k | rDoc.EnableExecuteLink(false); |
3510 | 9.73k | rDoc.SetInsertingFromOtherDoc(true); |
3511 | | |
3512 | 9.73k | ScDocRowHeightUpdater::TabRanges aRecalcRanges(0, rDoc.MaxRow()); |
3513 | 9.73k | std::map<SCCOL, ScColWidthParam> aColWidthParam; |
3514 | 9.73k | ErrCode eError = xDocShell->DBaseImport(aMedium.GetPhysicalName(), RTL_TEXTENCODING_IBM_850, aColWidthParam, aRecalcRanges.maRanges); |
3515 | | |
3516 | 9.73k | xDocShell->DoClose(); |
3517 | 9.73k | xDocShell.clear(); |
3518 | | |
3519 | 9.73k | return eError == ERRCODE_NONE; |
3520 | 9.73k | } |
3521 | | |
3522 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |