From 56dff7b244fb0ef28951193a410dd5c4a3126590 Mon Sep 17 00:00:00 2001 From: Laurent BP Date: Mon, 16 May 2022 22:47:25 +0200 Subject: tdf#96723 Number format: embedded text in decimal Embedded text in decimal part is represented by negative position Use number:position as it is defined as integer in schema [1] Add Unit test to import XLSX file with embedded text in decimal and export to ODS [1] https://opengrok.libreoffice.org/xref/core/schema/odf1.3/OpenDocument-v1.3-schema.rng?r=7f3c9da5#7142 Change-Id: Ic68471a071ccbb1c3bec442bfcbe21d84f41ebd8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135918 Tested-by: Jenkins Reviewed-by: Eike Rathke --- xmloff/source/style/xmlnumfe.cxx | 13 +++++++++++-- xmloff/source/style/xmlnumfi.cxx | 32 ++++++++++++++++---------------- 2 files changed, 27 insertions(+), 18 deletions(-) (limited to 'xmloff') diff --git a/xmloff/source/style/xmlnumfe.cxx b/xmloff/source/style/xmlnumfe.cxx index c4350c0db795..abf03285f818 100644 --- a/xmloff/source/style/xmlnumfe.cxx +++ b/xmloff/source/style/xmlnumfe.cxx @@ -603,6 +603,8 @@ void SvXMLNumFmtExport::WriteNumberElement_Impl( const SvXMLEmbeddedTextEntry *const pObj = &rEmbeddedEntries[nEntry]; // position attribute + // position == 0 is between first integer digit and decimal separator + // position < 0 is inside decimal part rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_POSITION, OUString::number( pObj->nFormatPos ) ); SvXMLElementExport aChildElem( rExport, XML_NAMESPACE_NUMBER, XML_EMBEDDED_TEXT, @@ -1389,6 +1391,10 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt if ( bAllowEmbedded ) { sal_Int32 nDigitsPassed = 0; + sal_Int32 nEmbeddedPositionsMax = nIntegerSymbols; + // Enable embedded text in decimal part only if there's a decimal part + if ( nPrecision ) + nEmbeddedPositionsMax += nPrecision + 1; nPos = 0; bEnd = false; while (!bEnd) @@ -1405,12 +1411,15 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt if ( pElemStr ) nDigitsPassed += pElemStr->getLength(); break; + case NF_SYMBOLTYPE_DECSEP: + nDigitsPassed++; + break; case NF_SYMBOLTYPE_STRING: case NF_SYMBOLTYPE_BLANK: case NF_SYMBOLTYPE_PERCENT: - if ( nDigitsPassed > 0 && nDigitsPassed < nIntegerSymbols && pElemStr ) + if ( 0 < nDigitsPassed && nDigitsPassed < nEmbeddedPositionsMax && pElemStr ) { - // text (literal or underscore) within the integer part of a number:number element + // text (literal or underscore) within the integer (>=0) or decimal (<0) part of a number:number element OUString aEmbeddedStr; if ( nElemType == NF_SYMBOLTYPE_STRING || nElemType == NF_SYMBOLTYPE_PERCENT ) diff --git a/xmloff/source/style/xmlnumfi.cxx b/xmloff/source/style/xmlnumfi.cxx index 618232990c96..bedd13bebcf6 100644 --- a/xmloff/source/style/xmlnumfi.cxx +++ b/xmloff/source/style/xmlnumfi.cxx @@ -457,7 +457,7 @@ SvXMLNumFmtEmbeddedTextContext::SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rIm { if ( aIter.getToken() == XML_ELEMENT(NUMBER, XML_POSITION) ) { - if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView() )) nTextPosition = nAttrVal; } else @@ -1707,8 +1707,8 @@ void SvXMLNumFormatContext::AddNumber( const SvXMLNumberInfo& rInfo ) bool bGrouping = rInfo.bGrouping; size_t const nEmbeddedCount = rInfo.m_EmbeddedElements.size(); - if ( nEmbeddedCount ) - bGrouping = false; // grouping and embedded characters can't be used together + if ( nEmbeddedCount && rInfo.m_EmbeddedElements.rbegin()->first > 0 ) + bGrouping = false; // grouping and embedded characters in integer part can't be used together sal_uInt32 nStdIndex = pFormatter->GetStandardIndex( nFormatLang ); OUStringBuffer aNumStr(pFormatter->GenerateFormat( nStdIndex, nFormatLang, @@ -1746,10 +1746,21 @@ void SvXMLNumFormatContext::AddNumber( const SvXMLNumberInfo& rInfo ) } } + if ( ( rInfo.bDecReplace || rInfo.nMinDecimalDigits < rInfo.nDecimals ) && nPrec ) // add decimal replacement (dashes) + { + // add dashes for explicit decimal replacement, # or ? for variable decimals + sal_Unicode cAdd = rInfo.bDecReplace ? '-' : ( rInfo.bDecAlign ? '?': '#' ); + + if ( rInfo.nMinDecimalDigits == 0 ) + aNumStr.append( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() ); + for ( sal_uInt16 i=rInfo.nMinDecimalDigits; i=0) and decimal (position <0) part // nZeroPos is the string position where format position 0 is inserted sal_Int32 nZeroPos = aNumStr.indexOf( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() ); @@ -1778,7 +1789,7 @@ void SvXMLNumFormatContext::AddNumber( const SvXMLNumberInfo& rInfo ) { sal_Int32 const nFormatPos = it.first; sal_Int32 nInsertPos = nZeroPos - nFormatPos; - if ( nFormatPos >= 0 && nInsertPos >= 0 ) + if ( nInsertPos >= 0 ) { // #107805# always quote embedded strings - even space would otherwise // be recognized as thousands separator in French. @@ -1792,17 +1803,6 @@ void SvXMLNumFormatContext::AddNumber( const SvXMLNumberInfo& rInfo ) aFormatCode.append( aNumStr ); - if ( ( rInfo.bDecReplace || rInfo.nMinDecimalDigits < rInfo.nDecimals ) && nPrec ) // add decimal replacement (dashes) - { - // add dashes for explicit decimal replacement, # or ? for variable decimals - sal_Unicode cAdd = rInfo.bDecReplace ? '-' : ( rInfo.bDecAlign ? '?': '#' ); - - if ( rInfo.nMinDecimalDigits == 0 ) - aFormatCode.append( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() ); - for ( sal_uInt16 i=rInfo.nMinDecimalDigits; i