officecfg/registry/schema/org/openoffice/Office/Calc.xcs | 24 ++++ sc/inc/formulaopt.hxx | 4 sc/inc/globstr.hrc | 1 sc/source/core/tool/formulaopt.cxx | 62 ++++++++++-- sc/source/filter/xml/xmlimprt.cxx | 77 ++++++++++++++- sc/source/filter/xml/xmlimprt.hxx | 1 sc/source/ui/inc/tpformula.hxx | 1 sc/source/ui/optdlg/tpformula.cxx | 12 ++ sc/uiconfig/scalc/ui/optformula.ui | 37 +++++++ 9 files changed, 211 insertions(+), 8 deletions(-)
New commits: commit 2d2974f22ab59ea7dab1aee778308c4f50ff5464 Author: Balazs Varga <balazs.varga.ext...@allotropia.de> AuthorDate: Wed Feb 14 22:34:10 2024 +0100 Commit: Balazs Varga <balazs.varga.ext...@allotropia.de> CommitDate: Mon Feb 19 23:24:54 2024 +0100 tdf#124098 sc add global config setting "RecalcOptimalRowHeightMode" to optimal row height recalculation for optimal document loading. If the "RecalcOptimalRowHeightMode" is set to "Recalc always" we always recalculate the optimal row heights at load time, without any warning dialog. If the "RecalcOptimalRowHeightMode" is set to "Recalc" we never recalculate the optimal row heights at load time, without any warning dialog. If the "RecalcOptimalRowHeightMode" is set to "Ask before Recalc" we ask the user if want to recalculate the optimal row heights at load time or not. The default value is the same what we are doing now: "Recalc always" This option was necessary, since optimal row height calculation depending on also the result of the conditional formatted formulas and it takes a lot of time to calculate the optimal row heights and load the document. Because we allow a lot of text/cell format attribute which are effect on the cell size, therefor it is necessary to evaluate all the formulas. Also if we have 20 condition for a cell range we need to evaluate all the 20 formulas for all the cells and it is very expensive at load time. Change-Id: I9288d11dd2f061f85fa36292a909402a6bb89ea9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163421 Tested-by: Jenkins Reviewed-by: Balazs Varga <balazs.varga.ext...@allotropia.de> diff --git a/officecfg/registry/schema/org/openoffice/Office/Calc.xcs b/officecfg/registry/schema/org/openoffice/Office/Calc.xcs index de97c822c7c1..5582b346910d 100644 --- a/officecfg/registry/schema/org/openoffice/Office/Calc.xcs +++ b/officecfg/registry/schema/org/openoffice/Office/Calc.xcs @@ -1540,6 +1540,30 @@ </constraints> <value>1</value> </prop> + <prop oor:name="RecalcOptimalRowHeightMode" oor:type="xs:int" oor:nillable="false"> + <!-- UIHint: Tools - Options - Spreadsheet - Formula --> + <info> + <desc>Specifies whether to force a hard recalc after load on optimal row heights.</desc> + </info> + <constraints> + <enumeration oor:value="0"> + <info> + <desc>Recalc always</desc> + </info> + </enumeration> + <enumeration oor:value="1"> + <info> + <desc>Recalc never</desc> + </info> + </enumeration> + <enumeration oor:value="2"> + <info> + <desc>Ask before Recalc</desc> + </info> + </enumeration> + </constraints> + <value>0</value> + </prop> </group> </group> <group oor:name="Revision"> diff --git a/sc/inc/formulaopt.hxx b/sc/inc/formulaopt.hxx index de46b52643c8..6cc1dedcbbb4 100644 --- a/sc/inc/formulaopt.hxx +++ b/sc/inc/formulaopt.hxx @@ -30,6 +30,7 @@ private: ScRecalcOptions meOOXMLRecalc; ScRecalcOptions meODFRecalc; + ScRecalcOptions meReCalcOptiRowHeights; public: ScFormulaOptions(); @@ -64,6 +65,9 @@ public: void SetODFRecalcOptions( ScRecalcOptions eOpt ) { meODFRecalc = eOpt; } ScRecalcOptions GetODFRecalcOptions() const { return meODFRecalc; } + void SetReCalcOptiRowHeights( ScRecalcOptions eOpt ) { meReCalcOptiRowHeights = eOpt; } + ScRecalcOptions GetReCalcOptiRowHeights() const { return meReCalcOptiRowHeights; } + void ResetFormulaSeparators(); static void GetDefaultFormulaSeparators(OUString& rSepArg, OUString& rSepArrayCol, OUString& rSepArrayRow); diff --git a/sc/inc/globstr.hrc b/sc/inc/globstr.hrc index b5badb52dff3..04bfae4f6f82 100644 --- a/sc/inc/globstr.hrc +++ b/sc/inc/globstr.hrc @@ -504,6 +504,7 @@ #define STR_EDIT_EXISTING_COND_FORMATS NC_("STR_EDIT_EXISTING_COND_FORMATS", "The selected cell already contains conditional formatting. You can either edit the existing conditional format or you define a new overlapping conditional format. Do you want to edit the existing conditional format?") #define STR_QUERY_FORMULA_RECALC_ONLOAD_ODS NC_("STR_QUERY_FORMULA_RECALC_ONLOAD_ODS", "This document was last saved by an application other than %PRODUCTNAME. Some formula cells may produce different results when recalculated. Do you want to recalculate all formula cells in this document now?") #define STR_QUERY_FORMULA_RECALC_ONLOAD_XLS NC_("STR_QUERY_FORMULA_RECALC_ONLOAD_XLS", "This document was saved in Excel file format (.xlsx). Some formula cells may produce different results when recalculated. Do you want to recalculate all formula cells now?") +#define STR_QUERY_OPT_ROW_HEIGHT_RECALC_ONLOAD NC_("STR_QUERY_OPT_ROW_HEIGHT_RECALC_ONLOAD", "The content of some cells may not be entirely visible. Recalculating row heights will make them visible, but may take some time. Do you want to recalculate all row heights now?") #define STR_NO_INSERT_DELETE_OVER_PIVOT_TABLE NC_("STR_NO_INSERT_DELETE_OVER_PIVOT_TABLE", "You cannot insert or delete cells when the affected range intersects with pivot table.") #define STR_DPFIELD_GROUP_BY_SECONDS NC_("STR_DPFIELD_GROUP_BY_SECONDS", "Seconds") #define STR_DPFIELD_GROUP_BY_MINUTES NC_("STR_DPFIELD_GROUP_BY_MINUTES", "Minutes") diff --git a/sc/source/core/tool/formulaopt.cxx b/sc/source/core/tool/formulaopt.cxx index 08c660a44ac1..77a5e3cad9f2 100644 --- a/sc/source/core/tool/formulaopt.cxx +++ b/sc/source/core/tool/formulaopt.cxx @@ -35,6 +35,7 @@ void ScFormulaOptions::SetDefaults() mbWriteCalcConfig = true; meOOXMLRecalc = RECALC_ASK; meODFRecalc = RECALC_ASK; + meReCalcOptiRowHeights = RECALC_ASK; // unspecified means use the current formula syntax. aCalcConfig.reset(); @@ -116,7 +117,8 @@ bool ScFormulaOptions::operator==( const ScFormulaOptions& rOpt ) const && aFormulaSepArrayRow == rOpt.aFormulaSepArrayRow && aFormulaSepArrayCol == rOpt.aFormulaSepArrayCol && meOOXMLRecalc == rOpt.meOOXMLRecalc - && meODFRecalc == rOpt.meODFRecalc; + && meODFRecalc == rOpt.meODFRecalc + && meReCalcOptiRowHeights == rOpt.meReCalcOptiRowHeights; } bool ScFormulaOptions::operator!=( const ScFormulaOptions& rOpt ) const @@ -159,11 +161,12 @@ constexpr OUStringLiteral CFGPATH_FORMULA = u"Office.Calc/Formula"; #define SCFORMULAOPT_EMPTY_OUSTRING_AS_ZERO 7 #define SCFORMULAOPT_OOXML_RECALC 8 #define SCFORMULAOPT_ODF_RECALC 9 -#define SCFORMULAOPT_OPENCL_AUTOSELECT 10 -#define SCFORMULAOPT_OPENCL_DEVICE 11 -#define SCFORMULAOPT_OPENCL_SUBSET_ONLY 12 -#define SCFORMULAOPT_OPENCL_MIN_SIZE 13 -#define SCFORMULAOPT_OPENCL_SUBSET_OPS 14 +#define SCFORMULAOPT_ROW_HEIGHT_RECALC 10 +#define SCFORMULAOPT_OPENCL_AUTOSELECT 11 +#define SCFORMULAOPT_OPENCL_DEVICE 12 +#define SCFORMULAOPT_OPENCL_SUBSET_ONLY 13 +#define SCFORMULAOPT_OPENCL_MIN_SIZE 14 +#define SCFORMULAOPT_OPENCL_SUBSET_OPS 15 Sequence<OUString> ScFormulaCfg::GetPropertyNames() { @@ -177,6 +180,7 @@ Sequence<OUString> ScFormulaCfg::GetPropertyNames() "Syntax/EmptyStringAsZero", // SCFORMULAOPT_EMPTY_OUSTRING_AS_ZERO "Load/OOXMLRecalcMode", // SCFORMULAOPT_OOXML_RECALC "Load/ODFRecalcMode", // SCFORMULAOPT_ODF_RECALC + "Load/RecalcOptimalRowHeightMode", // SCFORMULAOPT_ROW_HEIGHT_RECALC "Calculation/OpenCLAutoSelect", // SCFORMULAOPT_OPENCL_AUTOSELECT "Calculation/OpenCLDevice", // SCFORMULAOPT_OPENCL_DEVICE "Calculation/OpenCLSubsetOnly", // SCFORMULAOPT_OPENCL_SUBSET_ONLY @@ -198,6 +202,7 @@ ScFormulaCfg::PropsToIds ScFormulaCfg::GetPropNamesToId() SCFORMULAOPT_EMPTY_OUSTRING_AS_ZERO, SCFORMULAOPT_OOXML_RECALC, SCFORMULAOPT_ODF_RECALC, + SCFORMULAOPT_ROW_HEIGHT_RECALC, SCFORMULAOPT_OPENCL_AUTOSELECT, SCFORMULAOPT_OPENCL_DEVICE, SCFORMULAOPT_OPENCL_SUBSET_ONLY, @@ -419,6 +424,30 @@ void ScFormulaCfg::UpdateFromProperties( const Sequence<OUString>& aNames ) SetODFRecalcOptions(eOpt); } break; + case SCFORMULAOPT_ROW_HEIGHT_RECALC: + { + ScRecalcOptions eOpt = RECALC_ASK; + if (pValues[nProp] >>= nIntVal) + { + switch (nIntVal) + { + case 0: + eOpt = RECALC_ALWAYS; + break; + case 1: + eOpt = RECALC_NEVER; + break; + case 2: + eOpt = RECALC_ASK; + break; + default: + SAL_WARN("sc", "unknown optimal row height recalc option!"); + } + } + + SetReCalcOptiRowHeights(eOpt); + } + break; case SCFORMULAOPT_OPENCL_AUTOSELECT: { bool bVal = GetCalcConfig().mbOpenCLAutoSelect; @@ -595,6 +624,27 @@ void ScFormulaCfg::ImplCommit() pValues[nProp] <<= nVal; } break; + case SCFORMULAOPT_ROW_HEIGHT_RECALC: + { + sal_Int32 nVal = 2; + switch (GetReCalcOptiRowHeights()) + { + case RECALC_ALWAYS: + nVal = 0; + break; + case RECALC_NEVER: + nVal = 1; + break; + case RECALC_ASK: + nVal = 2; + break; + default: + SAL_WARN("sc", "unknown optimal row height recalc option!"); + } + + pValues[nProp] <<= nVal; + } + break; case SCFORMULAOPT_OPENCL_AUTOSELECT: { bool bVal = GetCalcConfig().mbOpenCLAutoSelect; diff --git a/sc/source/filter/xml/xmlimprt.cxx b/sc/source/filter/xml/xmlimprt.cxx index 243080b3b7f8..986aa69ebb7a 100644 --- a/sc/source/filter/xml/xmlimprt.cxx +++ b/sc/source/filter/xml/xmlimprt.cxx @@ -42,6 +42,7 @@ #include <svl/languageoptions.hxx> #include <editeng/editstat.hxx> #include <formula/errorcodes.hxx> +#include <formulaopt.hxx> #include <vcl/svapp.hxx> #include <appluno.hxx> @@ -50,12 +51,16 @@ #include <document.hxx> #include <docsh.hxx> #include <docuno.hxx> +#include <globstr.hrc> +#include <scresid.hxx> +#include <scmod.hxx> #include "xmlbodyi.hxx" #include "xmlstyli.hxx" #include <ViewSettingsSequenceDefines.hxx> #include <userdat.hxx> #include <compiler.hxx> +#include <officecfg/Office/Calc.hxx> #include "XMLConverter.hxx" #include "XMLDetectiveContext.hxx" @@ -1201,6 +1206,76 @@ sal_Int32 ScXMLImport::GetRangeType(std::u16string_view sRangeType) return nRangeType; } +namespace { + +class MessageWithCheck : public weld::MessageDialogController +{ +private: + std::unique_ptr<weld::CheckButton> m_xWarningOnBox; +public: + MessageWithCheck(weld::Window *pParent, const OUString& rUIFile, const OUString& rDialogId) + : MessageDialogController(pParent, rUIFile, rDialogId, "ask") + , m_xWarningOnBox(m_xBuilder->weld_check_button("ask")) + { + } + bool get_active() const { return m_xWarningOnBox->get_active(); } + void hide_ask() const { m_xWarningOnBox->set_visible(false); }; +}; + +} + +bool ScXMLImport::GetRecalcRowHeightsMode() +{ + ScRecalcOptions nRecalcMode = + static_cast<ScRecalcOptions>(officecfg::Office::Calc::Formula::Load::RecalcOptimalRowHeightMode::get()); + + bool bHardRecalc = false; + switch (nRecalcMode) + { + case RECALC_ASK: + { + if (pDoc->IsUserInteractionEnabled()) + { + // Ask if the user wants to perform full re-calculation. + MessageWithCheck aQueryBox(ScDocShell::GetActiveDialogParent(), + "modules/scalc/ui/recalcquerydialog.ui", "RecalcQueryDialog"); + 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); + + ScFormulaOptions aOpt = SC_MOD()->GetFormulaOptions(); + aOpt.SetReCalcOptiRowHeights(bHardRecalc ? RECALC_ALWAYS : RECALC_NEVER); + SC_MOD()->SetFormulaOptions(aOpt); + + batch->commit(); + } + } + } + break; + case RECALC_ALWAYS: + bHardRecalc = true; + break; + case RECALC_NEVER: + bHardRecalc = false; + break; + default: + SAL_WARN("sc", "unknown optimal row height recalc option!"); + } + + return bHardRecalc; +} + void ScXMLImport::SetLabelRanges() { if (maMyLabelRanges.empty()) @@ -1420,7 +1495,7 @@ void SAL_CALL ScXMLImport::endDocument() } // There are rows with optimal height which need to be updated - if (pDoc && !maRecalcRowRanges.empty()) + if (pDoc && !maRecalcRowRanges.empty() && GetRecalcRowHeightsMode()) { bool bLockHeight = pDoc->IsAdjustHeightLocked(); if (bLockHeight) diff --git a/sc/source/filter/xml/xmlimprt.hxx b/sc/source/filter/xml/xmlimprt.hxx index 843e86536088..546ccb97faf2 100644 --- a/sc/source/filter/xml/xmlimprt.hxx +++ b/sc/source/filter/xml/xmlimprt.hxx @@ -305,6 +305,7 @@ public: void SetRangeOverflowType(ErrCode nType); static sal_Int32 GetRangeType(std::u16string_view sRangeType); + bool GetRecalcRowHeightsMode(); void SetNamedRanges(); void SetSheetNamedRanges(); void SetLabelRanges(); diff --git a/sc/source/ui/inc/tpformula.hxx b/sc/source/ui/inc/tpformula.hxx index 14a72b751183..1172a323d948 100644 --- a/sc/source/ui/inc/tpformula.hxx +++ b/sc/source/ui/inc/tpformula.hxx @@ -82,6 +82,7 @@ private: std::unique_ptr<weld::ComboBox> mxLbOOXMLRecalcOptions; std::unique_ptr<weld::ComboBox> mxLbODFRecalcOptions; + std::unique_ptr<weld::ComboBox> mxLbRowHeightReCalcOptions; }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/optdlg/tpformula.cxx b/sc/source/ui/optdlg/tpformula.cxx index ab8cc38c122e..046cfc807e54 100644 --- a/sc/source/ui/optdlg/tpformula.cxx +++ b/sc/source/ui/optdlg/tpformula.cxx @@ -45,6 +45,7 @@ ScTpFormulaOptions::ScTpFormulaOptions(weld::Container* pPage, weld::DialogContr , mxBtnSepReset(m_xBuilder->weld_button("reset")) , mxLbOOXMLRecalcOptions(m_xBuilder->weld_combo_box("ooxmlrecalc")) , mxLbODFRecalcOptions(m_xBuilder->weld_combo_box("odfrecalc")) + , mxLbRowHeightReCalcOptions(m_xBuilder->weld_combo_box("rowheightrecalc")) { mxLbFormulaSyntax->append_text(ScResId(SCSTR_FORMULA_SYNTAX_CALC_A1)); mxLbFormulaSyntax->append_text(ScResId(SCSTR_FORMULA_SYNTAX_XL_A1)); @@ -306,6 +307,7 @@ bool ScTpFormulaOptions::FillItemSet(SfxItemSet* rCoreSet) OUString aSepArrayRow = mxEdSepArrayRow->get_text(); sal_Int16 nOOXMLRecalcMode = mxLbOOXMLRecalcOptions->get_active(); sal_Int16 nODFRecalcMode = mxLbODFRecalcOptions->get_active(); + sal_Int16 nReCalcOptRowHeights = mxLbRowHeightReCalcOptions->get_active(); if (mxBtnCustomCalcDefault->get_active()) { @@ -320,6 +322,7 @@ bool ScTpFormulaOptions::FillItemSet(SfxItemSet* rCoreSet) || mxEdSepArrayRow->get_saved_value() != aSepArrayRow || mxLbOOXMLRecalcOptions->get_saved_value() != mxLbOOXMLRecalcOptions->get_text(nOOXMLRecalcMode) || mxLbODFRecalcOptions->get_saved_value() != mxLbODFRecalcOptions->get_text(nODFRecalcMode) + || mxLbRowHeightReCalcOptions->get_saved_value() != mxLbRowHeightReCalcOptions->get_text(nReCalcOptRowHeights) || maSavedConfig != maCurrentConfig || maSavedDocOptions != maCurrentDocOptions ) { @@ -340,6 +343,7 @@ bool ScTpFormulaOptions::FillItemSet(SfxItemSet* rCoreSet) ScRecalcOptions eOOXMLRecalc = static_cast<ScRecalcOptions>(nOOXMLRecalcMode); ScRecalcOptions eODFRecalc = static_cast<ScRecalcOptions>(nODFRecalcMode); + ScRecalcOptions eReCalcOptRowHeights = static_cast<ScRecalcOptions>(nReCalcOptRowHeights); aOpt.SetFormulaSyntax(eGram); aOpt.SetUseEnglishFuncName(bEnglishFuncName); @@ -349,6 +353,7 @@ bool ScTpFormulaOptions::FillItemSet(SfxItemSet* rCoreSet) aOpt.SetCalcConfig(maCurrentConfig); aOpt.SetOOXMLRecalcOptions(eOOXMLRecalc); aOpt.SetODFRecalcOptions(eODFRecalc); + aOpt.SetReCalcOptiRowHeights(eReCalcOptRowHeights); aOpt.SetWriteCalcConfig( maCurrentDocOptions.IsWriteCalcConfig()); rCoreSet->Put( ScTpFormulaItem( std::move(aOpt) ) ); @@ -396,6 +401,13 @@ void ScTpFormulaOptions::Reset(const SfxItemSet* rCoreSet) mxLbODFRecalcOptions->save_value(); mxLbODFRecalcOptions->set_sensitive( !officecfg::Office::Calc::Formula::Load::ODFRecalcMode::isReadOnly() ); + // Recalc optimal row heights at load + ScRecalcOptions eReCalcOptRowHeights = aOpt.GetReCalcOptiRowHeights(); + mxLbRowHeightReCalcOptions->set_active(static_cast<sal_uInt16>(eReCalcOptRowHeights)); + mxLbRowHeightReCalcOptions->save_value(); + mxLbRowHeightReCalcOptions->set_sensitive( + !officecfg::Office::Calc::Formula::Load::RecalcOptimalRowHeightMode::isReadOnly() ); + // english function name. mxCbEnglishFuncName->set_active( aOpt.GetUseEnglishFuncName() ); mxCbEnglishFuncName->save_state(); diff --git a/sc/uiconfig/scalc/ui/optformula.ui b/sc/uiconfig/scalc/ui/optformula.ui index 545c0759fd1c..a6f65635831e 100644 --- a/sc/uiconfig/scalc/ui/optformula.ui +++ b/sc/uiconfig/scalc/ui/optformula.ui @@ -99,7 +99,7 @@ <property name="label-xalign">0</property> <property name="shadow-type">none</property> <child> - <!-- n-columns=2 n-rows=2 --> + <!-- n-columns=2 n-rows=3 --> <object class="GtkGrid" id="grid4"> <property name="visible">True</property> <property name="can-focus">False</property> @@ -167,6 +167,41 @@ <property name="top-attach">1</property> </packing> </child> + <child> + <object class="GtkLabel" id="label5"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="label" translatable="yes" context="optformula|label10">Optimal row height:</property> + <property name="use-underline">True</property> + <property name="mnemonic-widget">odfrecalc</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left-attach">0</property> + <property name="top-attach">2</property> + </packing> + </child> + <child> + <object class="GtkComboBoxText" id="rowheightrecalc"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="hexpand">True</property> + <items> + <item translatable="yes" context="optformula|odfrecalc">Always recalculate</item> + <item translatable="yes" context="optformula|odfrecalc">Never recalculate</item> + <item translatable="yes" context="optformula|odfrecalc">Prompt user</item> + </items> + <child internal-child="accessible"> + <object class="AtkObject" id="rowheightrecalc-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="optformula|extended_tip|rowheightrecalc">Define either we want to calculate the optimal row heights or we do not want at load time.</property> + </object> + </child> + </object> + <packing> + <property name="left-attach">1</property> + <property name="top-attach">2</property> + </packing> + </child> </object> </child> <child type="label">