sw/qa/extras/ooxmlexport/data/paragraph-sdt.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport.cxx | 18 ++--- sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx | 10 +++ sw/source/filter/ww8/docxattributeoutput.cxx | 70 ++++++++++++++++++++--- sw/source/filter/ww8/docxattributeoutput.hxx | 4 + writerfilter/source/dmapper/DomainMapper.cxx | 7 +- writerfilter/source/dmapper/SdtHelper.cxx | 1 writerfilter/source/dmapper/SdtHelper.hxx | 12 +++ 8 files changed, 104 insertions(+), 18 deletions(-)
New commits: commit 28a315694348c4d1a4fd9aea7e720b3e821e8eb3 Author: Miklos Vajna <vmik...@collabora.co.uk> Date: Tue Jul 29 17:56:08 2014 +0200 DOCX filter: map <w:sdt> outside paragraphs to paragraph properties Previously the type of the SDT was used to decide if the SDT will be a character or paragraph property. Improve this situation by always mapping <w:sdt> elements outside paragraph to paragraph properties. In practice, this means that if the SDT was a rectangle (as it wasn't only around a run), then it remains so, while previously it could become a polygon instead (when painted). Fix several testcases that tested that a <w:sdt> outside a paragraph is exported as a character property. Change-Id: Ia26c1a4cf6bc553b46224e4b17ee40725c5f3622 diff --git a/sw/qa/extras/ooxmlexport/data/paragraph-sdt.docx b/sw/qa/extras/ooxmlexport/data/paragraph-sdt.docx new file mode 100644 index 0000000..c86f599 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/paragraph-sdt.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx index 77d8b4c..207ad5b 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx @@ -2603,9 +2603,9 @@ DECLARE_OOXMLEXPORT_TEST(testCheckBoxControl, "checkbox-control.docx") xmlDocPtr pXmlDoc = parseExport("word/document.xml"); if (!pXmlDoc) return; - assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtPr/w14:checkbox/w14:checked", "val", "1"); - assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtPr/w14:checkbox/w14:checkedState", "val", "2612"); - assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtPr/w14:checkbox/w14:uncheckedState", "val", "2610"); + assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w14:checkbox/w14:checked", "val", "1"); + assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w14:checkbox/w14:checkedState", "val", "2612"); + assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w14:checkbox/w14:uncheckedState", "val", "2610"); // TODO: import control and add a check here } @@ -2664,7 +2664,7 @@ DECLARE_OOXMLEXPORT_TEST(testSdtContent, "SdtContent.docx") xmlDocPtr pXmlDoc = parseExport("word/header1.xml"); if (!pXmlDoc) return; - assertXPath(pXmlDoc, "/w:hdr[1]/w:p[1]/w:sdt[1]/w:sdtContent[1]/w:del[1]"); + assertXPath(pXmlDoc, "/w:hdr[1]/w:sdt[1]/w:sdtContent[1]/w:p[1]/w:del[1]"); } DECLARE_OOXMLEXPORT_TEST(testFdo76016, "fdo76016.docx") @@ -2749,8 +2749,8 @@ DECLARE_OOXMLEXPORT_TEST(testSimpleSdts, "simple-sdts.docx") if (!pXmlDoc) return; - assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:sdt/w:sdtPr/w:text", 1); - assertXPath(pXmlDoc, "/w:document/w:body/w:p[2]/w:sdt/w:sdtPr/w:id", 1); + assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:text", 1); + assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:id", 3); assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:picture", 1); assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:group", 1); assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtPr/w:citation", 1); @@ -2797,8 +2797,8 @@ DECLARE_OOXMLEXPORT_TEST(testAuthorPropertySdt, "author-property.docx") if (!pXmlDoc) return; - assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtPr/w:dataBinding", "xpath", "/ns1:coreProperties[1]/ns0:creator[1]"); - assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtPr/w:dataBinding", "storeItemID","{6C3C8BC8-F283-45AE-878A-BAB7291924A1}"); + assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:dataBinding", "xpath", "/ns1:coreProperties[1]/ns0:creator[1]"); + assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:dataBinding", "storeItemID","{6C3C8BC8-F283-45AE-878A-BAB7291924A1}"); // FIXME: the next property doesn't match, though it's correct in theory. A bug in assertXPath? // assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:dataBinding", "prefixMappings", // "xmlns:ns0='http://purl.org/dc/elements/1.1/' xmlns:ns1='http://schemas.openxmlformats.org/package/2006/metadata/core-properties'"); @@ -3366,7 +3366,7 @@ DECLARE_OOXMLEXPORT_TEST(testSdtAlias, "sdt-alias.docx") return; // <w:alias> was completely missing. - assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtPr/w:alias", "val", "Subtitle"); + assertXPath(pXmlDoc, "/w:document/w:body/w:sdt/w:sdtPr/w:alias", "val", "Subtitle"); } DECLARE_OOXMLEXPORT_TEST(testSdtDateCharformat, "sdt-date-charformat.docx") diff --git a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx index 5d2732b..9b4b380 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx @@ -510,6 +510,16 @@ DECLARE_OOXMLEXPORT_TEST(testSdtCitationRun, "sdt-citation-run.docx") } } +DECLARE_OOXMLEXPORT_TEST(testParagraphSdt, "paragraph-sdt.docx") +{ + // The problem was that the SDT was around the run only, not the whole paragraph. + if (xmlDocPtr pXmlDoc = parseExport()) + { + // The path to w:sdt contained a w:p. + assertXPath(pXmlDoc, "/w:document/w:body/w:tbl/w:tr/w:tc/w:sdt"); + } +} + #endif CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 8eb11f8..ec65d8b 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -518,15 +518,15 @@ void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pT } m_pSerializer->endElementNS( XML_w, XML_p ); - OUString aParagraphSdtPrAlias; if( !m_bAnchorLinkedToNode ) - WriteSdtBlock( m_nParagraphSdtPrToken, m_pParagraphSdtPrTokenChildren, m_pParagraphSdtPrDataBindingAttrs, aParagraphSdtPrAlias, /*bPara=*/true ); + WriteSdtBlock( m_nParagraphSdtPrToken, m_pParagraphSdtPrTokenChildren, m_pParagraphSdtPrDataBindingAttrs, m_aParagraphSdtPrAlias, /*bPara=*/true ); else { //These should be written out to the actual Node and not to the anchor. //Clear them as they will be repopulated when the node is processed. m_nParagraphSdtPrToken = 0; - lcl_deleteAndResetTheLists( m_pParagraphSdtPrTokenChildren, m_pParagraphSdtPrDataBindingAttrs, aParagraphSdtPrAlias ); + m_bParagraphSdtHasId = false; + lcl_deleteAndResetTheLists( m_pParagraphSdtPrTokenChildren, m_pParagraphSdtPrDataBindingAttrs, m_aParagraphSdtPrAlias ); } //sdtcontent is written so Set m_bParagraphHasDrawing to false @@ -588,13 +588,14 @@ void DocxAttributeOutput::WriteSdtBlock( sal_Int32& nSdtPrToken, m_pSerializer->endElement( nSdtPrToken ); } - else if( nSdtPrToken == FSNS( XML_w, XML_id ) ) + else if( (nSdtPrToken > 0) && !(m_bRunTextIsOn && m_rExport.SdrExporter().IsParagraphHasDrawing())) + m_pSerializer->singleElement( nSdtPrToken, FSEND ); + + if( nSdtPrToken == FSNS( XML_w, XML_id ) || ( bPara && m_bParagraphSdtHasId ) ) //Word won't open a document with an empty id tag, we fill it with a random number - m_pSerializer->singleElement( nSdtPrToken, + m_pSerializer->singleElementNS(XML_w, XML_id, FSNS(XML_w, XML_val), OString::number( rand() ), FSEND ); - else if( (nSdtPrToken > 0) && !(m_bRunTextIsOn && m_rExport.SdrExporter().IsParagraphHasDrawing())) - m_pSerializer->singleElement( nSdtPrToken, FSEND ); if(( pSdtPrDataBindingAttrs ) && !m_rExport.SdrExporter().IsParagraphHasDrawing()) { @@ -7663,6 +7664,60 @@ void DocxAttributeOutput::ParaGrabBag(const SfxGrabBagItem& rItem) m_nParagraphSdtPrToken = FSNS( XML_w, XML_citation ); else if (aPropertyValue.Name == "ooxml:CT_SdtPr_group") m_nParagraphSdtPrToken = FSNS( XML_w, XML_group ); + else if (aPropertyValue.Name == "ooxml:CT_SdtPr_text") + m_nParagraphSdtPrToken = FSNS(XML_w, XML_text); + else if (aPropertyValue.Name == "ooxml:CT_SdtPr_dataBinding" && !m_pParagraphSdtPrDataBindingAttrs) + { + 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_DataBinding_prefixMappings") + AddToAttrList( m_pParagraphSdtPrDataBindingAttrs, + FSNS( XML_w, XML_prefixMappings ), + rtl::OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() ); + else if (aGrabBag[j].Name == "ooxml:CT_DataBinding_xpath") + AddToAttrList( m_pParagraphSdtPrDataBindingAttrs, + FSNS( XML_w, XML_xpath ), + rtl::OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() ); + else if (aGrabBag[j].Name == "ooxml:CT_DataBinding_storeItemID") + AddToAttrList( m_pParagraphSdtPrDataBindingAttrs, + FSNS( XML_w, XML_storeItemID ), + rtl::OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() ); + } + } + else if (aPropertyValue.Name == "ooxml:CT_SdtPr_alias" && m_aParagraphSdtPrAlias.isEmpty()) + { + if (!(aPropertyValue.Value >>= m_aParagraphSdtPrAlias)) + SAL_WARN("sw.ww8", "DocxAttributeOutput::ParaGrabBag: unexpected sdt alias value"); + } + else if (aPropertyValue.Name == "ooxml:CT_SdtPr_checkbox") + { + m_nParagraphSdtPrToken = FSNS( XML_w14, XML_checkbox ); + 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_SdtCheckbox_checked") + AddToAttrList( m_pParagraphSdtPrTokenChildren, + FSNS( XML_w14, XML_checked ), + rtl::OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() ); + else if (aGrabBag[j].Name == "ooxml:CT_SdtCheckbox_checkedState") + AddToAttrList( m_pParagraphSdtPrTokenChildren, + FSNS( XML_w14, XML_checkedState ), + rtl::OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() ); + else if (aGrabBag[j].Name == "ooxml:CT_SdtCheckbox_uncheckedState") + AddToAttrList( m_pParagraphSdtPrTokenChildren, + FSNS( XML_w14, XML_uncheckedState ), + rtl::OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() ); + } + } + else if (aPropertyValue.Name == "ooxml:CT_SdtPr_id") + m_bParagraphSdtHasId = true; + else + SAL_INFO("sw.ww8", "DocxAttributeOutput::ParaGrabBag: unhandled SdtPr grab bag property " << aPropertyValue.Name); } } else @@ -7927,6 +7982,7 @@ DocxAttributeOutput::DocxAttributeOutput( DocxExport &rExport, FSHelperPtr pSeri , m_nRunSdtPrToken(0) , m_pRunSdtPrTokenChildren(NULL) , m_pRunSdtPrDataBindingAttrs(NULL) + , m_bParagraphSdtHasId(false) { } diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index 04770c5..ff4ed70 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -897,7 +897,11 @@ private: sal_Int32 m_nRunSdtPrToken; ::sax_fastparser::FastAttributeList *m_pRunSdtPrTokenChildren; ::sax_fastparser::FastAttributeList *m_pRunSdtPrDataBindingAttrs; + /// Value of the <w:alias> paragraph SDT element. + OUString m_aParagraphSdtPrAlias; OUString m_aRunSdtPrAlias; + /// Currently paragraph SDT has a <w:id> child element. + bool m_bParagraphSdtHasId; std::map<sal_uInt16, css::table::BorderLine2> m_aTableStyleConf; diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index c32d86a..b305afd 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -2371,6 +2371,7 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, PropertyMapPtr rContext ) } else m_pImpl->m_pSdtHelper->appendToInteropGrabBag(getInteropGrabBag()); + m_pImpl->m_pSdtHelper->setOutsideAParagraph(m_pImpl->IsOutsideAParagraph()); m_pImpl->disableInteropGrabBag(); } break; @@ -2669,6 +2670,8 @@ void DomainMapper::lcl_endShape( ) lcl_endParagraphGroup(); m_pImpl->PopShapeContext( ); + // A shape is always inside a shape (anchored or inline). + m_pImpl->SetIsOutsideAParagraph(false); } } @@ -2833,12 +2836,12 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len) { // there are unsupported SDT properties in the document // save them in the paragraph interop grab bag - if(m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_checkbox") || + if((m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_checkbox") || m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_text") || m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_dataBinding") || m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_citation") || (m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_id") && - m_pImpl->m_pSdtHelper->getInteropGrabBagSize() == 1)) + m_pImpl->m_pSdtHelper->getInteropGrabBagSize() == 1)) && !m_pImpl->m_pSdtHelper->isOutsideAParagraph()) { PropertyMapPtr pContext = m_pImpl->GetTopContextOfType(CONTEXT_CHARACTER); diff --git a/writerfilter/source/dmapper/SdtHelper.cxx b/writerfilter/source/dmapper/SdtHelper.cxx index ce57d60..bf268a3 100644 --- a/writerfilter/source/dmapper/SdtHelper.cxx +++ b/writerfilter/source/dmapper/SdtHelper.cxx @@ -70,6 +70,7 @@ awt::Size lcl_getOptimalWidth(StyleSheetTablePtr pStyleSheet, OUString& rDefault SdtHelper::SdtHelper(DomainMapper_Impl& rDM_Impl) : m_rDM_Impl(rDM_Impl) , m_bHasElements(false) + , m_bOutsideAParagraph(false) { } diff --git a/writerfilter/source/dmapper/SdtHelper.hxx b/writerfilter/source/dmapper/SdtHelper.hxx index f4f56ab..c8d59bc 100644 --- a/writerfilter/source/dmapper/SdtHelper.hxx +++ b/writerfilter/source/dmapper/SdtHelper.hxx @@ -60,6 +60,8 @@ class SdtHelper com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> m_aGrabBag; bool m_bHasElements; + /// The last stored SDT element is outside paragraphs. + bool m_bOutsideAParagraph; /// Create and append the drawing::XControlShape, containing the various models. void createControlShape(css::awt::Size aSize, css::uno::Reference<css::awt::XControlModel> const&); @@ -94,6 +96,16 @@ public: return m_bHasElements; } + void setOutsideAParagraph(bool bOutsideAParagraph) + { + m_bOutsideAParagraph = bOutsideAParagraph; + } + + bool isOutsideAParagraph() + { + return m_bOutsideAParagraph; + } + /// Create drop-down control from w:sdt's w:dropDownList. void createDropDownControl(); /// Create date control from w:sdt's w:date. _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits