sw/inc/bitmaps.hlst                |    1 
 sw/inc/crsrsh.hxx                  |    3 
 sw/inc/strings.hrc                 |    4 +
 sw/source/core/crsr/crstrvl.cxx    |   18 +++++
 sw/source/uibase/inc/content.hxx   |   16 ++++
 sw/source/uibase/inc/swcont.hxx    |    5 -
 sw/source/uibase/inc/wrtsh.hxx     |    4 -
 sw/source/uibase/utlui/content.cxx |  127 ++++++++++++++++++++++++++++++++++++-
 sw/source/uibase/wrtsh/move.cxx    |    8 ++
 9 files changed, 179 insertions(+), 7 deletions(-)

New commits:
commit fc44168ebe840fa2e772f034232fed15460e4977
Author:     Jim Raykowski <rayk...@gmail.com>
AuthorDate: Fri Oct 1 15:51:08 2021 -0800
Commit:     Jim Raykowski <rayk...@gmail.com>
CommitDate: Mon Oct 4 01:18:20 2021 +0200

    tdf#144788 SwNavigator: Add footnotes and endnotes to content tree
    
    This patch introduces lcl_SelectByContentTypeAndAddress function which
    is useful for content types that can have non unique string entries
    which can be selected incorrectly by use of the
    lcl_SelectByContentTypeAndName function. Although footnotes and
    endnotes names are always unique, lcl_SelectByContentTypeAndAddress
    is used here in preference of lcl_SelectByContentTypeAndName.
    
    Change-Id: Ia118f717f72877cddb932ef19f6d155a7227845d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/122970
    Tested-by: Jenkins
    Reviewed-by: Jim Raykowski <rayk...@gmail.com>

diff --git a/sw/inc/bitmaps.hlst b/sw/inc/bitmaps.hlst
index 7643989dd2e9..b3353862bee0 100644
--- a/sw/inc/bitmaps.hlst
+++ b/sw/inc/bitmaps.hlst
@@ -88,6 +88,7 @@
 #define RID_BMP_NAVI_POSTIT                     "sw/res/nc20010.png"
 #define RID_BMP_NAVI_DRAWOBJECT                 "sw/res/nc20011.png"
 #define RID_BMP_NAVI_TEXTFIELD                  "sw/res/nc20005.png"
+#define RID_BMP_NAVI_FOOTNOTE                   "sw/res/nc20000.png"
 #define RID_BMP_DROP_REGION                     "sw/res/sc20235.png"
 #define RID_BMP_DROP_LINK                       "sw/res/sc20238.png"
 #define RID_BMP_DROP_COPY                       "sw/res/sc20239.png"
diff --git a/sw/inc/crsrsh.hxx b/sw/inc/crsrsh.hxx
index 9f60a87345d5..14507f20097c 100644
--- a/sw/inc/crsrsh.hxx
+++ b/sw/inc/crsrsh.hxx
@@ -55,6 +55,7 @@ class SwRangeRedline;
 class SwBlockCursor;
 class SwPostItField;
 class SwTextField;
+class SwTextFootnote;
 
 namespace i18nutil {
     struct SearchOptions2;
@@ -812,6 +813,8 @@ public:
     const SwRangeRedline* SelPrevRedline();
     const SwRangeRedline* GotoRedline( SwRedlineTable::size_type nArrPos, bool 
bSelect );
 
+    bool GotoFootnoteAnchor(const SwTextFootnote& rTextFootnote);
+
     SAL_DLLPRIVATE SvxFrameDirection GetTextDirection( const Point* pPt = 
nullptr ) const;
     // is cursor or the point in/over a vertical formatted text?
     bool IsInVerticalText( const Point* pPt = nullptr ) const;
diff --git a/sw/inc/strings.hrc b/sw/inc/strings.hrc
index 359e25b49312..395cfc63bd53 100644
--- a/sw/inc/strings.hrc
+++ b/sw/inc/strings.hrc
@@ -371,6 +371,7 @@
 #define STR_CONTENT_TYPE_INDEX                  NC_("STR_CONTENT_TYPE_INDEX", 
"Indexes")
 #define STR_CONTENT_TYPE_DRAWOBJECT             
NC_("STR_CONTENT_TYPE_DRAWOBJECT", "Drawing objects")
 #define STR_CONTENT_TYPE_TEXTFIELD              
NC_("STR_CONTENT_TYPE_TEXTFIELD", "Fields")
+#define STR_CONTENT_TYPE_FOOTNOTE               
NC_("STR_CONTENT_TYPE_FOOTNOTE", "Footnotes and Endnotes")
 #define STR_CONTENT_TYPE_POSTIT                 NC_("STR_CONTENT_TYPE_POSTIT", 
"Comments")
 #define STR_IDXEXAMPLE_IDXTXT_HEADING1          
NC_("STR_IDXEXAMPLE_IDXTXT_HEADING1", "Heading 1")
 #define STR_IDXEXAMPLE_IDXTXT_ENTRY1            
NC_("STR_IDXEXAMPLE_IDXTXT_ENTRY1", "This is the content from the first 
chapter. This is a user directory entry.")
@@ -400,6 +401,9 @@
 #define STR_CONTENT_TYPE_SINGLE_POSTIT          
NC_("STR_CONTENT_TYPE_SINGLE_POSTIT", "Comment")
 #define STR_CONTENT_TYPE_SINGLE_DRAWOBJECT      
NC_("STR_CONTENT_TYPE_SINGLE_DRAWOBJECT", "Draw object")
 #define STR_CONTENT_TYPE_SINGLE_TEXTFIELD       
NC_("STR_CONTENT_TYPE_SINGLE_TEXTFIELD", "Field")
+#define STR_CONTENT_TYPE_SINGLE_FOOTNOTE        
NC_("STR_CONTENT_TYPE_SINGLE_FOOTNOTE", "Footnote or Endnote")
+#define STR_CONTENT_FOOTNOTE                    NC_("STR_CONTENT_FOOTNOTE", 
"Footnote")
+#define STR_CONTENT_ENDNOTE                     NC_("STR_CONTENT_ENDNOTE", 
"Endnote")
 #define STR_DEFINE_NUMBERFORMAT                 NC_("STR_DEFINE_NUMBERFORMAT", 
"Additional formats...")
 #define RID_STR_SYSTEM                          NC_("RID_STR_SYSTEM", 
"[System]")
 #define STR_MULT_INTERACT_HYPH_WARN             
