Kaydet (Commit) 1575b462 authored tarafından Serge Krot's avatar Serge Krot Kaydeden (comit) Thorsten Behrens

tdf#121561: sw: DOCX: add std/stdPr/stdContent around TOC

During export into DOCX from ODT we need to do it
because in this case the TOC title will be recognized
inside MS Word as part of the TOC.

Later we could add support of these keywords in LO import
in order to detect TOC title from DOCX input.

Added unit test for export.

Change-Id: I7135e91dc04d4c0501e6074a046fc473e041f014
Reviewed-on: https://gerrit.libreoffice.org/63786
Tested-by: Jenkins
Reviewed-by: 's avatarThorsten Behrens <Thorsten.Behrens@CIB.de>
üst f84f5b0a
......@@ -131,6 +131,19 @@ DECLARE_OOXMLEXPORT_TEST(testTdf121456_tabsOffset, "tdf121456_tabsOffset.odt")
}
}
// tdf#121561: make sure w:sdt/w:sdtContent around TOC is written during ODT->DOCX conversion
DECLARE_OOXMLEXPORT_TEST(testTdf121561_tocTitle, "tdf121456_tabsOffset.odt")
{
xmlDocPtr pXmlDoc = parseExport();
if (!pXmlDoc)
return;
assertXPathContent(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtContent/w:p/w:r/w:t", "Inhaltsverzeichnis");
assertXPathContent(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtContent/w:p/w:r/w:instrText", " TOC \\f \\o \"1-9\" \\h");
assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:docPartObj/w:docPartGallery", "val", "Table of Contents");
assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:docPartObj/w:docPartUnique", 1);
}
DECLARE_OOXMLEXPORT_TEST(testTdf106174_rtlParaAlign, "tdf106174_rtlParaAlign.docx")
{
CPPUNIT_ASSERT_EQUAL(sal_Int16(style::ParagraphAdjust_CENTER), getProperty<sal_Int16>(getParagraph(1), "ParaAdjust"));
......
......@@ -693,7 +693,7 @@ DECLARE_OOXMLEXPORT_TEST(testFdo77129, "fdo77129.docx")
return;
// Data was lost from this paragraph.
assertXPathContent(pXmlDoc, "/w:document/w:body/w:p[5]/w:r[1]/w:t", "Abstract");
assertXPathContent(pXmlDoc, "/w:document/w:body/w:p[4]/w:r[1]/w:t", "Abstract");
}
DECLARE_OOXMLEXPORT_TEST(testfdo79969_xlsm, "fdo79969_xlsm.docx")
......
......@@ -143,7 +143,7 @@ DECLARE_OOXMLEXPORT_TEST(testFieldFlagO,"TOC_field_f.docx")
// FIXME "p[2]" will have to be "p[1]", once the TOC import code is fixed
// not to insert an empty paragraph before TOC.
assertXPathContent(pXmlDoc, "/w:document/w:body/w:p[2]/w:r[2]/w:instrText", " TOC \\z \\f \\o \"1-3\" \\u \\h");
assertXPathContent(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtContent/w:p[1]/w:r[2]/w:instrText", " TOC \\z \\f \\o \"1-3\" \\u \\h");
}
DECLARE_OOXMLEXPORT_TEST(testTOCFlag_f, "toc_doc.docx")
......@@ -160,7 +160,7 @@ DECLARE_OOXMLEXPORT_TEST(testTOCFlag_f, "toc_doc.docx")
// FIXME "p[2]" will have to be "p[1]", once the TOC import code is fixed
// not to insert an empty paragraph before TOC.
assertXPathContent(pXmlDoc, "/w:document/w:body/w:p[2]/w:r[2]/w:instrText", " TOC \\z \\o \"1-3\" \\u \\h");
assertXPathContent(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtContent/w:p[1]/w:r[2]/w:instrText", " TOC \\z \\o \"1-3\" \\u \\h");
}
DECLARE_OOXMLEXPORT_TEST(testPreserveZfield,"preserve_Z_field_TOC.docx")
......@@ -190,7 +190,7 @@ DECLARE_OOXMLEXPORT_TEST(testFieldFlagB,"TOC_field_b.docx")
// FIXME "p[2]" will have to be "p[1]", once the TOC import code is fixed
// not to insert an empty paragraph before TOC.
assertXPathContent(pXmlDoc, "/w:document/w:body/w:p[2]/w:r[2]/w:instrText", " TOC \\b \"bookmark111\" \\o \"1-9\" \\h");
assertXPathContent(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtContent/w:p[1]/w:r[2]/w:instrText", " TOC \\b \"bookmark111\" \\o \"1-9\" \\h");
}
DECLARE_OOXMLEXPORT_TEST(testPreserveXfieldTOC, "PreserveXfieldTOC.docx")
......@@ -448,7 +448,7 @@ DECLARE_OOXMLEXPORT_TEST(testFDO78654 , "fdo78654.docx")
return;
// In case of two "Hyperlink" tags in one paragraph and one of them
// contains "PAGEREF" field then field end tag was missing from hyperlink.
assertXPath ( pXmlDoc, "/w:document/w:body/w:sdt/w:sdtContent/w:p[2]/w:hyperlink[3]/w:r[5]/w:fldChar", "fldCharType", "end" );
assertXPath ( pXmlDoc, "/w:document/w:body/w:p[2]/w:hyperlink[3]/w:r[5]/w:fldChar", "fldCharType", "end" );
}
......
......@@ -92,6 +92,7 @@
#include <oox/export/vmlexport.hxx>
#include <sfx2/docfile.hxx>
#include <sal/log.hxx>
#include <comphelper/propertysequence.hxx>
#include "sprmids.hxx"
......@@ -3055,7 +3056,101 @@ void MSWordExportBase::OutputSectionNode( const SwSectionNode& rSectionNode )
}
}
if ( TOX_CONTENT_SECTION == rSection.GetType() )
{
m_bStartTOX = true;
UpdateTocSectionNodeProperties(rSectionNode);
}
}
// tdf#121561: During export of the ODT file with TOC inside into DOCX format,
// the TOC title is being exported as regular paragraph. We should surround it
// with <w:sdt><w:sdtPr><w:sdtContent> to make it (TOC title) recognizable
// by MS Word as part of the TOC.
void MSWordExportBase::UpdateTocSectionNodeProperties(const SwSectionNode& rSectionNode)
{
// check section type
{
const SwSection& rSection = rSectionNode.GetSection();
if (TOX_CONTENT_SECTION != rSection.GetType())
return;
const SwTOXBase* pTOX = rSection.GetTOXBase();
if (pTOX)
{
TOXTypes type = pTOX->GetType();
if (type != TOXTypes::TOX_CONTENT)
return;
}
}
// get section node, skip toc-header node
const SwSectionNode* pSectNd = &rSectionNode;
{
SwNodeIndex aIdxNext( *pSectNd, 1 );
const SwNode& rNdNext = aIdxNext.GetNode();
if (rNdNext.IsSectionNode())
{
const SwSectionNode* pSectNdNext = static_cast<const SwSectionNode*>(&rNdNext);
if (TOX_HEADER_SECTION == pSectNdNext->GetSection().GetType() &&
pSectNdNext->StartOfSectionNode()->IsSectionNode())
{
pSectNd = pSectNdNext;
}
}
}
// get node of the first paragraph inside TOC
SwNodeIndex aIdxNext( *pSectNd, 1 );
const SwNode& rNdTocPara = aIdxNext.GetNode();
const SwContentNode* pNode = rNdTocPara.GetContentNode();
if (!pNode)
return;
// put required flags into grab bag of the first node in TOC
{
uno::Sequence<beans::PropertyValue> aDocPropertyValues(comphelper::InitPropertySequence(
{
{"ooxml:CT_SdtDocPart_docPartGallery", uno::makeAny(OUString("Table of Contents"))},
{"ooxml:CT_SdtDocPart_docPartUnique", uno::makeAny(OUString("true"))},
}));
uno::Sequence<beans::PropertyValue> aSdtPrPropertyValues(comphelper::InitPropertySequence(
{
{"ooxml:CT_SdtPr_docPartObj", uno::makeAny(aDocPropertyValues)},
}));
SfxGrabBagItem aGrabBag(RES_PARATR_GRABBAG);
aGrabBag.GetGrabBag()["SdtPr"] <<= aSdtPrPropertyValues;
// create temp attr set
SwAttrSet aSet(pNode->GetSwAttrSet());
aSet.Put(aGrabBag);
// set new attr to node
const_cast<SwContentNode*>(pNode)->SetAttr(aSet);
}
// set flag for the next node after TOC
// in order to indicate that std area has been finished
// see, DomainMapper::lcl_startParagraphGroup() for the same functionality during load
{
SwNodeIndex aEndTocNext( *rSectionNode.EndOfSectionNode(), 1 );
const SwNode& rEndTocNextNode = aEndTocNext.GetNode();
const SwContentNode* pNodeAfterToc = rEndTocNextNode.GetContentNode();
if (pNodeAfterToc)
{
SfxGrabBagItem aGrabBag(RES_PARATR_GRABBAG);
aGrabBag.GetGrabBag()["ParaSdtEndBefore"] <<= true;
// create temp attr set
SwAttrSet aSet(pNodeAfterToc->GetSwAttrSet());
aSet.Put(aGrabBag);
// set new attr to node
const_cast<SwContentNode*>(pNodeAfterToc)->SetAttr(aSet);
}
}
}
void WW8Export::AppendSection( const SwPageDesc *pPageDesc, const SwSectionFormat* pFormat, sal_uLong nLnNum )
......
......@@ -843,6 +843,7 @@ protected:
/// Output SwSectionNode
void OutputSectionNode( const SwSectionNode& );
static void UpdateTocSectionNodeProperties(const SwSectionNode& rSectionNode);
virtual void AppendSection( const SwPageDesc *pPageDesc, const SwSectionFormat* pFormat, sal_uLong nLnNum ) = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment