1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <com/sun/star/uno/Sequence.hxx>
11 #include <com/sun/star/lang/Locale.hpp>
12 #include <osl/diagnose.h>
13 #include <sal/log.hxx>
14 #include <unotools/localedatawrapper.hxx>
15 #include <formulaopt.hxx>
17 #include <formulagroup.hxx>
22 using namespace com::sun::star::uno
;
23 namespace lang
= ::com::sun::star::lang
;
26 ScFormulaOptions::ScFormulaOptions()
31 void ScFormulaOptions::SetDefaults()
33 bUseEnglishFuncName
= false;
34 eFormulaGrammar
= ::formula::FormulaGrammar::GRAM_NATIVE
;
35 mbWriteCalcConfig
= true;
36 meOOXMLRecalc
= RECALC_ASK
;
37 meODFRecalc
= RECALC_ASK
;
38 meReCalcOptiRowHeights
= RECALC_ASK
;
40 // unspecified means use the current formula syntax.
43 ResetFormulaSeparators();
46 void ScFormulaOptions::ResetFormulaSeparators()
48 GetDefaultFormulaSeparators(aFormulaSepArg
, aFormulaSepArrayCol
, aFormulaSepArrayRow
);
51 void ScFormulaOptions::GetDefaultFormulaSeparators(
52 OUString
& rSepArg
, OUString
& rSepArrayCol
, OUString
& rSepArrayRow
)
54 // Defaults to the old separator values.
59 const lang::Locale
& rLocale
= ScGlobal::GetLocale();
60 const OUString
& rLang
= rLocale
.Language
;
62 // Don't do automatic guess for these languages, and fall back to
63 // the old separator set.
66 const LocaleDataWrapper
& rLocaleData
= ScGlobal::getLocaleData();
67 const OUString
& rDecSep
= rLocaleData
.getNumDecimalSep();
68 const OUString
& rListSep
= rLocaleData
.getListSep();
70 if (rDecSep
.isEmpty() || rListSep
.isEmpty())
71 // Something is wrong. Stick with the default separators.
74 sal_Unicode cDecSep
= rDecSep
[0];
75 sal_Unicode cListSep
= rListSep
[0];
76 sal_Unicode cDecSepAlt
= rLocaleData
.getNumDecimalSepAlt().toChar(); // usually 0 (empty)
78 // Excel by default uses system's list separator as the parameter
79 // separator, which in English locales is a comma. However, OOo's list
80 // separator value is set to ';' for all English locales. Because of this
81 // discrepancy, we will hardcode the separator value here, for now.
82 // Similar for decimal separator alternative.
83 // However, if the decimal separator alternative is '.' and the decimal
84 // separator is ',' this makes no sense, fall back to ';' in that case.
85 if (cDecSep
== '.' || (cDecSepAlt
== '.' && cDecSep
!= ','))
87 else if (cDecSep
== ',' && cDecSepAlt
== '.')
90 // Special case for de_CH locale.
91 if (rLocale
.Language
== "de" && rLocale
.Country
== "CH")
94 // by default, the parameter separator equals the locale-specific
96 rSepArg
= OUString(cListSep
);
98 if (cDecSep
== cListSep
&& cDecSep
!= ';')
99 // if the decimal and list separators are equal, set the
100 // parameter separator to be ';', unless they are both
101 // semicolon in which case don't change the decimal separator.
110 bool ScFormulaOptions::operator==( const ScFormulaOptions
& rOpt
) const
112 return bUseEnglishFuncName
== rOpt
.bUseEnglishFuncName
113 && eFormulaGrammar
== rOpt
.eFormulaGrammar
114 && aCalcConfig
== rOpt
.aCalcConfig
115 && mbWriteCalcConfig
== rOpt
.mbWriteCalcConfig
116 && aFormulaSepArg
== rOpt
.aFormulaSepArg
117 && aFormulaSepArrayRow
== rOpt
.aFormulaSepArrayRow
118 && aFormulaSepArrayCol
== rOpt
.aFormulaSepArrayCol
119 && meOOXMLRecalc
== rOpt
.meOOXMLRecalc
120 && meODFRecalc
== rOpt
.meODFRecalc
121 && meReCalcOptiRowHeights
== rOpt
.meReCalcOptiRowHeights
;
124 bool ScFormulaOptions::operator!=( const ScFormulaOptions
& rOpt
) const
126 return !(operator==(rOpt
));
129 ScTpFormulaItem::ScTpFormulaItem( ScFormulaOptions aOpt
) :
130 SfxPoolItem ( SID_SCFORMULAOPTIONS
, SfxItemType::ScTpFormulaItemType
),
131 theOptions (std::move( aOpt
))
135 ScTpFormulaItem::~ScTpFormulaItem()
139 bool ScTpFormulaItem::operator==( const SfxPoolItem
& rItem
) const
141 assert(SfxPoolItem::operator==(rItem
));
143 const ScTpFormulaItem
& rPItem
= static_cast<const ScTpFormulaItem
&>(rItem
);
144 return ( theOptions
== rPItem
.theOptions
);
147 ScTpFormulaItem
* ScTpFormulaItem::Clone( SfxItemPool
* ) const
149 return new ScTpFormulaItem( *this );
152 constexpr OUStringLiteral CFGPATH_FORMULA
= u
"Office.Calc/Formula";
154 #define SCFORMULAOPT_GRAMMAR 0
155 #define SCFORMULAOPT_ENGLISH_FUNCNAME 1
156 #define SCFORMULAOPT_SEP_ARG 2
157 #define SCFORMULAOPT_SEP_ARRAY_ROW 3
158 #define SCFORMULAOPT_SEP_ARRAY_COL 4
159 #define SCFORMULAOPT_STRING_REF_SYNTAX 5
160 #define SCFORMULAOPT_STRING_CONVERSION 6
161 #define SCFORMULAOPT_EMPTY_OUSTRING_AS_ZERO 7
162 #define SCFORMULAOPT_OOXML_RECALC 8
163 #define SCFORMULAOPT_ODF_RECALC 9
164 #define SCFORMULAOPT_ROW_HEIGHT_RECALC 10
165 #define SCFORMULAOPT_OPENCL_AUTOSELECT 11
166 #define SCFORMULAOPT_OPENCL_DEVICE 12
167 #define SCFORMULAOPT_OPENCL_SUBSET_ONLY 13
168 #define SCFORMULAOPT_OPENCL_MIN_SIZE 14
169 #define SCFORMULAOPT_OPENCL_SUBSET_OPS 15
171 Sequence
<OUString
> ScFormulaCfg::GetPropertyNames()
173 return {u
"Syntax/Grammar"_ustr
, // SCFORMULAOPT_GRAMMAR
174 u
"Syntax/EnglishFunctionName"_ustr
, // SCFORMULAOPT_ENGLISH_FUNCNAME
175 u
"Syntax/SeparatorArg"_ustr
, // SCFORMULAOPT_SEP_ARG
176 u
"Syntax/SeparatorArrayRow"_ustr
, // SCFORMULAOPT_SEP_ARRAY_ROW
177 u
"Syntax/SeparatorArrayCol"_ustr
, // SCFORMULAOPT_SEP_ARRAY_COL
178 u
"Syntax/StringRefAddressSyntax"_ustr
, // SCFORMULAOPT_STRING_REF_SYNTAX
179 u
"Syntax/StringConversion"_ustr
, // SCFORMULAOPT_STRING_CONVERSION
180 u
"Syntax/EmptyStringAsZero"_ustr
, // SCFORMULAOPT_EMPTY_OUSTRING_AS_ZERO
181 u
"Load/OOXMLRecalcMode"_ustr
, // SCFORMULAOPT_OOXML_RECALC
182 u
"Load/ODFRecalcMode"_ustr
, // SCFORMULAOPT_ODF_RECALC
183 u
"Load/RecalcOptimalRowHeightMode"_ustr
, // SCFORMULAOPT_ROW_HEIGHT_RECALC
184 u
"Calculation/OpenCLAutoSelect"_ustr
, // SCFORMULAOPT_OPENCL_AUTOSELECT
185 u
"Calculation/OpenCLDevice"_ustr
, // SCFORMULAOPT_OPENCL_DEVICE
186 u
"Calculation/OpenCLSubsetOnly"_ustr
, // SCFORMULAOPT_OPENCL_SUBSET_ONLY
187 u
"Calculation/OpenCLMinimumDataSize"_ustr
, // SCFORMULAOPT_OPENCL_MIN_SIZE
188 u
"Calculation/OpenCLSubsetOpCodes"_ustr
}; // SCFORMULAOPT_OPENCL_SUBSET_OPS
191 ScFormulaCfg::PropsToIds
ScFormulaCfg::GetPropNamesToId()
193 Sequence
<OUString
> aPropNames
= GetPropertyNames();
194 static sal_uInt16 aVals
[] = {
195 SCFORMULAOPT_GRAMMAR
,
196 SCFORMULAOPT_ENGLISH_FUNCNAME
,
197 SCFORMULAOPT_SEP_ARG
,
198 SCFORMULAOPT_SEP_ARRAY_ROW
,
199 SCFORMULAOPT_SEP_ARRAY_COL
,
200 SCFORMULAOPT_STRING_REF_SYNTAX
,
201 SCFORMULAOPT_STRING_CONVERSION
,
202 SCFORMULAOPT_EMPTY_OUSTRING_AS_ZERO
,
203 SCFORMULAOPT_OOXML_RECALC
,
204 SCFORMULAOPT_ODF_RECALC
,
205 SCFORMULAOPT_ROW_HEIGHT_RECALC
,
206 SCFORMULAOPT_OPENCL_AUTOSELECT
,
207 SCFORMULAOPT_OPENCL_DEVICE
,
208 SCFORMULAOPT_OPENCL_SUBSET_ONLY
,
209 SCFORMULAOPT_OPENCL_MIN_SIZE
,
210 SCFORMULAOPT_OPENCL_SUBSET_OPS
,
212 OSL_ENSURE( SAL_N_ELEMENTS(aVals
) == aPropNames
.getLength(), "Properties and ids are out of Sync");
213 PropsToIds aPropIdMap
;
214 for ( sal_Int32 i
=0; i
<aPropNames
.getLength(); ++i
)
215 aPropIdMap
[aPropNames
[i
]] = aVals
[ i
];
219 ScFormulaCfg::ScFormulaCfg() :
220 ConfigItem( CFGPATH_FORMULA
)
222 Sequence
<OUString
> aNames
= GetPropertyNames();
223 UpdateFromProperties( aNames
);
224 EnableNotification( aNames
);
227 void ScFormulaCfg::UpdateFromProperties( const Sequence
<OUString
>& aNames
)
229 Sequence
<Any
> aValues
= GetProperties(aNames
);
230 const Any
* pValues
= aValues
.getConstArray();
231 OSL_ENSURE(aValues
.getLength() == aNames
.getLength(), "GetProperties failed");
232 PropsToIds aPropMap
= GetPropNamesToId();
233 if(aValues
.getLength() != aNames
.getLength())
236 sal_Int32 nIntVal
= 0;
237 for(int nProp
= 0; nProp
< aNames
.getLength(); nProp
++)
239 PropsToIds::iterator it_end
= aPropMap
.end();
240 PropsToIds::iterator it
= aPropMap
.find( aNames
[nProp
] );
241 if(pValues
[nProp
].hasValue() && it
!= it_end
)
245 case SCFORMULAOPT_GRAMMAR
:
247 // Get default value in case this option is not set.
248 ::formula::FormulaGrammar::Grammar eGram
= GetFormulaSyntax();
252 if (!(pValues
[nProp
] >>= nIntVal
))
253 // extracting failed.
259 eGram
= ::formula::FormulaGrammar::GRAM_NATIVE
;
262 eGram
= ::formula::FormulaGrammar::GRAM_NATIVE_XL_A1
;
264 case 2: // Excel R1C1
265 eGram
= ::formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1
;
272 SetFormulaSyntax(eGram
);
275 case SCFORMULAOPT_ENGLISH_FUNCNAME
:
277 bool bEnglish
= false;
278 if (pValues
[nProp
] >>= bEnglish
)
279 SetUseEnglishFuncName(bEnglish
);
282 case SCFORMULAOPT_SEP_ARG
:
285 if ((pValues
[nProp
] >>= aSep
) && !aSep
.isEmpty())
286 SetFormulaSepArg(aSep
);
289 case SCFORMULAOPT_SEP_ARRAY_ROW
:
292 if ((pValues
[nProp
] >>= aSep
) && !aSep
.isEmpty())
293 SetFormulaSepArrayRow(aSep
);
296 case SCFORMULAOPT_SEP_ARRAY_COL
:
299 if ((pValues
[nProp
] >>= aSep
) && !aSep
.isEmpty())
300 SetFormulaSepArrayCol(aSep
);
303 case SCFORMULAOPT_STRING_REF_SYNTAX
:
305 // Get default value in case this option is not set.
306 ::formula::FormulaGrammar::AddressConvention eConv
= GetCalcConfig().meStringRefAddressSyntax
;
310 if (!(pValues
[nProp
] >>= nIntVal
))
311 // extraction failed.
316 case -1: // Same as the formula grammar.
317 eConv
= formula::FormulaGrammar::CONV_UNSPECIFIED
;
320 eConv
= formula::FormulaGrammar::CONV_OOO
;
323 eConv
= formula::FormulaGrammar::CONV_XL_A1
;
325 case 2: // Excel R1C1
326 eConv
= formula::FormulaGrammar::CONV_XL_R1C1
;
328 case 3: // Calc A1 | Excel A1
329 eConv
= formula::FormulaGrammar::CONV_A1_XL_A1
;
336 GetCalcConfig().meStringRefAddressSyntax
= eConv
;
339 case SCFORMULAOPT_STRING_CONVERSION
:
341 // Get default value in case this option is not set.
342 ScCalcConfig::StringConversion eConv
= GetCalcConfig().meStringConversion
;
346 if (!(pValues
[nProp
] >>= nIntVal
))
347 // extraction failed.
353 eConv
= ScCalcConfig::StringConversion::ILLEGAL
;
356 eConv
= ScCalcConfig::StringConversion::ZERO
;
359 eConv
= ScCalcConfig::StringConversion::UNAMBIGUOUS
;
362 eConv
= ScCalcConfig::StringConversion::LOCALE
;
365 SAL_WARN("sc", "unknown string conversion option!");
369 GetCalcConfig().meStringConversion
= eConv
;
372 case SCFORMULAOPT_EMPTY_OUSTRING_AS_ZERO
:
374 bool bVal
= GetCalcConfig().mbEmptyStringAsZero
;
375 pValues
[nProp
] >>= bVal
;
376 GetCalcConfig().mbEmptyStringAsZero
= bVal
;
379 case SCFORMULAOPT_OOXML_RECALC
:
381 ScRecalcOptions eOpt
= RECALC_ASK
;
382 if (pValues
[nProp
] >>= nIntVal
)
387 eOpt
= RECALC_ALWAYS
;
396 SAL_WARN("sc", "unknown ooxml recalc option!");
400 SetOOXMLRecalcOptions(eOpt
);
403 case SCFORMULAOPT_ODF_RECALC
:
405 ScRecalcOptions eOpt
= RECALC_ASK
;
406 if (pValues
[nProp
] >>= nIntVal
)
411 eOpt
= RECALC_ALWAYS
;
420 SAL_WARN("sc", "unknown odf recalc option!");
424 SetODFRecalcOptions(eOpt
);
427 case SCFORMULAOPT_ROW_HEIGHT_RECALC
:
429 ScRecalcOptions eOpt
= RECALC_ASK
;
430 if (pValues
[nProp
] >>= nIntVal
)
435 eOpt
= RECALC_ALWAYS
;
444 SAL_WARN("sc", "unknown optimal row height recalc option!");
448 SetReCalcOptiRowHeights(eOpt
);
451 case SCFORMULAOPT_OPENCL_AUTOSELECT
:
453 bool bVal
= GetCalcConfig().mbOpenCLAutoSelect
;
454 pValues
[nProp
] >>= bVal
;
455 GetCalcConfig().mbOpenCLAutoSelect
= bVal
;
458 case SCFORMULAOPT_OPENCL_DEVICE
:
460 OUString aOpenCLDevice
= GetCalcConfig().maOpenCLDevice
;
461 pValues
[nProp
] >>= aOpenCLDevice
;
462 GetCalcConfig().maOpenCLDevice
= aOpenCLDevice
;
465 case SCFORMULAOPT_OPENCL_SUBSET_ONLY
:
467 bool bVal
= GetCalcConfig().mbOpenCLSubsetOnly
;
468 pValues
[nProp
] >>= bVal
;
469 GetCalcConfig().mbOpenCLSubsetOnly
= bVal
;
472 case SCFORMULAOPT_OPENCL_MIN_SIZE
:
474 sal_Int32 nVal
= GetCalcConfig().mnOpenCLMinimumFormulaGroupSize
;
475 pValues
[nProp
] >>= nVal
;
476 GetCalcConfig().mnOpenCLMinimumFormulaGroupSize
= nVal
;
479 case SCFORMULAOPT_OPENCL_SUBSET_OPS
:
481 OUString sVal
= ScOpCodeSetToSymbolicString(GetCalcConfig().mpOpenCLSubsetOpCodes
);
482 pValues
[nProp
] >>= sVal
;
483 GetCalcConfig().mpOpenCLSubsetOpCodes
= ScStringToOpCodeSet(sVal
);
491 void ScFormulaCfg::ImplCommit()
493 Sequence
<OUString
> aNames
= GetPropertyNames();
494 Sequence
<Any
> aValues(aNames
.getLength());
495 Any
* pValues
= aValues
.getArray();
497 Sequence
<Any
> aOldValues
= GetProperties(aNames
);
498 Any
* pOldValues
= aOldValues
.getArray();
500 bool bSetOpenCL
= false;
502 for (int nProp
= 0; nProp
< aNames
.getLength(); ++nProp
)
506 case SCFORMULAOPT_GRAMMAR
:
509 switch (GetFormulaSyntax())
511 case ::formula::FormulaGrammar::GRAM_NATIVE_XL_A1
: nVal
= 1; break;
512 case ::formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1
: nVal
= 2; break;
515 pValues
[nProp
] <<= nVal
;
518 case SCFORMULAOPT_ENGLISH_FUNCNAME
:
520 bool b
= GetUseEnglishFuncName();
521 pValues
[nProp
] <<= b
;
524 case SCFORMULAOPT_SEP_ARG
:
525 pValues
[nProp
] <<= GetFormulaSepArg();
527 case SCFORMULAOPT_SEP_ARRAY_ROW
:
528 pValues
[nProp
] <<= GetFormulaSepArrayRow();
530 case SCFORMULAOPT_SEP_ARRAY_COL
:
531 pValues
[nProp
] <<= GetFormulaSepArrayCol();
533 case SCFORMULAOPT_STRING_REF_SYNTAX
:
537 if (GetWriteCalcConfig())
539 switch (GetCalcConfig().meStringRefAddressSyntax
)
541 case ::formula::FormulaGrammar::CONV_OOO
: nVal
= 0; break;
542 case ::formula::FormulaGrammar::CONV_XL_A1
: nVal
= 1; break;
543 case ::formula::FormulaGrammar::CONV_XL_R1C1
: nVal
= 2; break;
544 case ::formula::FormulaGrammar::CONV_A1_XL_A1
: nVal
= 3; break;
547 pValues
[nProp
] <<= nVal
;
551 pValues
[nProp
] = pOldValues
[nProp
];
555 case SCFORMULAOPT_STRING_CONVERSION
:
557 if (GetWriteCalcConfig())
561 switch (GetCalcConfig().meStringConversion
)
563 case ScCalcConfig::StringConversion::ILLEGAL
: nVal
= 0; break;
564 case ScCalcConfig::StringConversion::ZERO
: nVal
= 1; break;
565 case ScCalcConfig::StringConversion::UNAMBIGUOUS
: nVal
= 2; break;
566 case ScCalcConfig::StringConversion::LOCALE
: nVal
= 3; break;
568 pValues
[nProp
] <<= nVal
;
572 pValues
[nProp
] = pOldValues
[nProp
];
576 case SCFORMULAOPT_EMPTY_OUSTRING_AS_ZERO
:
578 if (GetWriteCalcConfig())
580 bool bVal
= GetCalcConfig().mbEmptyStringAsZero
;
581 pValues
[nProp
] <<= bVal
;
585 pValues
[nProp
] = pOldValues
[nProp
];
589 case SCFORMULAOPT_OOXML_RECALC
:
592 switch (GetOOXMLRecalcOptions())
605 pValues
[nProp
] <<= nVal
;
608 case SCFORMULAOPT_ODF_RECALC
:
611 switch (GetODFRecalcOptions())
624 pValues
[nProp
] <<= nVal
;
627 case SCFORMULAOPT_ROW_HEIGHT_RECALC
:
630 switch (GetReCalcOptiRowHeights())
642 SAL_WARN("sc", "unknown optimal row height recalc option!");
645 pValues
[nProp
] <<= nVal
;
648 case SCFORMULAOPT_OPENCL_AUTOSELECT
:
650 bool bVal
= GetCalcConfig().mbOpenCLAutoSelect
;
651 pValues
[nProp
] <<= bVal
;
655 case SCFORMULAOPT_OPENCL_DEVICE
:
657 OUString aOpenCLDevice
= GetCalcConfig().maOpenCLDevice
;
658 pValues
[nProp
] <<= aOpenCLDevice
;
662 case SCFORMULAOPT_OPENCL_SUBSET_ONLY
:
664 bool bVal
= GetCalcConfig().mbOpenCLSubsetOnly
;
665 pValues
[nProp
] <<= bVal
;
668 case SCFORMULAOPT_OPENCL_MIN_SIZE
:
670 sal_Int32 nVal
= GetCalcConfig().mnOpenCLMinimumFormulaGroupSize
;
671 pValues
[nProp
] <<= nVal
;
674 case SCFORMULAOPT_OPENCL_SUBSET_OPS
:
676 OUString sVal
= ScOpCodeSetToSymbolicString(GetCalcConfig().mpOpenCLSubsetOpCodes
);
677 pValues
[nProp
] <<= sVal
;
682 #if !HAVE_FEATURE_OPENCL
686 sc::FormulaGroupInterpreter::switchOpenCLDevice(
687 GetCalcConfig().maOpenCLDevice
, GetCalcConfig().mbOpenCLAutoSelect
);
689 PutProperties(aNames
, aValues
);
692 void ScFormulaCfg::SetOptions( const ScFormulaOptions
& rNew
)
694 *static_cast<ScFormulaOptions
*>(this) = rNew
;
698 void ScFormulaCfg::Notify( const css::uno::Sequence
< OUString
>& rNames
)
700 UpdateFromProperties( rNames
);
703 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */