sw/qa/extras/ooxmlexport/data/custom-styles-TOC-semicolon.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport17.cxx | 24 ++++++++ sw/source/filter/ww8/ww8atr.cxx | 27 ++++++++-- writerfilter/source/dmapper/DomainMapper_Impl.cxx | 7 +- 4 files changed, 51 insertions(+), 7 deletions(-)
New commits: commit 5b8de6f5e19b4b85e9d13d86aa71ee6b7adae5f3 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Wed Jan 18 11:56:30 2023 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Thu Jan 19 12:43:48 2023 +0000 tdf#153082 writerfilter,sw: import/export locale-dependent TOC ... ... \t style name separators. OOXML says in 17.16.5.68 TOC: \t field-argument Uses paragraphs formatted with styles other than the built-in heading styles. text in this switch's field-argument specifies those styles as a set of comma-separated doublets, with each doublet being a comma-separated set of style name and table of content level. The reality is documented in Word online help: https://support.microsoft.com/en-us/office/field-codes-toc-table-of-contents-field-1f538bc4-60e6-4854-9f64-67754d78d05c?ui=en-US&rs=en-US&ad=US Note: Syntax shown here uses a comma (,) between the Style and Level parameters. A semicolon (;) is also valid, depending on which character is specified as the list separator in your operating system's regional and language settings. Because of language-specific dependencies, we recommend not using the \t switch in templates or documents that are intended for users across multiple language configurations. It's easy enough to recognize both ',' and ';' as separators on import, and unlikely that anybody would use these characters inside a style name; for export, both can't be written and a decision must be made. So do the same thing on export as Word does, assuming most document exchange is between users in the same locale; currently only for "de" locales but more can be added. Interestingly WW8 used to write ';' before 2009 when CWS hb32bugs01 changed it to ','. Change-Id: I2dcfdd009f448f6fae37cbd28929d0bbe504acf9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145744 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit 7b62d09090e5172e26141694fb97bc27562a81ce) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145722 Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/qa/extras/ooxmlexport/data/custom-styles-TOC-semicolon.docx b/sw/qa/extras/ooxmlexport/data/custom-styles-TOC-semicolon.docx new file mode 100644 index 000000000000..bef835c9bb46 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/custom-styles-TOC-semicolon.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx index b216e14d22fe..0e000bff9641 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx @@ -702,6 +702,30 @@ DECLARE_OOXMLEXPORT_TEST(testTdf148361, "tdf148361.docx") CPPUNIT_ASSERT_EQUAL(OUString("[Type text]"), aActual); } +DECLARE_OOXMLEXPORT_TEST(testTdf153082_semicolon, "custom-styles-TOC-semicolon.docx") +{ + uno::Reference<text::XDocumentIndexesSupplier> xIndexSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<container::XIndexAccess> xIndexes = xIndexSupplier->getDocumentIndexes(); + uno::Reference<text::XDocumentIndex> xTOC(xIndexes->getByIndex(0), uno::UNO_QUERY); + // check styles + uno::Reference<container::XIndexAccess> xParaStyles = + getProperty<uno::Reference<container::XIndexAccess>>(xTOC, "LevelParagraphStyles"); + uno::Sequence<OUString> styles; + xParaStyles->getByIndex(0) >>= styles; + CPPUNIT_ASSERT_EQUAL(uno::Sequence<OUString>{}, styles); + xParaStyles->getByIndex(1) >>= styles; + CPPUNIT_ASSERT_EQUAL(uno::Sequence<OUString>{}, styles); + xParaStyles->getByIndex(2) >>= styles; + // the first one is built-in Word style that was localised DE "Intensives Zitat" in the file + CPPUNIT_ASSERT_EQUAL((uno::Sequence<OUString>{"Intense Quote", "Custom1", "_MyStyle0"}), styles); + xTOC->update(); + OUString const tocContent(xTOC->getAnchor()->getString()); + CPPUNIT_ASSERT(tocContent.startsWith("Table of Contents")); + CPPUNIT_ASSERT(tocContent.indexOf("Lorem ipsum dolor sit amet, consectetuer adipiscing elit.") != -1); + CPPUNIT_ASSERT(tocContent.indexOf("Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.") != -1); + CPPUNIT_ASSERT(tocContent.indexOf("Proin pharetra nonummy pede. Mauris et orci.") != -1); +} + DECLARE_OOXMLEXPORT_TEST(testTdf153082_comma, "custom-styles-TOC-comma.docx") { uno::Reference<text::XDocumentIndexesSupplier> xIndexSupplier(mxComponent, uno::UNO_QUERY); diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx index d0bed9c5c5bf..301b46e86319 100644 --- a/sw/source/filter/ww8/ww8atr.cxx +++ b/sw/source/filter/ww8/ww8atr.cxx @@ -138,6 +138,7 @@ #include "ww8par.hxx" #include "ww8attributeoutput.hxx" #include "fields.hxx" +#include <i18nlangtag/mslangid.hxx> #include <i18nlangtag/languagetag.hxx> #include <unotools/fltrcfg.hxx> @@ -2252,6 +2253,21 @@ void AttributeOutputBase::GenerateBookmarksForSequenceField(const SwTextNode& rN } } +static auto GetSeparatorForLocale() -> OUString +{ + switch (sal_uInt16(MsLangId::getSystemLanguage())) + { + case sal_uInt16(LANGUAGE_GERMAN): + case sal_uInt16(LANGUAGE_GERMAN_AUSTRIAN): + case sal_uInt16(LANGUAGE_GERMAN_LIECHTENSTEIN): + case sal_uInt16(LANGUAGE_GERMAN_LUXEMBOURG): + case sal_uInt16(LANGUAGE_GERMAN_SWISS): + return ";"; + default: + return ","; + } +} + void AttributeOutputBase::StartTOX( const SwSection& rSect ) { if ( const SwTOXBase* pTOX = rSect.GetTOXBase() ) @@ -2361,6 +2377,9 @@ void AttributeOutputBase::StartTOX( const SwSection& rSect ) sStr = FieldString(eCode); OUString sTOption; + // tdf#153082 Word's separator interpretation in DOCX + // fields varies by system locale. + auto const tsep(GetSeparatorForLocale()); sal_uInt16 n, nTOXLvl = pTOX->GetLevel(); if( !nTOXLvl ) ++nTOXLvl; @@ -2462,8 +2481,8 @@ void AttributeOutputBase::StartTOX( const SwSection& rSect ) if (nTestLvl < nTOXLvl && nTestLvl >= nMaxMSAutoEvaluate) { if (!sTOption.isEmpty()) - sTOption += ","; - sTOption += pColl->GetName() + "," + OUString::number( nTestLvl + 1 ); + sTOption += tsep; + sTOption += pColl->GetName() + tsep + OUString::number(nTestLvl + 1); } } } @@ -2483,7 +2502,7 @@ void AttributeOutputBase::StartTOX( const SwSection& rSect ) if( !rStyles.isEmpty() ) { sal_Int32 nPos = 0; - const OUString sLvl{ "," + OUString::number( n + 1 ) }; + const OUString sLvl{tsep + OUString::number(n + 1)}; do { const OUString sStyle( rStyles.getToken( 0, TOX_STYLE_DELIMITER, nPos )); if( !sStyle.isEmpty() ) @@ -2494,7 +2513,7 @@ void AttributeOutputBase::StartTOX( const SwSection& rSect ) if (!pColl->IsAssignedToListLevelOfOutlineStyle() || pColl->GetAssignedOutlineStyleLevel() < nTOXLvl) { if( !sTOption.isEmpty() ) - sTOption += ","; + sTOption += tsep; sTOption += sStyle + sLvl; } } diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 3f33280f5a22..21ee55444ca6 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -6255,13 +6255,14 @@ void DomainMapper_Impl::handleToc TOCStyleMap aMap; sal_Int32 nLevel; sal_Int32 nPosition = 0; + auto const tsep(sTemplate.indexOf(',') != -1 ? ',' : ';'); while( nPosition >= 0) { - OUString sStyleName = sTemplate.getToken( 0, ',', nPosition ); + OUString sStyleName = sTemplate.getToken(0, tsep, nPosition); //empty tokens should be skipped while( sStyleName.isEmpty() && nPosition > 0 ) - sStyleName = sTemplate.getToken( 0, ',', nPosition ); - nLevel = o3tl::toInt32(o3tl::getToken(sTemplate, 0, ',', nPosition )); + sStyleName = sTemplate.getToken(0, tsep, nPosition); + nLevel = o3tl::toInt32(o3tl::getToken(sTemplate, 0, tsep, nPosition )); if( !nLevel ) nLevel = 1; if( !sStyleName.isEmpty() )