summaryrefslogtreecommitdiff
path: root/sw
diff options
context:
space:
mode:
authorJacobo Aragunde Pérez <jaragunde@igalia.com>2014-03-17 13:44:36 +0100
committerJacobo Aragunde Pérez <jaragunde@igalia.com>2014-03-17 14:08:43 +0100
commit55211e612d2cbed03dd81c039d07ea4e936c2804 (patch)
treec252b9de285d62a661534ce353349578157e6aa3 /sw
parenta45fde7235f95792bf8e6f6979d0040637c5785d (diff)
ooxml: preserve w:sdt blocks containing w:docPartObj properties
The <w:docPartObj> property inside <w:sdt> blocks determines a block inside the document that can be dinamically updated and enables Word 2010 to show a hover button to update it. It is used for TOCs, bibliography, etc. LibreOffice ignored these blocks and removed them from the document on export. In this patch, we make the importer save the <w:docPartObj> tag and its contents in the paragraph interop grab bag. On export we read the paragraph grab bag and restore the sdt block back to the document; we don't know if the paragraph must be enclosed in a sdt block when we start it, so we used the parser marks to be able to prepend the start of the block before the paragraph opening tag. The grab bag on import is managed by the SdtHelper class. Added a set of methods for that purpose. The ooxml model file was modified to assign token ids to the children of w:docPartObj. Fixed several unit tests that didn't expect the <w:sdt> tag to be exported. Also modified testBibliography inside ooxmlexport test suite to add checks for this patch. TODO: in the imported documents the sdtContent block may contain several paragraphs but the exporter code as it is can only wrap one paragraph. As a result, if the sdt block contained several paragraphs the second and next paragraphs will be outside the block in the exported document. Change-Id: I5333fc5ad91a3c50198a4f7647424a2101268c12
Diffstat (limited to 'sw')
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport.cxx16
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlsdrexport.cxx2
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx73
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.hxx6
4 files changed, 88 insertions, 9 deletions
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
index e31bef9974f8..0bc7d601e3c8 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
@@ -2165,9 +2165,7 @@ DECLARE_OOXMLEXPORT_TEST(testPreserveZfield,"preserve_Z_field_TOC.docx")
if (!pXmlDoc)
return;
- // 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\" \\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\" \\h");
}
DECLARE_OOXMLEXPORT_TEST(testPreserveWfieldTOC, "PreserveWfieldTOC.docx")
@@ -2176,7 +2174,7 @@ DECLARE_OOXMLEXPORT_TEST(testPreserveWfieldTOC, "PreserveWfieldTOC.docx")
if (!pXmlDoc)
return;
- assertXPathContent(pXmlDoc, "/w:document/w:body/w:p[2]/w:r[2]/w:instrText", " TOC \\z \\w \\f \\o \"1-3\" \\h");
+ assertXPathContent(pXmlDoc, "/w:document/w:body/w:p/w:r[2]/w:instrText", " TOC \\z \\w \\f \\o \"1-3\" \\h");
}
DECLARE_OOXMLEXPORT_TEST(testFieldFlagB,"TOC_field_b.docx")
@@ -2197,7 +2195,7 @@ DECLARE_OOXMLEXPORT_TEST(testPreserveXfieldTOC, "PreserveXfieldTOC.docx")
if (!pXmlDoc)
return;
- assertXPathContent(pXmlDoc, "/w:document/w:body/w:p[2]/w:r[2]/w:instrText", " TOC \\x \\f \\o \"1-3\" \\h");
+ assertXPathContent(pXmlDoc, "/w:document/w:body/w:p/w:r[2]/w:instrText", " TOC \\x \\f \\o \"1-3\" \\h");
}
DECLARE_OOXMLEXPORT_TEST(testTrackChangesParagraphProperties, "testTrackChangesParagraphProperties.docx")
@@ -2260,7 +2258,7 @@ DECLARE_OOXMLEXPORT_TEST(testTOCFlag_u,"testTOCFlag_u.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-9\" \\u \\h");
+ assertXPathContent(pXmlDoc, "/w:document/w:body/w:p/w:r[2]/w:instrText", " TOC \\z \\o \"1-9\" \\u \\h");
}
DECLARE_OOXMLEXPORT_TEST(testTestTitlePage, "testTitlePage.docx")
@@ -2610,7 +2608,7 @@ DECLARE_OOXMLEXPORT_TEST(testPageref, "testPageref.docx")
if (!pXmlDoc)
return;
- assertXPathContent(pXmlDoc, "/w:document/w:body/w:p[2]/w:hyperlink/w:r[3]/w:instrText", "PAGEREF _Toc355095261 \\h");
+ assertXPathContent(pXmlDoc, "/w:document/w:body/w:p[1]/w:hyperlink/w:r[3]/w:instrText", "PAGEREF _Toc355095261 \\h");
}
DECLARE_OOXMLEXPORT_TEST(testAlphabeticalIndex_AutoColumn,"alphabeticalIndex_AutoColumn.docx")
@@ -2637,7 +2635,9 @@ DECLARE_OOXMLEXPORT_TEST(testBibliography,"FDO75133.docx")
if (!pXmlDoc)
return;
- assertXPathContent(pXmlDoc, "/w:document/w:body/w:p[3]/w:r[2]/w:instrText", " BIBLIOGRAPHY ");
+ assertXPathContent(pXmlDoc, "/w:document/w:body/w:p/w:r[2]/w:instrText", " BIBLIOGRAPHY ");
+ assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:docPartObj/w:docPartGallery", "val", "Bibliographies");
+ assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:docPartObj/w:docPartUnique", 1);
}
DECLARE_OOXMLEXPORT_TEST(testOleObject, "test_ole_object.docx")
diff --git a/sw/qa/extras/ooxmlexport/ooxmlsdrexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlsdrexport.cxx
index d46f58351630..361b523a37f4 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlsdrexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlsdrexport.cxx
@@ -750,7 +750,7 @@ DECLARE_OOXMLEXPORT_TEST(testFdo69616, "fdo69616.docx")
if (!pXmlDoc)
return;
// VML
- CPPUNIT_ASSERT(getXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent/mc:Fallback/w:pict/v:group", "coordorigin").match("696,725"));
+ CPPUNIT_ASSERT(getXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtContent/w:p[1]/w:r[1]/mc:AlternateContent/mc:Fallback/w:pict/v:group", "coordorigin").match("696,725"));
}
DECLARE_OOXMLEXPORT_TEST(testAlignForShape,"Shape.docx")
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 968fd5584728..ac4f211d4200 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -270,6 +270,10 @@ void DocxAttributeOutput::StartParagraph( ww8::WW8TableNodeInfo::Pointer_t pText
}
}
+ // this mark is used to be able to enclose the paragraph inside a sdr tag.
+ // We will only know if we have to do that later.
+ m_pSerializer->mark();
+
m_pSerializer->startElementNS( XML_w, XML_p, FSEND );
// postpone the output of the run (we get it before the paragraph
@@ -357,6 +361,9 @@ void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pT
m_pSerializer->endElementNS( XML_w, XML_p );
+ WriteParagraphSdt();
+ m_pSerializer->mergeTopMarks();
+
// Check for end of cell, rows, tables here
FinishTableRowCell( pTextNodeInfoInner );
@@ -364,6 +371,45 @@ void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pT
}
+void DocxAttributeOutput::WriteParagraphSdt()
+{
+ if( m_nSdtPrToken > 0 )
+ {
+ // sdt start mark
+ m_pSerializer->mark();
+
+ m_pSerializer->startElementNS( XML_w, XML_sdt, FSEND );
+
+ // output sdt properties
+ m_pSerializer->startElementNS( XML_w, XML_sdtPr, FSEND );
+ m_pSerializer->startElement( m_nSdtPrToken, FSEND );
+
+ uno::Sequence<xml::FastAttribute> aChildren = m_pSdtPrTokenChildren->getFastAttributes();
+ for( sal_Int32 i=0; i < aChildren.getLength(); ++i )
+ m_pSerializer->singleElement( aChildren[i].Token,
+ FSNS(XML_w, XML_val),
+ rtl::OUStringToOString( aChildren[i].Value, RTL_TEXTENCODING_UTF8 ).getStr(),
+ FSEND );
+
+ m_pSerializer->endElement( m_nSdtPrToken );
+ m_pSerializer->endElementNS( XML_w, XML_sdtPr );
+
+ // sdt contents start tag
+ m_pSerializer->startElementNS( XML_w, XML_sdtContent, FSEND );
+
+ // prepend the tags since the sdt start mark before the paragraph
+ m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_PREPEND );
+
+ // write the ending tags after the paragraph
+ m_pSerializer->endElementNS( XML_w, XML_sdtContent );
+ m_pSerializer->endElementNS( XML_w, XML_sdt );
+
+ // clear sdt status
+ m_nSdtPrToken = 0;
+ delete m_pSdtPrTokenChildren; m_pSdtPrTokenChildren = NULL;
+ }
+}
+
void DocxAttributeOutput::FinishTableRowCell( ww8::WW8TableNodeInfoInner::Pointer_t pInner, bool bForceEmptyParagraph )
{
if ( pInner.get() )
@@ -6811,6 +6857,30 @@ void DocxAttributeOutput::ParaGrabBag(const SfxGrabBagItem& rItem)
FSNS(XML_w, XML_themeFill), OUStringToOString(sThemeFill, RTL_TEXTENCODING_UTF8).getStr(),
FSNS(XML_w, XML_fill), OUStringToOString(sOriginalFill, RTL_TEXTENCODING_UTF8).getStr());
}
+ else if (i->first == "ParaSdtPr")
+ {
+ beans::PropertyValue aPropertyValue = i->second.get<beans::PropertyValue>();
+ if (aPropertyValue.Name == "ooxml:CT_SdtPr_docPartObj")
+ {
+ m_nSdtPrToken = FSNS( XML_w, XML_docPartObj );
+ uno::Sequence<beans::PropertyValue> aGrabBag;
+ aPropertyValue.Value >>= aGrabBag;
+ for (sal_Int32 j=0; j < aGrabBag.getLength(); ++j)
+ {
+ OUString sValue = aGrabBag[j].Value.get<OUString>();
+ if (aGrabBag[j].Name == "ooxml:CT_SdtDocPart_docPartGallery")
+ AddToAttrList( m_pSdtPrTokenChildren,
+ FSNS( XML_w, XML_docPartGallery ),
+ rtl::OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
+ else if (aGrabBag[j].Name == "ooxml:CT_SdtDocPart_docPartCategory")
+ AddToAttrList( m_pSdtPrTokenChildren,
+ FSNS( XML_w, XML_docPartCategory ),
+ rtl::OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
+ else if (aGrabBag[j].Name == "ooxml:CT_SdtDocPart_docPartUnique")
+ AddToAttrList( m_pSdtPrTokenChildren, FSNS( XML_w, XML_docPartUnique ), "" );
+ }
+ }
+ }
else
SAL_INFO("sw.ww8", "DocxAttributeOutput::ParaGrabBag: unhandled grab bag property " << i->first );
}
@@ -6987,6 +7057,8 @@ DocxAttributeOutput::DocxAttributeOutput( DocxExport &rExport, FSHelperPtr pSeri
m_nParaBeforeSpacing(0),
m_nParaAfterSpacing(0),
m_setFootnote(false)
+ , m_nSdtPrToken(0)
+ , m_pSdtPrTokenChildren(NULL)
{
}
@@ -7005,6 +7077,7 @@ DocxAttributeOutput::~DocxAttributeOutput()
delete m_pEndnotesList, m_pEndnotesList = NULL;
delete m_pTableWrt, m_pTableWrt = NULL;
+ delete m_pSdtPrTokenChildren; m_pSdtPrTokenChildren = NULL;
}
DocxExport& DocxAttributeOutput::GetExport()
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx
index 042fea6b7273..b5a58d8afb3f 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -682,6 +682,8 @@ private:
void WritePostponedVMLDrawing();
void WritePostponedDMLDrawing();
+ void WriteParagraphSdt();
+
void StartField_Impl( FieldInfos& rInfos, bool bWriteRun = false );
void DoWriteCmd( const OUString& rCmd );
void CmdField_Impl( FieldInfos& rInfos );
@@ -854,6 +856,10 @@ private:
/// RelId <-> Graphic* cache, so that in case of alternate content, the same graphic only gets written once.
std::map<const Graphic*, OString> m_aRelIdCache;
+ /// members to control the existence of grabbagged SDT properties in the paragraph
+ sal_Int32 m_nSdtPrToken;
+ ::sax_fastparser::FastAttributeList *m_pSdtPrTokenChildren;
+
public:
DocxAttributeOutput( DocxExport &rExport, ::sax_fastparser::FSHelperPtr pSerializer, oox::drawingml::DrawingML* pDrawingML );