include/oox/vml/vmlshape.hxx | 2 - include/oox/vml/vmlshapecontext.hxx | 4 +- oox/source/token/properties.txt | 1 oox/source/vml/vmlshape.cxx | 7 ++- oox/source/vml/vmlshapecontext.cxx | 13 +++---- sw/qa/extras/ooxmlexport/data/docxopenhyperlinkbox.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport9.cxx | 23 ++++++++++++ sw/source/filter/ww8/docxsdrexport.cxx | 29 +++++++++++++++- 8 files changed, 67 insertions(+), 12 deletions(-)
New commits: commit 47346fcf18b3c3534c038321a991c901e4edd56e Author: Samuel Mehrbrodt <samuel.mehrbr...@allotropia.de> AuthorDate: Wed Aug 4 21:57:39 2021 +0200 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Thu Aug 5 11:37:27 2021 +0200 tdf#123643 Import/Export for hyperlinks on text boxes Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120028 Tested-by: Jenkins Reviewed-by: Samuel Mehrbrodt <samuel.mehrbr...@allotropia.de> Conflicts: include/oox/vml/vmlshape.hxx sw/qa/extras/ooxmlexport/ooxmlexport16.cxx sw/source/filter/ww8/docxsdrexport.cxx Change-Id: Ied436c4a619985f27e5854369d319d76c05890d1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120057 Tested-by: Samuel Mehrbrodt <samuel.mehrbr...@allotropia.de> Tested-by: Thorsten Behrens <thorsten.behr...@allotropia.de> Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de> diff --git a/include/oox/vml/vmlshape.hxx b/include/oox/vml/vmlshape.hxx index 4b0068f1175b..952080870cb0 100644 --- a/include/oox/vml/vmlshape.hxx +++ b/include/oox/vml/vmlshape.hxx @@ -113,7 +113,6 @@ struct OOX_DLLPUBLIC ShapeTypeModel OptValue<OUString> moCropRight; ///< Specifies how much to crop the image from the right in as a fraction of picture size. OptValue<OUString> moCropTop; ///< Specifies how much to crop the image from the top down as a fraction of picture size. OUString maLayoutFlowAlt; ///< Specifies the alternate layout flow for text in textboxes. - OUString maHyperlink; ///< The hyperlink assigned to the shape explicit ShapeTypeModel(); @@ -218,6 +217,7 @@ struct ShapeModel OUString maSignatureLineSigningInstructions; bool mbSignatureLineShowSignDate; bool mbSignatureLineCanAddComment; + OUString maHyperlink; ///< The hyperlink assigned to the shape explicit ShapeModel(); ~ShapeModel(); diff --git a/include/oox/vml/vmlshapecontext.hxx b/include/oox/vml/vmlshapecontext.hxx index 4cdcd78b2031..15b1fe29987f 100644 --- a/include/oox/vml/vmlshapecontext.hxx +++ b/include/oox/vml/vmlshapecontext.hxx @@ -108,8 +108,6 @@ public: private: /** Processes the 'style' attribute. */ void setStyle( const OUString& rStyle ); - /** Processes the 'href' attribute. */ - void setHyperlink( const OUString& rHyperlink ); /** Resolve a relation identifier to a fragment path. */ OptValue< OUString > decodeFragmentPath( const AttributeList& rAttribs, sal_Int32 nToken ) const; @@ -142,6 +140,8 @@ private: void setControl2( const OUString& rPoints ); /** Processes the 'path' attribute. */ void setVmlPath( const OUString& rPath ); + /** Processes the 'href' attribute. */ + void setHyperlink( const OUString& rHyperlink ); private: ShapeBase& mrShape; diff --git a/oox/source/token/properties.txt b/oox/source/token/properties.txt index 70f15974045e..58f1df0e2fcb 100644 --- a/oox/source/token/properties.txt +++ b/oox/source/token/properties.txt @@ -246,6 +246,7 @@ HoriOrientRelation HorizontalSplitMode HorizontalSplitPositionTwips Hyperlink +HyperLinkURL IgnoreBlankCells IgnoreCase IgnoreLeadingSpaces diff --git a/oox/source/vml/vmlshape.cxx b/oox/source/vml/vmlshape.cxx index dcb231727535..cd89fc5792c4 100644 --- a/oox/source/vml/vmlshape.cxx +++ b/oox/source/vml/vmlshape.cxx @@ -745,6 +745,9 @@ Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes { PropertySet(xShape).setAnyProperty(PROP_WritingMode, uno::makeAny(nWritingMode)); } + // tdf#123626 + if (!maShapeModel.maHyperlink.isEmpty()) + PropertySet(xShape).setAnyProperty(PROP_HyperLinkURL, makeAny(maShapeModel.maHyperlink)); } else { @@ -785,8 +788,8 @@ Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes PropertySet(xShape).setAnyProperty(PROP_TextVerticalAdjust, makeAny(eTextVerticalAdjust)); // tdf#123626 - if (!maTypeModel.maHyperlink.isEmpty()) - PropertySet(xShape).setAnyProperty(PROP_Hyperlink, makeAny(maTypeModel.maHyperlink)); + if (!maShapeModel.maHyperlink.isEmpty()) + PropertySet(xShape).setAnyProperty(PROP_Hyperlink, makeAny(maShapeModel.maHyperlink)); PropertySet(xShape).setAnyProperty(PROP_TextAutoGrowHeight, makeAny(maTypeModel.mbAutoHeight)); diff --git a/oox/source/vml/vmlshapecontext.cxx b/oox/source/vml/vmlshapecontext.cxx index 94db859ff988..3058c5e01bf1 100644 --- a/oox/source/vml/vmlshapecontext.cxx +++ b/oox/source/vml/vmlshapecontext.cxx @@ -303,7 +303,6 @@ ShapeTypeContext::ShapeTypeContext(ContextHandler2Helper const & rParent, mrTypeModel.moCoordPos = lclDecodeInt32Pair( rAttribs, XML_coordorigin ); mrTypeModel.moCoordSize = lclDecodeInt32Pair( rAttribs, XML_coordsize ); setStyle( rAttribs.getString( XML_style, OUString() ) ); - setHyperlink( rAttribs.getString( XML_href, OUString() ) ); if( lclDecodeBool( rAttribs, O_TOKEN( hr )).get( false )) { // MSO's handling of o:hr width is nowhere near what the spec says: // - o:hrpct is not in % but in 0.1% @@ -461,11 +460,6 @@ void ShapeTypeContext::setStyle( const OUString& rStyle ) } } -void ShapeTypeContext::setHyperlink( const OUString& rHyperlink ) -{ - mrTypeModel.maHyperlink = rHyperlink; -} - ShapeContext::ShapeContext(ContextHandler2Helper const& rParent, const std::shared_ptr<ShapeBase>& pShape, const AttributeList& rAttribs) : ShapeTypeContext(rParent, pShape, rAttribs) @@ -482,6 +476,7 @@ ShapeContext::ShapeContext(ContextHandler2Helper const& rParent, setControl1(rAttribs.getString(XML_control1, OUString())); setControl2(rAttribs.getString(XML_control2, OUString())); setVmlPath(rAttribs.getString(XML_path, OUString())); + setHyperlink(rAttribs.getString(XML_href, OUString())); } ContextHandlerRef ShapeContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) @@ -594,6 +589,12 @@ void ShapeContext::setVmlPath( const OUString& rPath ) mrShapeModel.maVmlPath = rPath; } +void ShapeContext::setHyperlink( const OUString& rHyperlink ) +{ + if (!rHyperlink.isEmpty()) + mrShapeModel.maHyperlink = rHyperlink; +} + GroupShapeContext::GroupShapeContext(ContextHandler2Helper const& rParent, const std::shared_ptr<GroupShape>& pShape, const AttributeList& rAttribs) diff --git a/sw/qa/extras/ooxmlexport/data/docxopenhyperlinkbox.docx b/sw/qa/extras/ooxmlexport/data/docxopenhyperlinkbox.docx new file mode 100644 index 000000000000..2653e620202a Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/docxopenhyperlinkbox.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx index b9965be36431..7de2f6502c56 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx @@ -1340,6 +1340,29 @@ DECLARE_OOXMLEXPORT_TEST(testTdf115557, "tdf115557.docx") assertXPath(pXmlDoc, "//w:footnote/w:p/w:r/w:drawing", 1); } + +CPPUNIT_TEST_FIXTURE(Test, testTextframeHyperlink) +{ + // Make sure hyperlink is imported correctly + load(mpTestDocumentPath, "docxopenhyperlinkbox.docx"); + uno::Reference<text::XTextFramesSupplier> xTextFramesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<container::XIndexAccess> xIndexAccess(xTextFramesSupplier->getTextFrames(), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount()); + + uno::Reference<beans::XPropertySet> xFrame(xIndexAccess->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("https://libreoffice.org/"), getProperty<OUString>(xFrame, "HyperLinkURL")); + + // FIXME: After save&reload, the text frame should still be a text frame, and the above test should still work. + // (Currently the Writer text frame becomes a text box (shape based)). See tdf#140961 + reload(mpFilter, "docxopenhyperlinkbox.docx"); + + xmlDocPtr pXmlDoc = parseExport(); + // DML + assertXPath(pXmlDoc, "//w:drawing/wp:anchor/wp:docPr/a:hlinkClick", 1); + // VML + assertXPath(pXmlDoc, "//w:pict/v:rect", "href", "https://libreoffice.org/"); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/filter/ww8/docxsdrexport.cxx b/sw/source/filter/ww8/docxsdrexport.cxx index 68e67be808dd..dd0455674649 100644 --- a/sw/source/filter/ww8/docxsdrexport.cxx +++ b/sw/source/filter/ww8/docxsdrexport.cxx @@ -1226,7 +1226,24 @@ void DocxSdrExport::writeDMLTextFrame(ww8::Frame const* pParentFrame, int nAncho pDocPrAttrList->add( XML_name, OUStringToOString(rFrameFormat.GetName(), RTL_TEXTENCODING_UTF8).getStr()); sax_fastparser::XFastAttributeListRef xDocPrAttrListRef(pDocPrAttrList); - pFS->singleElementNS(XML_wp, XML_docPr, xDocPrAttrListRef); + pFS->startElementNS(XML_wp, XML_docPr, pDocPrAttrList); + + OUString sHyperlink; + if (xPropertySet.is()) + xPropertySet->getPropertyValue("HyperLinkURL") >>= sHyperlink; + if (!sHyperlink.isEmpty()) + { + OUString sRelId = m_pImpl->getExport().GetFilter().addRelation( + pFS->getOutputStream(), oox::getRelationship(Relationship::HYPERLINK), + oox::drawingml::URLTransformer().getTransformedString(sHyperlink), + oox::drawingml::URLTransformer().isExternalURL(sHyperlink)); + pFS->singleElementNS( + XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId.toUtf8().getStr(), + FSNS(XML_xmlns, XML_a), + m_pImpl->getExport().GetFilter().getNamespaceURL(OOX_NS(dml)).toUtf8()); + } + + pFS->endElementNS(XML_wp, XML_docPr); pFS->startElementNS(XML_a, XML_graphic, FSNS(XML_xmlns, XML_a), m_pImpl->getExport().GetFilter().getNamespaceURL(OOX_NS(dml)).toUtf8()); @@ -1507,6 +1524,16 @@ void DocxSdrExport::writeVMLTextFrame(ww8::Frame const* pParentFrame, bool bText if (!sAnchorId.isEmpty()) m_pImpl->getFlyAttrList()->addNS(XML_w14, XML_anchorId, OUStringToOString(sAnchorId, RTL_TEXTENCODING_UTF8)); + + uno::Reference<drawing::XShape> xShape(const_cast<SdrObject*>(pObject)->getUnoShape(), + uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + OUString sHyperlink; + if (xShapeProps.is()) + xShapeProps->getPropertyValue("HyperLinkURL") >>= sHyperlink; + if (!sHyperlink.isEmpty()) + m_pImpl->getFlyAttrList()->add(XML_href, + OUStringToOString(sHyperlink, RTL_TEXTENCODING_UTF8)); } sax_fastparser::XFastAttributeListRef xFlyAttrList(m_pImpl->getFlyAttrList().get()); m_pImpl->getFlyAttrList().clear();