summaryrefslogtreecommitdiff
path: root/sw
diff options
context:
space:
mode:
authorSerge Krot <Serge.Krot@cib.de>2018-12-06 19:11:58 +0100
committerMichael Stahl <Michael.Stahl@cib.de>2019-01-15 19:01:57 +0100
commit736a38419f49d4b96bd845f5767a028df59e4cff (patch)
tree18d202a7b89c09cbd1692fea8663423a1685a4a2 /sw
parent6aa9f0980612d5c7dcc02cfe11babb73605be4ca (diff)
sw: DOCX: recognize TOC title during import
Change-Id: Ifa4fb59858d61580f76e3d104aa4caa6b5902d1b Reviewed-on: https://gerrit.libreoffice.org/64735 Tested-by: Jenkins Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de> 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: Thorsten Behrens <Thorsten.Behrens@CIB.de> Reviewed-on: https://gerrit.libreoffice.org/66307 Reviewed-by: Michael Stahl <Michael.Stahl@cib.de>
Diffstat (limited to 'sw')
-rw-r--r--sw/inc/doc.hxx4
-rwxr-xr-xsw/qa/extras/ooxmlexport/data/tdf121456_tabsOffset.odtbin0 -> 14208 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport11.cxx27
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport5.cxx2
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx8
-rw-r--r--sw/source/core/doc/doctxm.cxx16
-rw-r--r--sw/source/core/unocore/unoidx.cxx6
-rw-r--r--sw/source/filter/ww8/wrtw8nds.cxx96
-rw-r--r--sw/source/filter/ww8/wrtww8.hxx1
9 files changed, 146 insertions, 14 deletions
diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index f92fbc70fe8b..1413def85409 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -911,6 +911,10 @@ public:
const SwTOXBase& rTOX,
const SfxItemSet* pSet = nullptr,
bool bExpand = false );
+ SwTOXBaseSection* InsertTableOf( const SwPaM& aPam,
+ const SwTOXBase& rTOX,
+ const SfxItemSet* pSet = nullptr,
+ bool bExpand = false );
void InsertTableOf( sal_uLong nSttNd, sal_uLong nEndNd,
const SwTOXBase& rTOX,
const SfxItemSet* pSet );
diff --git a/sw/qa/extras/ooxmlexport/data/tdf121456_tabsOffset.odt b/sw/qa/extras/ooxmlexport/data/tdf121456_tabsOffset.odt
new file mode 100755
index 000000000000..ff8d5400950b
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf121456_tabsOffset.odt
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
index c7dc952d2c40..41194b02db98 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
@@ -23,6 +23,7 @@
#include <com/sun/star/graphic/XGraphic.hpp>
#include <com/sun/star/text/RubyAdjust.hpp>
#include <com/sun/star/text/RubyPosition.hpp>
+#include <com/sun/star/text/XDocumentIndex.hpp>
#include <sfx2/docfile.hxx>
@@ -79,6 +80,32 @@ DECLARE_OOXMLEXPORT_TEST(testTdf63561_clearTabs2, "tdf63561_clearTabs2.docx")
CPPUNIT_ASSERT_EQUAL(sal_Int32(4), getProperty< uno::Sequence<style::TabStop> >(getParagraph(4), "ParaTabStops").getLength());
}
+// 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(testTdf121561_tocTitleDocx, "tdf121456_tabsOffset.odt")
+{
+ xmlDocPtr pXmlDoc = parseExport();
+ if (!pXmlDoc)
+ return;
+
+ uno::Reference<text::XDocumentIndexesSupplier> xIndexSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xIndexes(xIndexSupplier->getDocumentIndexes( ), uno::UNO_QUERY);
+ uno::Reference<text::XDocumentIndex> xTOCIndex(xIndexes->getByIndex(0), uno::UNO_QUERY);
+
+ CPPUNIT_ASSERT_EQUAL(OUString("Inhaltsverzeichnis"), getProperty<OUString>(xTOCIndex, "Title"));
+}
+
DECLARE_OOXMLEXPORT_TEST(testTdf82065_Ind_start_strict, "tdf82065_Ind_start_strict.docx")
{
uno::Reference<beans::XPropertySet> xPropertySet(getStyles("NumberingStyles")->getByName("WWNum1"), uno::UNO_QUERY);
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
index 0f8e562a0f8a..54bb46946354 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
@@ -722,7 +722,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")
diff --git a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
index fb41c037a76e..789a6bc8b32e 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
@@ -144,7 +144,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")
@@ -161,7 +161,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")
@@ -191,7 +191,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")
@@ -449,7 +449,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" );
}
diff --git a/sw/source/core/doc/doctxm.cxx b/sw/source/core/doc/doctxm.cxx
index 84d57cff5cf4..1305dfe90a1f 100644
--- a/sw/source/core/doc/doctxm.cxx
+++ b/sw/source/core/doc/doctxm.cxx
@@ -333,14 +333,22 @@ const SwTOXMark& SwDoc::GotoTOXMark( const SwTOXMark& rCurTOXMark,
}
SwTOXBaseSection* SwDoc::InsertTableOf( const SwPosition& rPos,
- const SwTOXBase& rTOX,
- const SfxItemSet* pSet,
- bool bExpand )
+ const SwTOXBase& rTOX,
+ const SfxItemSet* pSet,
+ bool bExpand)
+{
+ SwPaM aPam( rPos );
+ return InsertTableOf( aPam, rTOX, pSet, bExpand );
+}
+
+SwTOXBaseSection* SwDoc::InsertTableOf( const SwPaM& aPam,
+ const SwTOXBase& rTOX,
+ const SfxItemSet* pSet,
+ bool bExpand )
{
GetIDocumentUndoRedo().StartUndo( SwUndoId::INSTOX, nullptr );
OUString sSectNm = GetUniqueTOXBaseName( *rTOX.GetTOXType(), rTOX.GetTOXName() );
- SwPaM aPam( rPos );
SwSectionData aSectionData( TOX_CONTENT_SECTION, sSectNm );
SwTOXBaseSection *const pNewSection = dynamic_cast<SwTOXBaseSection *>(
InsertSwSection( aPam, aSectionData, & rTOX, pSet, false ));
diff --git a/sw/source/core/unocore/unoidx.cxx b/sw/source/core/unocore/unoidx.cxx
index 76f4faf3e09b..8bb22a061b4f 100644
--- a/sw/source/core/unocore/unoidx.cxx
+++ b/sw/source/core/unocore/unoidx.cxx
@@ -1339,10 +1339,6 @@ SwXDocumentIndex::attach(const uno::Reference< text::XTextRange > & xTextRange)
}
UnoActionContext aAction(pDoc);
- if (aPam.HasMark())
- {
- pDoc->getIDocumentContentOperations().DeleteAndJoin(aPam);
- }
SwTOXBase & rTOXBase = m_pImpl->m_pProps->GetTOXBase();
SwTOXType const*const pTOXType = rTOXBase.GetTOXType();
@@ -1353,7 +1349,7 @@ SwXDocumentIndex::attach(const uno::Reference< text::XTextRange > & xTextRange)
}
//TODO: apply Section attributes (columns and background)
SwTOXBaseSection *const pTOX =
- pDoc->InsertTableOf( *aPam.GetPoint(), rTOXBase );
+ pDoc->InsertTableOf( aPam, rTOXBase );
pDoc->SetTOXBaseName(*pTOX, m_pImpl->m_pProps->GetTOXBase().GetTOXName());
diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx
index c1d94eda7f6c..f147adce2078 100644
--- a/sw/source/filter/ww8/wrtw8nds.cxx
+++ b/sw/source/filter/ww8/wrtw8nds.cxx
@@ -91,6 +91,8 @@
#include <com/sun/star/text/RubyPosition.hpp>
#include <oox/export/vmlexport.hxx>
#include <sfx2/docfile.hxx>
+#include <sal/log.hxx>
+#include <comphelper/propertysequence.hxx>
#include "sprmids.hxx"
@@ -3083,7 +3085,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 )
diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx
index 8a911bd381e9..ec31a1b41622 100644
--- a/sw/source/filter/ww8/wrtww8.hxx
+++ b/sw/source/filter/ww8/wrtww8.hxx
@@ -847,6 +847,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;