NC_("STR_MULT_INTERACT_HYPH_WARN", "The interactive hyphenation is already 
active\nin a different document")
diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx
index 87ab068e6ded..03f94624aae2 100644
--- a/sw/source/core/crsr/crstrvl.cxx
+++ b/sw/source/core/crsr/crstrvl.cxx
@@ -831,6 +831,24 @@ bool SwCursorShell::MoveFieldType(
     return bRet;
 }
 
+bool SwCursorShell::GotoFootnoteAnchor(const SwTextFootnote& rTextFootnote)
+{
+    bool bRet = false;
+    SwCursor* pCursor = getShellCursor(true);
+
+    CurrShell aCurr(this);
+    SwCallLink aLk(*this); // watch Cursor-Moves
+    SwCursorSaveState aSaveState(*pCursor);
+
+    pCursor->GetPoint()->nNode = rTextFootnote.GetTextNode();
+    
pCursor->GetPoint()->nContent.Assign(const_cast<SwTextNode*>(&rTextFootnote.GetTextNode()),
+                                         rTextFootnote.GetStart());
+    bRet = !pCursor->IsSelOvr();
+    if (bRet)
+        
UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
+    return bRet;
+}
+
 bool SwCursorShell::GotoFormatField( const SwFormatField& rField )
 {
     bool bRet = false;
diff --git a/sw/source/uibase/inc/content.hxx b/sw/source/uibase/inc/content.hxx
index 64b1e265f10b..195dfd5ff6f3 100644
--- a/sw/source/uibase/inc/content.hxx
+++ b/sw/source/uibase/inc/content.hxx
@@ -31,6 +31,7 @@ class SwFormatField;
 class SwTextINetFormat;
 class SwTOXBase;
 class SwRangeRedline;
+class SwTextFootnote;
 
 //  helper classes
 
@@ -104,6 +105,21 @@ public:
     virtual bool IsProtect() const override;
 };
 
+class SwTextFootnoteContent final : public SwContent
+{
+    const SwTextFootnote* m_pTextFootnote;
+public:
+    SwTextFootnoteContent(const SwContentType* pCnt,
+                       const OUString& rName,
+                       const SwTextFootnote* pTextFootnote,
+                       tools::Long nYPos)
+        : SwContent(pCnt, rName, nYPos),
+          m_pTextFootnote(pTextFootnote)
+    {}
+
+    const SwTextFootnote* GetTextFootnote() const {return m_pTextFootnote;}
+};
+
 class SwPostItContent final : public SwContent
 {
     const SwFormatField*     pField;
diff --git a/sw/source/uibase/inc/swcont.hxx b/sw/source/uibase/inc/swcont.hxx
index d65c4fa59aca..2e32944efb48 100644
--- a/sw/source/uibase/inc/swcont.hxx
+++ b/sw/source/uibase/inc/swcont.hxx
@@ -40,8 +40,9 @@ enum class ContentTypeId
     INDEX          = 9,
     POSTIT         = 10,
     DRAWOBJECT     = 11,
-    TEXTFIELD          = 12,
-    LAST           = TEXTFIELD,
+    TEXTFIELD      = 12,
+    FOOTNOTE       = 13,
+    LAST           = FOOTNOTE,
     UNKNOWN        = -1
 };
 
diff --git a/sw/source/uibase/inc/wrtsh.hxx b/sw/source/uibase/inc/wrtsh.hxx
index 727d4cfb64c9..8e2573916e8b 100644
--- a/sw/source/uibase/inc/wrtsh.hxx
+++ b/sw/source/uibase/inc/wrtsh.hxx
@@ -114,7 +114,7 @@ private:
     SELECTFUNC  m_fnKillSel   = &SwWrtShell::Ignore;
 
 public:
-
+    using SwCursorShell::GotoFootnoteAnchor;
     using SwEditShell::Insert;
 
     tools::Long CallSetCursor(const Point* pPt, bool bProp) { return 
(this->*m_fnSetCursor)(pPt, bProp); }
@@ -486,7 +486,7 @@ typedef bool (SwWrtShell::*FNSimpleMove)();
     void GotoFormatField( const SwFormatField& rField );
     const SwRangeRedline* GotoRedline( SwRedlineTable::size_type nArrPos, bool 
bSelect);
     bool GotoDrawingObject(std::u16string_view rName);
-
+    void GotoFootnoteAnchor(const SwTextFootnote& rTextFootnote);
     void ChangeHeaderOrFooter(std::u16string_view rStyleName, bool bHeader, 
bool bOn, bool bShowWarning);
     virtual void SetShowHeaderFooterSeparator( FrameControlType eControl, bool 
bShow ) override;
 
diff --git a/sw/source/uibase/utlui/content.cxx 
b/sw/source/uibase/utlui/content.cxx
index 8f8e1531f45c..f6caf32c5aed 100644
--- a/sw/source/uibase/utlui/content.cxx
+++ b/sw/source/uibase/utlui/content.cxx
@@ -103,6 +103,10 @@
 #include <com/sun/star/text/XTextRange.hpp>
 #include <com/sun/star/text/XTextRangeCompare.hpp>
 
+#include <ftnidx.hxx>
+#include <txtftn.hxx>
+#include <fmtftn.hxx>
+
 #define CTYPE_CNT   0
 #define CTYPE_CTT   1
 
@@ -258,7 +262,8 @@ const TranslateId STR_CONTENT_TYPE_ARY[] =
     STR_CONTENT_TYPE_INDEX,
     STR_CONTENT_TYPE_POSTIT,
     STR_CONTENT_TYPE_DRAWOBJECT,
-    STR_CONTENT_TYPE_TEXTFIELD
+    STR_CONTENT_TYPE_TEXTFIELD,
+    STR_CONTENT_TYPE_FOOTNOTE
 };
 
 const TranslateId STR_CONTENT_TYPE_SINGLE_ARY[] =
@@ -275,7 +280,8 @@ const TranslateId STR_CONTENT_TYPE_SINGLE_ARY[] =
     STR_CONTENT_TYPE_SINGLE_INDEX,
     STR_CONTENT_TYPE_SINGLE_POSTIT,
     STR_CONTENT_TYPE_SINGLE_DRAWOBJECT,
-    STR_CONTENT_TYPE_SINGLE_TEXTFIELD
+    STR_CONTENT_TYPE_SINGLE_TEXTFIELD,
+    STR_CONTENT_TYPE_SINGLE_FOOTNOTE
 };
 
 namespace
@@ -409,6 +415,16 @@ void SwContentType::Init(bool* pbInvalidateWindow)
             }
         }
         break;
+        case ContentTypeId::FOOTNOTE:
+        {
+            m_nMemberCount = 0;
+            m_sTypeToken.clear();
+            m_bEdit = true;
+            m_bDelete = false;
+            const SwFootnoteIdxs& rFootnoteIdxs = 
m_pWrtShell->GetDoc()->GetFootnoteIdxs();
+            m_nMemberCount = rFootnoteIdxs.size();
+        }
+        break;
         case ContentTypeId::BOOKMARK:
         {
             IDocumentMarkAccess* const pMarkAccess = 
m_pWrtShell->getIDocumentMarkAccess();
@@ -845,7 +861,26 @@ void SwContentType::FillMemberList(bool* 
pbLevelOrVisibilityChanged)
             m_nMemberCount = m_pMember->size();
         }
         break;
-
+        case ContentTypeId::FOOTNOTE:
+        {
+            const SwFootnoteIdxs& rFootnoteIdxs = 
m_pWrtShell->GetDoc()->GetFootnoteIdxs();
+            for (SwTextFootnote* pTextFootnote : rFootnoteIdxs)
+            {
+                const SwFormatFootnote& rFormatFootnote = 
pTextFootnote->GetFootnote();
+                const OUString& sText =
+                        rFormatFootnote.GetViewNumStr(*m_pWrtShell->GetDoc(),
+                                                      
m_pWrtShell->GetLayout(), true) + " " +
+                        
rFormatFootnote.GetFootnoteText(*m_pWrtShell->GetLayout());
+                std::unique_ptr<SwTextFootnoteContent> pCnt(new 
SwTextFootnoteContent(
+                                                                this, sText, 
pTextFootnote,
+                                                                
rFormatFootnote.GetNumber()));
+                if 
(!pTextFootnote->GetTextNode().getLayoutFrame(m_pWrtShell->GetLayout()))
+                    pCnt->SetInvisible();
+                m_pMember->insert(std::move(pCnt));
+            }
+            m_nMemberCount = m_pMember->size();
+        }
+        break;
         case ContentTypeId::REGION    :
         {
             m_nMemberCount = m_pWrtShell->GetSectionFormatCount();
@@ -2122,6 +2157,9 @@ namespace
             case ContentTypeId::TEXTFIELD:
                 sResId = RID_BMP_NAVI_TEXTFIELD;
                 break;
+            case ContentTypeId::FOOTNOTE:
+                sResId = RID_BMP_NAVI_FOOTNOTE;
+                break;
             case ContentTypeId::UNKNOWN:
                 SAL_WARN("sw.ui", "ContentTypeId::UNKNOWN has no bitmap 
preview");
                 break;
@@ -3283,6 +3321,66 @@ void SwContentTree::HideTree()
     m_xTreeView->hide();
 }
 
+static void lcl_SelectByContentTypeAndAddress(SwContentTree* pThis, 
weld::TreeView& rContentTree,
+                                              ContentTypeId nType, const void* 
ptr)
+{
+    if (!ptr)
+        return;
+
+    // find content type entry
+    std::unique_ptr<weld::TreeIter> xIter(rContentTree.make_iterator());
+
+    bool bFoundEntry = rContentTree.get_iter_first(*xIter);
+    while (bFoundEntry)
+    {
+        void* pUserData = 
reinterpret_cast<void*>(rContentTree.get_id(*xIter).toInt64());
+        
assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pUserData)));
+        if (nType == static_cast<SwContentType*>(pUserData)->GetType())
+            break;
+        bFoundEntry = rContentTree.iter_next_sibling(*xIter);
+    }
+
+    if (bFoundEntry)
+    {
+        // assure content type entry is expanded
+        rContentTree.expand_row(*xIter);
+
+        // find content type content entry and select it
+        const void* p = nullptr;
+        while (rContentTree.iter_next(*xIter) && lcl_IsContent(*xIter, 
rContentTree))
+        {
+            void* pUserData = 
reinterpret_cast<void*>(rContentTree.get_id(*xIter).toInt64());
+            switch( nType )
+            {
+                case ContentTypeId::FOOTNOTE:
+                {
+                    
assert(dynamic_cast<SwTextFootnoteContent*>(static_cast<SwTypeNumber*>(pUserData)));
+                    SwTextFootnoteContent* pCnt = 
static_cast<SwTextFootnoteContent*>(pUserData);
+                    p = pCnt->GetTextFootnote();
+                    break;
+                }
+                default:
+                    break;
+            }
+            if (ptr == p)
+            {
+                // get first selected for comparison
+                std::unique_ptr<weld::TreeIter> 
xFirstSelected(rContentTree.make_iterator());
+                if (!rContentTree.get_selected(xFirstSelected.get()))
+                    xFirstSelected.reset();
+                if (rContentTree.count_selected_rows() != 1 ||
+                        rContentTree.iter_compare(*xIter, *xFirstSelected) != 
0)
+                {
+                    // unselect all entries and make passed entry visible and 
selected
+                    rContentTree.set_cursor(*xIter);
+                    pThis->Select();
+                }
+                return;
+            }
+        }
+    }
+}
+
 static void lcl_SelectByContentTypeAndName(SwContentTree* pThis, 
weld::TreeView& rContentTree,
                                            std::u16string_view 
rContentTypeName, std::u16string_view rName)
 {
@@ -3400,6 +3498,15 @@ void SwContentTree::UpdateTracking()
         return;
     }
 
