/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
usingnamespace com::sun::star; using ::com::sun::star::uno::Reference; using ::com::sun::star::lang::XMultiServiceFactory; using std::shared_ptr; using ::std::vector;
HiddenInformation ScDocShell::GetHiddenInformationState( HiddenInformation nStates )
{ // get global state like HiddenInformation::DOCUMENTVERSIONS
HiddenInformation nState = SfxObjectShell::GetHiddenInformationState( nStates );
// prevent unnecessary broadcasts and updates
OSL_ENSURE(m_pModificator == nullptr, "The Modificator should not exist");
m_pModificator.reset( new ScDocShellModificator( *this ) );
m_pDocument->SetImportingXML( true );
m_pDocument->EnableExecuteLink( false ); // #i101304# to be safe, prevent nested loading from external references
m_pDocument->EnableUndo( false ); // prevent unnecessary broadcasts and "half way listeners"
m_pDocument->SetInsertingFromOtherDoc( true );
}
void ScDocShell::AfterXMLLoading(bool bRet)
{ if (GetCreateMode() != SfxObjectCreateMode::ORGANIZER)
{
UpdateLinks(); // don't prevent establishing of listeners anymore
m_pDocument->SetInsertingFromOtherDoc( false ); if ( bRet )
{
ScChartListenerCollection* pChartListener = m_pDocument->GetChartListenerCollection(); if (pChartListener)
pChartListener->UpdateDirtyCharts();
// #95582#; set the table names of linked tables to the new path
SCTAB nTabCount = m_pDocument->GetTableCount(); for (SCTAB i = 0; i < nTabCount; ++i)
{ if (m_pDocument->IsLinked( i ))
{
OUString aName;
m_pDocument->GetName(i, aName);
OUString aLinkTabName = m_pDocument->GetLinkTab(i);
sal_Int32 nLinkTabNameLength = aLinkTabName.getLength();
sal_Int32 nNameLength = aName.getLength(); if (nLinkTabNameLength < nNameLength)
{
// remove the quotes on begin and end of the docname and restore the escaped quotes const sal_Unicode* pNameBuffer = aName.getStr(); if ( *pNameBuffer == '\'' && // all docnames have to have a ' character on the first pos
ScGlobal::UnicodeStrChr( pNameBuffer, SC_COMPILER_FILE_TAB_SEP ) )
{
OUStringBuffer aDocURLBuffer; bool bQuote = true; // Document name is always quoted
++pNameBuffer; while ( bQuote && *pNameBuffer )
{ if ( *pNameBuffer == '\'' && *(pNameBuffer-1) != '\\' )
bQuote = false; elseif( *pNameBuffer != '\\' || *(pNameBuffer+1) != '\'' )
aDocURLBuffer.append(*pNameBuffer); // If escaped quote: only quote in the name
++pNameBuffer;
}
if( *pNameBuffer == SC_COMPILER_FILE_TAB_SEP ) // after the last quote of the docname should be the # char
{
sal_Int32 nIndex = nNameLength - nLinkTabNameLength;
INetURLObject aINetURLObject(aDocURLBuffer); if(aName.match( aLinkTabName, nIndex) &&
(aName[nIndex - 1] == '#') && // before the table name should be the # char
!aINetURLObject.HasError()) // the docname should be a valid URL
{
aName = ScGlobal::GetDocTabName( m_pDocument->GetLinkDoc( i ), m_pDocument->GetLinkTab( i ) );
m_pDocument->RenameTab(i, aName, true/*bExternalDocument*/);
} // else; nothing has to happen, because it is a user given name
} // else; nothing has to happen, because it is a user given name
} // else; nothing has to happen, because it is a user given name
} // else; nothing has to happen, because it is a user given name
}
}
// #i94570# DataPilot table names have to be unique, or the tables can't be accessed by API. // If no name (or an invalid name, skipped in ScXMLDataPilotTableContext::EndElement) was set, create a new name.
ScDPCollection* pDPCollection = m_pDocument->GetDPCollection(); if ( pDPCollection )
{
size_t nDPCount = pDPCollection->GetCount(); for (size_t nDP=0; nDP<nDPCount; ++nDP)
{
ScDPObject& rDPObj = (*pDPCollection)[nDP]; if (rDPObj.GetName().isEmpty())
rDPObj.SetName( pDPCollection->CreateNewName() );
}
}
}
} else
m_pDocument->SetInsertingFromOtherDoc( false );
if (m_pModificator)
{
ScDocument::HardRecalcState eRecalcState = m_pDocument->GetHardRecalcState(); // Temporarily set hard-recalc to prevent calling // ScFormulaCell::Notify() during destruction of the Modificator which // will set the cells dirty. if (eRecalcState == ScDocument::HardRecalcState::OFF)
m_pDocument->SetHardRecalcState(ScDocument::HardRecalcState::TEMPORARY);
m_pModificator.reset();
m_pDocument->SetHardRecalcState(eRecalcState);
} else
{
OSL_FAIL("The Modificator should exist");
}
const sc::ImportPostProcessData::DataStream& r = *rData.mpDataStream; if (!r.maRange.IsValid()) return;
// Break the streamed range into the top range and the height limit. A // height limit of 0 means unlimited i.e. the streamed data will go all // the way to the last row.
bool bHardRecalc = false; switch (nRecalcMode)
{ case RECALC_ASK:
{ if (m_pDocument->IsUserInteractionEnabled())
{ // Ask if the user wants to perform full re-calculation.
MessageWithCheck aQueryBox(ScDocShell::GetActiveDialogParent(),
u"modules/scalc/ui/recalcquerydialog.ui"_ustr,
u"RecalcQueryDialog"_ustr);
aQueryBox.set_primary_text(ScResId(STR_QUERY_OPT_ROW_HEIGHT_RECALC_ONLOAD));
aQueryBox.set_default_response(RET_YES);
if (officecfg::Office::Calc::Formula::Load::RecalcOptimalRowHeightMode::isReadOnly())
aQueryBox.hide_ask();
bHardRecalc = aQueryBox.run() == RET_YES;
if (aQueryBox.get_active())
{ // Always perform selected action in the future.
std::shared_ptr<comphelper::ConfigurationChanges> batch(
comphelper::ConfigurationChanges::create());
officecfg::Office::Calc::Formula::Load::RecalcOptimalRowHeightMode::set(
bHardRecalc ? static_cast<sal_Int32>(RECALC_ALWAYS)
: static_cast<sal_Int32>(RECALC_NEVER),
batch);
//if the document was not generated by LibreOffice, do hard recalc in case some other document //generator saved cached formula results that differ from LibreOffice's calculated results or //did not use cached formula results.
uno::Reference<document::XDocumentProperties> xDocProps = GetModel()->getDocumentProperties();
bool bHardRecalc = false; if (nRecalcMode == RECALC_ASK)
{
OUString sProductName(utl::ConfigManager::getProductName()); if (m_pDocument->IsUserInteractionEnabled() && xDocProps->getGenerator().indexOf(sProductName) == -1)
{ // Generator is not LibreOffice. Ask if the user wants to perform // full re-calculation.
MessageWithCheck aQueryBox(GetActiveDialogParent(),
u"modules/scalc/ui/recalcquerydialog.ui"_ustr, u"RecalcQueryDialog"_ustr);
aQueryBox.set_primary_text(ScResId(STR_QUERY_FORMULA_RECALC_ONLOAD_ODS));
aQueryBox.set_default_response(RET_YES);
if ( officecfg::Office::Calc::Formula::Load::OOXMLRecalcMode::isReadOnly() )
aQueryBox.hide_ask();
bHardRecalc = aQueryBox.run() == RET_YES;
if (aQueryBox.get_active())
{ // Always perform selected action in the future.
std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
officecfg::Office::Calc::Formula::Load::ODFRecalcMode::set(sal_Int32(0), batch);
ScModule* mod = ScModule::get();
ScFormulaOptions aOpt = mod->GetFormulaOptions();
aOpt.SetODFRecalcOptions(bHardRecalc ? RECALC_ALWAYS : RECALC_NEVER); /* XXX is this really supposed to set the ScModule options?
* Not the ScDocShell options? */
mod->SetFormulaOptions(aOpt);
if (bHardRecalc)
DoHardRecalc(); else
{ // still need to recalc volatile formula cells.
m_pDocument->Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS));
}
// only the latin script language is loaded // -> initialize the others from options (before loading)
InitOptions(true);
// If this is an ODF file being loaded, then by default, use legacy processing // (if required, it will be overridden in *::ReadUserDataSequence()) if (IsOwnStorageFormat(rMedium))
{ if (ScDrawLayer* pDrawLayer = m_pDocument->GetDrawLayer())
{
pDrawLayer->SetCompatibilityFlag(SdrCompatibilityFlag::AnchoredTextOverflowLegacy, true); // for tdf#99729
pDrawLayer->SetCompatibilityFlag(SdrCompatibilityFlag::LegacyFontwork, true); // for tdf#148000
}
}
GetUndoManager()->Clear();
bool bRet = SfxObjectShell::Load(rMedium); if (bRet)
{
SetInitialLinkUpdate(&rMedium);
{ // prepare a valid document for XML filter // (for ConvertFrom, InitNew is called before)
m_pDocument->MakeTable(0);
m_pDocument->GetStyleSheetPool()->CreateStandardStyles();
m_pDocument->getCellAttributeHelper().UpdateAllStyleSheets(*m_pDocument);
/* Create styles that are imported through Orcus */
if ( bNoLockAccess )
{ // TODO/LATER: in future an error regarding impossibility to open file for writing could be shown
ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
} else
{
OUString aMessage( ScResId( STR_FILE_LOCKED_SAVE_LATER ) );
aMessage = aMessage.replaceFirst( "%1", aUserName );
// store to shared file if ( bSaveToShared )
{ bool bChangedViewSettings = false;
ScChangeViewSettings* pChangeViewSet = m_pDocument->GetChangeViewSettings(); if ( pChangeViewSet && pChangeViewSet->ShowChanges() )
{
pChangeViewSet->SetShowChanges( false );
pChangeViewSet->SetShowAccepted( false );
m_pDocument->SetChangeViewSettings( *pChangeViewSet );
bChangedViewSettings = true;
}
// TODO/LATER: More entries from the MediaDescriptor might be interesting for the merge
uno::Sequence< beans::PropertyValue > aValues{
comphelper::makePropertyValue(
u"FilterName"_ustr,
GetMedium()->GetFilter()->GetFilterName())
};
if ( bEntriesNotAccessible )
{ // TODO/LATER: in future an error regarding impossibility to write to share control file could be shown
ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
} else
{
std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
VclMessageType::Warning, VclButtonsType::Ok,
ScResId(STR_DOC_NOLONGERSHARED)));
xWarn->run();
if ( !bSuccess )
SetError(ERRCODE_IO_ABORT); // this error code will produce no error message, but will break the further saving process
} #endif
if (m_pSheetSaveData)
m_pSheetSaveData->SetInSupportedSave(true);
} break; case SfxEventHintId::SaveAsDoc:
{ if ( GetDocument().GetExternalRefManager()->containsUnsavedReferences() )
{
std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
VclMessageType::Warning, VclButtonsType::YesNo,
ScResId(STR_UNSAVED_EXT_REF))); if (RET_NO == xWarn->run())
{
SetError(ERRCODE_IO_ABORT); // this error code will produce no error message, but will break the further saving process
}
}
[[fallthrough]];
} case SfxEventHintId::SaveToDoc: // #i108978# If no event is sent before saving, there will also be no "...DONE" event, // and SAVE/SAVEAS can't be distinguished from SAVETO. So stream copying is only enabled // if there is a SAVE/SAVEAS/SAVETO event first. if (m_pSheetSaveData)
m_pSheetSaveData->SetInSupportedSave(true); break; case SfxEventHintId::SaveDocDone: case SfxEventHintId::SaveAsDocDone:
{ // new positions are used after "save" and "save as", but not "save to"
UseSheetSaveEntries(); // use positions from saved file for next saving
[[fallthrough]];
} case SfxEventHintId::SaveToDocDone: // only reset the flag, don't use the new positions if (m_pSheetSaveData)
m_pSheetSaveData->SetInSupportedSave(false); break; default:
{
} break;
}
} elseif (rHint.GetId() == SfxHintId::TitleChanged) // Without parameter
{
m_pDocument->SetName( SfxShell::GetName() ); // RegisterNewTargetNames doesn't exist any longer
SfxGetpApp()->Broadcast(SfxHint( SfxHintId::ScDocNameChanged )); // Navigator
} elseif (rHint.GetId() == SfxHintId::Deinitializing)
{
if (m_pDocument->IsClipboardSource())
{ // Notes copied to the clipboard have a raw SdrCaptionObj pointer // copied from this document, forget it as it references this // document's drawing layer pages and what not, which otherwise when // pasting to another document after this document was destructed would // attempt to access non-existing data. Preserve the text data though.
ScDocument* pClipDoc = ScModule::GetClipDoc(); if (pClipDoc)
pClipDoc->ClosingClipboardSource();
}
}
if (rHint.GetId() != SfxHintId::ThisIsAnSfxEventHint) return;
// All filters need the complete file in one piece (not asynchronously) // So make sure that we transfer the whole file with CreateFileStream
rMedium.GetPhysicalName(); //! Call CreateFileStream directly, if available
MakeDrawLayer(); //! In the filter
CalcOutputFactor(); // prepare update of row height
ErrCode eError = ScFormatFilter::Get().ScImportExcel( rMedium, m_pDocument.get(), eFormat );
m_pDocument->UpdateFontCharSet(); if ( m_pDocument->IsChartListenerCollectionNeedsUpdate() )
m_pDocument->UpdateChartListenerCollection(); //! For all imports?
// all graphics objects must have names
m_pDocument->EnsureGraphicNames();
// tdf#82254 - check whether to include a byte-order-mark in the output if (constbool bIncludeBOM = aImpEx.GetIncludeBOM())
{
aOptions.SetIncludeBOM(bIncludeBOM);
rMedium.GetItemSet().Put(
SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions.WriteToString()));
}
// for mobile case, we use a copy of the original document and give it a temporary name before editing // Therefore, the sheet name becomes ugly, long and nonsensical. #if !(defined ANDROID) // The same resulting name has to be handled in // ScExternalRefCache::initializeDoc() and related, hence // pass 'true' for RenameTab()'s bExternalDocument for a // composed name so ValidTabName() will not be checked, // which could veto the rename in case it contained // characters that Excel does not handle. If we wanted to // change that then it needed to be handled in all // corresponding places of the external references // manager/cache. Likely then we'd also need a method to // compose a name excluding such characters.
m_pDocument->RenameTab( 0, INetURLObject( rMedium.GetName()).GetBase(), true/*bExternalDocument*/); #endif
bOverflowRow = aImpEx.IsOverflowRow();
bOverflowCol = aImpEx.IsOverflowCol();
bOverflowCell = aImpEx.IsOverflowCell();
} else
{
OSL_FAIL( "No Stream" );
}
}
// Order is important: First width, then height if ( bSetColWidths )
{ for ( SCCOL nCol=0; nCol <= nEndCol; nCol++ )
{ if (!bSetSimpleTextColWidths)
aColWidthParam[nCol].mbSimpleText = false;
if (pFilter->GetProviderName() == "orcus")
{
ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters(); if (!pOrcus) returnfalse;
auto res = pOrcus->importByName(*m_pDocument, rMed, pFilter->GetName()); if (res != ScOrcusFilters::ImportResult::Success) returnfalse;
FinishedLoading(); returntrue;
}
returnfalse;
}
ScDocShell::PrepareSaveGuard::PrepareSaveGuard( ScDocShell& rDocShell )
: mrDocShell( rDocShell)
{ // DoEnterHandler not here (because of AutoSave), is in ExecuteSave.
ScChartListenerCollection* pCharts = mrDocShell.m_pDocument->GetChartListenerCollection(); if (pCharts)
pCharts->UpdateDirtyCharts(); // Charts to be updated.
mrDocShell.m_pDocument->StopTemporaryChartLock(); if (mrDocShell.m_pAutoStyleList)
mrDocShell.m_pAutoStyleList->ExecuteAllNow(); // Execute template timeouts now. if (mrDocShell.m_pDocument->HasExternalRefManager())
{
ScExternalRefManager* pRefMgr = mrDocShell.m_pDocument->GetExternalRefManager(); if (pRefMgr && pRefMgr->hasExternalData())
{
pRefMgr->setAllCacheTableReferencedStati( false);
mrDocShell.m_pDocument->MarkUsedExternalReferences(); // Mark tables of external references to be written.
}
} if (mrDocShell.GetCreateMode()== SfxObjectCreateMode::STANDARD)
mrDocShell.SfxObjectShell::SetVisArea( tools::Rectangle() ); // "Normally" worked on => no VisArea.
}
ScDocShell::PrepareSaveGuard::~PrepareSaveGuard() COVERITY_NOEXCEPT_FALSE
{ if (mrDocShell.m_pDocument->HasExternalRefManager())
{
ScExternalRefManager* pRefMgr = mrDocShell.m_pDocument->GetExternalRefManager(); if (pRefMgr && pRefMgr->hasExternalData())
{ // Prevent accidental data loss due to lack of knowledge.
pRefMgr->setAllCacheTableReferencedStati( true);
}
}
}
if (constauto pFrame1 = SfxViewFrame::GetFirst(this))
{ if (auto pSysWin = pFrame1->GetWindow().GetSystemWindow())
{
pSysWin->SetAccessibleName(OUString());
}
} // wait cursor is handled with progress bar bool bRet = SfxObjectShell::Save(); if( bRet )
bRet = SaveXML( GetMedium(), nullptr ); return bRet;
}
namespace {
/** * Remove the file name from the full path, to keep only the directory path.
*/ void popFileName(OUString& rPath)
{ if (!rPath.isEmpty())
{
INetURLObject aURLObj(rPath);
aURLObj.removeSegment();
rPath = aURLObj.GetMainURL(INetURLObject::DecodeMechanism::NONE);
}
}
}
void ScDocShell::TerminateEditing()
{ // Commit any cell changes before saving.
ScModule::get()->InputEnterHandler();
}
bool ScDocShell::SaveAs( SfxMedium& rMedium )
{
OUString aCurPath; // empty for new document that hasn't been saved. const SfxMedium* pCurMedium = GetMedium(); if (pCurMedium)
{
aCurPath = pCurMedium->GetName();
popFileName(aCurPath);
}
if (!aCurPath.isEmpty())
{ // current document has a path -> not a brand-new document.
OUString aNewPath = rMedium.GetName();
popFileName(aNewPath);
OUString aRel = URIHelper::simpleNormalizedMakeRelative(aCurPath, aNewPath); if (!aRel.isEmpty())
{ // Directory path will change before and after the save.
m_pDocument->InvalidateStreamOnSave();
}
}
ScTabViewShell* pViewShell = GetBestViewShell(); bool bNeedsRehash = ScPassHashHelper::needsPassHashRegen(*m_pDocument, PASSHASH_SHA1); if (bNeedsRehash) // legacy xls hash double-hashed by SHA1 is also supported.
bNeedsRehash = ScPassHashHelper::needsPassHashRegen(*m_pDocument, PASSHASH_XL, PASSHASH_SHA1); if (bNeedsRehash)
{ // SHA256 explicitly supported in ODF 1.2, implicitly in ODF 1.1
bNeedsRehash = ScPassHashHelper::needsPassHashRegen(*m_pDocument, PASSHASH_SHA256);
}
if (pViewShell && bNeedsRehash)
{ bool bAutoSaveEvent = false;
utl::MediaDescriptor lArgs(rMedium.GetArgs());
lArgs[utl::MediaDescriptor::PROP_AUTOSAVEEVENT] >>= bAutoSaveEvent; if (bAutoSaveEvent)
{ // skip saving recovery file instead of showing re-type password dialog window
SAL_WARN("sc.filter", "Should re-type password for own format, won't export recovery file");
rMedium.SetError(ERRCODE_SFX_WRONGPASSWORD); returnfalse;
}
if (!pViewShell->ExecuteRetypePassDlg(PASSHASH_SHA1)) // password re-type cancelled. Don't save the document. returnfalse;
}
// wait cursor is handled with progress bar bool bRet = SfxObjectShell::SaveAs( rMedium ); if (bRet)
bRet = SaveXML( &rMedium, nullptr );
return bRet;
}
namespace {
// Xcl-like column width measured in characters of standard font.
sal_Int32 lcl_ScDocShell_GetColWidthInChars( sal_uInt16 nWidth )
{ double f = nWidth;
f *= 1328.0 / 25.0;
f += 90.0;
f *= 1.0 / 23.0;
f /= 256.0;
return sal_Int32( f );
}
void lcl_ScDocShell_GetFixedWidthString( OUString& rStr, const ScDocument& rDoc,
SCTAB nTab, SCCOL nCol, bool bValue, SvxCellHorJustify eHorJust )
{
OUString aString = rStr;
sal_Int32 nLen = lcl_ScDocShell_GetColWidthInChars(
rDoc.GetColWidth( nCol, nTab ) ); //If the text won't fit in the column if ( nLen < aString.getLength() )
{
OUStringBuffer aReplacement; if (bValue)
aReplacement.append("###"); else
aReplacement.append(aString); //truncate to the number of characters that should fit, even in the //bValue case nLen might be < len ###
aString = comphelper::string::truncateToLength(aReplacement, nLen).makeStringAndClear();
} if ( nLen > aString.getLength() )
{ if ( bValue && eHorJust == SvxCellHorJustify::Standard )
eHorJust = SvxCellHorJustify::Right;
OUStringBuffer aTmp(nLen); switch ( eHorJust )
{ case SvxCellHorJustify::Right:
comphelper::string::padToLength( aTmp, nLen - aString.getLength(), ' ' );
aString = aTmp.append(aString); break; case SvxCellHorJustify::Center:
comphelper::string::padToLength( aTmp, (nLen - aString.getLength()) / 2, ' ' );
[[fallthrough]]; default:
aTmp.append(aString);
comphelper::string::padToLength( aTmp, nLen, ' ' );
}
aString = aTmp.makeStringAndClear();
}
rStr = aString;
}
// Treat the top left cell separator "sep=" special. // Here nStartRow == 0 && nStartCol == 0 if (!bFixedWidth && cDelim != 0)
{ // First row iterator.
ScHorizontalCellIterator aIter( *m_pDocument, nTab, nStartCol, nStartRow, nEndCol, nStartRow);
ScRefCellValue* pCell; // Must be first column and all following cells on this row must be // empty to fiddle with "sep=". if ((pCell = aIter.GetNext( nCol, nRow)) != nullptr && nCol == nStartCol && !aIter.GetNext( nCol, nRow))
{ if (pCell->getType() == CELLTYPE_STRING)
{
aString = pCell->getSharedString()->getString(); if (aString.getLength() <= 5 && aString.startsWithIgnoreAsciiCase("sep="))
{ // Cell content is /^sep=.?$/ so write current separator. // Force the quote character to '"' regardless what is set // for export because that is the only one recognized on // import.
aString = "sep=" + OUStringChar(cDelim); if (cStrDelim != 0)
rStream.WriteUniOrByteChar( '"', eCharSet);
rStream.WriteUnicodeOrByteText(aString, eCharSet); if (cStrDelim != 0)
rStream.WriteUniOrByteChar( '"', eCharSet);
endlub( rStream );
++nStartRow;
}
}
}
}
if ( bNeedQuotes || bForceQuotes )
rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
rStream.WriteUnicodeOrByteText(aUniString, eCharSet); if ( bNeedQuotes || bForceQuotes )
rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
} else
{ // This is nasty. The Unicode to byte encoding // may convert typographical quotation marks to ASCII // quotation marks, which may interfere with the delimiter, // so we have to escape delimiters after the string has // been encoded. Since this may happen also with UTF-8 // encoded typographical quotation marks if such was // specified as a delimiter we have to check for the full // encoded delimiter string, not just one character. // Now for RTL_TEXTENCODING_ISO_2022_... and similar brain // dead encodings where one code point (and especially a // low ASCII value) may represent different characters, we // have to convert forth and back and forth again. Same for // UTF-7 since it is a context sensitive encoding too.
if ( bContextOrNotAsciiEncoding )
{ // to byte encoding
OString aStrEnc = OUStringToOString(aUniString, eCharSet); // back to Unicode
OUString aStrDec = OStringToOUString(aStrEnc, eCharSet);
// #i6500# don't call DoEnterHandler here (doesn't work with AutoSave), // it's already in ExecuteSave (as for Save and SaveAs)
if (m_pAutoStyleList)
m_pAutoStyleList->ExecuteAllNow(); // Execute template timeouts now if (GetCreateMode()== SfxObjectCreateMode::STANDARD)
SfxObjectShell::SetVisArea( tools::Rectangle() ); // Edited normally -> no VisArea
/* #i104990# If the imported document contains a medium password, determine if we can save it, otherwise ask the users
whether they want to save without it. */ if( (rMed.GetFilter()->GetFilterFlags() & SfxFilterFlags::ENCRYPTION) == SfxFilterFlags::NONE )
{
SfxItemSet& rItemSet = rMed.GetItemSet(); if( rItemSet.GetItemState( SID_PASSWORD ) == SfxItemState::SET )
{
bDoSave = ScWarnPassword::WarningOnPassword( rMed ); // #i42858# remove password from medium (warn only one time) if( bDoSave )
rItemSet.ClearItem( SID_PASSWORD );
}
}
weld::WaitObject aWait( GetActiveDialogParent() ); // Hack so that Sba can overwrite the opened TempFile.
rMed.CloseOutStream(); bool bHasMemo = false;
// tdf#40713: don't lose dbt file // if aDbtFile corresponds exactly to aTmpFile, we just have to return if (aDbtFile.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ) ==
aTmpFile.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ))
{ if (eError != ERRCODE_NONE && !GetErrorIgnoreWarning())
SetError(eError); return bRet;
}
bool ScDocShell::HasAutomaticTableName( std::u16string_view rFilter )
{ // sal_True for those filters that keep the default table name // (which is language specific)
void ScDocShell::SetDocumentModified()
{ // BroadcastUno must also happen right away with pPaintLockData // FIXME: Also for SetDrawModified, if Drawing is connected // FIXME: Then own Hint?
if ( m_pPaintLockData )
{ // #i115009# broadcast BCA_BRDCST_ALWAYS, so a component can read recalculated results // of RecalcModeAlways formulas (like OFFSET) after modifying cells
m_pDocument->Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS));
m_pDocument->InvalidateTableArea(); // #i105279# needed here
m_pDocument->BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
m_pPaintLockData->SetModified(); // Later on ... return;
}
// Detective AutoUpdate: // Update if formulas were modified (DetectiveDirty) or the list contains // "Trace Error" entries (Trace Error can look completely different // after changes to non-formula cells).
ScDetOpList* pList = m_pDocument->GetDetOpList(); if ( pList && ( m_pDocument->IsDetectiveDirty() || pList->HasAddError() ) &&
pList->Count() && !IsInUndo() && ScModule::get()->GetAppOptions().GetDetectiveAuto() )
{
GetDocFunc().DetectiveRefresh(true); // sal_True = caused by automatic update
}
m_pDocument->SetDetectiveDirty(false); // always reset, also if not refreshed
}
if (m_bAreasChangedNeedBroadcast)
{
m_bAreasChangedNeedBroadcast = false;
SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged));
}
// notify UNO objects after BCA_BRDCST_ALWAYS etc.
m_pDocument->BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
}
/** * SetDrawModified - without Formula update * * Drawing also needs to be updated for the normal SetDocumentModified * e.g.: when deleting tables etc.
*/ void ScDocShell::SetDrawModified()
{ bool bUpdate = !IsModified();
if (pBindings)
{ // #i105960# Undo etc used to be volatile. // They always have to be invalidated, including drawing layer or row height changes // (but not while pPaintLockData is set).
pBindings->Invalidate( SID_UNDO );
pBindings->Invalidate( SID_REDO );
pBindings->Invalidate( SID_REPEAT );
}
// Only for statistics, if this Doc is shown; not from the Doc Manager if( pDocSh == this )
{
ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
::CreateTabPage ScDocStatPageCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_STAT);
OSL_ENSURE(ScDocStatPageCreate, "Tabpage create fail!");
xDlg->AddFontTabPage();
xDlg->AddTabPage(u"calcstats"_ustr, ScResId(STR_DOC_STAT), ScDocStatPageCreate);
} return xDlg;
}
// Remove all involved keys first, because swapping commands don't work // well without doing this.
removeKeysIfExists(xScAccel, aKeys);
xScAccel->store();
if (!bHasEntries)
{ // if no positions were set (for example, export to other format), // reset all "valid" flags for (nTab = 0; nTab < nTabCount; ++nTab)
m_pDocument->SetStreamValid(nTab, false);
}
}
void ScDocShellModificator::SetDocumentModified()
{
ScDocument& rDoc = rDocShell.GetDocument();
rDoc.PrepareFormulaCalc(); if ( !rDoc.IsImportingXML() )
{ // temporarily restore AutoCalcShellDisabled bool bDisabled = rDoc.IsAutoCalcShellDisabled();
rDoc.SetAutoCalcShellDisabled( bAutoCalcShellDisabled );
rDocShell.SetDocumentModified();
rDoc.SetAutoCalcShellDisabled( bDisabled );
} else
{ // uno broadcast is necessary for api to work // -> must also be done during xml import
rDoc.BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.