tdf#172401 Add Hyperlink navigation to Navigate By

Change-Id: I0304ec359b3a03af4c1393ac6346105d0c65b184
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207016
Tested-by: Jenkins
Reviewed-by: Jim Raykowski <raykowj@gmail.com>
This commit is contained in:
Jim Raykowski
2026-06-23 01:07:33 +02:00
parent d73a5a8515
commit 6a3cbb79c6
7 changed files with 129 additions and 5 deletions
+1
View File
@@ -78,6 +78,7 @@ inline constexpr OUString RID_BMP_RIBBAR_ERROR = u"sw/res/sr20019.png"_ustr;
inline constexpr OUString RID_BMP_RIBBAR_RECENCY = u"sw/res/sr20020.png"_ustr;
inline constexpr OUString RID_BMP_RIBBAR_FIELD = u"sw/res/sr20021.png"_ustr;
inline constexpr OUString RID_BMP_RIBBAR_FIELD_BYTYPE = u"sw/res/sr20022.png"_ustr;
inline constexpr OUString RID_BMP_RIBBAR_HYPERLINK = u"sw/res/nc20007.png"_ustr;
inline constexpr OUString RID_BMP_NAVI_OUTLINE = u"sw/res/nc20000.png"_ustr;
inline constexpr OUString RID_BMP_NAVI_TABLE = u"sw/res/nc20001.png"_ustr;
+1
View File
@@ -737,6 +737,7 @@ public:
// optionally only to broken formulas
bool GotoNxtPrvTableFormula( bool bNext = true,
bool bOnlyErrors = false );
bool GotoNxtPrvHyperlink(bool bNext);
// jump to the next / previous hyperlink - inside text and also
// on graphics
bool SelectNxtPrvHyperlink( bool bNext );
+2
View File
@@ -1286,6 +1286,8 @@
#define STR_IMGBTN_FIELD_DOWN NC_("STR_IMGBTN_FIELD_DOWN", "Next field")
#define STR_IMGBTN_FIELD_BYTYPE_UP NC_("STR_IMGBTN_FIELD_BYTYPE_UP", "Previous '%FIELDTYPE' field")
#define STR_IMGBTN_FIELD_BYTYPE_DOWN NC_("STR_IMGBTN_FIELD_BYTYPE_DOWN", "Next '%FIELDTYPE' field")
#define STR_IMGBTN_HYPERLINK_UP NC_("STR_IMGBTN_HYPERLINK_UP", "Previous hyperlink")
#define STR_IMGBTN_HYPERLINK_DOWN NC_("STR_IMGBTN_HYPLERLINK_DOWN", "Next hyperlink")
#define STR_GOTO_PAGE_DLG_TITLE NC_("STR_GOTO_PAGE_DLG_TITLE", "Go to Page")
#define STR_REDLINE_INSERT NC_("STR_REDLINE_INSERT", "Inserted")
+108
View File
@@ -76,6 +76,8 @@
#include <wrtsh.hxx>
#include <textcontentcontrol.hxx>
#include <fmtanchr.hxx>
using namespace ::com::sun::star;
void SwCursorShell::MoveCursorToNum()
@@ -2961,4 +2963,110 @@ bool SwCursorShell::SelectNxtPrvHyperlink( bool bNext )
return bRet;
}
// 1. Create a sorted list of document model positions containing the current cursor position and
// hyperlink positions excluding TOX links.
// 2. Search the sorted list for the current cursor position entry.
// 3. Assign the current cursor to the next or previous list entry document model position.
bool SwCursorShell::GotoNxtPrvHyperlink(bool bNext)
{
std::vector<std::unique_ptr<SwPosition>> aArr;
// add current cursor position
SwPosition* pCursorPos = m_pCurrentCursor->GetPoint();
aArr.push_back(
std::make_unique<SwPosition>(*pCursorPos->GetContentNode(), pCursorPos->GetContentIndex()));
const SwCharFormats* pFormats = GetDoc()->GetCharFormats();
for (size_t i = pFormats->size(); i > 1;)
{
SwIterator<SwTextINetFormat, SwCharFormat> aIter(*(*pFormats)[--i]);
for (SwTextINetFormat* pFnd = aIter.First(); pFnd; pFnd = aIter.Next())
{
const SwTextNode* pTextNode = pFnd->GetpTextNode();
if (pTextNode && pTextNode->GetNodes().IsDocNodes())
{
// don't include table of contents hyperlinks
if (const SwSectionNode* pSectNd = pTextNode->FindSectionNode();
pSectNd && pSectNd->GetSection().GetType() == SectionType::ToxContent)
continue;
aArr.push_back(std::make_unique<SwPosition>(*pFnd->GetTextNode().GetContentNode(),
pFnd->GetStart()));
}
}
}
// return if there is only the cursor entry in the list
if (aArr.size() == 1)
return false;
const SwNodeOffset nEndOfExtrasIndex = GetNodes().GetEndOfExtras().GetIndex();
std::stable_sort(
aArr.begin(), aArr.end(),
[nEndOfExtrasIndex](const std::unique_ptr<SwPosition>& a,
const std::unique_ptr<SwPosition>& b)
{
const SwNode& aTextNode = a->GetNode();
const SwNode& bTextNode = b->GetNode();
SwPosition aPos(*aTextNode.GetContentNode(), a->GetContentIndex());
SwPosition bPos(*bTextNode.GetContentNode(), b->GetContentIndex());
// use anchor position for entries that are located in flys
if (nEndOfExtrasIndex >= aTextNode.GetIndex())
if (auto pFlyFormat = aTextNode.GetFlyFormat())
if (const SwPosition* pPos = pFlyFormat->GetAnchor().GetContentAnchor())
aPos = *pPos;
if (nEndOfExtrasIndex >= bTextNode.GetIndex())
if (auto pFlyFormat = bTextNode.GetFlyFormat())
if (const SwPosition* pPos = pFlyFormat->GetAnchor().GetContentAnchor())
bPos = *pPos;
return aPos < bPos;
});
// Search the array for the entry that has the cursor position then move the cursor to the
// position stored in the next or previous entry.
SwPosition aAssignPos(*aArr[0]);
for (size_t i = 0; i < aArr.size(); ++i)
{
if (*pCursorPos != *aArr[i])
continue;
if (bNext)
{
if (i == aArr.size() - 1)
i = 0;
else
{
while (*pCursorPos == *aArr[i])
{
if (++i == aArr.size())
{
i = 0;
break;
}
}
}
}
else
{
if (i == 0)
i = aArr.size() - 1;
else
--i;
}
aAssignPos.Assign(*aArr[i]->GetNode().GetContentNode(), aArr[i]->GetContentIndex());
break;
}
CurrShell aCurr(this);
SwCallLink aLk(*this); // watch Cursor-Moves
SwCursorSaveState aSaveState(*m_pCurrentCursor);
m_pCurrentCursor->GetPoint()->Assign(aAssignPos.GetNode(), aAssignPos.GetContentIndex());
if (!m_pCurrentCursor->IsSelOvr())
UpdateCursor(SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE | SwCursorShell::READONLY);
return true;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+2 -1
View File
@@ -53,7 +53,8 @@ using namespace ::com::sun::star;
#define NID_RECENCY 20018
#define NID_FIELD 20019
#define NID_FIELD_BYTYPE 20020
#define NID_COUNT 21
#define NID_HYPERLINK 20021
#define NID_COUNT 22
class SwTbxAutoTextCtrl final : public SfxToolBoxControl
{
+9 -4
View File
@@ -58,7 +58,7 @@
#include <sfx2/viewfrm.hxx>
// Size check
#define NAVI_ENTRIES 21
#define NAVI_ENTRIES 22
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
@@ -189,7 +189,8 @@ const sal_uInt16 aNavigationInsertIds[ NAVI_ENTRIES ] =
NID_TABLE_FORMULA_ERROR,
NID_RECENCY,
NID_FIELD,
NID_FIELD_BYTYPE
NID_FIELD_BYTYPE,
NID_HYPERLINK
};
OUString constexpr aNavigationImgIds[ NAVI_ENTRIES ] =
@@ -214,7 +215,8 @@ OUString constexpr aNavigationImgIds[ NAVI_ENTRIES ] =
RID_BMP_RIBBAR_ERROR,
RID_BMP_RIBBAR_RECENCY,
RID_BMP_RIBBAR_FIELD,
RID_BMP_RIBBAR_FIELD_BYTYPE
RID_BMP_RIBBAR_FIELD_BYTYPE,
RID_BMP_RIBBAR_HYPERLINK
};
const TranslateId aNavigationStrIds[ NAVI_ENTRIES ] =
@@ -239,7 +241,8 @@ const TranslateId aNavigationStrIds[ NAVI_ENTRIES ] =
ST_TABLE_FORMULA_ERROR,
ST_RECENCY,
STR_CONTENT_TYPE_TEXTFIELD,
ST_FIELD_BYTYPE
ST_FIELD_BYTYPE,
STR_CONTENT_TYPE_URLFIELD
};
// these are global strings
@@ -266,6 +269,7 @@ const TranslateId STR_IMGBTN_ARY[] =
STR_IMGBTN_RECENCY_DOWN,
STR_IMGBTN_FIELD_DOWN,
STR_IMGBTN_FIELD_BYTYPE_DOWN,
STR_IMGBTN_HYPERLINK_DOWN,
STR_IMGBTN_TBL_UP,
STR_IMGBTN_FRM_UP,
STR_IMGBTN_PGE_UP,
@@ -287,6 +291,7 @@ const TranslateId STR_IMGBTN_ARY[] =
STR_IMGBTN_RECENCY_UP,
STR_IMGBTN_FIELD_UP,
STR_IMGBTN_FIELD_BYTYPE_UP,
STR_IMGBTN_HYPERLINK_UP
};
static OUString lcl_GetScrollToolTip(bool bNext)
+6
View File
@@ -641,6 +641,12 @@ void SwView::MoveNavigation(bool bNext)
rSh.UpdateCursor(SwCursorShell::SCROLLWIN);
}
break;
case NID_HYPERLINK:
{
rSh.AssureStdMode();
rSh.GotoNxtPrvHyperlink(bNext);
break;
}
}
if (NID_POSTIT != s_nMoveType)
m_pEditWin->GrabFocus();