+    // footnotes and endnotes
+    if (SwContentAtPos aContentAtPos(IsAttrAtPos::Ftn);
+            m_pActiveShell->GetContentAtPos(m_pActiveShell->GetCursorDocPos(), 
aContentAtPos) &&
+            !(m_bIsRoot && m_nRootType != ContentTypeId::FOOTNOTE))
+    {
+        lcl_SelectByContentTypeAndAddress(this, *m_xTreeView, 
ContentTypeId::FOOTNOTE,
+                                          aContentAtPos.pFndTextAttr);
+        return;
+    }
     // bookmarks - track first bookmark at cursor
     SwDoc* pDoc = m_pActiveShell->GetDoc();
     uno::Reference<text::XBookmarksSupplier> 
xBookmarksSupplier(pDoc->GetDocShell()->GetBaseModel(),
@@ -4080,6 +4187,12 @@ IMPL_LINK(SwContentTree, QueryTooltipHdl, const 
weld::TreeIter&, rEntry, OUStrin
                 }
             }
             break;
+            case ContentTypeId::FOOTNOTE:
+                
assert(dynamic_cast<SwTextFootnoteContent*>(static_cast<SwTypeNumber*>(pUserData)));
+                sEntry = 
static_cast<SwTextFootnoteContent*>(pUserData)->GetTextFootnote()->
+                        GetFootnote().IsEndNote() ? 
SwResId(STR_CONTENT_ENDNOTE) :
+                                                    
SwResId(STR_CONTENT_FOOTNOTE);
+            break;
             default: break;
         }
         if(static_cast<SwContent*>(pUserData)->IsInvisible())
@@ -4658,6 +4771,10 @@ void SwContentTree::EditEntry(const weld::TreeIter& 
rEntry, EditEntryMode nMode)
             else if(nMode == EditEntryMode::RENAME)
                 nSlot = FN_NAME_SHAPE;
         break;
+        case ContentTypeId::FOOTNOTE:
+            if (EditEntryMode::EDIT == nMode)
+                nSlot = FN_FORMAT_FOOTNOTE_DLG;
+        break;
         default: break;
     }
     if(nSlot)
@@ -4788,6 +4905,10 @@ void SwContentTree::GotoContent(const SwContent* pCnt)
             m_pActiveShell->GotoDrawingObject(pCnt->GetName());
         }
         break;
+        case ContentTypeId::FOOTNOTE:
+            m_pActiveShell->GotoFootnoteAnchor(
+                        *static_cast<const 
SwTextFootnoteContent*>(pCnt)->GetTextFootnote());
+        break;
         default: break;
     }
 
diff --git a/sw/source/uibase/wrtsh/move.cxx b/sw/source/uibase/wrtsh/move.cxx
index 95443ba16ca7..a5f10d5f8800 100644
--- a/sw/source/uibase/wrtsh/move.cxx
+++ b/sw/source/uibase/wrtsh/move.cxx
@@ -706,6 +706,14 @@ void SwWrtShell::GotoFormatField( const SwFormatField& 
rField ) {
         m_aNavigationMgr.addEntry(aPos);
 }
 
+void SwWrtShell::GotoFootnoteAnchor(const SwTextFootnote& rTextFootnote)
+{
+    SwPosition aPos = *GetCursor()->GetPoint();
+    bool bRet = SwCursorShell::GotoFootnoteAnchor(rTextFootnote);
+    if (bRet)
+        m_aNavigationMgr.addEntry(aPos);
+}
+
 const SwRangeRedline* SwWrtShell::GotoRedline( SwRedlineTable::size_type 
nArrPos, bool bSelect ) {
     SwPosition aPos = *GetCursor()->GetPoint();
     const SwRangeRedline *pRedline = SwCursorShell::GotoRedline(nArrPos, 
bSelect);

Reply via email to