diff options
-rw-r--r-- | include/xmloff/xmlnumfe.hxx | 3 | ||||
-rw-r--r-- | include/xmloff/xmlnumfi.hxx | 2 | ||||
-rw-r--r-- | xmloff/source/style/xmlnumfe.cxx | 16 | ||||
-rw-r--r-- | xmloff/source/style/xmlnumfi.cxx | 20 |
4 files changed, 37 insertions, 4 deletions
diff --git a/include/xmloff/xmlnumfe.hxx b/include/xmloff/xmlnumfe.hxx index 98584ac93873..28bfe8d1a2ad 100644 --- a/include/xmloff/xmlnumfe.hxx +++ b/include/xmloff/xmlnumfe.hxx @@ -50,7 +50,8 @@ private: SvXMLExport& rExport; OUString sPrefix; SvNumberFormatter* pFormatter; - OUStringBuffer sTextContent; + OUStringBuffer sTextContent; + bool bHasText; std::unique_ptr<SvXMLNumUsedList_Impl> pUsedList; std::unique_ptr<CharClass> pCharClass; std::unique_ptr<LocaleDataWrapper> pLocaleData; diff --git a/include/xmloff/xmlnumfi.hxx b/include/xmloff/xmlnumfi.hxx index 0f6384f3b785..8026b4e1846b 100644 --- a/include/xmloff/xmlnumfi.hxx +++ b/include/xmloff/xmlnumfi.hxx @@ -145,6 +145,7 @@ private: bool bAutoDec; // set in AddNumber bool bAutoInt; // set in AddNumber bool bHasExtraText; + bool bHasTrailingEmptyText; OUStringBuffer aFormatCode{64}; OUStringBuffer aConditions{32}; bool bHasLongDoW; @@ -189,6 +190,7 @@ public: bool HasLongDoW() const { return bHasLongDoW; } void SetHasLongDoW(bool bSet) { bHasLongDoW = bSet; } + void SetHasTrailingEmptyText(bool bSet) { bHasTrailingEmptyText = bSet; } void UpdateCalendar( const OUString& rNewCalendar ); ImplicitCalendar GetImplicitCalendarState() const { return eImplicitCalendar; } diff --git a/xmloff/source/style/xmlnumfe.cxx b/xmloff/source/style/xmlnumfe.cxx index 2695a84fa38b..caba160252f3 100644 --- a/xmloff/source/style/xmlnumfe.cxx +++ b/xmloff/source/style/xmlnumfe.cxx @@ -210,7 +210,8 @@ SvXMLNumFmtExport::SvXMLNumFmtExport( const uno::Reference< util::XNumberFormatsSupplier >& rSupp ) : rExport( rExp ), sPrefix( OUString("N") ), - pFormatter( nullptr ) + pFormatter( nullptr ), + bHasText( false ) { // supplier must be SvNumberFormatsSupplierObj SvNumberFormatsSupplierObj* pObj = @@ -242,7 +243,8 @@ SvXMLNumFmtExport::SvXMLNumFmtExport( const OUString& rPrefix ) : rExport( rExp ), sPrefix( rPrefix ), - pFormatter( nullptr ) + pFormatter( nullptr ), + bHasText( false ) { // supplier must be SvNumberFormatsSupplierObj SvNumberFormatsSupplierObj* pObj = @@ -320,16 +322,21 @@ void SvXMLNumFmtExport::AddToTextElement_Impl( std::u16string_view rString ) // to avoid several text elements following each other sTextContent.append( rString ); + // Also empty string leads to a number:text element as it may separate + // keywords of the same letter (e.g. MM""MMM) that otherwise would be + // concatenated when reading back in. + bHasText = true; } void SvXMLNumFmtExport::FinishTextElement_Impl(bool bUseExtensionNS) { - if ( !sTextContent.isEmpty() ) + if ( bHasText ) { sal_uInt16 nNS = bUseExtensionNS ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER; SvXMLElementExport aElem( rExport, nNS, XML_TEXT, true, false ); rExport.Characters( sTextContent.makeStringAndClear() ); + bHasText = false; } } @@ -1415,6 +1422,8 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt { case 0: bEnd = true; // end of format reached + if (bHasText && sTextContent.isEmpty()) + bHasText = false; // don't write trailing empty text break; case NF_SYMBOLTYPE_STRING: case NF_SYMBOLTYPE_DATESEP: @@ -1463,6 +1472,7 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt break; case NF_KEY_GENERAL : WriteNumberElement_Impl( -1, -1, 1, OUString(), false, 0, aEmbeddedEntries ); + bAnyContent = true; break; case NF_KEY_CCC: if (pElemStr) diff --git a/xmloff/source/style/xmlnumfi.cxx b/xmloff/source/style/xmlnumfi.cxx index 863a9f55d2cb..121831c395bf 100644 --- a/xmloff/source/style/xmlnumfi.cxx +++ b/xmloff/source/style/xmlnumfi.cxx @@ -878,6 +878,13 @@ void SvXMLNumFmtElementContext::endFastElement(sal_Int32 ) lcl_EnquoteIfNecessary( aContent, rParent ); rParent.AddToCode( aContent.makeStringAndClear() ); } + else + { + // Quoted empty text may be significant to separate. + aContent.append("\"\""); + rParent.AddToCode( aContent.makeStringAndClear() ); + rParent.SetHasTrailingEmptyText(true); // *after* AddToCode() + } break; case SvXMLStyleTokens::Number: @@ -1131,6 +1138,7 @@ SvXMLNumFormatContext::SvXMLNumFormatContext( SvXMLImport& rImport, bAutoDec( false ), bAutoInt( false ), bHasExtraText( false ), + bHasTrailingEmptyText( false ), bHasLongDoW( false ), bHasDateTime( false ), bRemoveAfterUse( false ), @@ -1267,6 +1275,7 @@ SvXMLNumFormatContext::SvXMLNumFormatContext( SvXMLImport& rImport, bAutoDec( false ), bAutoInt( false ), bHasExtraText( false ), + bHasTrailingEmptyText( false ), bHasLongDoW( false ), bHasDateTime( false ), bRemoveAfterUse( false ), @@ -1486,12 +1495,22 @@ sal_Int32 SvXMLNumFormatContext::CreateAndInsert(SvNumberFormatter* pFormatter) } } + sal_Int32 nBufLen; if ( aFormatCode.isEmpty() ) { // insert empty format as empty string (with quotes) // #93901# this check has to be done before inserting the conditions aFormatCode.append("\"\""); // "" } + else if (bHasTrailingEmptyText && (nBufLen = aFormatCode.getLength()) >= 3) + { + // Remove a trailing empty text. Earlier this may had been written to + // file, like in "General;General" written with elements for + // 'General"";General""' (whyever); when reading, empty text was + // ignored, which it isn't anymore, so get rid of those. + if (aFormatCode[nBufLen-1] == '"' && aFormatCode[nBufLen-2] == '"') + aFormatCode.truncate( nBufLen - 2); + } aFormatCode.insert( 0, aConditions.makeStringAndClear() ); OUString sFormat = aFormatCode.makeStringAndClear(); @@ -1631,6 +1650,7 @@ void SvXMLNumFormatContext::AddToCode( std::u16string_view rString ) { aFormatCode.append( rString ); bHasExtraText = true; + bHasTrailingEmptyText = false; // is set by caller again if so } void SvXMLNumFormatContext::AddNumber( const SvXMLNumberInfo& rInfo ) |