[Libreoffice-commits] core.git: 3 commits - sc/inc sc/qa sc/source sc/uiconfig

Eike Rathke erack at redhat.com
Fri Mar 14 05:30:48 PDT 2014


 sc/inc/calcconfig.hxx                             |   10 +
 sc/qa/unit/ucalc.cxx                              |   77 +++++++++
 sc/source/core/tool/calcconfig.cxx                |    2 
 sc/source/core/tool/formulaopt.cxx                |   66 +++++++-
 sc/source/core/tool/interpr4.cxx                  |   99 ++++++++----
 sc/source/ui/optdlg/calcoptionsdlg.cxx            |  174 ++++++++++++++++++++--
 sc/source/ui/optdlg/calcoptionsdlg.hxx            |   11 +
 sc/uiconfig/scalc/ui/formulacalculationoptions.ui |  104 +++++++++++--
 8 files changed, 469 insertions(+), 74 deletions(-)

New commits:
commit af88ab2ee9167279cb70a577fb399d23f2ce136f
Author: Eike Rathke <erack at redhat.com>
Date:   Fri Mar 14 13:27:22 2014 +0100

    unit test for string conversion feature, related fdo#37132 fdo#74622
    
    Change-Id: If7d9c032d6025a6c6bf850e338923296ba2590dd

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index c903f4f..68713df 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -1661,12 +1661,14 @@ void Test::testFuncParam()
     m_pDoc->SetString(0, 0, 0, OUString("=\"\"+3"));    // empty string
     m_pDoc->SetString(0, 1, 0, OUString("=\" \"+3"));   // only blank
     m_pDoc->SetString(0, 2, 0, OUString("=\" 4 \"+3")); // number in blanks
-    m_pDoc->SetString(0, 3, 0, OUString("=\" x \"+3")); // non-numeric => #VALUE! error
+    m_pDoc->SetString(0, 3, 0, OUString("=\" x \"+3")); // non-numeric
+    m_pDoc->SetString(0, 4, 0, OUString("=\"4.4\"+3")); // locale dependent
 
     OUString aVal;
     ScCalcConfig aConfig;
 
-    // With "Empty string as zero" option.
+    // With "Convert also locale dependent" and "Empty string as zero"=True option.
+    aConfig.meStringConversion = ScCalcConfig::STRING_CONVERSION_LOCALE_DEPENDENT;
     aConfig.mbEmptyStringAsZero = true;
     ScInterpreter::SetGlobalConfig(aConfig);
     m_pDoc->CalcAll();
@@ -1678,8 +1680,11 @@ void Test::testFuncParam()
     CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7);
     aVal = m_pDoc->GetString( 0, 3, 0);
     CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
+    m_pDoc->GetValue(0, 4, 0, val);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7.4);
 
-    // Without "Empty string as zero" option.
+    // With "Convert also locale dependent" and "Empty string as zero"=False option.
+    aConfig.meStringConversion = ScCalcConfig::STRING_CONVERSION_LOCALE_DEPENDENT;
     aConfig.mbEmptyStringAsZero = false;
     ScInterpreter::SetGlobalConfig(aConfig);
     m_pDoc->CalcAll();
@@ -1691,6 +1696,72 @@ void Test::testFuncParam()
     CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7);
     aVal = m_pDoc->GetString( 0, 3, 0);
     CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
+    m_pDoc->GetValue(0, 4, 0, val);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7.4);
+
+    // With "Convert only unambiguous" and "Empty string as zero"=True option.
+    aConfig.meStringConversion = ScCalcConfig::STRING_CONVERSION_UNAMBIGUOUS;
+    aConfig.mbEmptyStringAsZero = true;
+    ScInterpreter::SetGlobalConfig(aConfig);
+    m_pDoc->CalcAll();
+    m_pDoc->GetValue(0, 0, 0, val);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
+    m_pDoc->GetValue(0, 1, 0, val);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
+    m_pDoc->GetValue(0, 2, 0, val);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7);
+    aVal = m_pDoc->GetString( 0, 3, 0);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
+    aVal = m_pDoc->GetString( 0, 4, 0);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
+
+    // With "Convert only unambiguous" and "Empty string as zero"=False option.
+    aConfig.meStringConversion = ScCalcConfig::STRING_CONVERSION_UNAMBIGUOUS;
+    aConfig.mbEmptyStringAsZero = false;
+    ScInterpreter::SetGlobalConfig(aConfig);
+    m_pDoc->CalcAll();
+    aVal = m_pDoc->GetString( 0, 0, 0);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
+    aVal = m_pDoc->GetString( 0, 1, 0);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
+    m_pDoc->GetValue(0, 2, 0, val);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7);
+    aVal = m_pDoc->GetString( 0, 3, 0);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
+    aVal = m_pDoc->GetString( 0, 4, 0);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
+
+    // With "Treat as zero" ("Empty string as zero" is ignored).
+    aConfig.meStringConversion = ScCalcConfig::STRING_CONVERSION_AS_ZERO;
+    aConfig.mbEmptyStringAsZero = true;
+    ScInterpreter::SetGlobalConfig(aConfig);
+    m_pDoc->CalcAll();
+    m_pDoc->GetValue(0, 0, 0, val);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
+    m_pDoc->GetValue(0, 1, 0, val);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
+    m_pDoc->GetValue(0, 2, 0, val);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
+    m_pDoc->GetValue(0, 3, 0, val);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
+    m_pDoc->GetValue(0, 4, 0, val);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
+
+    // With "Generate #VALUE! error" ("Empty string as zero" is ignored).
+    aConfig.meStringConversion = ScCalcConfig::STRING_CONVERSION_AS_ERROR;
+    aConfig.mbEmptyStringAsZero = false;
+    ScInterpreter::SetGlobalConfig(aConfig);
+    m_pDoc->CalcAll();
+    aVal = m_pDoc->GetString( 0, 0, 0);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
+    aVal = m_pDoc->GetString( 0, 1, 0);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
+    aVal = m_pDoc->GetString( 0, 2, 0);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
+    aVal = m_pDoc->GetString( 0, 3, 0);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
+    aVal = m_pDoc->GetString( 0, 4, 0);
+    CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
 
     m_pDoc->DeleteTab(0);
 }
