[Libreoffice-commits] core.git: sw/inc sw/source

Michael Stahl (via logerrit) logerrit at kemper.freedesktop.org
Fri Apr 16 11:15:55 UTC 2021


 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.stahl at allotropia.de>
AuthorDate: Thu Apr 15 20:00:57 2021 +0200
Commit:     Michael Stahl <michael.stahl at 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.stahl at 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);
         }


More information about the Libreoffice-commits mailing list