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