sw/inc/tox.hxx | 3 + sw/source/filter/ww8/attributeoutputbase.hxx | 2 - sw/source/filter/ww8/docxattributeoutput.cxx | 42 ++++++++++++++++++++++++--- sw/source/filter/ww8/docxattributeoutput.hxx | 6 ++- sw/source/filter/ww8/rtfattributeoutput.cxx | 3 + sw/source/filter/ww8/rtfattributeoutput.hxx | 2 - sw/source/filter/ww8/wrtw8nds.cxx | 12 ++++++- sw/source/filter/ww8/wrtww8.cxx | 21 +++++++++++++ sw/source/filter/ww8/wrtww8.hxx | 2 + sw/source/filter/ww8/ww8attributeoutput.hxx | 2 - sw/source/uibase/uiview/view2.cxx | 42 ++++++++++++++++++--------- 11 files changed, 112 insertions(+), 25 deletions(-)
New commits: commit aef98f20529f8702579916d68c46cd2129e205cb Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Thu Apr 15 20:00:57 2021 +0200 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Fri Apr 16 13:15:17 2021 +0200 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.st...@allotropia.de> 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); } _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits