summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Mehrbrodt <samuel.mehrbrodt@allotropia.de>2021-08-04 21:57:39 +0200
committerSamuel Mehrbrodt <samuel.mehrbrodt@allotropia.de>2021-08-05 09:00:45 +0200
commite12d4c7e361f449fcf143a61caed92129aca3468 (patch)
treec3f56e29552a6306f610a144cdebdbc5deb8ec54
parent13377fd2e1d6e00597bb23a480ed9ad0aa9a563c (diff)
tdf#123643 Import/Export for hyperlinks on text boxes
Change-Id: Ied436c4a619985f27e5854369d319d76c05890d1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120028 Tested-by: Jenkins Reviewed-by: Samuel Mehrbrodt <samuel.mehrbrodt@allotropia.de>
-rw-r--r--include/oox/vml/vmlshape.hxx2
-rw-r--r--include/oox/vml/vmlshapecontext.hxx4
-rw-r--r--oox/source/token/properties.txt1
-rw-r--r--oox/source/vml/vmlshape.cxx7
-rw-r--r--oox/source/vml/vmlshapecontext.cxx13
-rw-r--r--sw/qa/extras/ooxmlexport/data/docxopenhyperlinkbox.docxbin0 -> 18197 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport16.cxx22
-rw-r--r--sw/source/filter/ww8/docxsdrexport.cxx29
8 files changed, 66 insertions, 12 deletions
diff --git a/include/oox/vml/vmlshape.hxx b/include/oox/vml/vmlshape.hxx
index d90ecc2865bf..19c82384efcd 100644
--- a/include/oox/vml/vmlshape.hxx
+++ b/include/oox/vml/vmlshape.hxx
@@ -112,7 +112,6 @@ struct 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
bool mbSignatureLineShowSignDate;
bool mbSignatureLineCanAddComment;
bool mbInGroup;
+ 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 0d4b3ddd9e7e..49fc6826ae5a 100644
--- a/include/oox/vml/vmlshapecontext.hxx
+++ b/include/oox/vml/vmlshapecontext.hxx
@@ -107,8 +107,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;
@@ -141,6 +139,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 04b550e669ea..b35a5bc3cd4a 100644
--- a/oox/source/token/properties.txt
+++ b/oox/source/token/properties.txt
@@ -255,6 +255,7 @@ HoriOrientRelation
HorizontalSplitMode
HorizontalSplitPositionTwips
Hyperlink
+HyperLinkURL
IgnoreBlankCells
IgnoreCase
IgnoreLeadingSpaces
diff --git a/oox/source/vml/vmlshape.cxx b/oox/source/vml/vmlshape.cxx
index d1029173a1db..4e4b848db941 100644
--- a/oox/source/vml/vmlshape.cxx
+++ b/oox/source/vml/vmlshape.cxx
@@ -770,6 +770,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
{
@@ -814,8 +817,8 @@ Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes
PropertySet(xShape).setAnyProperty(PROP_TextWordWrap, makeAny(maTypeModel.maWrapStyle == "square"));
// 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 d53a924c278a..82ca210e7588 100644
--- a/oox/source/vml/vmlshapecontext.cxx
+++ b/oox/source/vml/vmlshapecontext.cxx
@@ -312,7 +312,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%
@@ -470,11 +469,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)
@@ -491,6 +485,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 )
@@ -609,6 +604,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
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/docxopenhyperlinkbox.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
index 37ed272b65b5..61f6b0be7176 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
@@ -447,6 +447,28 @@ DECLARE_OOXMLEXPORT_TEST(testShapeHyperlink, "hyperlinkshape.docx")
CPPUNIT_ASSERT_EQUAL(OUString("https://libreoffice.org/"), getProperty<OUString>(xShape, "Hyperlink"));
}
+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");
+
+ xmlDocUniquePtr 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/");
+}
+
DECLARE_OOXMLEXPORT_TEST(testTdf139580, "tdf139580.odt")
{
// Without the fix in place, this test would have crashed at export time
diff --git a/sw/source/filter/ww8/docxsdrexport.cxx b/sw/source/filter/ww8/docxsdrexport.cxx
index f8d486f73ca0..821cda8d053b 100644
--- a/sw/source/filter/ww8/docxsdrexport.cxx
+++ b/sw/source/filter/ww8/docxsdrexport.cxx
@@ -1661,7 +1661,24 @@ void DocxSdrExport::writeDMLTextFrame(ww8::Frame const* pParentFrame, int nAncho
pDocPrAttrList->add(XML_id, OString::number(nAnchorId).getStr());
pDocPrAttrList->add(XML_name,
OUStringToOString(rFrameFormat.GetName(), RTL_TEXTENCODING_UTF8));
- pFS->singleElementNS(XML_wp, XML_docPr, pDocPrAttrList);
+
+ 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,
+ FSNS(XML_xmlns, XML_a),
+ m_pImpl->getExport().GetFilter().getNamespaceURL(OOX_NS(dml)));
+ }
+
+ 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)));
@@ -1938,6 +1955,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));
}
rtl::Reference<FastAttributeList> xFlyAttrList(m_pImpl->getFlyAttrList());
m_pImpl->getFlyAttrList().clear();