summaryrefslogtreecommitdiff
path: root/xmloff
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2022-07-13 11:37:30 +0300
committerMike Kaganski <mike.kaganski@collabora.com>2022-07-14 07:43:14 +0200
commit9f4af852c4050d45bb5ab314480fc83639bea90a (patch)
tree23ce60d8ef929d52efc587d3d6308fd24641cd7d /xmloff
parentfc8b757dad5d98f4ba1cd40d03505873128670cd (diff)
tdf#148198: merge identical hyperlinks of adjacent text ranges on ODF export
The true hyperlink boundaries are available as SwpHints starts/ends, which are used in DOC(X) export (see SwWW8AttrIter::OutAttrWithRange). However, I don't see a reasonable way to expose this information to xmloff, so I decided instead to just merge the identical hyperlink properties of adjacent ranges into a single hyperlink. This will allow to fix already split hyperlinks saved in previous versions. The downside is that this disallows to have separate adjacent identical hyperlinks - I hope that this would not be a real issue. Change-Id: I901e6035a5e89bc515b5742c6a5f564c77faf05b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137013 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Diffstat (limited to 'xmloff')
-rw-r--r--xmloff/source/text/txtflde.cxx35
-rw-r--r--xmloff/source/text/txtftne.cxx30
-rw-r--r--xmloff/source/text/txtparae.cxx288
3 files changed, 169 insertions, 184 deletions
diff --git a/xmloff/source/text/txtflde.cxx b/xmloff/source/text/txtflde.cxx
index 242b641369c8..54341aab0b01 100644
--- a/xmloff/source/text/txtflde.cxx
+++ b/xmloff/source/text/txtflde.cxx
@@ -991,44 +991,15 @@ void XMLTextFieldExport::ExportField(
? aStates
: nullptr;
- // find out whether we need to set the style or hyperlink
- bool bHasHyperlink;
+ // find out whether we need to set the style
bool bIsUICharStyle;
bool bHasAutoStyle;
OUString sStyle = GetExport().GetTextParagraphExport()->
- FindTextStyleAndHyperlink( xRangePropSet, bHasHyperlink, bIsUICharStyle,
- bHasAutoStyle, pStates );
+ FindTextStyle( xRangePropSet, bIsUICharStyle, bHasAutoStyle, pStates );
bool bHasStyle = !sStyle.isEmpty();
- // export hyperlink (if we have one)
- Reference < XPropertySetInfo > xRangePropSetInfo;
- if( bHasHyperlink )
- {
- Reference<XPropertyState> xRangePropState( xRangePropSet, UNO_QUERY );
- xRangePropSetInfo = xRangePropSet->getPropertySetInfo();
- bHasHyperlink =
- GetExport().GetTextParagraphExport()->addHyperlinkAttributes(
- xRangePropSet, xRangePropState,
- xRangePropSetInfo );
- }
- SvXMLElementExport aHyperlink( GetExport(), bHasHyperlink,
- XML_NAMESPACE_TEXT, XML_A,
- false, false );
-
- if( bHasHyperlink )
- {
- // export events (if supported)
- OUString sHyperLinkEvents("HyperLinkEvents");
- if (xRangePropSetInfo->hasPropertyByName(sHyperLinkEvents))
- {
- Any aAny = xRangePropSet->getPropertyValue(sHyperLinkEvents);
- Reference<XNameReplace> xName;
- aAny >>= xName;
- GetExport().GetEventExport().Export(xName, false);
- }
- }
-
{
+ Reference<XPropertySetInfo> xRangePropSetInfo;
XMLTextCharStyleNamesElementExport aCharStylesExport(
GetExport(), bIsUICharStyle &&
GetExport().GetTextParagraphExport()
diff --git a/xmloff/source/text/txtftne.cxx b/xmloff/source/text/txtftne.cxx
index ff37cd990b32..333ec7c6f783 100644
--- a/xmloff/source/text/txtftne.cxx
+++ b/xmloff/source/text/txtftne.cxx
@@ -89,38 +89,10 @@ void XMLTextParagraphExport::exportTextFootnote(
{
// create span (for citation mark) if necessary; footnote content
// will be handled via exportTextFootnoteHelper, exportText
- bool bHasHyperlink;
bool bIsUICharStyle = false;
bool bHasAutoStyle = false;
- OUString sStyle = FindTextStyleAndHyperlink( rPropSet, bHasHyperlink,
- bIsUICharStyle, bHasAutoStyle );
-
- // export hyperlink (if we have one)
- Reference < XPropertySetInfo > xPropSetInfo;
- if( bHasHyperlink )
- {
- Reference<XPropertyState> xPropState( rPropSet, UNO_QUERY );
- xPropSetInfo = rPropSet->getPropertySetInfo();
- bHasHyperlink =
- addHyperlinkAttributes( rPropSet, xPropState, xPropSetInfo );
- }
- SvXMLElementExport aHyperlink( GetExport(), bHasHyperlink,
- XML_NAMESPACE_TEXT, XML_A,
- false, false );
-
- if( bHasHyperlink )
- {
- // export events (if supported)
- OUString sHyperLinkEvents("HyperLinkEvents");
- if (xPropSetInfo->hasPropertyByName(sHyperLinkEvents))
- {
- Any a = rPropSet->getPropertyValue(sHyperLinkEvents);
- Reference<XNameReplace> xName;
- a >>= xName;
- GetExport().GetEventExport().Export(xName, false);
- }
- }
+ OUString sStyle = FindTextStyle( rPropSet, bIsUICharStyle, bHasAutoStyle );
{
XMLTextCharStyleNamesElementExport aCharStylesExport(
diff --git a/xmloff/source/text/txtparae.cxx b/xmloff/source/text/txtparae.cxx
index 5b2cb233dd38..13378e3902e2 100644
--- a/xmloff/source/text/txtparae.cxx
+++ b/xmloff/source/text/txtparae.cxx
@@ -280,6 +280,148 @@ namespace
void ExportParameter(const OUString& sKey, const OUString& sValue);
};
+
+ struct HyperlinkData
+ {
+ OUString href, name, targetFrame, ustyleName, vstyleName;
+ bool serverMap = false;
+ css::uno::Reference<css::container::XNameReplace> events;
+
+ HyperlinkData() = default;
+ HyperlinkData(const css::uno::Reference<css::beans::XPropertySet>& rPropSet);
+
+ bool operator==(const HyperlinkData&);
+ bool operator!=(const HyperlinkData& rOther) { return !operator==(rOther); }
+
+ bool addHyperlinkAttributes(SvXMLExport& rExport);
+ void exportEvents(SvXMLExport& rExport);
+ };
+
+ HyperlinkData::HyperlinkData(const css::uno::Reference<css::beans::XPropertySet>& rPropSet)
+ {
+ const css::uno::Reference<css::beans::XPropertyState> xPropState(rPropSet, UNO_QUERY);
+ const auto xPropSetInfo(rPropSet->getPropertySetInfo());
+ if (xPropSetInfo->hasPropertyByName(gsHyperLinkURL)
+ && (!xPropState.is()
+ || PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsHyperLinkURL)))
+ {
+ rPropSet->getPropertyValue(gsHyperLinkURL) >>= href;
+ }
+
+ if (href.isEmpty())
+ return;
+
+ if (xPropSetInfo->hasPropertyByName(gsHyperLinkName)
+ && (!xPropState.is()
+ || PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsHyperLinkName)))
+ {
+ rPropSet->getPropertyValue(gsHyperLinkName) >>= name;
+ }
+
+ if (xPropSetInfo->hasPropertyByName(gsHyperLinkTarget)
+ && (!xPropState.is()
+ || PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsHyperLinkTarget)))
+ {
+ rPropSet->getPropertyValue(gsHyperLinkTarget) >>= targetFrame;
+ }
+
+ if (xPropSetInfo->hasPropertyByName(gsServerMap)
+ && (!xPropState.is()
+ || PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsServerMap)))
+ {
+ serverMap = *o3tl::doAccess<bool>(rPropSet->getPropertyValue(gsServerMap));
+ }
+
+ if (xPropSetInfo->hasPropertyByName(gsUnvisitedCharStyleName)
+ && (!xPropState.is()
+ || PropertyState_DIRECT_VALUE
+ == xPropState->getPropertyState(gsUnvisitedCharStyleName)))
+ {
+ rPropSet->getPropertyValue(gsUnvisitedCharStyleName) >>= ustyleName;
+ }
+
+ if (xPropSetInfo->hasPropertyByName(gsVisitedCharStyleName)
+ && (!xPropState.is()
+ || PropertyState_DIRECT_VALUE
+ == xPropState->getPropertyState(gsVisitedCharStyleName)))
+ {
+ rPropSet->getPropertyValue(gsVisitedCharStyleName) >>= vstyleName;
+ }
+
+ static constexpr OUStringLiteral sHyperLinkEvents(u"HyperLinkEvents");
+ if (xPropSetInfo->hasPropertyByName(sHyperLinkEvents))
+ {
+ events.set(rPropSet->getPropertyValue(sHyperLinkEvents), uno::UNO_QUERY);
+ }
+ }
+
+ bool HyperlinkData::operator==(const HyperlinkData& rOther)
+ {
+ if (href != rOther.href || name != rOther.name || targetFrame != rOther.targetFrame
+ || ustyleName != rOther.ustyleName || vstyleName != rOther.vstyleName
+ || serverMap != rOther.serverMap)
+ return false;
+
+ if (events == rOther.events)
+ return true;
+ if (!events || !rOther.events)
+ return false;
+
+ const css::uno::Sequence<OUString> aNames = events->getElementNames();
+ if (aNames != rOther.events->getElementNames())
+ return false;
+ for (const auto& rName : aNames)
+ {
+ const css::uno::Any aAny = events->getByName(rName);
+ const css::uno::Any aOtherAny = rOther.events->getByName(rName);
+ if (aAny != aOtherAny)
+ return false;
+ }
+ return true;
+ }
+
+ bool HyperlinkData::addHyperlinkAttributes(SvXMLExport& rExport)
+ {
+ if (href.isEmpty())
+ {
+ // hyperlink without a URL does not make sense
+ OSL_ENSURE(false, "hyperlink without a URL --> no export to ODF");
+ return false;
+ }
+
+ rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
+ rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, rExport.GetRelativeReference(href));
+
+ if (!name.isEmpty())
+ rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_NAME, name);
+
+ if (!targetFrame.isEmpty())
+ {
+ rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_TARGET_FRAME_NAME, targetFrame);
+ enum XMLTokenEnum eTok = targetFrame == "_blank" ? XML_NEW : XML_REPLACE;
+ rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, eTok);
+ }
+
+ if (serverMap)
+ rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_SERVER_MAP, XML_TRUE);
+
+ if (!ustyleName.isEmpty())
+ rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_STYLE_NAME,
+ rExport.EncodeStyleName(ustyleName));
+
+ if (!vstyleName.isEmpty())
+ rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_VISITED_STYLE_NAME,
+ rExport.EncodeStyleName(vstyleName));
+
+ return true;
+ }
+
+ void HyperlinkData::exportEvents(SvXMLExport& rExport)
+ {
+ // export events (if supported)
+ if (events)
+ rExport.GetEventExport().Export(events, false);
+ }
}
namespace xmloff
@@ -769,9 +911,8 @@ OUString XMLTextParagraphExport::Find(
return sName;
}
-OUString XMLTextParagraphExport::FindTextStyleAndHyperlink(
+OUString XMLTextParagraphExport::FindTextStyle(
const Reference < XPropertySet > & rPropSet,
- bool& rbHyperlink,
bool& rbHasCharStyle,
bool& rbHasAutoStyle,
const XMLPropertyState** ppAddStates ) const
@@ -781,7 +922,7 @@ OUString XMLTextParagraphExport::FindTextStyleAndHyperlink(
// Get parent and remove hyperlinks (they aren't of interest)
OUString sName;
- rbHyperlink = rbHasCharStyle = rbHasAutoStyle = false;
+ rbHasCharStyle = rbHasAutoStyle = false;
sal_uInt16 nIgnoreProps = 0;
rtl::Reference< XMLPropertySetMapper > xPM(xPropMapper->getPropertySetMapper());
::std::vector< XMLPropertyState >::iterator aFirstDel = aPropStates.end();
@@ -808,7 +949,6 @@ OUString XMLTextParagraphExport::FindTextStyleAndHyperlink(
nIgnoreProps++;
break;
case CTF_HYPERLINK_URL:
- rbHyperlink = true;
i->mnIndex = -1;
if( nIgnoreProps )
aSecondDel = i;
@@ -2123,12 +2263,29 @@ void XMLTextParagraphExport::exportTextRangeEnumeration(
* bookmarks are used instead of fieldmarks. */
FieldmarkType openFieldMark = NONE;
+ std::optional<SvXMLElementExport> oTextA;
+ HyperlinkData aHyperlinkData;
+
while( rTextEnum->hasMoreElements() )
{
Reference<XPropertySet> xPropSet(rTextEnum->nextElement(), UNO_QUERY);
Reference < XTextRange > xTxtRange(xPropSet, uno::UNO_QUERY);
Reference<XPropertySetInfo> xPropInfo(xPropSet->getPropertySetInfo());
+ if (!bAutoStyles)
+ {
+ if (HyperlinkData aNewHyperlinkData(xPropSet); aNewHyperlinkData != aHyperlinkData)
+ {
+ aHyperlinkData = aNewHyperlinkData;
+ oTextA.reset();
+ if (aHyperlinkData.addHyperlinkAttributes(GetExport()))
+ {
+ oTextA.emplace(GetExport(), true, XML_NAMESPACE_TEXT, XML_A, false, false);
+ aHyperlinkData.exportEvents(GetExport());
+ }
+ }
+ }
+
if (xPropInfo->hasPropertyByName(gsTextPortionType))
{
OUString sType;
@@ -2890,7 +3047,6 @@ void XMLTextParagraphExport::exportAnyTextFrame(
else
{
Reference< XPropertySetInfo > xPropSetInfo(xPropSet->getPropertySetInfo());
- Reference< XPropertyState > xPropState( xPropSet, UNO_QUERY );
{
bool bAddCharStyles = pRangePropSet &&
lcl_txtpara_isBoundAsChar( xPropSet, xPropSetInfo );
@@ -2901,10 +3057,7 @@ void XMLTextParagraphExport::exportAnyTextFrame(
OUString sStyle;
if( bAddCharStyles )
- {
- bool bDummy;
- sStyle = FindTextStyleAndHyperlink( *pRangePropSet, bDummy, bIsUICharStyle, bHasAutoStyle );
- }
+ sStyle = FindTextStyle( *pRangePropSet, bIsUICharStyle, bHasAutoStyle );
else
bIsUICharStyle = false;
@@ -2924,8 +3077,7 @@ void XMLTextParagraphExport::exportAnyTextFrame(
{
SvXMLElementExport aElement( GetExport(),
FrameType::Shape != eType &&
- addHyperlinkAttributes( xPropSet,
- xPropState,xPropSetInfo ),
+ HyperlinkData(xPropSet).addHyperlinkAttributes(GetExport()),
XML_NAMESPACE_DRAW, XML_A, false, false );
switch( eType )
{
@@ -3364,89 +3516,6 @@ void XMLTextParagraphExport::exportTitleAndDescription(
}
}
-bool XMLTextParagraphExport::addHyperlinkAttributes(
- const Reference< XPropertySet > & rPropSet,
- const Reference< XPropertyState > & rPropState,
- const Reference< XPropertySetInfo > & rPropSetInfo )
-{
- OUString sHRef;
-
- if( rPropSetInfo->hasPropertyByName( gsHyperLinkURL ) &&
- ( !rPropState.is() || PropertyState_DIRECT_VALUE ==
- rPropState->getPropertyState( gsHyperLinkURL ) ) )
- {
- rPropSet->getPropertyValue( gsHyperLinkURL ) >>= sHRef;
- }
-
- if ( sHRef.isEmpty() )
- {
- // hyperlink without a URL does not make sense
- OSL_ENSURE( false, "hyperlink without a URL --> no export to ODF" );
- return false;
- }
-
- GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
- GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_HREF,
- GetExport().GetRelativeReference(sHRef));
-
- if ( rPropSetInfo->hasPropertyByName( gsHyperLinkName )
- && ( !rPropState.is()
- || PropertyState_DIRECT_VALUE == rPropState->getPropertyState( gsHyperLinkName ) ) )
- {
- OUString sName;
- rPropSet->getPropertyValue( gsHyperLinkName ) >>= sName;
- if( !sName.isEmpty() )
- GetExport().AddAttribute(XML_NAMESPACE_OFFICE, XML_NAME, sName);
- }
-
- if ( rPropSetInfo->hasPropertyByName( gsHyperLinkTarget )
- && ( !rPropState.is()
- || PropertyState_DIRECT_VALUE == rPropState->getPropertyState( gsHyperLinkTarget ) ) )
- {
- OUString sTargetFrame;
- rPropSet->getPropertyValue( gsHyperLinkTarget ) >>= sTargetFrame;
- if( !sTargetFrame.isEmpty() )
- {
- GetExport().AddAttribute(XML_NAMESPACE_OFFICE, XML_TARGET_FRAME_NAME, sTargetFrame);
- enum XMLTokenEnum eTok = sTargetFrame == "_blank" ? XML_NEW : XML_REPLACE;
- GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, eTok);
- }
- }
-
- if ( rPropSetInfo->hasPropertyByName( gsServerMap )
- && ( !rPropState.is()
- || PropertyState_DIRECT_VALUE == rPropState->getPropertyState( gsServerMap ) ) )
- {
- bool bServerMap = *o3tl::doAccess<bool>(rPropSet->getPropertyValue( gsServerMap ));
- if ( bServerMap )
- GetExport().AddAttribute(XML_NAMESPACE_OFFICE, XML_SERVER_MAP, XML_TRUE);
- }
-
- if ( rPropSetInfo->hasPropertyByName( gsUnvisitedCharStyleName )
- && ( !rPropState.is()
- || PropertyState_DIRECT_VALUE == rPropState->getPropertyState( gsUnvisitedCharStyleName ) ) )
- {
- OUString sUStyleName;
- rPropSet->getPropertyValue( gsUnvisitedCharStyleName ) >>= sUStyleName;
- if( !sUStyleName.isEmpty() )
- GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_STYLE_NAME,
- GetExport().EncodeStyleName(sUStyleName));
- }
-
- if ( rPropSetInfo->hasPropertyByName( gsVisitedCharStyleName )
- && ( !rPropState.is()
- || PropertyState_DIRECT_VALUE == rPropState->getPropertyState( gsVisitedCharStyleName ) ) )
- {
- OUString sVStyleName;
- rPropSet->getPropertyValue( gsVisitedCharStyleName ) >>= sVStyleName;
- if( !sVStyleName.isEmpty() )
- GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_VISITED_STYLE_NAME,
- GetExport().EncodeStyleName(sVStyleName));
- }
-
- return true;
-}
-
void XMLTextParagraphExport::exportTextRangeSpan(
const css::uno::Reference< css::text::XTextRange > & rTextRange,
Reference< XPropertySet > const & xPropSet,
@@ -3492,40 +3561,13 @@ void XMLTextParagraphExport::exportTextRange(
}
else
{
- bool bHyperlink = false;
bool bIsUICharStyle = false;
bool bHasAutoStyle = false;
const OUString sStyle(
- FindTextStyleAndHyperlink( xPropSet, bHyperlink, bIsUICharStyle, bHasAutoStyle ) );
+ FindTextStyle( xPropSet, bIsUICharStyle, bHasAutoStyle ) );
Reference < XPropertySetInfo > xPropSetInfo;
- bool bHyperlinkAttrsAdded = false;
- if ( bHyperlink )
- {
- Reference< XPropertyState > xPropState( xPropSet, UNO_QUERY );
- xPropSetInfo.set( xPropSet->getPropertySetInfo() );
- bHyperlinkAttrsAdded = addHyperlinkAttributes( xPropSet, xPropState, xPropSetInfo );
- }
-
- if ( bHyperlink && bHyperlinkAttrsAdded )
- {
- SvXMLElementExport aElem( GetExport(), true, XML_NAMESPACE_TEXT, XML_A, false, false );
-
- // export events (if supported)
- OUString sHyperLinkEvents(
- "HyperLinkEvents");
- if (xPropSetInfo->hasPropertyByName(sHyperLinkEvents))
- {
- Reference< XNameReplace > xName( xPropSet->getPropertyValue( sHyperLinkEvents ), uno::UNO_QUERY );
- GetExport().GetEventExport().Export( xName, false );
- }
-
- exportTextRangeSpan( rTextRange, xPropSet, xPropSetInfo, bIsUICharStyle, bHasAutoStyle, sStyle, rPrevCharIsSpace, openFieldMark );
- }
- else
- {
- exportTextRangeSpan( rTextRange, xPropSet, xPropSetInfo, bIsUICharStyle, bHasAutoStyle, sStyle, rPrevCharIsSpace, openFieldMark );
- }
+ exportTextRangeSpan( rTextRange, xPropSet, xPropSetInfo, bIsUICharStyle, bHasAutoStyle, sStyle, rPrevCharIsSpace, openFieldMark );
}
}