sw/qa/extras/ooxmlexport/data/WordOK.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport22.cxx | 18 ++++++ sw/source/core/doc/number.cxx | 75 ++++++++++++++++++++--------- 3 files changed, 71 insertions(+), 22 deletions(-)
New commits: commit 1db81743594f7b858ff4d17c80a7366adee2b3fe Author: Michael Stahl <michael.st...@collabora.com> AuthorDate: Wed Jun 25 14:00:22 2025 +0200 Commit: Michael Stahl <michael.st...@collabora.com> CommitDate: Thu Jul 10 14:51:02 2025 +0200 tdf#166975 sw: fix expansion of list level format with repeated levels SwNumRule::MakeNumString() would only replace each level's placeholder once in the format string; rework this so it iterates the whole format string. Change-Id: I1d0c5bf5c60c3003cc0257acfb69b37d209be617 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/186977 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> (cherry picked from commit e200c729797e7f3c19e958f9796a1d0fbae829d1) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/187020 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@collabora.com> diff --git a/sw/qa/extras/ooxmlexport/data/WordOK.docx b/sw/qa/extras/ooxmlexport/data/WordOK.docx new file mode 100644 index 000000000000..19fb0c9f5665 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/WordOK.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx index 08e086856381..fedacb31d54b 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx @@ -73,6 +73,24 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf166201_simplePosCM) getProperty<sal_Int32>(getShape(1), u"VertOrientPosition"_ustr)); } +CPPUNIT_TEST_FIXTURE(Test, testTdf166975) +{ + loadAndSave("WordOK.docx"); + + CPPUNIT_ASSERT_EQUAL(u"a)"_ustr, + getProperty<OUString>(getParagraph(2), u"ListLabelString"_ustr)); + // this was a%6%) + CPPUNIT_ASSERT_EQUAL(u"aa)"_ustr, + getProperty<OUString>(getParagraph(3), u"ListLabelString"_ustr)); + // this was a%7%%7%) + CPPUNIT_ASSERT_EQUAL(u"aaa)"_ustr, + getProperty<OUString>(getParagraph(4), u"ListLabelString"_ustr)); + CPPUNIT_ASSERT_EQUAL(u"bbb)"_ustr, + getProperty<OUString>(getParagraph(5), u"ListLabelString"_ustr)); + CPPUNIT_ASSERT_EQUAL(u"ccc)"_ustr, + getProperty<OUString>(getParagraph(6), u"ListLabelString"_ustr)); +} + CPPUNIT_TEST_FIXTURE(Test, testTdf165492_exactWithBottomSpacing) { // Given a document with "exact row height" of 2cm diff --git a/sw/source/core/doc/number.cxx b/sw/source/core/doc/number.cxx index 4eec424907a4..61ae291a536a 100644 --- a/sw/source/core/doc/number.cxx +++ b/sw/source/core/doc/number.cxx @@ -773,13 +773,43 @@ OUString SwNumRule::MakeNumString( const SwNumberTree::tNumberVector & rNumVecto // In this case we are ignoring GetIncludeUpperLevels: we put all // level numbers requested by level format - for (SwNumberTree::tNumberVector::size_type i=0; i <= nLevel; ++i) + for (sal_Int32 nPosition{0}; nPosition < sLevelFormat.getLength() - 2;) { - OUString sReplacement; - const SwNumFormat& rNFormat = Get(i); + if (sLevelFormat[nPosition] != '%') + { + ++nPosition; + continue; + } + SwNumberTree::tNumberVector::size_type nReplaceLevel; + decltype(nPosition) nEndPosition; + if (sLevelFormat[nPosition+1] == '1' + && sLevelFormat[nPosition+2] == '0' + && (nPosition+3) < sLevelFormat.getLength() + && sLevelFormat[nPosition+3] == '%') + { + nReplaceLevel = 9; // special case %10% + nEndPosition = nPosition + 4; + } + else if (sLevelFormat[nPosition+2] == '%' + && '1' <= sLevelFormat[nPosition+1] + && sLevelFormat[nPosition+1] <= '9') + { + nReplaceLevel = sLevelFormat[nPosition+1] - '1'; // need to subtract 1 + nEndPosition = nPosition + 3; + } + else + { + ++nPosition; + continue; // ignore it + } + if (nLevel < nReplaceLevel) + { + nPosition = nEndPosition; + // there is no number to insert - in this case Word 2013 + continue; // shows no label at all, we just skip it + } - OUString sFind("%" + OUString::number(i + 1) + "%"); - sal_Int32 nPosition = sLevelFormat.indexOf(sFind); + SwNumFormat const& rNFormat{Get(nReplaceLevel)}; if (rNFormat.GetNumberingType() == SVX_NUM_NUMBER_NONE) { @@ -789,37 +819,38 @@ OUString SwNumRule::MakeNumString( const SwNumberTree::tNumberVector & rNumVecto // NOTE: if changed, fix MSWordExportBase::NumberingLevel to match new behaviour. - sal_Int32 nPositionNext = sLevelFormat.indexOf('%', nPosition + sFind.getLength()); - if (nPosition >= 0 && nPositionNext > nPosition) + sal_Int32 const nPositionNext{sLevelFormat.indexOf('%', nEndPosition)}; + if (nPositionNext > nPosition) { sLevelFormat = sLevelFormat.replaceAt(nPosition, nPositionNext - nPosition, u""); } continue; } - else if (rNumVector[i]) - sReplacement = Get(i).GetNumStr(rNumVector[i], aLocale, rMyNFormat.GetIsLegal()); + + OUString sReplacement; + if (rNumVector[nReplaceLevel]) + sReplacement = rNFormat.GetNumStr(rNumVector[nReplaceLevel], aLocale, rMyNFormat.GetIsLegal()); else sReplacement = "0"; // all 0 level are a 0 - if (nPosition >= 0) + sLevelFormat = sLevelFormat.replaceAt(nPosition, nEndPosition - nPosition, sReplacement); + nPosition += sReplacement.getLength(); + + if (bHideNonNumerical) { - if (bHideNonNumerical) - { - sal_Int32 nPositionNext = sLevelFormat.indexOf('%', nPosition + sFind.getLength()); + sal_Int32 const nPositionNext{sLevelFormat.indexOf('%', nPosition)}; - if (nPositionNext >= nPosition) { - sal_Int32 nReplaceStart = nPosition + sFind.getLength(); - sal_Int32 nReplaceCount = nPositionNext - nReplaceStart; + if (nPosition < nPositionNext) + { + sal_Int32 nReplaceCount = nPositionNext - nPosition; - OUString sSeparator = sLevelFormat.copy(nReplaceStart, nReplaceCount); - StripNonDelimiter(sSeparator); + OUString sSeparator = sLevelFormat.copy(nPosition, nReplaceCount); + StripNonDelimiter(sSeparator); - sLevelFormat = sLevelFormat.replaceAt(nReplaceStart, nReplaceCount, sSeparator); - } + sLevelFormat = sLevelFormat.replaceAt(nPosition, nReplaceCount, sSeparator); } - - sLevelFormat = sLevelFormat.replaceAt(nPosition, sFind.getLength(), sReplacement); } + } aStr = sLevelFormat;