diff --git a/sw/qa/extras/ooxmlimport/ooxmlimport2.cxx b/sw/qa/extras/ooxmlimport/ooxmlimport2.cxx index ba97147876e7..c12c5deeac1c 100644 --- a/sw/qa/extras/ooxmlimport/ooxmlimport2.cxx +++ b/sw/qa/extras/ooxmlimport/ooxmlimport2.cxx @@ -1050,39 +1050,46 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf154319) CPPUNIT_ASSERT_EQUAL(sal_Int32(11), xLevelFormats->getCount()); const auto checkPropVal = [](const auto& expected, const css::beans::PropertyValues& entry, - const OUString& name) { + const OUString& name, sal_Int32 level) { auto it = std::find_if(entry.begin(), entry.end(), [&name](const css::beans::PropertyValue& p) { return p.Name == name; }); - OString msg = "Property: " + name.toUtf8(); + OString msg = "Property: " + name.toUtf8() + ", level: " + OString::number(level); CPPUNIT_ASSERT_MESSAGE(msg.getStr(), it != entry.end()); CPPUNIT_ASSERT_EQUAL_MESSAGE(msg.getStr(), css::uno::Any(expected), it->Value); }; + // tdf#154360: check tab stops between the number and the entry text + constexpr sal_Int32 levelTabStops[] + = { 776, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270 }; + //start with level 1, 0 is the header level for (sal_Int32 nLevel = 1; nLevel < xLevelFormats->getCount(); ++nLevel) { css::uno::Sequence aLevel; xLevelFormats->getByIndex(nLevel) >>= aLevel; - CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aLevel.getLength()); + CPPUNIT_ASSERT_EQUAL(sal_Int32(9), aLevel.getLength()); - checkPropVal(OUString("TokenHyperlinkStart"), aLevel[0], "TokenType"); + checkPropVal(OUString("TokenHyperlinkStart"), aLevel[0], "TokenType", nLevel); - checkPropVal(OUString("TokenEntryNumber"), aLevel[1], "TokenType"); + checkPropVal(OUString("TokenEntryNumber"), aLevel[1], "TokenType", nLevel); - checkPropVal(OUString("TokenEntryText"), aLevel[2], "TokenType"); + checkPropVal(OUString("TokenTabStop"), aLevel[2], "TokenType", nLevel); + checkPropVal(levelTabStops[nLevel - 1], aLevel[2], "TabStopPosition", nLevel); - checkPropVal(OUString("TokenTabStop"), aLevel[3], "TokenType"); + checkPropVal(OUString("TokenEntryText"), aLevel[3], "TokenType", nLevel); - checkPropVal(OUString("TokenChapterInfo"), aLevel[4], "TokenType"); + checkPropVal(OUString("TokenTabStop"), aLevel[4], "TokenType", nLevel); - checkPropVal(OUString("TokenText"), aLevel[5], "TokenType"); - checkPropVal(OUString("\""), aLevel[5], "Text"); + checkPropVal(OUString("TokenChapterInfo"), aLevel[5], "TokenType", nLevel); - checkPropVal(OUString("TokenPageNumber"), aLevel[6], "TokenType"); + checkPropVal(OUString("TokenText"), aLevel[6], "TokenType", nLevel); + checkPropVal(OUString("\""), aLevel[6], "Text", nLevel); - checkPropVal(OUString("TokenHyperlinkEnd"), aLevel[7], "TokenType"); + checkPropVal(OUString("TokenPageNumber"), aLevel[7], "TokenType", nLevel); + + checkPropVal(OUString("TokenHyperlinkEnd"), aLevel[8], "TokenType", nLevel); } } diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 01e244bd5e87..3f402c50b3ee 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -6073,35 +6073,34 @@ void DomainMapper_Impl::handleAuthor } static uno::Sequence< beans::PropertyValues > lcl_createTOXLevelHyperlinks( bool bHyperlinks, const OUString& sChapterNoSeparator, - const uno::Sequence< beans::PropertyValues >& aLevel ) + const uno::Sequence< beans::PropertyValues >& aLevel, const uno::Sequence& tabs) { //create a copy of the level and add new entries std::vector aNewLevel; - aNewLevel.reserve(aLevel.getLength() + 4); // at most 4 added items + aNewLevel.reserve(aLevel.getLength() + 5); // at most 5 added items static constexpr OUStringLiteral tokType(u"TokenType"); static constexpr OUStringLiteral tokHStart(u"TokenHyperlinkStart"); static constexpr OUStringLiteral tokHEnd(u"TokenHyperlinkEnd"); static constexpr OUStringLiteral tokPNum(u"TokenPageNumber"); + static constexpr OUStringLiteral tokENum(u"TokenEntryNumber"); if (bHyperlinks) aNewLevel.push_back({ comphelper::makePropertyValue(tokType, tokHStart) }); for (const auto& item : aLevel) { - if (bHyperlinks - && std::any_of(item.begin(), item.end(), - [](const css::beans::PropertyValue& p) { - return p.Name == tokType - && (p.Value == tokHStart || p.Value == tokHEnd); - })) + OUString tokenType; + if (auto it = std::find_if(item.begin(), item.end(), + [](const auto& p) { return p.Name == tokType; }); + it != item.end()) + it->Value >>= tokenType; + + if (bHyperlinks && (tokenType == tokHStart || tokenType == tokHEnd)) continue; // We add hyperlink ourselves, so just skip existing hyperlink start / end - if (!sChapterNoSeparator.isEmpty() - && std::any_of(item.begin(), item.end(), - [](const css::beans::PropertyValue& p) - { return p.Name == tokType && p.Value == tokPNum; })) + if (!sChapterNoSeparator.isEmpty() && tokenType == tokPNum) { // This is an existing page number token; insert the chapter and separator before it aNewLevel.push_back( @@ -6112,6 +6111,14 @@ static uno::Sequence< beans::PropertyValues > lcl_createTOXLevelHyperlinks( bool } aNewLevel.push_back(item); + + if (tabs.hasElements() && tokenType == tokENum) + { + // There is a fixed tab stop position needed in the level after the numbering + aNewLevel.push_back( + { comphelper::makePropertyValue(tokType, OUString("TokenTabStop")), + comphelper::makePropertyValue("TabStopPosition", tabs[0].Position) }); + } } if (bHyperlinks) @@ -6464,22 +6471,38 @@ void DomainMapper_Impl::handleToc xTOC->setPropertyValue(getPropertyName(PROP_CREATE_FROM_LEVEL_PARAGRAPH_STYLES), uno::Any( true )); } - if(bHyperlinks || !sChapterNoSeparator.isEmpty()) - { - uno::Reference< container::XIndexReplace> xLevelFormats; - xTOC->getPropertyValue(getPropertyName(PROP_LEVEL_FORMAT)) >>= xLevelFormats; - sal_Int32 nLevelCount = xLevelFormats->getCount(); - //start with level 1, 0 is the header level - for( sal_Int32 nLevel = 1; nLevel < nLevelCount; ++nLevel) - { - uno::Sequence< beans::PropertyValues > aLevel; - xLevelFormats->getByIndex( nLevel ) >>= aLevel; - uno::Sequence< beans::PropertyValues > aNewLevel = lcl_createTOXLevelHyperlinks( - bHyperlinks, sChapterNoSeparator, - aLevel ); - xLevelFormats->replaceByIndex( nLevel, uno::Any( aNewLevel ) ); + uno::Reference xStyles; + if (auto xStylesSupplier = GetTextDocument().query()) + { + auto xStyleFamilies = xStylesSupplier->getStyleFamilies(); + xStyleFamilies->getByName(getPropertyName(PROP_PARAGRAPH_STYLES)) >>= xStyles; + } + + uno::Reference< container::XIndexReplace> xLevelFormats; + xTOC->getPropertyValue(getPropertyName(PROP_LEVEL_FORMAT)) >>= xLevelFormats; + sal_Int32 nLevelCount = xLevelFormats->getCount(); + //start with level 1, 0 is the header level + for( sal_Int32 nLevel = 1; nLevel < nLevelCount; ++nLevel) + { + uno::Sequence< beans::PropertyValues > aLevel; + xLevelFormats->getByIndex( nLevel ) >>= aLevel; + + // Get the tab stops coming from the styles; store to the level definitions + uno::Sequence tabStops; + if (xStyles) + { + OUString style; + xTOC->getPropertyValue("ParaStyleLevel" + OUString::number(nLevel)) >>= style; + uno::Reference xStyle; + if (xStyles->getByName(style) >>= xStyle) + xStyle->getPropertyValue("ParaTabStops") >>= tabStops; } + + uno::Sequence< beans::PropertyValues > aNewLevel = lcl_createTOXLevelHyperlinks( + bHyperlinks, sChapterNoSeparator, + aLevel, tabStops); + xLevelFormats->replaceByIndex( nLevel, uno::Any( aNewLevel ) ); } } else // if (bTableOfFigures) @@ -6503,7 +6526,7 @@ void DomainMapper_Impl::handleToc uno::Sequence< beans::PropertyValues > aNewLevel = lcl_createTOXLevelHyperlinks( bHyperlinks, sChapterNoSeparator, - aLevel ); + aLevel, {}); xLevelFormats->replaceByIndex( 1, uno::Any( aNewLevel ) ); } }