sc/source/filter/inc/workbookhelper.hxx | 4 ++ sc/source/filter/oox/formulabuffer.cxx | 44 +++++++++++++++++++++--------- sc/source/filter/oox/workbookfragment.cxx | 7 ++++ sc/source/filter/oox/workbookhelper.cxx | 17 +++++++++++ 4 files changed, 59 insertions(+), 13 deletions(-)
New commits: commit ec912956903b2657f4a6b67a68c2687e8be32508 Author: Eike Rathke <er...@redhat.com> AuthorDate: Wed Jul 26 17:43:32 2023 +0200 Commit: Eike Rathke <er...@redhat.com> CommitDate: Wed Jul 26 20:29:57 2023 +0200 Resolves: tdf#147955 Recalculate OOXML for bad generators with all 0.0 results Change-Id: I0ad301dddfe986a38303ce1134e080bafbf312de Reviewed-on: https://gerrit.libreoffice.org/c/core/+/154944 Reviewed-by: Eike Rathke <er...@redhat.com> Tested-by: Jenkins diff --git a/sc/source/filter/inc/workbookhelper.hxx b/sc/source/filter/inc/workbookhelper.hxx index 7aec3a68409c..7b3047759329 100644 --- a/sc/source/filter/inc/workbookhelper.hxx +++ b/sc/source/filter/inc/workbookhelper.hxx @@ -121,6 +121,10 @@ public: sal_Int16 getCurrentSheetIndex() const; /** Returns true when reading a file generated by a known good generator. */ bool isGeneratorKnownGood() const; + /** Returns true if any formula cell is calculated. */ + bool hasCalculatedFormulaCells() const; + /** Set if any formula cell is calculated. */ + void setCalculatedFormulaCells(); /** Sets the VBA project storage used to import VBA source code and forms. */ void setVbaProjectStorage( const StorageRef& rxVbaPrjStrg ); diff --git a/sc/source/filter/oox/formulabuffer.cxx b/sc/source/filter/oox/formulabuffer.cxx index dc934d1d41a4..0e7f3cdd5001 100644 --- a/sc/source/filter/oox/formulabuffer.cxx +++ b/sc/source/filter/oox/formulabuffer.cxx @@ -106,7 +106,7 @@ void applySharedFormulas( SvNumberFormatter& rFormatter, std::vector<FormulaBuffer::SharedFormulaEntry>& rSharedFormulas, std::vector<FormulaBuffer::SharedFormulaDesc>& rCells, - bool bGeneratorKnownGood) + WorkbookHelper& rWorkbookHelper) { sc::SharedFormulaGroups aGroups; { @@ -130,6 +130,8 @@ void applySharedFormulas( { svl::SharedStringPool& rStrPool = rDoc.getDoc().GetSharedStringPool(); + const bool bGeneratorKnownGood = rWorkbookHelper.isGeneratorKnownGood(); + bool bHasCalculatedFormulaCells = rWorkbookHelper.hasCalculatedFormulaCells(); // Process formulas that use shared formulas. for (const FormulaBuffer::SharedFormulaDesc& rDesc : rCells) { @@ -192,12 +194,20 @@ void applySharedFormulas( break; case XML_n: // numeric value. - pCell->SetResultDouble(rDesc.maCellValue.toDouble()); - /* TODO: is it on purpose that we never reset dirty here - * and thus recalculate anyway if cell was dirty? Or is it - * never dirty and therefore set dirty below otherwise? This - * is different from the non-shared case in - * applyCellFormulaValues(). */ + { + const double fVal = rDesc.maCellValue.toDouble(); + if (!bHasCalculatedFormulaCells && fVal != 0.0) + { + rWorkbookHelper.setCalculatedFormulaCells(); + bHasCalculatedFormulaCells = true; + } + pCell->SetResultDouble(fVal); + /* TODO: is it on purpose that we never reset dirty here + * and thus recalculate anyway if cell was dirty? Or is it + * never dirty and therefore set dirty below otherwise? This + * is different from the non-shared case in + * applyCellFormulaValues(). */ + } break; case XML_str: if (bGeneratorKnownGood) @@ -301,9 +311,11 @@ void applyArrayFormulas( } void applyCellFormulaValues( - ScDocumentImport& rDoc, const std::vector<FormulaBuffer::FormulaValue>& rVector, bool bGeneratorKnownGood ) + ScDocumentImport& rDoc, const std::vector<FormulaBuffer::FormulaValue>& rVector, WorkbookHelper& rWorkbookHelper ) { svl::SharedStringPool& rStrPool = rDoc.getDoc().GetSharedStringPool(); + const bool bGeneratorKnownGood = rWorkbookHelper.isGeneratorKnownGood(); + bool bHasCalculatedFormulaCells = rWorkbookHelper.hasCalculatedFormulaCells(); for (const FormulaBuffer::FormulaValue& rValue : rVector) { @@ -317,7 +329,13 @@ void applyCellFormulaValues( { case XML_n: { - pCell->SetResultDouble(rValueStr.toDouble()); + const double fVal = rValueStr.toDouble(); + if (!bHasCalculatedFormulaCells && fVal != 0.0) + { + rWorkbookHelper.setCalculatedFormulaCells(); + bHasCalculatedFormulaCells = true; + } + pCell->SetResultDouble(fVal); pCell->ResetDirty(); pCell->SetChanged(false); } @@ -349,11 +367,11 @@ void applyCellFormulaValues( void processSheetFormulaCells( ScDocumentImport& rDoc, FormulaBuffer::SheetItem& rItem, SvNumberFormatter& rFormatter, - const Sequence<ExternalLinkInfo>& rExternalLinks, bool bGeneratorKnownGood ) + const Sequence<ExternalLinkInfo>& rExternalLinks, WorkbookHelper& rWorkbookHelper ) { if (rItem.mpSharedFormulaEntries && rItem.mpSharedFormulaIDs) applySharedFormulas(rDoc, rFormatter, *rItem.mpSharedFormulaEntries, - *rItem.mpSharedFormulaIDs, bGeneratorKnownGood); + *rItem.mpSharedFormulaIDs, rWorkbookHelper); if (rItem.mpCellFormulas) { @@ -365,7 +383,7 @@ void processSheetFormulaCells( applyArrayFormulas(rDoc, rFormatter, rExternalLinks, *rItem.mpArrayFormulas); if (rItem.mpCellFormulaValues) - applyCellFormulaValues(rDoc, *rItem.mpCellFormulaValues, bGeneratorKnownGood); + applyCellFormulaValues(rDoc, *rItem.mpCellFormulaValues, rWorkbookHelper); } } @@ -418,7 +436,7 @@ void FormulaBuffer::finalizeImport() for (SheetItem& rItem : aSheetItems) processSheetFormulaCells(rDoc, rItem, *rDoc.getDoc().GetFormatTable(), getExternalLinks().getLinkInfos(), - isGeneratorKnownGood()); + *this); // With formula results being set and not recalculated we need to // force-trigger adding all linked external files to the LinkManager. diff --git a/sc/source/filter/oox/workbookfragment.cxx b/sc/source/filter/oox/workbookfragment.cxx index 2f99a49d595e..20e595ee6e65 100644 --- a/sc/source/filter/oox/workbookfragment.cxx +++ b/sc/source/filter/oox/workbookfragment.cxx @@ -600,6 +600,13 @@ void WorkbookFragment::recalcFormulaCells() } else if (nRecalcMode == RECALC_ALWAYS) bHardRecalc = true; + else if (!hasCalculatedFormulaCells()) + { + // Did not encounter any other formula result than 0.0 (or none / no + // formula cells at all, in which case recalculation is almost a no-op) + // in a non-known-good-generator document. + bHardRecalc = true; + } if (bHardRecalc) rDocSh.DoHardRecalc(); diff --git a/sc/source/filter/oox/workbookhelper.cxx b/sc/source/filter/oox/workbookhelper.cxx index 3f9e3fe7d0ec..be37703908d9 100644 --- a/sc/source/filter/oox/workbookhelper.cxx +++ b/sc/source/filter/oox/workbookhelper.cxx @@ -127,6 +127,10 @@ public: sal_Int16 getCurrentSheetIndex() const { return mnCurrSheet; } /** Returns true when reading a file generated by a known good generator. */ bool isGeneratorKnownGood() const { return mbGeneratorKnownGood; } + /** Returns true if any formula cell appears to have a calculated value + not 0.0 nor "", or when reading a known good generator's file. */ + bool hasCalculatedFormulaCells() const { return mbHasCalculatedFormulaCells; } + void setCalculatedFormulaCells() { mbHasCalculatedFormulaCells = true; } /** Sets the VBA project storage used to import VBA source code and forms. */ void setVbaProjectStorage( const StorageRef& rxVbaPrjStrg ) { mxVbaPrjStrg = rxVbaPrjStrg; } @@ -262,6 +266,7 @@ private: StorageRef mxVbaPrjStrg; /// Storage containing the VBA project. sal_Int16 mnCurrSheet; /// Current sheet index in Calc document. bool mbGeneratorKnownGood; /// Whether reading a file generated by Excel or Calc. + bool mbHasCalculatedFormulaCells; /// Assumed to have calculated formula cells. // buffers FormulaBufferPtr mxFormulaBuffer; @@ -533,6 +538,7 @@ void WorkbookGlobals::initialize() maPageStyleServ = "com.sun.star.style.PageStyle"; mnCurrSheet = -1; mbGeneratorKnownGood = false; + mbHasCalculatedFormulaCells = false; meTextEnc = osl_getThreadTextEncoding(); // the spreadsheet document @@ -566,6 +572,7 @@ void WorkbookGlobals::initialize() { mbGeneratorKnownGood = true; } + mbHasCalculatedFormulaCells = mbGeneratorKnownGood; mxDocImport.reset(new ScDocumentImport(*mpDoc)); @@ -683,6 +690,16 @@ bool WorkbookHelper::isGeneratorKnownGood() const return mrBookGlob.isGeneratorKnownGood(); } +bool WorkbookHelper::hasCalculatedFormulaCells() const +{ + return mrBookGlob.hasCalculatedFormulaCells(); +} + +void WorkbookHelper::setCalculatedFormulaCells() +{ + return mrBookGlob.setCalculatedFormulaCells(); +} + void WorkbookHelper::setVbaProjectStorage( const StorageRef& rxVbaPrjStrg ) { mrBookGlob.setVbaProjectStorage( rxVbaPrjStrg );