From 4fee05e680217e876210b341f904df9441a0b7cd Mon Sep 17 00:00:00 2001 From: Laurent Balland-Poirier Date: Fri, 3 Apr 2015 11:59:37 +0200 Subject: tdf#90133 Extend ODF: variable decimal in scientific format Variable decimal is only saved in ODF for number, and do not consider partial variable decimal: 0.0## is saved as 0.000 This patch extend ODF with loext:min-decimal-digit for number format and scientific format Change-Id: I5022458da47bbd33c3e195c280e75c43faca5f8d Reviewed-on: https://gerrit.libreoffice.org/15135 Reviewed-by: Eike Rathke Tested-by: Eike Rathke --- include/xmloff/xmlnumfe.hxx | 6 +++--- include/xmloff/xmltoken.hxx | 1 + xmloff/source/core/xmltoken.cxx | 1 + xmloff/source/style/xmlnumfe.cxx | 43 ++++++++++++++++++++++++++-------------- xmloff/source/style/xmlnumfi.cxx | 34 +++++++++++++++++++++++-------- 5 files changed, 59 insertions(+), 26 deletions(-) diff --git a/include/xmloff/xmlnumfe.hxx b/include/xmloff/xmlnumfe.hxx index 1f4198a738c5..9a770a173843 100644 --- a/include/xmloff/xmlnumfe.hxx +++ b/include/xmloff/xmlnumfe.hxx @@ -62,11 +62,11 @@ private: SAL_DLLPRIVATE void FinishTextElement_Impl(bool bUseExtensionNS = false); SAL_DLLPRIVATE void WriteColorElement_Impl( const Color& rColor ); - SAL_DLLPRIVATE void WriteNumberElement_Impl( sal_Int32 nDecimals, sal_Int32 nInteger, - const OUString& rDashStr, bool bVarDecimals, + SAL_DLLPRIVATE void WriteNumberElement_Impl( sal_Int32 nDecimals, sal_Int32 nMinDecimals, + sal_Int32 nInteger, const OUString& rDashStr, bool bGrouping, sal_Int32 nTrailingThousands, const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries ); - SAL_DLLPRIVATE void WriteScientificElement_Impl( sal_Int32 nDecimals, sal_Int32 nInteger, + SAL_DLLPRIVATE void WriteScientificElement_Impl( sal_Int32 nDecimals, sal_Int32 nMinDecimals, sal_Int32 nInteger, bool bGrouping, sal_Int32 nExp, sal_Int32 nExpInterval, bool bExpSign ); SAL_DLLPRIVATE void WriteFractionElement_Impl( sal_Int32 nInteger, bool bGrouping, sal_Int32 nNumeratorDigits, sal_Int32 nDenominatorDigits, sal_Int32 nDenominator ); diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx index af2fcdbcaa18..5b0167116dbc 100644 --- a/include/xmloff/xmltoken.hxx +++ b/include/xmloff/xmltoken.hxx @@ -3251,6 +3251,7 @@ namespace xmloff { namespace token { XML_EXPONENT_INTERVAL, XML_EXPONENT_SIGN, + XML_MIN_DECIMAL_DIGITS, XML_TOKEN_END }; diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx index 5a853e767391..e242f8cc9ef3 100644 --- a/xmloff/source/core/xmltoken.cxx +++ b/xmloff/source/core/xmltoken.cxx @@ -3249,6 +3249,7 @@ namespace xmloff { namespace token { TOKEN( "exponent-interval", XML_EXPONENT_INTERVAL ), TOKEN( "exponent-sign", XML_EXPONENT_SIGN ), + TOKEN( "min-decimal-digits", XML_MIN_DECIMAL_DIGITS ), #if OSL_DEBUG_LEVEL > 0 { 0, NULL, NULL, XML_TOKEN_END } diff --git a/xmloff/source/style/xmlnumfe.cxx b/xmloff/source/style/xmlnumfe.cxx index 2c0bab4f7352..6b7142fa366a 100644 --- a/xmloff/source/style/xmlnumfe.cxx +++ b/xmloff/source/style/xmlnumfe.cxx @@ -556,8 +556,8 @@ void SvXMLNumFmtExport::WriteAMPMElement_Impl() // numbers void SvXMLNumFmtExport::WriteNumberElement_Impl( - sal_Int32 nDecimals, sal_Int32 nInteger, - const OUString& rDashStr, bool bVarDecimals, + sal_Int32 nDecimals, sal_Int32 nMinDecimals, + sal_Int32 nInteger, const OUString& rDashStr, bool bGrouping, sal_Int32 nTrailingThousands, const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries ) { @@ -570,6 +570,12 @@ void SvXMLNumFmtExport::WriteNumberElement_Impl( OUString::number( nDecimals ) ); } + if ( nMinDecimals >= 0 ) // negative = automatic + { + rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_MIN_DECIMAL_DIGITS, + OUString::number( nMinDecimals ) ); + } + // integer digits if ( nInteger >= 0 ) // negative = automatic { @@ -578,9 +584,9 @@ void SvXMLNumFmtExport::WriteNumberElement_Impl( } // decimal replacement (dashes) or variable decimals (#) - if ( !rDashStr.isEmpty() || bVarDecimals ) + if ( !rDashStr.isEmpty() || nMinDecimals < nDecimals ) { - // variable decimals means an empty replacement string + // full variable decimals means an empty replacement string rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_REPLACEMENT, rDashStr ); } @@ -633,7 +639,7 @@ void SvXMLNumFmtExport::WriteNumberElement_Impl( } void SvXMLNumFmtExport::WriteScientificElement_Impl( - sal_Int32 nDecimals, sal_Int32 nInteger, + sal_Int32 nDecimals, sal_Int32 nMinDecimals, sal_Int32 nInteger, bool bGrouping, sal_Int32 nExp, sal_Int32 nExpInterval, bool bExpSign ) { FinishTextElement_Impl(); @@ -645,6 +651,12 @@ void SvXMLNumFmtExport::WriteScientificElement_Impl( OUString::number( nDecimals ) ); } + if ( nMinDecimals >= 0 ) // negative = automatic + { + rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_MIN_DECIMAL_DIGITS, + OUString::number( nMinDecimals ) ); + } + // integer digits if ( nInteger >= 0 ) // negative = automatic { @@ -1154,7 +1166,7 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt if ( eBuiltIn == NF_NUMBER_STANDARD ) { // default number format contains just one number element - WriteNumberElement_Impl( -1, 1, OUString(), false, false, 0, aEmbeddedEntries ); + WriteNumberElement_Impl( -1, -1, 1, OUString(), false, 0, aEmbeddedEntries ); bAnyContent = true; } else if ( eBuiltIn == NF_BOOLEAN ) @@ -1168,7 +1180,6 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt // first loop to collect attributes bool bDecDashes = false; - bool bVarDecimals = false; bool bExpFound = false; bool bCurrFound = false; bool bInInteger = true; @@ -1176,6 +1187,7 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt sal_Int32 nExpDigits = 0; sal_Int32 nIntegerSymbols = 0; // for embedded-text, including "#" sal_Int32 nTrailingThousands = 0; // thousands-separators after all digits + sal_Int32 nMinDecimals = nPrecision; OUString sCurrExt; OUString aCalendar; sal_uInt16 nPos = 0; @@ -1195,11 +1207,12 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt nExpDigits += pElemStr->getLength(); else if ( !bDecDashes && pElemStr && (*pElemStr)[0] == '-' ) bDecDashes = true; - else if ( !bVarDecimals && !bInInteger && pElemStr && (*pElemStr)[0] == '#' ) + else if ( !bInInteger && pElemStr ) { - // If the decimal digits string starts with a '#', variable - // decimals is assumed (for 0.###, but not 0.0##). - bVarDecimals = true; + for ( sal_Int32 i = pElemStr->getLength()-1; i >= 0 && (*pElemStr)[i] == '#'; i-- ) + { + nMinDecimals --; + } } if ( bInInteger && pElemStr ) nIntegerSymbols += pElemStr->getLength(); @@ -1352,7 +1365,7 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt } break; case NF_KEY_GENERAL : - WriteNumberElement_Impl( -1, 1, OUString(), false, false, 0, aEmbeddedEntries ); + WriteNumberElement_Impl( -1, -1, 1, OUString(), false, 0, aEmbeddedEntries ); break; case NF_KEY_CCC: if (pElemStr) @@ -1419,8 +1432,8 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt if (bDecDashes && nPrecision > 0) comphelper::string::padToLength(sDashStr, nPrecision, '-'); - WriteNumberElement_Impl(nDecimals, nInteger, sDashStr.makeStringAndClear(), - bVarDecimals, bThousand, nTrailingThousands, aEmbeddedEntries); + WriteNumberElement_Impl(nDecimals, nMinDecimals, nInteger, sDashStr.makeStringAndClear(), + bThousand, nTrailingThousands, aEmbeddedEntries); bAnyContent = true; } break; @@ -1428,7 +1441,7 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt // #i43959# for scientific numbers, count all integer symbols ("0" and "#") // as integer digits: use nIntegerSymbols instead of nLeading // nIntegerSymbols represents exponent interval (for engineering notation) - WriteScientificElement_Impl( nPrecision, nLeading, bThousand, nExpDigits, nIntegerSymbols, bExpSign ); + WriteScientificElement_Impl( nPrecision, nMinDecimals, nLeading, bThousand, nExpDigits, nIntegerSymbols, bExpSign ); bAnyContent = true; break; case css::util::NumberFormat::FRACTION: diff --git a/xmloff/source/style/xmlnumfi.cxx b/xmloff/source/style/xmlnumfi.cxx index 02f31cd98a04..d5a44c37d84e 100644 --- a/xmloff/source/style/xmlnumfi.cxx +++ b/xmloff/source/style/xmlnumfi.cxx @@ -114,17 +114,18 @@ struct SvXMLNumberInfo sal_Int32 nNumerDigits; sal_Int32 nDenomDigits; sal_Int32 nFracDenominator; + sal_Int32 nMinDecimalDigits; bool bGrouping; bool bDecReplace; - bool bVarDecimals; bool bExpSign; double fDisplayFactor; SvXMLEmbeddedElementArr aEmbeddedElements; SvXMLNumberInfo() { - nDecimals = nInteger = nExpDigits = nExpInterval = nNumerDigits = nDenomDigits = nFracDenominator = -1; - bGrouping = bDecReplace = bVarDecimals = false; + nDecimals = nInteger = nExpDigits = nExpInterval = nNumerDigits = nDenomDigits = + nFracDenominator = nMinDecimalDigits = -1; + bGrouping = bDecReplace = false; bExpSign = true; fDisplayFactor = 1.0; } @@ -273,6 +274,7 @@ enum SvXMLStyleAttrTokens enum SvXMLStyleElemAttrTokens { XML_TOK_ELEM_ATTR_DECIMAL_PLACES, + XML_TOK_ELEM_ATTR_MIN_DECIMAL_DIGITS, XML_TOK_ELEM_ATTR_MIN_INTEGER_DIGITS, XML_TOK_ELEM_ATTR_GROUPING, XML_TOK_ELEM_ATTR_DISPLAY_FACTOR, @@ -570,6 +572,7 @@ const SvXMLTokenMap& SvXMLNumImpData::GetStyleElemAttrTokenMap() { // attributes for an element within a style { XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES, XML_TOK_ELEM_ATTR_DECIMAL_PLACES }, + { XML_NAMESPACE_LO_EXT, XML_MIN_DECIMAL_DIGITS, XML_TOK_ELEM_ATTR_MIN_DECIMAL_DIGITS }, { XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS, XML_TOK_ELEM_ATTR_MIN_INTEGER_DIGITS }, { XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TOK_ELEM_ATTR_GROUPING }, { XML_NAMESPACE_NUMBER, XML_DISPLAY_FACTOR, XML_TOK_ELEM_ATTR_DISPLAY_FACTOR }, @@ -924,6 +927,7 @@ SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport, LanguageTagODF aLanguageTagODF; sal_Int32 nAttrVal; bool bAttrBool(false); + bool bVarDecimals = false; sal_uInt16 nAttrEnum; double fAttrDouble; @@ -944,6 +948,10 @@ SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport, if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 )) aNumInfo.nDecimals = std::min(nAttrVal, MAX_SECOND_DIGITS); break; + case XML_TOK_ELEM_ATTR_MIN_DECIMAL_DIGITS: + if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 )) + aNumInfo.nMinDecimalDigits = nAttrVal; + break; case XML_TOK_ELEM_ATTR_MIN_INTEGER_DIGITS: if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 )) aNumInfo.nInteger = nAttrVal; @@ -960,7 +968,7 @@ SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport, if ( !sValue.isEmpty() ) aNumInfo.bDecReplace = true; // only a default string is supported else - aNumInfo.bVarDecimals = true; // empty replacement string: variable decimals + bVarDecimals = true; // empty replacement string: variable decimals break; case XML_TOK_ELEM_ATTR_MIN_EXPONENT_DIGITS: if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 )) @@ -1011,6 +1019,13 @@ SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport, break; } } + if ( aNumInfo.nMinDecimalDigits == -1) + { + if ( bVarDecimals ) + aNumInfo.nMinDecimalDigits = 0; + else + aNumInfo.nMinDecimalDigits = aNumInfo.nDecimals; + } if ( !aLanguageTagODF.isEmpty() ) { @@ -1799,7 +1814,9 @@ void SvXMLNumFormatContext::AddNumber( const SvXMLNumberInfo& rInfo ) } sal_uInt16 nGenPrec = nPrec; - if ( rInfo.bDecReplace || rInfo.bVarDecimals ) + if ( rInfo.nMinDecimalDigits >= 0 ) + nGenPrec = rInfo.nMinDecimalDigits; + if ( rInfo.bDecReplace ) nGenPrec = 0; // generate format without decimals... bool bGrouping = rInfo.bGrouping; @@ -1892,13 +1909,14 @@ void SvXMLNumFormatContext::AddNumber( const SvXMLNumberInfo& rInfo ) aFormatCode.append( aNumStr.makeStringAndClear() ); - if ( ( rInfo.bDecReplace || rInfo.bVarDecimals ) && nPrec ) // add decimal replacement (dashes) + if ( ( rInfo.bDecReplace || rInfo.nMinDecimalDigits < rInfo.nDecimals ) && nPrec ) // add decimal replacement (dashes) { // add dashes for explicit decimal replacement, # for variable decimals sal_Unicode cAdd = rInfo.bDecReplace ? '-' : '#'; - aFormatCode.append( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() ); - for ( sal_uInt16 i=0; iGetLocaleData( nFormatLang ).getNumDecimalSep() ); + for ( sal_uInt16 i=rInfo.nMinDecimalDigits; i