commit c52f3ea0eb327343b1945290c43d3b66f546dfe9
Author: Eike Rathke <erack at redhat.com>
Date:   Thu Mar 13 19:50:14 2014 +0100

    user selectable string conversion models, related fdo#37132 fdo#74622
    
    Determines how to treat text when encountered as operand in an arithmetic
    operation or as argument to a function that expects a number instead.
    
    Selectable under Tools->Options->Calc->Formula "Detailed calculation settings"
    "Custom" from "Conversion from text to number" are:
    
    Generate #VALUE! error:         =1+"1" or =1+"x" give #VALUE!
    Treat as zero:                  =1+"1" or =1+"x" give 1
    Convert only unambiguous:       =1+"1" gives 2, but =1+"1.000" or =1+"x" give #VALUE!
    Convert also locale dependent:  =1+"1.000" may be 2 or 1001 ... =1+"x" gives #VALUE!
    
    For "Generate #VALUE! error" and "Treat as zero" the "Treat empty string as
    zero" option follows these settings, for "Convert only unambiguous" and
    "Convert also locale dependent" it can be set independently.
    
    When reading documents created by other spreadsheet applications or older
    versions of LibreOffice, and to interchange documents between different locales
    the "Convert only unambiguous" with "Treat empty string as zero = True" setting
    is recommended, though LibreOffice so far acted as "Convert also locale
    dependent" with "Treat empty string as zero = False", which is the reason that
    option is kept as default.
    
    The best setting to create new documents that can be interpreted by all
    spreadsheet applications without on-the-fly string conversion is
    "Generate #VALUE! error". Not having to convert strings during
    calculation ist also faster, of course.
    
    Change-Id: Ie6dc34a00a82064a2d862b2178ce715fab945f85

