formula/source/core/api/FormulaCompiler.cxx | 154 +++++++++++++++++++++++----- include/formula/FormulaCompiler.hxx | 42 ++++++- sc/inc/addincol.hxx | 10 + sc/inc/compiler.hxx | 4 sc/inc/funcdesc.hxx | 2 sc/source/core/data/funcdesc.cxx | 4 sc/source/core/data/global.cxx | 3 sc/source/core/tool/addincol.cxx | 64 ++++++----- sc/source/core/tool/calcconfig.cxx | 13 ++ sc/source/core/tool/compiler.cxx | 10 + sc/source/ui/docshell/docsh6.cxx | 3 11 files changed, 240 insertions(+), 69 deletions(-)
New commits: commit 32019fae7730fc8d94f14d47ebaccbdc6775340a Author: Eike Rathke <[email protected]> AuthorDate: Fri Aug 5 12:43:36 2022 +0200 Commit: Xisco Fauli <[email protected]> CommitDate: Mon Sep 5 16:18:47 2022 +0200 Resolves: tdf#135993 Create ScFunctionList and ScFuncDesc with English names This is a combination of 4 commits. Related: tdf#135993 Destroy temporary OpCodeMap when reading config Initialized at FormulaCompiler base class instance it lacks AddIn mapping and a still existing OpCodeMap prevents necessary reinitialization from derived ScCompiler instance later. xChange-Id: I0c2db41dd45829abfb8460730264f097ab76ab2e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137881 Tested-by: Jenkins Reviewed-by: Eike Rathke <[email protected]> (cherry picked from commit 28c4c72a4e81821d9e567757725937f74a6d114f) Related: tdf#135993 Use ScCompiler to create English OpCodeMap with AddIns ... instead of formula::FormulaCompiler base class that doesn't know anything about AddIns, and copy AddIns along to new resulting native map. xChange-Id: I9e4ece2f7450a561ac502ca1dbddaa5a697fa2fe Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137882 Tested-by: Eike Rathke <[email protected]> Reviewed-by: Eike Rathke <[email protected]> (cherry picked from commit 0a78f11fdd13d914d5f063007b2df9796e6dce9d) Resolves: tdf#135993 Create ScFunctionList and ScFuncDesc with English names Used in Function Wizard and formula tooltips. Without, no matching name is found for AddIn English name and no tooltip/description/arguments are displayed. xChange-Id: Ib0cf419c476dae495467c444f1ee1f84a55633a7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137883 Tested-by: Jenkins Reviewed-by: Eike Rathke <[email protected]> (cherry picked from commit d778c6fd5c2ba8e27df46ec9e183a61ad29e30d5) Use CharClass::uppercase() for AddIns' English UI names, tdf#135993 follow-up ... instead of OUString::toAsciiUpperCase(). English names should consist of ASCII alphanumeric only, but we don't know what an AddIn's author comes up with. Lookup in ScCompiler is done with CharClass as well. For this, use the static ScCompiler::GetCharClassEnglish() instance made public and guard creation with a mutex. xChange-Id: Icb79d49d4c7339c8d01b141de2a34715d794dd92 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138004 Reviewed-by: Eike Rathke <[email protected]> Tested-by: Jenkins (cherry picked from commit 33c8c9d0dc8e76bc7dacb92175047a89f7d39a3c) Change-Id: Ib0cf419c476dae495467c444f1ee1f84a55633a7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/139229 Tested-by: Jenkins Reviewed-by: Xisco Fauli <[email protected]> diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx index be926e7d521a..591b28744289 100644 --- a/formula/source/core/api/FormulaCompiler.cxx +++ b/formula/source/core/api/FormulaCompiler.cxx @@ -823,37 +823,37 @@ FormulaCompiler::OpCodeMapPtr FormulaCompiler::GetOpCodeMap( const sal_Int32 nLa { case FormulaLanguage::ODFF : if (!mxSymbolsODFF) - InitSymbolsODFF(); + InitSymbolsODFF( InitSymbols::INIT); xMap = mxSymbolsODFF; break; case FormulaLanguage::ODF_11 : if (!mxSymbolsPODF) - InitSymbolsPODF(); + InitSymbolsPODF( InitSymbols::INIT); xMap = mxSymbolsPODF; break; case FormulaLanguage::ENGLISH : if (!mxSymbolsEnglish) - InitSymbolsEnglish(); + InitSymbolsEnglish( InitSymbols::INIT); xMap = mxSymbolsEnglish; break; case FormulaLanguage::NATIVE : if (!mxSymbolsNative) - InitSymbolsNative(); + InitSymbolsNative( InitSymbols::INIT); xMap = mxSymbolsNative; break; case FormulaLanguage::XL_ENGLISH: if (!mxSymbolsEnglishXL) - InitSymbolsEnglishXL(); + InitSymbolsEnglishXL( InitSymbols::INIT); xMap = mxSymbolsEnglishXL; break; case FormulaLanguage::OOXML: if (!mxSymbolsOOXML) - InitSymbolsOOXML(); + InitSymbolsOOXML( InitSymbols::INIT); xMap = mxSymbolsOOXML; break; case FormulaLanguage::API : if (!mxSymbolsAPI) - InitSymbolsAPI(); + InitSymbolsAPI( InitSymbols::INIT); xMap = mxSymbolsAPI; break; default: @@ -862,6 +862,62 @@ FormulaCompiler::OpCodeMapPtr FormulaCompiler::GetOpCodeMap( const sal_Int32 nLa return xMap; } +void FormulaCompiler::DestroyOpCodeMap( const sal_Int32 nLanguage ) +{ + using namespace sheet; + switch (nLanguage) + { + case FormulaLanguage::ODFF : + InitSymbolsODFF( InitSymbols::DESTROY); + break; + case FormulaLanguage::ODF_11 : + InitSymbolsPODF( InitSymbols::DESTROY); + break; + case FormulaLanguage::ENGLISH : + InitSymbolsEnglish( InitSymbols::DESTROY); + break; + case FormulaLanguage::NATIVE : + InitSymbolsNative( InitSymbols::DESTROY); + break; + case FormulaLanguage::XL_ENGLISH: + InitSymbolsEnglishXL( InitSymbols::DESTROY); + break; + case FormulaLanguage::OOXML: + InitSymbolsOOXML( InitSymbols::DESTROY); + break; + case FormulaLanguage::API : + InitSymbolsAPI( InitSymbols::DESTROY); + break; + default: + ; // nothing + } +} + +bool FormulaCompiler::HasOpCodeMap( const sal_Int32 nLanguage ) const +{ + using namespace sheet; + switch (nLanguage) + { + case FormulaLanguage::ODFF : + return InitSymbolsODFF( InitSymbols::ASK); + case FormulaLanguage::ODF_11 : + return InitSymbolsPODF( InitSymbols::ASK); + case FormulaLanguage::ENGLISH : + return InitSymbolsEnglish( InitSymbols::ASK); + case FormulaLanguage::NATIVE : + return InitSymbolsNative( InitSymbols::ASK); + case FormulaLanguage::XL_ENGLISH: + return InitSymbolsEnglishXL( InitSymbols::ASK); + case FormulaLanguage::OOXML: + return InitSymbolsOOXML( InitSymbols::ASK); + case FormulaLanguage::API : + return InitSymbolsAPI( InitSymbols::ASK); + default: + ; // nothing + } + return false; +} + OUString FormulaCompiler::FindAddInFunction( const OUString& /*rUpperName*/, bool /*bLocalFirst*/ ) const { return OUString(); @@ -898,12 +954,16 @@ FormulaCompiler::OpCodeMapPtr FormulaCompiler::CreateOpCodeMap( return xMap; } -static void lcl_fillNativeSymbols( FormulaCompiler::NonConstOpCodeMapPtr& xMap, bool bDestroy = false ) +static bool lcl_fillNativeSymbols( FormulaCompiler::NonConstOpCodeMapPtr& xMap, FormulaCompiler::InitSymbols eWhat = FormulaCompiler::InitSymbols::INIT ) { static OpCodeMapData aSymbolMap; osl::MutexGuard aGuard(&aSymbolMap.maMtx); - if ( bDestroy ) + if (eWhat == FormulaCompiler::InitSymbols::ASK) + { + return bool(aSymbolMap.mxSymbolMap); + } + else if (eWhat == FormulaCompiler::InitSymbols::DESTROY) { aSymbolMap.mxSymbolMap.reset(); } @@ -919,6 +979,8 @@ static void lcl_fillNativeSymbols( FormulaCompiler::NonConstOpCodeMapPtr& xMap, } xMap = aSymbolMap.mxSymbolMap; + + return true; } const OUString& FormulaCompiler::GetNativeSymbol( OpCode eOp ) @@ -933,54 +995,80 @@ sal_Unicode FormulaCompiler::GetNativeSymbolChar( OpCode eOp ) return GetNativeSymbol(eOp)[0]; } -void FormulaCompiler::InitSymbolsNative() const +bool FormulaCompiler::InitSymbolsNative( FormulaCompiler::InitSymbols eWhat ) const { - lcl_fillNativeSymbols( mxSymbolsNative); + return lcl_fillNativeSymbols( mxSymbolsNative, eWhat); } -void FormulaCompiler::InitSymbolsEnglish() const +bool FormulaCompiler::InitSymbolsEnglish( FormulaCompiler::InitSymbols eWhat ) const { static OpCodeMapData aMap; osl::MutexGuard aGuard(&aMap.maMtx); - if (!aMap.mxSymbolMap) + if (eWhat == InitSymbols::ASK) + return bool(aMap.mxSymbolMap); + else if (eWhat == InitSymbols::DESTROY) + aMap.mxSymbolMap.reset(); + else if (!aMap.mxSymbolMap) loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_ENGLISH, aMap.mxSymbolMap); mxSymbolsEnglish = aMap.mxSymbolMap; + return true; } -void FormulaCompiler::InitSymbolsPODF() const +bool FormulaCompiler::InitSymbolsPODF( FormulaCompiler::InitSymbols eWhat ) const { static OpCodeMapData aMap; osl::MutexGuard aGuard(&aMap.maMtx); - if (!aMap.mxSymbolMap) + if (eWhat == InitSymbols::ASK) + return bool(aMap.mxSymbolMap); + else if (eWhat == InitSymbols::DESTROY) + aMap.mxSymbolMap.reset(); + else if (!aMap.mxSymbolMap) loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_PODF, FormulaGrammar::GRAM_PODF, aMap.mxSymbolMap, SeparatorType::RESOURCE_BASE); mxSymbolsPODF = aMap.mxSymbolMap; + return true; } -void FormulaCompiler::InitSymbolsAPI() const +bool FormulaCompiler::InitSymbolsAPI( FormulaCompiler::InitSymbols eWhat ) const { static OpCodeMapData aMap; osl::MutexGuard aGuard(&aMap.maMtx); - if (!aMap.mxSymbolMap) + if (eWhat == InitSymbols::ASK) + return bool(aMap.mxSymbolMap); + else if (eWhat == InitSymbols::DESTROY) + aMap.mxSymbolMap.reset(); + else if (!aMap.mxSymbolMap) loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_API, FormulaGrammar::GRAM_API, aMap.mxSymbolMap, SeparatorType::RESOURCE_BASE); mxSymbolsAPI = aMap.mxSymbolMap; + return true; } -void FormulaCompiler::InitSymbolsODFF() const +bool FormulaCompiler::InitSymbolsODFF( FormulaCompiler::InitSymbols eWhat ) const { static OpCodeMapData aMap; osl::MutexGuard aGuard(&aMap.maMtx); - if (!aMap.mxSymbolMap) + if (eWhat == InitSymbols::ASK) + return bool(aMap.mxSymbolMap); + else if (eWhat == InitSymbols::DESTROY) + aMap.mxSymbolMap.reset(); + else if (!aMap.mxSymbolMap) loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF, FormulaGrammar::GRAM_ODFF, aMap.mxSymbolMap, SeparatorType::RESOURCE_BASE); mxSymbolsODFF = aMap.mxSymbolMap; + return true; } -void FormulaCompiler::InitSymbolsEnglishXL() const +bool FormulaCompiler::InitSymbolsEnglishXL( FormulaCompiler::InitSymbols eWhat ) const { static OpCodeMapData aMap; osl::MutexGuard aGuard(&aMap.maMtx); - if (!aMap.mxSymbolMap) + if (eWhat == InitSymbols::ASK) + return bool(aMap.mxSymbolMap); + else if (eWhat == InitSymbols::DESTROY) + aMap.mxSymbolMap.reset(); + else if (!aMap.mxSymbolMap) loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH, FormulaGrammar::GRAM_ENGLISH, aMap.mxSymbolMap); mxSymbolsEnglishXL = aMap.mxSymbolMap; + if (eWhat != InitSymbols::INIT) + return true; // TODO: For now, just replace the separators to the Excel English // variants. Later, if we want to properly map Excel functions with Calc @@ -988,15 +1076,22 @@ void FormulaCompiler::InitSymbolsEnglishXL() const mxSymbolsEnglishXL->putOpCode( OUString(','), ocSep, nullptr); mxSymbolsEnglishXL->putOpCode( OUString(','), ocArrayColSep, nullptr); mxSymbolsEnglishXL->putOpCode( OUString(';'), ocArrayRowSep, nullptr); + + return true; } -void FormulaCompiler::InitSymbolsOOXML() const +bool FormulaCompiler::InitSymbolsOOXML( FormulaCompiler::InitSymbols eWhat ) const { static OpCodeMapData aMap; osl::MutexGuard aGuard(&aMap.maMtx); - if (!aMap.mxSymbolMap) + if (eWhat == InitSymbols::ASK) + return bool(aMap.mxSymbolMap); + else if (eWhat == InitSymbols::DESTROY) + aMap.mxSymbolMap.reset(); + else if (!aMap.mxSymbolMap) loadSymbols(RID_STRLIST_FUNCTION_NAMES_ENGLISH_OOXML, FormulaGrammar::GRAM_OOXML, aMap.mxSymbolMap, SeparatorType::RESOURCE_BASE); mxSymbolsOOXML = aMap.mxSymbolMap; + return true; } @@ -1201,7 +1296,16 @@ void FormulaCompiler::OpCodeMap::copyFrom( const OpCodeMap& r ) } } - // TODO: maybe copy the external maps too? + // This was meant to copy to native map that does not have AddIn symbols + // but needs them from the source map. It is unclear what should happen if + // the destination already had externals, so do it only if it doesn't. + if (!hasExternals()) + { + maExternalHashMap = r.maExternalHashMap; + maReverseExternalHashMap = r.maReverseExternalHashMap; + mbCore = r.mbCore; + mbEnglish = r.mbEnglish; + } } @@ -2588,7 +2692,7 @@ void FormulaCompiler::UpdateSeparatorsNative( void FormulaCompiler::ResetNativeSymbols() { NonConstOpCodeMapPtr xSymbolsNative; - lcl_fillNativeSymbols( xSymbolsNative, true); + lcl_fillNativeSymbols( xSymbolsNative, InitSymbols::DESTROY); lcl_fillNativeSymbols( xSymbolsNative); } diff --git a/include/formula/FormulaCompiler.hxx b/include/formula/FormulaCompiler.hxx index 5544ff8786c0..36632035602e 100644 --- a/include/formula/FormulaCompiler.hxx +++ b/include/formula/FormulaCompiler.hxx @@ -203,6 +203,26 @@ public: */ OpCodeMapPtr GetOpCodeMap( const sal_Int32 nLanguage ) const; + /** Destroy the singleton OpCodeMap for formula language. + + This unconditionally destroys the underlying singleton instance of the + map to be reinitialized again later on the next GetOpCodeMap() call. + Use if the base class FormulaCompiler::GetOpCodeMap() was called and + created the map (i.e. HasOpCodeMap() before returned false) and later a + derived class like ScCompiler shall initialize it including AddIns. + + @param nLanguage + One of css::sheet::FormulaLanguage constants. + */ + void DestroyOpCodeMap( const sal_Int32 nLanguage ); + + /** Whether the singleton OpCodeMap for formula language exists already. + + @param nLanguage + One of css::sheet::FormulaLanguage constants. + */ + bool HasOpCodeMap( const sal_Int32 nLanguage ) const; + /** Create an internal symbol map from API mapping. @param bEnglish Use English number parser / formatter instead of native. @@ -370,14 +390,22 @@ protected: bool mbComputeII; // whether to attempt computing implicit intersection ranges while building the RPN array. bool mbMatrixFlag; // whether the formula is a matrix formula (needed for II computation) +public: + enum InitSymbols + { + ASK = 0, + INIT, + DESTROY + }; + private: - void InitSymbolsNative() const; /// only SymbolsNative, on first document creation - void InitSymbolsEnglish() const; /// only SymbolsEnglish, maybe later - void InitSymbolsPODF() const; /// only SymbolsPODF, on demand - void InitSymbolsAPI() const; /// only SymbolsAPI, on demand - void InitSymbolsODFF() const; /// only SymbolsODFF, on demand - void InitSymbolsEnglishXL() const; /// only SymbolsEnglishXL, on demand - void InitSymbolsOOXML() const; /// only SymbolsOOXML, on demand + bool InitSymbolsNative( InitSymbols ) const; /// only SymbolsNative, on first document creation + bool InitSymbolsEnglish( InitSymbols ) const; /// only SymbolsEnglish, maybe later + bool InitSymbolsPODF( InitSymbols ) const; /// only SymbolsPODF, on demand + bool InitSymbolsAPI( InitSymbols ) const; /// only SymbolsAPI, on demand + bool InitSymbolsODFF( InitSymbols ) const; /// only SymbolsODFF, on demand + bool InitSymbolsEnglishXL( InitSymbols ) const; /// only SymbolsEnglishXL, on demand + bool InitSymbolsOOXML( InitSymbols ) const; /// only SymbolsOOXML, on demand void loadSymbols(const std::pair<const char*, int>* pSymbols, FormulaGrammar::Grammar eGrammar, NonConstOpCodeMapPtr& rxMap, SeparatorType eSepType = SeparatorType::SEMICOLON_BASE) const; diff --git a/sc/inc/addincol.hxx b/sc/inc/addincol.hxx index 14af12006637..bb89f8d3c87a 100644 --- a/sc/inc/addincol.hxx +++ b/sc/inc/addincol.hxx @@ -87,6 +87,7 @@ private: OUString aLocalName; ///< for display OUString aUpperName; ///< for entering formulas OUString aUpperLocal; ///< for entering formulas + OUString aUpperEnglish; ///< for Function Wizard and tooltips OUString aDescription; css::uno::Reference< css::reflection::XIdlMethod> xFunction; css::uno::Any aObject; @@ -113,6 +114,7 @@ public: const OUString& GetLocalName() const { return aLocalName; } const OUString& GetUpperName() const { return aUpperName; } const OUString& GetUpperLocal() const { return aUpperLocal; } + const OUString& GetUpperEnglish() const { return aUpperEnglish; } const css::uno::Reference< css::reflection::XIdlMethod>& GetFunction() const { return xFunction; } const css::uno::Any& GetObject() const { return aObject; } @@ -132,6 +134,9 @@ public: void SetArguments( tools::Long nNewCount, const ScAddInArgDesc* pNewDescs ); void SetCallerPos( tools::Long nNewPos ); void SetCompNames( ::std::vector< LocalizedName >&& rNew ); + + /// Takes care of handling an empty name *after* upper local name was set. + void SetEnglishName( const OUString& rEnglishName ); }; class SC_DLLPUBLIC ScUnoAddInCollection @@ -175,9 +180,10 @@ public: void LocalizeString( OUString& rName ); ///< modify rName - input: exact name tools::Long GetFuncCount(); - bool FillFunctionDesc( tools::Long nFunc, ScFuncDesc& rDesc ); + bool FillFunctionDesc( tools::Long nFunc, ScFuncDesc& rDesc, bool bEnglishFunctionNames ); - static bool FillFunctionDescFromData( const ScUnoAddInFuncData& rFuncData, ScFuncDesc& rDesc ); + static bool FillFunctionDescFromData( const ScUnoAddInFuncData& rFuncData, ScFuncDesc& rDesc, + bool bEnglishFunctionNames ); /// leave rRetExcelName unchanged, if no matching name is found bool GetExcelName( const OUString& rCalcName, LanguageType eDestLang, OUString& rRetExcelName ); /// leave rRetCalcName unchanged, if no matching name is found diff --git a/sc/inc/compiler.hxx b/sc/inc/compiler.hxx index 0cd48fccc92e..5f6c521d11cf 100644 --- a/sc/inc/compiler.hxx +++ b/sc/inc/compiler.hxx @@ -257,6 +257,7 @@ public: private: + static osl::Mutex maMutex; static const CharClass *pCharClassEnglish; // character classification for en_US locale static const CharClass *pCharClassLocalized; // character classification for UI locale static const Convention *pConventions[ formula::FormulaGrammar::CONV_LAST ]; @@ -377,8 +378,9 @@ private: bool HasPossibleNamedRangeConflict(SCTAB nTab) const; - static const CharClass* GetCharClassEnglish(); static const CharClass* GetCharClassLocalized(); +public: + static const CharClass* GetCharClassEnglish(); public: ScCompiler( sc::CompileFormulaContext& rCxt, const ScAddress& rPos, diff --git a/sc/inc/funcdesc.hxx b/sc/inc/funcdesc.hxx index 58c6957316b3..0f37e924d941 100644 --- a/sc/inc/funcdesc.hxx +++ b/sc/inc/funcdesc.hxx @@ -241,7 +241,7 @@ public: class ScFunctionList { public: - ScFunctionList(); + explicit ScFunctionList( bool bEnglishFunctionNames ); ~ScFunctionList(); sal_uInt32 GetCount() const diff --git a/sc/source/core/data/funcdesc.cxx b/sc/source/core/data/funcdesc.cxx index dfbfd9a3a78e..c8045e6c1abf 100644 --- a/sc/source/core/data/funcdesc.cxx +++ b/sc/source/core/data/funcdesc.cxx @@ -397,7 +397,7 @@ bool ScFuncDesc::compareByName(const ScFuncDesc* a, const ScFuncDesc* b) #define ENTRY(CODE) CODE, SAL_N_ELEMENTS(CODE) -ScFunctionList::ScFunctionList() +ScFunctionList::ScFunctionList( bool bEnglishFunctionNames ) { sal_Int32 nMaxFuncNameLen = 0; // Length of longest function name @@ -958,7 +958,7 @@ ScFunctionList::ScFunctionList() pDesc = new ScFuncDesc; pDesc->nFIndex = nNextId++; - if ( pUnoAddIns->FillFunctionDesc( nFunc, *pDesc ) ) + if ( pUnoAddIns->FillFunctionDesc( nFunc, *pDesc, bEnglishFunctionNames ) ) { tmpFuncVector.push_back(pDesc); nStrLen = pDesc->mxFuncName->getLength(); diff --git a/sc/source/core/data/global.cxx b/sc/source/core/data/global.cxx index a338c0c76c31..46277a807db0 100644 --- a/sc/source/core/data/global.cxx +++ b/sc/source/core/data/global.cxx @@ -74,6 +74,7 @@ #include <editutil.hxx> #include <docsh.hxx> #include <sharedstringpoolpurge.hxx> +#include <formulaopt.hxx> tools::SvRef<ScDocShell> ScGlobal::xDrawClipDocShellRef; std::unique_ptr<SvxSearchItem> ScGlobal::xSearchItem; @@ -621,7 +622,7 @@ ScFunctionList* ScGlobal::GetStarCalcFunctionList() { assert(!bThreadedGroupCalcInProgress); if ( !xStarCalcFunctionList ) - xStarCalcFunctionList.reset(new ScFunctionList); + xStarCalcFunctionList.reset( new ScFunctionList( SC_MOD()->GetFormulaOptions().GetUseEnglishFuncName())); return xStarCalcFunctionList.get(); } diff --git a/sc/source/core/tool/addincol.cxx b/sc/source/core/tool/addincol.cxx index ea2184233f62..9027f0456ff4 100644 --- a/sc/source/core/tool/addincol.cxx +++ b/sc/source/core/tool/addincol.cxx @@ -59,6 +59,7 @@ #include <funcdesc.hxx> #include <svl/sharedstring.hxx> #include <formulaopt.hxx> +#include <compiler.hxx> #include <memory> using namespace com::sun::star; @@ -138,6 +139,19 @@ void ScUnoAddInFuncData::SetCompNames( ::std::vector< ScUnoAddInFuncData::Locali bCompInitialized = true; } +void ScUnoAddInFuncData::SetEnglishName( const OUString& rEnglishName ) +{ + if (!rEnglishName.isEmpty()) + aUpperEnglish = ScCompiler::GetCharClassEnglish()->uppercase(rEnglishName); + else + { + // A dumb fallback to not have an empty name, mainly just for the + // assignment to ScFuncDesc::mxFuncName for the Function Wizard and + // formula input tooltips. + aUpperEnglish = aUpperLocal; + } +} + bool ScUnoAddInFuncData::GetExcelName( const LanguageTag& rDestLang, OUString& rRetExcelName, bool bFallbackToAny ) const { const ::std::vector<LocalizedName>& rCompNames = GetCompNames(); @@ -544,9 +558,10 @@ void ScUnoAddInCollection::ReadConfiguration() else { pEnglishHashMap->emplace( - aEnglishName.toAsciiUpperCase(), + ScCompiler::GetCharClassEnglish()->uppercase(aEnglishName), pData ); } + pData->SetEnglishName(aEnglishName); // takes care of handling empty } } } @@ -720,12 +735,11 @@ void ScUnoAddInCollection::ReadFromAddIn( const uno::Reference<uno::XInterface>& if ( !(xAddIn.is() && xName.is()) ) return; - // fdo50118 when GetUseEnglishFunctionName() returns true, set the - // locale to en-US to get English function names - if ( SC_MOD()->GetFormulaOptions().GetUseEnglishFuncName() ) - xAddIn->setLocale( lang::Locale( "en", "US", "")); - else - xAddIn->setLocale( Application::GetSettings().GetUILanguageTag().getLocale()); + // Even if GetUseEnglishFunctionName() would return true, do not set the + // locale to en-US to get English function names as that also would mix in + // English descriptions and parameter names. English function names are now + // handled below. + xAddIn->setLocale( Application::GetSettings().GetUILanguageTag().getLocale()); OUString aServiceName( xName->getServiceName() ); ScUnoAddInHelpIdGenerator aHelpIdGenerator( aServiceName ); @@ -919,8 +933,7 @@ void ScUnoAddInCollection::ReadFromAddIn( const uno::Reference<uno::XInterface>& xFunc, aObject, nVisibleCount, pVisibleArgs.get(), nCallerPos ) ); - const ScUnoAddInFuncData* pData = - ppFuncData[nFuncPos+nOld].get(); + ScUnoAddInFuncData* pData = ppFuncData[nFuncPos+nOld].get(); pExactHashMap->emplace( pData->GetOriginalName(), pData ); @@ -937,18 +950,21 @@ void ScUnoAddInCollection::ReadFromAddIn( const uno::Reference<uno::XInterface>& else { pEnglishHashMap->emplace( - aEnglishName.toAsciiUpperCase(), + ScCompiler::GetCharClassEnglish()->uppercase(aEnglishName), pData ); } + pData->SetEnglishName(aEnglishName); // takes care of handling empty } } } } } -static void lcl_UpdateFunctionList( const ScFunctionList& rFunctionList, const ScUnoAddInFuncData& rFuncData ) +static void lcl_UpdateFunctionList( const ScFunctionList& rFunctionList, const ScUnoAddInFuncData& rFuncData, + bool bEnglishFunctionNames ) { - const OUString& aCompare = rFuncData.GetUpperLocal(); // as used in FillFunctionDescFromData + // as used in FillFunctionDescFromData + const OUString& aCompare = (bEnglishFunctionNames ? rFuncData.GetUpperEnglish() : rFuncData.GetUpperLocal()); sal_uLong nCount = rFunctionList.GetCount(); for (sal_uLong nPos=0; nPos<nCount; nPos++) @@ -956,7 +972,8 @@ static void lcl_UpdateFunctionList( const ScFunctionList& rFunctionList, const S const ScFuncDesc* pDesc = rFunctionList.GetFunction( nPos ); if ( pDesc && pDesc->mxFuncName && *pDesc->mxFuncName == aCompare ) { - ScUnoAddInCollection::FillFunctionDescFromData( rFuncData, *const_cast<ScFuncDesc*>(pDesc) ); + ScUnoAddInCollection::FillFunctionDescFromData( rFuncData, *const_cast<ScFuncDesc*>(pDesc), + bEnglishFunctionNames); break; } } @@ -977,16 +994,10 @@ static const ScAddInArgDesc* lcl_FindArgDesc( const ScUnoAddInFuncData& rFuncDat void ScUnoAddInCollection::UpdateFromAddIn( const uno::Reference<uno::XInterface>& xInterface, std::u16string_view rServiceName ) { + const bool bEnglishFunctionNames = SC_MOD()->GetFormulaOptions().GetUseEnglishFuncName(); uno::Reference<lang::XLocalizable> xLoc( xInterface, uno::UNO_QUERY ); if ( xLoc.is() ) // optional in new add-ins - { - // fdo50118 when GetUseEnglishFunctionName() returns true, set the - // locale to en-US to get English function names - if ( SC_MOD()->GetFormulaOptions().GetUseEnglishFuncName() ) - xLoc->setLocale( lang::Locale( "en", "US", "")); - else - xLoc->setLocale( Application::GetSettings().GetUILanguageTag().getLocale()); - } + xLoc->setLocale( Application::GetSettings().GetUILanguageTag().getLocale()); // if function list was already initialized, it must be updated @@ -1092,7 +1103,7 @@ void ScUnoAddInCollection::UpdateFromAddIn( const uno::Reference<uno::XInterface pOldData->SetCallerPos( nCallerPos ); if ( pFunctionList ) - lcl_UpdateFunctionList( *pFunctionList, *pOldData ); + lcl_UpdateFunctionList( *pFunctionList, *pOldData, bEnglishFunctionNames ); } } } @@ -1193,7 +1204,7 @@ tools::Long ScUnoAddInCollection::GetFuncCount() return nFuncCount; } -bool ScUnoAddInCollection::FillFunctionDesc( tools::Long nFunc, ScFuncDesc& rDesc ) +bool ScUnoAddInCollection::FillFunctionDesc( tools::Long nFunc, ScFuncDesc& rDesc, bool bEnglishFunctionNames ) { if (!bInitialized) Initialize(); @@ -1203,10 +1214,11 @@ bool ScUnoAddInCollection::FillFunctionDesc( tools::Long nFunc, ScFuncDesc& rDes const ScUnoAddInFuncData& rFuncData = *ppFuncData[nFunc]; - return FillFunctionDescFromData( rFuncData, rDesc ); + return FillFunctionDescFromData( rFuncData, rDesc, bEnglishFunctionNames ); } -bool ScUnoAddInCollection::FillFunctionDescFromData( const ScUnoAddInFuncData& rFuncData, ScFuncDesc& rDesc ) +bool ScUnoAddInCollection::FillFunctionDescFromData( const ScUnoAddInFuncData& rFuncData, ScFuncDesc& rDesc, + bool bEnglishFunctionNames ) { rDesc.Clear(); @@ -1221,7 +1233,7 @@ bool ScUnoAddInCollection::FillFunctionDescFromData( const ScUnoAddInFuncData& r // nFIndex is set from outside - rDesc.mxFuncName = rFuncData.GetUpperLocal(); //TODO: upper? + rDesc.mxFuncName = (bEnglishFunctionNames ? rFuncData.GetUpperEnglish() : rFuncData.GetUpperLocal()); rDesc.nCategory = rFuncData.GetCategory(); rDesc.sHelpId = rFuncData.GetHelpId(); diff --git a/sc/source/core/tool/calcconfig.cxx b/sc/source/core/tool/calcconfig.cxx index f1673e0ebe68..27836704dab9 100644 --- a/sc/source/core/tool/calcconfig.cxx +++ b/sc/source/core/tool/calcconfig.cxx @@ -187,7 +187,11 @@ bool ScCalcConfig::operator!= (const ScCalcConfig& r) const OUString ScOpCodeSetToSymbolicString(const ScCalcConfig::OpCodeSet& rOpCodes) { OUStringBuffer result(256); + // If GetOpCodeMap() initializes the map at base class + // formula::FormulaCompiler before any ScCompiler did, all AddIn mapping + // would be missing also in future. So if it didn't exist destroy it again. formula::FormulaCompiler aCompiler; + const bool bTemporary = !aCompiler.HasOpCodeMap(css::sheet::FormulaLanguage::ENGLISH); formula::FormulaCompiler::OpCodeMapPtr pOpCodeMap(aCompiler.GetOpCodeMap(css::sheet::FormulaLanguage::ENGLISH)); for (auto i = rOpCodes->begin(); i != rOpCodes->end(); ++i) @@ -197,13 +201,18 @@ OUString ScOpCodeSetToSymbolicString(const ScCalcConfig::OpCodeSet& rOpCodes) result.append(pOpCodeMap->getSymbol(*i)); } + if (bTemporary) + aCompiler.DestroyOpCodeMap(css::sheet::FormulaLanguage::ENGLISH); + return result.makeStringAndClear(); } ScCalcConfig::OpCodeSet ScStringToOpCodeSet(std::u16string_view rOpCodes) { ScCalcConfig::OpCodeSet result = std::make_shared<o3tl::sorted_vector< OpCode >>(); + // Same as above. formula::FormulaCompiler aCompiler; + const bool bTemporary = !aCompiler.HasOpCodeMap(css::sheet::FormulaLanguage::ENGLISH); formula::FormulaCompiler::OpCodeMapPtr pOpCodeMap(aCompiler.GetOpCodeMap(css::sheet::FormulaLanguage::ENGLISH)); const formula::OpCodeHashMap& rHashMap(pOpCodeMap->getHashMap()); @@ -234,6 +243,10 @@ ScCalcConfig::OpCodeSet ScStringToOpCodeSet(std::u16string_view rOpCodes) // HACK: Both unary and binary minus have the same string but different opcodes. if( result->find( ocSub ) != result->end()) result->insert( ocNegSub ); + + if (bTemporary) + aCompiler.DestroyOpCodeMap(css::sheet::FormulaLanguage::ENGLISH); + return result; } diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx index d7b628615d63..b6784f861f71 100644 --- a/sc/source/core/tool/compiler.cxx +++ b/sc/source/core/tool/compiler.cxx @@ -77,6 +77,7 @@ using namespace formula; using namespace ::com::sun::star; using ::std::vector; +osl::Mutex ScCompiler::maMutex; const CharClass* ScCompiler::pCharClassEnglish = nullptr; const CharClass* ScCompiler::pCharClassLocalized = nullptr; const ScCompiler::Convention* ScCompiler::pConventions[ ] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; @@ -225,9 +226,12 @@ const CharClass* ScCompiler::GetCharClassEnglish() { if (!pCharClassEnglish) { - css::lang::Locale aLocale( "en", "US", ""); - pCharClassEnglish = new CharClass( - ::comphelper::getProcessComponentContext(), LanguageTag( aLocale)); + osl::MutexGuard aGuard(maMutex); + if (!pCharClassEnglish) + { + pCharClassEnglish = new CharClass( ::comphelper::getProcessComponentContext(), + LanguageTag( LANGUAGE_ENGLISH_US)); + } } return pCharClassEnglish; } diff --git a/sc/source/ui/docshell/docsh6.cxx b/sc/source/ui/docshell/docsh6.cxx index 738c85110967..caefdfc0fed3 100644 --- a/sc/source/ui/docshell/docsh6.cxx +++ b/sc/source/ui/docshell/docsh6.cxx @@ -445,7 +445,8 @@ void ScDocShell::SetFormulaOptions( const ScFormulaOptions& rOpt, bool bForLoadi if (rOpt.GetUseEnglishFuncName()) { // switch native symbols to English. - formula::FormulaCompiler aComp; + ScAddress aAddress; + ScCompiler aComp( *m_pDocument, aAddress); ScCompiler::OpCodeMapPtr xMap = aComp.GetOpCodeMap(css::sheet::FormulaLanguage::ENGLISH); ScCompiler::SetNativeSymbols(xMap); }
