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 69184e2eff8eeb1f2a0b10279c1d08f70b2e7000
Author:     Eike Rathke <er...@redhat.com>
AuthorDate: Wed Jul 26 17:43:32 2023 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Thu Jul 27 13:29:30 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
    (cherry picked from commit ec912956903b2657f4a6b67a68c2687e8be32508)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/154953
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

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 3a542df0313e..adb3e899e825 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; }
@@ -260,6 +264,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;
@@ -526,6 +531,7 @@ void WorkbookGlobals::initialize()
     maPageStyleServ = "com.sun.star.style.PageStyle";
     mnCurrSheet = -1;
     mbGeneratorKnownGood = false;
+    mbHasCalculatedFormulaCells = false;
     meTextEnc = osl_getThreadTextEncoding();
 
     // the spreadsheet document
@@ -559,6 +565,7 @@ void WorkbookGlobals::initialize()
     {
         mbGeneratorKnownGood = true;
     }
+    mbHasCalculatedFormulaCells = mbGeneratorKnownGood;
 
     mxDocImport.reset(new ScDocumentImport(*mpDoc));
 
@@ -675,6 +682,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 );

Reply via email to