diff --git a/sc/inc/calcconfig.hxx b/sc/inc/calcconfig.hxx
index 94a72cc..c477e72 100644
--- a/sc/inc/calcconfig.hxx
+++ b/sc/inc/calcconfig.hxx
@@ -28,7 +28,17 @@ enum ScRecalcOptions
  */
 struct SC_DLLPUBLIC ScCalcConfig
 {
+    // from most stringent to most relaxed
+    enum StringConversion
+    {
+        STRING_CONVERSION_AS_ERROR = 0,     ///<  =1+"1" or =1+"x" give #VALUE!
+        STRING_CONVERSION_AS_ZERO,          ///<  =1+"1" or =1+"x" give 1
+        STRING_CONVERSION_UNAMBIGUOUS,      ///<  =1+"1" gives 2, but =1+"1.000" or =1+"x" give #VALUE!
+        STRING_CONVERSION_LOCALE_DEPENDENT  ///<  =1+"1.000" may be 2 or 1001 ... =1+"x" gives #VALUE!
+    };
+
     formula::FormulaGrammar::AddressConvention meStringRefAddressSyntax;
+    StringConversion meStringConversion;
     bool mbEmptyStringAsZero:1;
     bool mbOpenCLEnabled:1;
     bool mbOpenCLAutoSelect:1;
diff --git a/sc/source/core/tool/calcconfig.cxx b/sc/source/core/tool/calcconfig.cxx
index f910bb1..d33868f 100644
--- a/sc/source/core/tool/calcconfig.cxx
+++ b/sc/source/core/tool/calcconfig.cxx
@@ -11,6 +11,7 @@
 
 ScCalcConfig::ScCalcConfig() :
     meStringRefAddressSyntax(formula::FormulaGrammar::CONV_UNSPECIFIED),
+    meStringConversion(STRING_CONVERSION_LOCALE_DEPENDENT),     // old LibreOffice behavior
     mbEmptyStringAsZero(false),
     mbOpenCLEnabled(false),
     mbOpenCLAutoSelect(true)
@@ -25,6 +26,7 @@ void ScCalcConfig::reset()
 bool ScCalcConfig::operator== (const ScCalcConfig& r) const
 {
     return meStringRefAddressSyntax == r.meStringRefAddressSyntax &&
+           meStringConversion == r.meStringConversion &&
            mbEmptyStringAsZero == r.mbEmptyStringAsZero &&
            mbOpenCLEnabled == r.mbOpenCLEnabled &&
            mbOpenCLAutoSelect == r.mbOpenCLAutoSelect &&
diff --git a/sc/source/core/tool/formulaopt.cxx b/sc/source/core/tool/formulaopt.cxx
index 12b9cec..235a594 100644
--- a/sc/source/core/tool/formulaopt.cxx
+++ b/sc/source/core/tool/formulaopt.cxx
@@ -193,13 +193,14 @@ SfxPoolItem* ScTpFormulaItem::Clone( SfxItemPool * ) const
 #define SCFORMULAOPT_SEP_ARRAY_ROW        3
 #define SCFORMULAOPT_SEP_ARRAY_COL        4
 #define SCFORMULAOPT_STRING_REF_SYNTAX    5
-#define SCFORMULAOPT_EMPTY_OUSTRING_AS_ZERO 6
-#define SCFORMULAOPT_OOXML_RECALC         7
-#define SCFORMULAOPT_ODF_RECALC           8
-#define SCFORMULAOPT_OPENCL_ENABLED       9
-#define SCFORMULAOPT_OPENCL_AUTOSELECT   10
-#define SCFORMULAOPT_OPENCL_DEVICE       11
-#define SCFORMULAOPT_COUNT               12
+#define SCFORMULAOPT_STRING_CONVERSION    6
+#define SCFORMULAOPT_EMPTY_OUSTRING_AS_ZERO 7
+#define SCFORMULAOPT_OOXML_RECALC         8
+#define SCFORMULAOPT_ODF_RECALC           9
+#define SCFORMULAOPT_OPENCL_ENABLED      10
+#define SCFORMULAOPT_OPENCL_AUTOSELECT   11
+#define SCFORMULAOPT_OPENCL_DEVICE       12
+#define SCFORMULAOPT_COUNT               13
 
 Sequence<OUString> ScFormulaCfg::GetPropertyNames()
 {
@@ -211,6 +212,7 @@ Sequence<OUString> ScFormulaCfg::GetPropertyNames()
         "Syntax/SeparatorArrayRow",      // SCFORMULAOPT_SEP_ARRAY_ROW
         "Syntax/SeparatorArrayCol",      // SCFORMULAOPT_SEP_ARRAY_COL
         "Syntax/StringRefAddressSyntax", // SCFORMULAOPT_STRING_REF_SYNTAX
+        "Syntax/StringConversion",       // SCFORMULAOPT_STRING_CONVERSION
         "Syntax/EmptyStringAsZero",      // SCFORMULAOPT_EMPTY_OUSTRING_AS_ZERO
         "Load/OOXMLRecalcMode",          // SCFORMULAOPT_OOXML_RECALC
         "Load/ODFRecalcMode",            // SCFORMULAOPT_ODF_RECALC
@@ -229,7 +231,7 @@ Sequence<OUString> ScFormulaCfg::GetPropertyNames()
 ScFormulaCfg::PropsToIds ScFormulaCfg::GetPropNamesToId()
 {
     Sequence<OUString> aPropNames = GetPropertyNames();
-    static sal_uInt16 aVals[] = { SCFORMULAOPT_GRAMMAR, SCFORMULAOPT_ENGLISH_FUNCNAME, SCFORMULAOPT_SEP_ARG, SCFORMULAOPT_SEP_ARRAY_ROW, SCFORMULAOPT_SEP_ARRAY_COL, SCFORMULAOPT_STRING_REF_SYNTAX, SCFORMULAOPT_EMPTY_OUSTRING_AS_ZERO, SCFORMULAOPT_OOXML_RECALC, SCFORMULAOPT_ODF_RECALC, SCFORMULAOPT_OPENCL_ENABLED, SCFORMULAOPT_OPENCL_AUTOSELECT, SCFORMULAOPT_OPENCL_DEVICE };
+    static sal_uInt16 aVals[] = { SCFORMULAOPT_GRAMMAR, SCFORMULAOPT_ENGLISH_FUNCNAME, SCFORMULAOPT_SEP_ARG, SCFORMULAOPT_SEP_ARRAY_ROW, SCFORMULAOPT_SEP_ARRAY_COL, SCFORMULAOPT_STRING_REF_SYNTAX, SCFORMULAOPT_STRING_CONVERSION, SCFORMULAOPT_EMPTY_OUSTRING_AS_ZERO, SCFORMULAOPT_OOXML_RECALC, SCFORMULAOPT_ODF_RECALC, SCFORMULAOPT_OPENCL_ENABLED, SCFORMULAOPT_OPENCL_AUTOSELECT, SCFORMULAOPT_OPENCL_DEVICE };
     OSL_ENSURE( SAL_N_ELEMENTS(aVals) == aPropNames.getLength(), "Properties and ids are out of Sync");
     PropsToIds aPropIdMap;
     for ( sal_uInt16 i=0; i<aPropNames.getLength(); ++i )
@@ -328,7 +330,7 @@ void ScFormulaCfg::UpdateFromProperties( const Sequence<OUString>& aNames )
                     do
                     {
                         if (!(pValues[nProp] >>= nIntVal))
-                            // extractino failed.
+                            // extraction failed.
                             break;
 
                         switch (nIntVal)
@@ -353,6 +355,39 @@ void ScFormulaCfg::UpdateFromProperties( const Sequence<OUString>& aNames )
                     GetCalcConfig().meStringRefAddressSyntax = eConv;
                 }
                 break;
+                case SCFORMULAOPT_STRING_CONVERSION:
+                {
+                    // Get default value in case this option is not set.
+                    ScCalcConfig::StringConversion eConv = GetCalcConfig().meStringConversion;
+
+                    do
+                    {
+                        if (!(pValues[nProp] >>= nIntVal))
+                            // extraction failed.
+                            break;
+
+                        switch (nIntVal)
+                        {
+                            case 0:
+                                eConv = ScCalcConfig::STRING_CONVERSION_AS_ERROR;
+                            break;
+                            case 1:
+                                eConv = ScCalcConfig::STRING_CONVERSION_AS_ZERO;
+                            break;
+                            case 2:
+                                eConv = ScCalcConfig::STRING_CONVERSION_UNAMBIGUOUS;
+                            break;
+                            case 3:
+                                eConv = ScCalcConfig::STRING_CONVERSION_LOCALE_DEPENDENT;
+                            break;
+                            default:
+                                SAL_WARN("sc", "unknown string conversion option!");
+                        }
+                    }
+                    while (false);
+                    GetCalcConfig().meStringConversion = eConv;
+                }
+                break;
                 case SCFORMULAOPT_EMPTY_OUSTRING_AS_ZERO:
                 {
                     sal_Bool bVal = GetCalcConfig().mbEmptyStringAsZero;
@@ -492,6 +527,19 @@ void ScFormulaCfg::Commit()
                 pValues[nProp] <<= nVal;
             }
             break;
+            case SCFORMULAOPT_STRING_CONVERSION:
+            {
+                sal_Int32 nVal = 3;
+                switch (GetCalcConfig().meStringConversion)
+                {
+                    case ScCalcConfig::STRING_CONVERSION_AS_ERROR:          nVal = 0; break;
+                    case ScCalcConfig::STRING_CONVERSION_AS_ZERO:           nVal = 1; break;
+                    case ScCalcConfig::STRING_CONVERSION_UNAMBIGUOUS:       nVal = 2; break;
+                    case ScCalcConfig::STRING_CONVERSION_LOCALE_DEPENDENT:  nVal = 3; break;
+                }
+                pValues[nProp] <<= nVal;
+            }
+            break;
             case SCFORMULAOPT_EMPTY_OUSTRING_AS_ZERO:
             {
                 sal_Bool bVal = GetCalcConfig().mbEmptyStringAsZero;
diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx
index 2f390f5..232fcdb 100644
--- a/sc/source/core/tool/interpr4.cxx
+++ b/sc/source/core/tool/interpr4.cxx
@@ -189,6 +189,25 @@ sal_uInt16 ScInterpreter::GetCellErrCode( const ScRefCellValue& rCell )
     return rCell.meType == CELLTYPE_FORMULA ? rCell.mpFormula->GetErrCode() : 0;
 }
 
+namespace
+{
+bool isEmptyString( const OUString& rStr )
+{
+    if (rStr.isEmpty())
+        return true;
+    else if (rStr[0] == ' ')
+    {
+        const sal_Unicode* p = rStr.getStr() + 1;
+        const sal_Unicode* const pStop = p - 1 + rStr.getLength();
+        while (p < pStop && *p == ' ')
+            ++p;
+        if (p == pStop)
+            return true;
+    }
+    return false;
+}
+}
+
 /** Convert string content to numeric value.
 
     Converted are only integer numbers including exponent, and ISO 8601 dates
@@ -221,9 +240,9 @@ sal_uInt16 ScInterpreter::GetCellErrCode( const ScRefCellValue& rCell )
 
 double ScInterpreter::ConvertStringToValue( const OUString& rStr )
 {
-#if 1
-    // We keep this code until we provide a friendly way to convert string
-    // numbers into numbers in the UI.
+    // We keep ScCalcConfig::STRING_CONVERSION_LOCALE_DEPENDENT default until
+    // we provide a friendly way to convert string numbers into numbers in the UI.
+
     double fValue = 0.0;
     if (mnStringNoValueError == errCellNoValue)
     {
@@ -232,40 +251,51 @@ double ScInterpreter::ConvertStringToValue( const OUString& rStr )
         return fValue;
     }
 
-    if (GetGlobalConfig().mbEmptyStringAsZero)
+    switch (GetGlobalConfig().meStringConversion)
     {
-        // The number scanner does not accept empty strings or strings
-        // containing only spaces, be on par in these cases with what was
-        // accepted in OOo and is in AOO (see also the else branch below) and
-        // convert to 0 to prevent interoperability nightmares.
-        if (rStr.isEmpty())
+        case ScCalcConfig::STRING_CONVERSION_AS_ERROR:
+            SetError( mnStringNoValueError);
             return fValue;
-        else if (rStr[0] == ' ')
-        {
-            const sal_Unicode* p = rStr.getStr() + 1;
-            const sal_Unicode* const pStop = p - 1 + rStr.getLength();
-            while (p < pStop && *p == ' ')
-                ++p;
-            if (p == pStop)
+        case ScCalcConfig::STRING_CONVERSION_AS_ZERO:
+            return fValue;
+        case ScCalcConfig::STRING_CONVERSION_LOCALE_DEPENDENT:
+            {
+                if (GetGlobalConfig().mbEmptyStringAsZero)
+                {
+                    // The number scanner does not accept empty strings or strings
+                    // containing only spaces, be on par in these cases with what was
+                    // accepted in OOo and is in AOO (see also the
+                    // STRING_CONVERSION_UNAMBIGUOUS branch) and convert to 0 to prevent
+                    // interoperability nightmares.
+
+                    if (isEmptyString( rStr))
+                        return fValue;
+                }
+
+                sal_uInt32 nFIndex = 0;
+                if (!pFormatter->IsNumberFormat(rStr, nFIndex, fValue))
+                {
+                    SetError( mnStringNoValueError);
+                    fValue = 0.0;
+                }
                 return fValue;
-        }
+            }
+            break;
+        case ScCalcConfig::STRING_CONVERSION_UNAMBIGUOUS:
+            {
+                if (!GetGlobalConfig().mbEmptyStringAsZero)
+                {
+                    if (isEmptyString( rStr))
+                    {
+                        SetError( mnStringNoValueError);
+                        return fValue;
+                    }
+                }
+            }
+            // continue below, pulled from switch case for better readability
+            break;
     }
 
-    sal_uInt32 nFIndex = 0;
-    if (!pFormatter->IsNumberFormat(rStr, nFIndex, fValue))
-    {
-        SetError( mnStringNoValueError);
-        fValue = 0.0;
-    }
-    return fValue;
-#else
-    double fValue = 0.0;
-    if (mnStringNoValueError == errCellNoValue)
-    {
-        // Requested that all strings result in 0, error handled by caller.
-        SetError( mnStringNoValueError);
-        return fValue;
-    }
     OUString aStr( rStr);
     rtl_math_ConversionStatus eStatus;
     sal_Int32 nParseEnd;
@@ -305,14 +335,14 @@ double ScInterpreter::ConvertStringToValue( const OUString& rStr )
                     p = pStart;
                     while (p < pStop && *p == ' ')
                         ++p;
-                    if (p < pStop && !CharClass::isAsciiDigit(*p))
+                    if (p < pStop && !rtl::isAsciiDigit(*p))
                         SetError( mnStringNoValueError);
                     p = pLastStart;
                     while (p < pStop && !nGlobalError && eState < blank)
                     {
                         if (eState == minute)
                             nCurFmtType |= NUMBERFORMAT_TIME;
-                        if (CharClass::isAsciiDigit(*p))
+                        if (rtl::isAsciiDigit(*p))
                         {
                             // Maximum 2 digits per unit, except fractions.
                             if (p - pLastStart >= 2 && eState != fraction)
@@ -427,7 +457,6 @@ double ScInterpreter::ConvertStringToValue( const OUString& rStr )
             fValue = 0.0;
     }
     return fValue;
-#endif
 }
 
 double ScInterpreter::GetCellValue( const ScAddress& rPos, ScRefCellValue& rCell )
diff --git a/sc/source/ui/optdlg/calcoptionsdlg.cxx b/sc/source/ui/optdlg/calcoptionsdlg.cxx
index 0b5fd4c..82083cc 100644
--- a/sc/source/ui/optdlg/calcoptionsdlg.cxx
+++ b/sc/source/ui/optdlg/calcoptionsdlg.cxx
@@ -22,9 +22,10 @@
 namespace {
 
 typedef enum {
-    CALC_OPTION_REF_SYNTAX    = 0,
-    CALC_OPTION_EMPTY_AS_ZERO = 1,
-    CALC_OPTION_ENABLE_OPENCL = 2
+    CALC_OPTION_STRING_CONVERSION = 0,
+    CALC_OPTION_EMPTY_AS_ZERO     = 1,
+    CALC_OPTION_REF_SYNTAX        = 2,
+    CALC_OPTION_ENABLE_OPENCL     = 3
 } CalcOptionOrder;
 
 class OptionString : public SvLBoxString
@@ -101,6 +102,23 @@ formula::FormulaGrammar::AddressConvention toAddressConvention(sal_Int32 nPos)
     return formula::FormulaGrammar::CONV_UNSPECIFIED;
 }
 
+ScCalcConfig::StringConversion toStringConversion(sal_Int32 nPos)
+{
+    switch (nPos)
+    {
+        case 0:
+            return ScCalcConfig::STRING_CONVERSION_AS_ERROR;
+        case 1:
+            return ScCalcConfig::STRING_CONVERSION_AS_ZERO;
+        case 2:
+            return ScCalcConfig::STRING_CONVERSION_UNAMBIGUOUS;
+        case 3:
+            return ScCalcConfig::STRING_CONVERSION_LOCALE_DEPENDENT;
+    }
+
+    return ScCalcConfig::STRING_CONVERSION_AS_ERROR;
+}
+
 }
 
 ScCalcOptionsDialog::ScCalcOptionsDialog(Window* pParent, const ScCalcConfig& rConfig)
@@ -110,6 +128,7 @@ ScCalcOptionsDialog::ScCalcOptionsDialog(Window* pParent, const ScCalcConfig& rC
     , maExcelA1(ScResId(SCSTR_FORMULA_SYNTAX_XL_A1).toString())
     , maExcelR1C1(ScResId(SCSTR_FORMULA_SYNTAX_XL_R1C1).toString())
     , maConfig(rConfig)
+    , mbSelectedEmptyStringAsZero(rConfig.mbEmptyStringAsZero)
 {
     get(mpLbSettings, "settings");
     get(mpLbOptionEdit, "edit");
@@ -134,8 +153,17 @@ ScCalcOptionsDialog::ScCalcOptionsDialog(Window* pParent, const ScCalcConfig& rC
     maCaptionStringRefSyntax = get<Window>("ref_syntax_caption")->GetText();
     maDescStringRefSyntax = get<Window>("ref_syntax_desc")->GetText();
     maUseFormulaSyntax = get<Window>("use_formula_syntax")->GetText();
+
+    maCaptionStringConversion = get<Window>("string_conversion_caption")->GetText();
+    maDescStringConversion = get<Window>("string_conversion_desc")->GetText();
+    maStringConversionAsError = get<Window>("string_conversion_as_error")->GetText();
+    maStringConversionAsZero = get<Window>("string_conversion_as_zero")->GetText();
+    maStringConversionUnambiguous = get<Window>("string_conversion_unambiguous")->GetText();
+    maStringConversionLocaleDependent = get<Window>("string_conversion_locale_dependent")->GetText();
+
     maCaptionEmptyStringAsZero = get<Window>("empty_str_as_zero_caption")->GetText();
     maDescEmptyStringAsZero = get<Window>("empty_str_as_zero_desc")->GetText();
+
     maCaptionOpenCLEnabled = get<Window>("opencl_enabled")->GetText();
     maDescOpenCLEnabled = get<Window>("opencl_enabled_desc")->GetText();
     maSoftware = get<Window>("software")->GetText();
@@ -237,6 +265,18 @@ void ScCalcOptionsDialog::fillOpenclList()
 
 #endif
 
+
+namespace {
+void addOption( SvTreeList* pModel, OptionString* pItem )
+{
+    SvTreeListEntry* pEntry = new SvTreeListEntry;
+    pEntry->AddItem(new SvLBoxString(pEntry, 0, OUString()));
+    pEntry->AddItem(new SvLBoxContextBmp(pEntry, 0, Image(), Image(), false));
+    pEntry->AddItem(pItem);
+    pModel->Insert(pEntry);
+}
+}
+
 void ScCalcOptionsDialog::FillOptionsList()
 {
     mpLbSettings->SetUpdateMode(false);
@@ -245,17 +285,21 @@ void ScCalcOptionsDialog::FillOptionsList()
     SvTreeList* pModel = mpLbSettings->GetModel();
 
     {
+        // String conversion for arithmetic operations.
+        OptionString* pItem = new OptionString(
+            maCaptionStringConversion, toString(maConfig.meStringConversion));
+        addOption( pModel, pItem);
+    }
+
+    pModel->Insert(createBoolItem(maCaptionEmptyStringAsZero,maConfig.mbEmptyStringAsZero));
+
+    {
         // Syntax for INDIRECT function.
-        SvTreeListEntry* pEntry = new SvTreeListEntry;
-        pEntry->AddItem(new SvLBoxString(pEntry, 0, OUString()));
-        pEntry->AddItem(new SvLBoxContextBmp(pEntry, 0, Image(), Image(), false));
         OptionString* pItem = new OptionString(
             maCaptionStringRefSyntax, toString(maConfig.meStringRefAddressSyntax));
-        pEntry->AddItem(pItem);
-        pModel->Insert(pEntry);
+        addOption( pModel, pItem);
     }
 
-    pModel->Insert(createBoolItem(maCaptionEmptyStringAsZero,maConfig.mbEmptyStringAsZero));
 #if HAVE_FEATURE_OPENCL
     pModel->Insert(createBoolItem(maCaptionOpenCLEnabled,maConfig.mbOpenCLEnabled));
     fillOpenclList();
@@ -304,6 +348,38 @@ void ScCalcOptionsDialog::SelectionChanged()
         }
         break;
 
+        case CALC_OPTION_STRING_CONVERSION:
+        {
+            // String conversion for arithmetic operations.
+            mpBtnTrue->Hide();
+            mpBtnFalse->Hide();
+            mpLbOptionEdit->Show();
+            mpOpenclInfoList->GetParent()->Hide();
+
+            mpLbOptionEdit->Clear();
+            mpLbOptionEdit->InsertEntry(maStringConversionAsError);
+            mpLbOptionEdit->InsertEntry(maStringConversionAsZero);
+            mpLbOptionEdit->InsertEntry(maStringConversionUnambiguous);
+            mpLbOptionEdit->InsertEntry(maStringConversionLocaleDependent);
+            switch (maConfig.meStringConversion)
+            {
+                case ScCalcConfig::STRING_CONVERSION_AS_ERROR:
+                    mpLbOptionEdit->SelectEntryPos(0);
+                break;
+                case ScCalcConfig::STRING_CONVERSION_AS_ZERO:
+                    mpLbOptionEdit->SelectEntryPos(1);
+                break;
+                case ScCalcConfig::STRING_CONVERSION_UNAMBIGUOUS:
+                    mpLbOptionEdit->SelectEntryPos(2);
+                break;
+                case ScCalcConfig::STRING_CONVERSION_LOCALE_DEPENDENT:
+                    mpLbOptionEdit->SelectEntryPos(3);
+                break;
+            }
+            mpFtAnnotation->SetText(maDescStringConversion);
+        }
+        break;
+
         // booleans
         case CALC_OPTION_EMPTY_AS_ZERO:
         case CALC_OPTION_ENABLE_OPENCL:
@@ -314,11 +390,22 @@ void ScCalcOptionsDialog::SelectionChanged()
             mpBtnFalse->Show();
 
             bool bValue = false;
+            bool bEnable = true;
             if ( nSelectedPos == CALC_OPTION_EMPTY_AS_ZERO )
             {
                 bValue = maConfig.mbEmptyStringAsZero;
                 mpFtAnnotation->SetText(maDescEmptyStringAsZero);
                 mpOpenclInfoList->GetParent()->Hide();
+                switch (maConfig.meStringConversion)
+                {
+                    case ScCalcConfig::STRING_CONVERSION_AS_ERROR:
+                    case ScCalcConfig::STRING_CONVERSION_AS_ZERO:
+                        bEnable = false;
+                        break;
+                    case ScCalcConfig::STRING_CONVERSION_UNAMBIGUOUS:
+                    case ScCalcConfig::STRING_CONVERSION_LOCALE_DEPENDENT:
+                        break;  // nothing
+                }
             }
             else
             {
@@ -344,6 +431,16 @@ void ScCalcOptionsDialog::SelectionChanged()
                 mpBtnTrue->Check(false);
                 mpBtnFalse->Check(true);
             }
+            if (bEnable)
+            {
+                mpBtnTrue->Enable();
+                mpBtnFalse->Enable();
+            }
+            else
+            {
+                mpBtnTrue->Disable();
+                mpBtnFalse->Disable();
+            }
         }
         break;
         default:
@@ -366,6 +463,36 @@ void ScCalcOptionsDialog::ListOptionValueChanged()
         }
         break;
 
+        case CALC_OPTION_STRING_CONVERSION:
+        {
+            // String conversion for arithmetic operations.
+            sal_Int32 nPos = mpLbOptionEdit->GetSelectEntryPos();
+            maConfig.meStringConversion = toStringConversion(nPos);
+
+            setValueAt(nSelected, toString(maConfig.meStringConversion));
+
+            switch (maConfig.meStringConversion)
+            {
+                case ScCalcConfig::STRING_CONVERSION_AS_ERROR:
+                    maConfig.mbEmptyStringAsZero = false;
+                    setValueAt(CALC_OPTION_EMPTY_AS_ZERO, toString(maConfig.mbEmptyStringAsZero));
+                    mpLbOptionEdit->SelectEntryPos(0);
+                break;
+                case ScCalcConfig::STRING_CONVERSION_AS_ZERO:
+                    maConfig.mbEmptyStringAsZero = true;
+                    setValueAt(CALC_OPTION_EMPTY_AS_ZERO, toString(maConfig.mbEmptyStringAsZero));
+                    mpLbOptionEdit->SelectEntryPos(1);
+                break;
+                case ScCalcConfig::STRING_CONVERSION_UNAMBIGUOUS:
+                case ScCalcConfig::STRING_CONVERSION_LOCALE_DEPENDENT:
+                    // Reset to the value the user selected before.
+                    maConfig.mbEmptyStringAsZero = mbSelectedEmptyStringAsZero;
+                    setValueAt(CALC_OPTION_EMPTY_AS_ZERO, toString(maConfig.mbEmptyStringAsZero));
+                break;
+            }
+        }
+        break;
+
         case CALC_OPTION_EMPTY_AS_ZERO:
         case CALC_OPTION_ENABLE_OPENCL:
             break;
@@ -424,9 +551,10 @@ void ScCalcOptionsDialog::RadioValueChanged()
     switch (nSelected)
     {
         case CALC_OPTION_REF_SYNTAX:
+        case CALC_OPTION_STRING_CONVERSION:
             return;
         case CALC_OPTION_EMPTY_AS_ZERO:
-            maConfig.mbEmptyStringAsZero = bValue;
+            maConfig.mbEmptyStringAsZero = mbSelectedEmptyStringAsZero = bValue;
             break;
         case CALC_OPTION_ENABLE_OPENCL:
             maConfig.mbOpenCLEnabled = bValue;
@@ -458,6 +586,22 @@ OUString ScCalcOptionsDialog::toString(formula::FormulaGrammar::AddressConventio
     return maUseFormulaSyntax;
 }
 
+OUString ScCalcOptionsDialog::toString(ScCalcConfig::StringConversion eConv) const
+{
+    switch (eConv)
+    {
+        case ScCalcConfig::STRING_CONVERSION_AS_ERROR:
+            return maStringConversionAsError;
+        case ScCalcConfig::STRING_CONVERSION_AS_ZERO:
+            return maStringConversionAsZero;
+        case ScCalcConfig::STRING_CONVERSION_UNAMBIGUOUS:
+            return maStringConversionUnambiguous;
+        case ScCalcConfig::STRING_CONVERSION_LOCALE_DEPENDENT:
+            return maStringConversionLocaleDependent;
+    }
+    return maStringConversionAsError;
+}
+
 OUString ScCalcOptionsDialog::toString(bool bVal) const
 {
     return bVal ? maTrue : maFalse;
diff --git a/sc/source/ui/optdlg/calcoptionsdlg.hxx b/sc/source/ui/optdlg/calcoptionsdlg.hxx
index ae4f043..c542caa 100644
--- a/sc/source/ui/optdlg/calcoptionsdlg.hxx
+++ b/sc/source/ui/optdlg/calcoptionsdlg.hxx
@@ -50,6 +50,7 @@ private:
 #endif
 
     OUString toString(formula::FormulaGrammar::AddressConvention eConv) const;
+    OUString toString(ScCalcConfig::StringConversion eConv) const;
     OUString toString(bool bVal) const;
     SvTreeListEntry *createBoolItem(const OUString &rCaption, bool bValue) const;
     void     setValueAt(size_t nPos, const OUString &rString);
@@ -81,6 +82,14 @@ private:
     OUString maDescStringRefSyntax;
     OUString maUseFormulaSyntax;
 
+    OUString maStringConversionAsError;
+    OUString maStringConversionAsZero;
+    OUString maStringConversionUnambiguous;
+    OUString maStringConversionLocaleDependent;
+
+    OUString maCaptionStringConversion;
+    OUString maDescStringConversion;
+
     OUString maCaptionEmptyStringAsZero;
     OUString maDescEmptyStringAsZero;
 
@@ -93,6 +102,8 @@ private:
 #if HAVE_FEATURE_OPENCL
     std::vector<sc::OpenclPlatformInfo> maPlatformInfo;
 #endif
+
+    bool mbSelectedEmptyStringAsZero;
 };
 
 #endif
diff --git a/sc/uiconfig/scalc/ui/formulacalculationoptions.ui b/sc/uiconfig/scalc/ui/formulacalculationoptions.ui
index 305e8e3..b0442c2 100644
--- a/sc/uiconfig/scalc/ui/formulacalculationoptions.ui
+++ b/sc/uiconfig/scalc/ui/formulacalculationoptions.ui
@@ -188,10 +188,10 @@
               </packing>
             </child>
             <child>
-              <object class="GtkLabel" id="ref_syntax_caption">
+              <object class="GtkLabel" id="string_conversion_caption">
                 <property name="can_focus">False</property>
                 <property name="no_show_all">True</property>
-                <property name="label" translatable="yes">Reference syntax for string reference</property>
+                <property name="label" translatable="yes">Conversion from text to number</property>
               </object>
               <packing>
                 <property name="left_attach">0</property>
@@ -201,10 +201,10 @@
               </packing>
             </child>
             <child>
-              <object class="GtkLabel" id="ref_syntax_desc">
+              <object class="GtkLabel" id="string_conversion_desc">
                 <property name="can_focus">False</property>
                 <property name="no_show_all">True</property>
-                <property name="label" translatable="yes">Formula syntax to use when parsing references given in string parameters. This affects built-in functions such as INDIRECT that takes a reference as a string value.</property>
+                <property name="label" translatable="yes">How to treat text when encountered as operand in an arithmetic operation or as argument to a function that expects a number instead. Unambiguous conversion is possible for integer numbers including exponents and ISO 8601 dates and times in their extended formats with separators. Fractional numeric values with decimal separators or dates other than ISO 8601 are locale dependent. Note that in locale dependent conversions the resulting numeric value may differ between locales!</property>
                 <property name="wrap">True</property>
                 <property name="max_width_chars">56</property>
               </object>
@@ -216,10 +216,10 @@
               </packing>
             </child>
             <child>
-              <object class="GtkLabel" id="use_formula_syntax">
+              <object class="GtkLabel" id="string_conversion_as_error">
                 <property name="can_focus">False</property>
                 <property name="no_show_all">True</property>
-                <property name="label" translatable="yes">Use formula syntax</property>
+                <property name="label" translatable="yes">Generate #VALUE! error</property>
               </object>
               <packing>
                 <property name="left_attach">0</property>
@@ -229,6 +229,45 @@
               </packing>
             </child>
             <child>
+              <object class="GtkLabel" id="string_conversion_as_zero">
+                <property name="can_focus">False</property>
+                <property name="no_show_all">True</property>
+                <property name="label" translatable="yes">Treat as zero</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">7</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="string_conversion_unambiguous">
+                <property name="can_focus">False</property>
+                <property name="no_show_all">True</property>
+                <property name="label" translatable="yes">Convert only unambiguous</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">8</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="string_conversion_locale_dependent">
+                <property name="can_focus">False</property>
+                <property name="no_show_all">True</property>
+                <property name="label" translatable="yes">Convert also locale dependent</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">9</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
               <object class="GtkLabel" id="empty_str_as_zero_caption">
                 <property name="can_focus">False</property>
                 <property name="no_show_all">True</property>
@@ -236,7 +275,7 @@
               </object>
               <packing>
                 <property name="left_attach">0</property>
-                <property name="top_attach">7</property>
+                <property name="top_attach">10</property>
                 <property name="width">1</property>
                 <property name="height">1</property>
               </packing>
@@ -245,13 +284,54 @@
               <object class="GtkLabel" id="empty_str_as_zero_desc">
                 <property name="can_focus">False</property>
                 <property name="no_show_all">True</property>
-                <property name="label" translatable="yes">This option determines whether or not an empty string is to be treated as having a value of zero when used in arithmetic.</property>
+                <property name="label" translatable="yes">This option determines whether an empty string is to be treated as having a value of zero when used in arithmetic or generates an error. It is disabled if conversion from text to number is set to always generate an error or always treat text as zero and then follows that value.</property>
                 <property name="wrap">True</property>
                 <property name="max_width_chars">56</property>
               </object>
               <packing>
                 <property name="left_attach">0</property>
-                <property name="top_attach">8</property>
+                <property name="top_attach">11</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="ref_syntax_caption">
+                <property name="can_focus">False</property>
+                <property name="no_show_all">True</property>
+                <property name="label" translatable="yes">Reference syntax for string reference</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">12</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="ref_syntax_desc">
+                <property name="can_focus">False</property>
+                <property name="no_show_all">True</property>
+                <property name="label" translatable="yes">Formula syntax to use when parsing references given in string parameters. This affects built-in functions such as INDIRECT that takes a reference as a string value.</property>
+                <property name="wrap">True</property>
+                <property name="max_width_chars">56</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">13</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="use_formula_syntax">
+                <property name="can_focus">False</property>
+                <property name="no_show_all">True</property>
+                <property name="label" translatable="yes">Use formula syntax</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">14</property>
                 <property name="width">1</property>
                 <property name="height">1</property>
               </packing>
@@ -264,7 +344,7 @@
               </object>
               <packing>
                 <property name="left_attach">0</property>
-                <property name="top_attach">9</property>
+                <property name="top_attach">15</property>
                 <property name="width">1</property>
                 <property name="height">1</property>
               </packing>
@@ -279,7 +359,7 @@
               </object>
               <packing>
                 <property name="left_attach">0</property>
-                <property name="top_attach">10</property>
+                <property name="top_attach">16</property>
                 <property name="width">1</property>
                 <property name="height">1</property>
               </packing>
@@ -470,7 +550,7 @@
               </object>
               <packing>
                 <property name="left_attach">0</property>
-                <property name="top_attach">11</property>
+                <property name="top_attach">17</property>
                 <property name="width">1</property>
                 <property name="height">1</property>
               </packing>
commit cb87c1eefb434bb24fe1c5472328a93cbdc5d761
Author: Eike Rathke <erack at redhat.com>
Date:   Wed Mar 12 18:29:54 2014 +0100

    SvxCheckListBox/SvTreeList/ListBox position types nitpick
    
    Change-Id: Id77f90189d7dffe660ae509f563ea8eb6deb1727

diff --git a/sc/source/ui/optdlg/calcoptionsdlg.cxx b/sc/source/ui/optdlg/calcoptionsdlg.cxx
index fd48e76..0b5fd4c 100644
--- a/sc/source/ui/optdlg/calcoptionsdlg.cxx
+++ b/sc/source/ui/optdlg/calcoptionsdlg.cxx
@@ -83,7 +83,7 @@ void OptionString::Paint(const Point& rPos, SvTreeListBox& rDev, const SvViewDat
     rDev.Control::SetFont(aOldFont);
 }
 
-formula::FormulaGrammar::AddressConvention toAddressConvention(sal_uInt16 nPos)
+formula::FormulaGrammar::AddressConvention toAddressConvention(sal_Int32 nPos)
 {
     switch (nPos)
     {
@@ -269,7 +269,7 @@ void ScCalcOptionsDialog::FillOptionsList()
 
 void ScCalcOptionsDialog::SelectionChanged()
 {
-    sal_uInt16 nSelectedPos = mpLbSettings->GetSelectEntryPos();
+    sal_uLong nSelectedPos = mpLbSettings->GetSelectEntryPos();
     switch ((CalcOptionOrder)nSelectedPos)
     {
         case CALC_OPTION_REF_SYNTAX:
@@ -353,13 +353,13 @@ void ScCalcOptionsDialog::SelectionChanged()
 
 void ScCalcOptionsDialog::ListOptionValueChanged()
 {
-    sal_uInt16 nSelected = mpLbSettings->GetSelectEntryPos();
+    sal_uLong nSelected = mpLbSettings->GetSelectEntryPos();
     switch ((CalcOptionOrder) nSelected)
     {
         case CALC_OPTION_REF_SYNTAX:
         {
             // Formula syntax for INDIRECT function.
-            sal_uInt16 nPos = mpLbOptionEdit->GetSelectEntryPos();
+            sal_Int32 nPos = mpLbOptionEdit->GetSelectEntryPos();
             maConfig.meStringRefAddressSyntax = toAddressConvention(nPos);
 
             setValueAt(nSelected, toString(maConfig.meStringRefAddressSyntax));
@@ -419,7 +419,7 @@ void ScCalcOptionsDialog::SelectedDeviceChanged()
 
 void ScCalcOptionsDialog::RadioValueChanged()
 {
-    sal_uInt16 nSelected = mpLbSettings->GetSelectEntryPos();
+    sal_uLong nSelected = mpLbSettings->GetSelectEntryPos();
     bool bValue = mpBtnTrue->IsChecked();
     switch (nSelected)
     {


More information about the Libreoffice-commits mailing list