summaryrefslogtreecommitdiff
path: root/sw
diff options
context:
space:
mode:
authorMichael Stahl <michael.stahl@allotropia.de>2021-04-15 20:00:57 +0200
committerMichael Stahl <michael.stahl@allotropia.de>2021-04-16 13:15:17 +0200
commitaef98f20529f8702579916d68c46cd2129e205cb (patch)
tree509e794ec87c1842da77127a1be010113df7d168 /sw
parentbbbd6ce1c61fe8b1335e16dfa7b75c6bb5d375e4 (diff)
sw: DOCX export: write hyperlinks for TOXMark TOX entries
* add hyperlink preprocessing in MSWordExportBase::AddLinkTarget() * <w:hyperlink> in the TOX entry * <w:bookmarkStart>/<w:bookmarkEnd> in the field command Change-Id: I4d18778d8ac594a1b4cb43bf0e1234f875eeaf95 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114170 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
Diffstat (limited to 'sw')
-rw-r--r--sw/inc/tox.hxx3
-rw-r--r--sw/source/filter/ww8/attributeoutputbase.hxx2
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx42
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.hxx6
-rw-r--r--sw/source/filter/ww8/rtfattributeoutput.cxx3
-rw-r--r--sw/source/filter/ww8/rtfattributeoutput.hxx2
-rw-r--r--sw/source/filter/ww8/wrtw8nds.cxx12
-rw-r--r--sw/source/filter/ww8/wrtww8.cxx21
-rw-r--r--sw/source/filter/ww8/wrtww8.hxx2
-rw-r--r--sw/source/filter/ww8/ww8attributeoutput.hxx2
-rw-r--r--sw/source/uibase/uiview/view2.cxx42
11 files changed, 112 insertions, 25 deletions
diff --git a/sw/inc/tox.hxx b/sw/inc/tox.hxx
index f1b496091246..4555335e44ae 100644
--- a/sw/inc/tox.hxx
+++ b/sw/inc/tox.hxx
@@ -20,6 +20,7 @@
#define INCLUDED_SW_INC_TOX_HXX
#include <vector>
+#include <optional>
#include <cppuhelper/weakref.hxx>
#include <editeng/svxenum.hxx>
@@ -69,6 +70,8 @@ namespace sw {
const SwRootFrame* m_pLayout;
CollectTextTOXMarksForLayoutHint(std::vector<std::reference_wrapper<SwTextTOXMark>>& rMarks, const SwRootFrame* pLayout) : m_rMarks(rMarks), m_pLayout(pLayout) {}
};
+ SW_DLLPUBLIC auto PrepareJumpToTOXMark(SwDoc const& rDoc, OUString const& rName)
+ -> std::optional<std::pair<SwTOXMark, sal_Int32>>;
}
// Entry of content index, alphabetical index or user defined index
diff --git a/sw/source/filter/ww8/attributeoutputbase.hxx b/sw/source/filter/ww8/attributeoutputbase.hxx
index df84fa323120..a34848e6df7e 100644
--- a/sw/source/filter/ww8/attributeoutputbase.hxx
+++ b/sw/source/filter/ww8/attributeoutputbase.hxx
@@ -209,7 +209,7 @@ public:
/// Output URL end.
virtual bool EndURL(bool isAtEndOfParagraph) = 0;
- virtual void FieldVanish( const OUString& rText, ww::eField eType ) = 0;
+ virtual void FieldVanish(const OUString& rText, ww::eField eType, OUString const*) = 0;
/// MSO uses bookmarks to reference sequence fields, so we need to generate these additional bookmarks during export
void GenerateBookmarksForSequenceField(const SwTextNode& rNode, SwWW8AttrIter& rAttrIter);
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index d0fd48ffb15f..e3ad3f917942 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -1451,6 +1451,16 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /
}
if (pIt->bSep && !pIt->pField)
{
+ // for TOXMark:
+ // Word ignores bookmarks in field result that is empty;
+ // work around this by writing bookmark into field command.
+ if (!m_sFieldBkm.isEmpty())
+ {
+ DoWriteBookmarkTagStart(m_sFieldBkm);
+ DoWriteBookmarkTagEnd(m_nNextBookmarkId);
+ m_nNextBookmarkId++;
+ m_sFieldBkm.clear();
+ }
CmdEndField_Impl(pNode, nPos, true);
// Remove the field if no end needs to be written
if (!pIt->bClose)
@@ -2370,13 +2380,21 @@ void DocxAttributeOutput::EndField_Impl( const SwTextNode* pNode, sal_Int32 nPos
// Write the ref field if a bookmark had to be set and the field
// should be visible
if ( !rInfos.pField )
+ {
+ m_sFieldBkm.clear();
return;
+ }
sal_uInt16 nSubType = rInfos.pField->GetSubType( );
bool bIsSetField = rInfos.pField->GetTyp( )->Which( ) == SwFieldIds::SetExp;
bool bShowRef = bIsSetField && ( nSubType & nsSwExtendedSubType::SUB_INVISIBLE ) == 0;
- if ( m_sFieldBkm.isEmpty() || !bShowRef )
+ if (!bShowRef)
+ {
+ m_sFieldBkm.clear();
+ }
+
+ if (m_sFieldBkm.isEmpty())
return;
// Write the field beginning
@@ -3059,6 +3077,14 @@ bool DocxAttributeOutput::StartURL( const OUString& rUrl, const OUString& rTarge
}
}
}
+ else if (sMark.endsWith("|toxmark"))
+ {
+ if (auto const it = GetExport().m_TOXMarkBookmarksByURL.find(sMark);
+ it != GetExport().m_TOXMarkBookmarksByURL.end())
+ {
+ sMark = it->second;
+ }
+ }
// Spaces are prohibited in bookmark name.
sMark = sMark.replace(' ', '_');
m_pHyperlinkAttrList->add( FSNS( XML_w, XML_anchor ),
@@ -3085,9 +3111,10 @@ bool DocxAttributeOutput::EndURL(bool const)
return true;
}
-void DocxAttributeOutput::FieldVanish( const OUString& rText, ww::eField eType )
+void DocxAttributeOutput::FieldVanish(const OUString& rText,
+ ww::eField const eType, OUString const*const pBookmarkName)
{
- WriteField_Impl( nullptr, eType, rText, FieldFlags::All );
+ WriteField_Impl(nullptr, eType, rText, FieldFlags::All, pBookmarkName);
}
// The difference between 'Redline' and 'StartRedline'+'EndRedline' is that:
@@ -8044,7 +8071,9 @@ void DocxAttributeOutput::WriteExpand( const SwField* pField )
m_rExport.OutputField( pField, ww::eUNKNOWN, OUString() );
}
-void DocxAttributeOutput::WriteField_Impl( const SwField* pField, ww::eField eType, const OUString& rFieldCmd, FieldFlags nMode )
+void DocxAttributeOutput::WriteField_Impl(const SwField *const pField,
+ ww::eField const eType, const OUString& rFieldCmd, FieldFlags const nMode,
+ OUString const*const pBookmarkName)
{
if (m_bPreventDoubleFieldsHandling)
return;
@@ -8059,6 +8088,11 @@ void DocxAttributeOutput::WriteField_Impl( const SwField* pField, ww::eField eTy
infos.bOpen = bool(FieldFlags::Start & nMode);
m_Fields.push_back( infos );
+ if (pBookmarkName)
+ {
+ m_sFieldBkm = *pBookmarkName;
+ }
+
if ( !pField )
return;
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx
index 4b7e807c1927..8910c7eabf49 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -182,7 +182,7 @@ public:
/// Output URL end.
virtual bool EndURL(bool) override;
- virtual void FieldVanish( const OUString& rText, ww::eField eType ) override;
+ virtual void FieldVanish(const OUString& rText, ww::eField eType, OUString const*) override;
/// Output redlining.
///
@@ -356,7 +356,9 @@ public:
const OUString &rNumberingString,
const SvxBrushItem* pBrush ) override;
- void WriteField_Impl( const SwField* pField, ww::eField eType, const OUString& rFieldCmd, FieldFlags nMode );
+ void WriteField_Impl(const SwField* pField, ww::eField eType,
+ const OUString& rFieldCmd, FieldFlags nMode,
+ OUString const* pBookmarkName = nullptr);
void WriteFormData_Impl( const ::sw::mark::IFieldmark& rFieldmark );
void WriteBookmarks_Impl( std::vector< OUString >& rStarts, std::vector< OUString >& rEnds );
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx
index 37f50a9e6a89..35f30f67aff0 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -600,7 +600,8 @@ bool RtfAttributeOutput::EndURL(bool const isAtEndOfParagraph)
return true;
}
-void RtfAttributeOutput::FieldVanish(const OUString& /*rText*/, ww::eField /*eType*/)
+void RtfAttributeOutput::FieldVanish(const OUString& /*rText*/, ww::eField /*eType*/,
+ OUString const*)
{
SAL_INFO("sw.rtf", "TODO: " << __func__);
}
diff --git a/sw/source/filter/ww8/rtfattributeoutput.hxx b/sw/source/filter/ww8/rtfattributeoutput.hxx
index 94bb37af9686..ae44869ea2c8 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.hxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.hxx
@@ -103,7 +103,7 @@ public:
/// Output URL end.
bool EndURL(bool isAtEndOfParagraph) override;
- void FieldVanish(const OUString& rText, ww::eField eType) override;
+ void FieldVanish(const OUString& rText, ww::eField eType, OUString const*) override;
/// Output redlining.
///
diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx
index 5f96377e7d2c..9dcc1fdacd0e 100644
--- a/sw/source/filter/ww8/wrtw8nds.cxx
+++ b/sw/source/filter/ww8/wrtw8nds.cxx
@@ -1249,7 +1249,7 @@ void SwWW8AttrIter::SplitRun( sal_Int32 nSplitEndPos )
nCurrentSwPos = SearchNext(1);
}
-void WW8AttributeOutput::FieldVanish( const OUString& rText, ww::eField /*eType*/ )
+void WW8AttributeOutput::FieldVanish(const OUString& rText, ww::eField /*eType*/, OUString const*const)
{
ww::bytes aItems;
m_rWW8Export.GetCurrentItems( aItems );
@@ -1327,7 +1327,15 @@ void AttributeOutputBase::TOXMark( const SwTextNode& rNode, const SwTOXMark& rAt
}
if (!sText.isEmpty())
- FieldVanish( sText, eType );
+ {
+ OUString const* pBookmarkName(nullptr);
+ if (auto const it = GetExport().m_TOXMarkBookmarksByTOXMark.find(&rAttr);
+ it != GetExport().m_TOXMarkBookmarksByTOXMark.end())
+ {
+ pBookmarkName = &it->second;
+ }
+ FieldVanish(sText, eType, pBookmarkName);
+ }
}
int SwWW8AttrIter::OutAttrWithRange(const SwTextNode& rNode, sal_Int32 nPos)
diff --git a/sw/source/filter/ww8/wrtww8.cxx b/sw/source/filter/ww8/wrtww8.cxx
index bab71c2cff39..52c8ebf72dfa 100644
--- a/sw/source/filter/ww8/wrtww8.cxx
+++ b/sw/source/filter/ww8/wrtww8.cxx
@@ -3215,6 +3215,27 @@ void MSWordExportBase::AddLinkTarget(const OUString& rURL)
}
}
}
+ else if (sCmp == "toxmark")
+ {
+ OUString const name(aURL.copy(0, nPos));
+ OUString const nameDecoded(INetURLObject::decode(name,
+ INetURLObject::DecodeMechanism::WithCharset));
+ std::optional<std::pair<SwTOXMark, sal_Int32>> const tmp(
+ sw::PrepareJumpToTOXMark(m_rDoc, nameDecoded));
+ if (tmp)
+ {
+ SwTOXMark const* pMark(&tmp->first);
+ for (sal_Int32 i = 0; i < tmp->second; ++i)
+ {
+ pMark = &m_rDoc.GotoTOXMark(*pMark, TOX_SAME_NXT, true);
+ }
+ if (pMark != &tmp->first)
+ {
+ m_TOXMarkBookmarksByURL.emplace(aURL, name);
+ m_TOXMarkBookmarksByTOXMark.emplace(pMark, nameDecoded);
+ }
+ }
+ }
if (noBookmark)
{
aBookmarkPair aImplicitBookmark;
diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx
index 1c4c3e936d82..15e0d902731b 100644
--- a/sw/source/filter/ww8/wrtww8.hxx
+++ b/sw/source/filter/ww8/wrtww8.hxx
@@ -490,6 +490,8 @@ public:
public:
/* implicit bookmark vector containing pairs of node indexes and bookmark names */
std::vector<aBookmarkPair> m_aImplicitBookmarks;
+ std::unordered_map<OUString, OUString> m_TOXMarkBookmarksByURL;
+ std::unordered_map<SwTOXMark const*, OUString> m_TOXMarkBookmarksByTOXMark;
ww8::Frames m_aFrames; // The floating frames in this document
const SwPageDesc *m_pCurrentPageDesc;
bool m_bFirstTOCNodeWithSection;
diff --git a/sw/source/filter/ww8/ww8attributeoutput.hxx b/sw/source/filter/ww8/ww8attributeoutput.hxx
index f9ea183d1e6b..b748abb6e1da 100644
--- a/sw/source/filter/ww8/ww8attributeoutput.hxx
+++ b/sw/source/filter/ww8/ww8attributeoutput.hxx
@@ -84,7 +84,7 @@ public:
/// Output URL end.
virtual bool EndURL(bool) override;
- virtual void FieldVanish( const OUString& rText, ww::eField eType ) override;
+ virtual void FieldVanish(const OUString& rText, ww::eField eType, OUString const*) override;
/// Output redlining.
virtual void Redline( const SwRedlineData* pRedline ) override;
diff --git a/sw/source/uibase/uiview/view2.cxx b/sw/source/uibase/uiview/view2.cxx
index 70395f6f6275..941b82d038f8 100644
--- a/sw/source/uibase/uiview/view2.cxx
+++ b/sw/source/uibase/uiview/view2.cxx
@@ -2061,31 +2061,34 @@ void SwView::EditLinkDlg()
pDlg->Execute();
}
-static auto JumpToTOXMark(SwWrtShell & rSh, OUString const& rName) -> bool
+namespace sw {
+
+auto PrepareJumpToTOXMark(SwDoc const& rDoc, OUString const& rName)
+ -> std::optional<std::pair<SwTOXMark, sal_Int32>>
{
sal_Int32 const first(rName.indexOf(toxMarkSeparator));
if (first == -1)
{
SAL_WARN("sw.ui", "JumpToTOXMark: missing separator");
- return false;
+ return std::optional<std::pair<SwTOXMark, sal_Int32>>();
}
sal_Int32 const counter(rName.copy(0, first).toInt32());
if (counter <= 0)
{
SAL_WARN("sw.ui", "JumpToTOXMark: invalid counter");
- return false;
+ return std::optional<std::pair<SwTOXMark, sal_Int32>>();
}
sal_Int32 const second(rName.indexOf(toxMarkSeparator, first + 1));
if (second == -1)
{
SAL_WARN("sw.ui", "JumpToTOXMark: missing separator");
- return false;
+ return std::optional<std::pair<SwTOXMark, sal_Int32>>();
}
OUString const entry(rName.copy(first + 1, second - (first + 1)));
if (rName.getLength() < second + 2)
{
SAL_WARN("sw.ui", "JumpToTOXMark: invalid tox");
- return false;
+ return std::optional<std::pair<SwTOXMark, sal_Int32>>();
}
sal_uInt16 const indexType(rName[second + 1]);
OUString const indexName(rName.copy(second + 2));
@@ -2093,18 +2096,18 @@ static auto JumpToTOXMark(SwWrtShell & rSh, OUString const& rName) -> bool
switch (indexType)
{
case 'A':
- pType = rSh.GetTOXType(TOX_INDEX, 0);
+ pType = rDoc.GetTOXType(TOX_INDEX, 0);
assert(pType);
break;
case 'C':
- pType = rSh.GetTOXType(TOX_CONTENT, 0);
+ pType = rDoc.GetTOXType(TOX_CONTENT, 0);
assert(pType);
break;
case 'U':
- for (auto i = rSh.GetTOXTypeCount(TOX_USER); 0 < i; )
+ for (auto i = rDoc.GetTOXTypeCount(TOX_USER); 0 < i; )
{
--i;
- auto const pTmp(rSh.GetTOXType(TOX_USER, i));
+ auto const pTmp(rDoc.GetTOXType(TOX_USER, i));
if (pTmp->GetTypeName() == indexName)
{
pType = pTmp;
@@ -2116,16 +2119,29 @@ static auto JumpToTOXMark(SwWrtShell & rSh, OUString const& rName) -> bool
if (!pType)
{
SAL_WARN("sw.ui", "JumpToTOXMark: tox doesn't exist");
- return false;
+ return std::optional<std::pair<SwTOXMark, sal_Int32>>();
}
// type and alt text are the search keys
SwTOXMark tmp(pType);
tmp.SetAlternativeText(entry);
- SwTOXMark const* pMark(&tmp);
+ return std::optional<std::pair<SwTOXMark, sal_Int32>>(std::pair<SwTOXMark, sal_Int32>(tmp, counter));
+}
+
+} // namespace sw
+
+static auto JumpToTOXMark(SwWrtShell & rSh, OUString const& rName) -> bool
+{
+ std::optional<std::pair<SwTOXMark, sal_Int32>> const tmp(
+ sw::PrepareJumpToTOXMark(*rSh.GetDoc(), rName));
+ if (!tmp)
+ {
+ return false;
+ }
+ SwTOXMark const* pMark(&tmp->first);
// hack: check first if one exists
- if (&tmp != &rSh.GetDoc()->GotoTOXMark(tmp, TOX_SAME_NXT, rSh.IsReadOnlyAvailable()))
+ if (&tmp->first != &rSh.GetDoc()->GotoTOXMark(tmp->first, TOX_SAME_NXT, rSh.IsReadOnlyAvailable()))
{
- for (sal_Int32 i = 0; i < counter; ++i)
+ for (sal_Int32 i = 0; i < tmp->second; ++i)
{
pMark = &rSh.GotoTOXMark(*pMark, TOX_SAME_NXT);
}