tdf#123159 Make Hyperlinks keyboard accessible
Extend .uno:OpenHyperlinkOnCursor to open all hyperlinks
in a cell, when not in edit mode.
The UNO command can be assigned to a keyboard shortcut from
`Tools > Customize > Keyboard`. If the active cell is not in
edit mode, then pressing the shortcut opens all the hyperlinks
in the cell. If in edit mode, pressing the shortcut opens the
hyperlink under the caret "|".
Change-Id: I7ffdab54fa31b9f7f614e04cc3158d8be217825e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157666
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
Tested-by: Jenkins
diff --git a/sc/sdi/docsh.sdi b/sc/sdi/docsh.sdi
index b4a8a04..380ddb0 100644
--- a/sc/sdi/docsh.sdi
+++ b/sc/sdi/docsh.sdi
@@ -58,6 +58,7 @@ interface TableDocument
SID_CHART_ADDSOURCE [ ExecMethod = Execute; ]
FID_AUTO_CALC [ ExecMethod = Execute; StateMethod = GetState; ]
FID_RECALC [ ExecMethod = Execute; StateMethod = GetState; ]
SID_OPEN_HYPERLINK [ ExecMethod = Execute; StateMethod = GetState; ]
FID_HARD_RECALC [ ExecMethod = Execute; StateMethod = GetState; ]
SID_UPDATETABLINKS [ ExecMethod = Execute; ]
SID_REIMPORT_AFTER_LOAD [ ExecMethod = Execute; ]
diff --git a/sc/sdi/editsh.sdi b/sc/sdi/editsh.sdi
index 3dd0219..5dd18e8 100644
--- a/sc/sdi/editsh.sdi
+++ b/sc/sdi/editsh.sdi
@@ -74,7 +74,6 @@ interface TableText
SID_HYPERLINK_SETLINK [ ExecMethod = Execute; ]
SID_HYPERLINK_GETLINK [ StateMethod = GetState; ]
SID_OPEN_HYPERLINK [ ExecMethod = Execute; StateMethod = GetState; ]
SID_EDIT_HYPERLINK [ ExecMethod = Execute; StateMethod = GetState; ]
SID_COPY_HYPERLINK_LOCATION [ ExecMethod = Execute; StateMethod = GetState; ]
SID_REMOVE_HYPERLINK [ ExecMethod = Execute; StateMethod = GetState; ]
diff --git a/sc/source/ui/docshell/docsh4.cxx b/sc/source/ui/docshell/docsh4.cxx
index 741d60c..0348ce5 100644
--- a/sc/source/ui/docshell/docsh4.cxx
+++ b/sc/source/ui/docshell/docsh4.cxx
@@ -401,6 +401,54 @@ void ScDocShell::Execute( SfxRequest& rReq )
rReq.Done();
}
break;
case SID_OPEN_HYPERLINK:
{
ScViewData* pViewData = GetViewData();
if ( !pViewData )
{
rReq.Ignore();
break;
}
if (SC_MOD()->IsEditMode())
{
if (EditView* pEditView = pViewData->GetEditView(pViewData->GetActivePart()))
{
const SvxFieldItem* pFieldItem = pEditView->GetFieldAtSelection(/*bAlsoCheckBeforeCursor=*/true);
const SvxFieldData* pField = pFieldItem ? pFieldItem->GetField() : nullptr;
if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(pField))
{
ScGlobal::OpenURL(pURLField->GetURL(), pURLField->GetTargetFrame(), true);
rReq.Done();
break;
}
}
rReq.Ignore();
break;
}
ScGridWindow* pWin = pViewData->GetActiveWin();
if ( !pWin )
{
rReq.Ignore();
break;
}
ScAddress aCell {pViewData->GetCurPos()};
std::vector<UrlData> vUrls = pWin->GetEditUrls(aCell);
if (vUrls.empty())
{
rReq.Ignore();
break;
}
for (UrlData& data : vUrls)
{
ScGlobal::OpenURL(data.aUrl, data.aTarget, true);
}
rReq.Done();
}
break;
case FID_RECALC:
DoRecalc( rReq.IsAPI() );
rReq.Done();
diff --git a/sc/source/ui/inc/gridwin.hxx b/sc/source/ui/inc/gridwin.hxx
index 9e91409..5c548e5 100644
--- a/sc/source/ui/inc/gridwin.hxx
+++ b/sc/source/ui/inc/gridwin.hxx
@@ -81,6 +81,13 @@ class ScLokRTLContext;
#define SC_PD_BREAK_H 16
#define SC_PD_BREAK_V 32
struct UrlData
{
OUString aName;
OUString aUrl;
OUString aTarget;
};
// predefines
namespace sdr::overlay { class OverlayObjectList; }
@@ -509,6 +516,8 @@ public:
void initiatePageBreaks();
std::vector<UrlData> GetEditUrls(const ScAddress& rSelectedCell);
protected:
void ImpCreateOverlayObjects();
void ImpDestroyOverlayObjects();
diff --git a/sc/source/ui/view/editsh.cxx b/sc/source/ui/view/editsh.cxx
index 80b11d0..6058a6b 100644
--- a/sc/source/ui/view/editsh.cxx
+++ b/sc/source/ui/view/editsh.cxx
@@ -639,15 +639,6 @@ void ScEditShell::Execute( SfxRequest& rReq )
}
}
break;
case SID_OPEN_HYPERLINK:
{
const SvxFieldItem* pFieldItem
= pEditView->GetFieldAtSelection(/*AlsoCheckBeforeCursor=*/true);
const SvxFieldData* pField = pFieldItem ? pFieldItem->GetField() : nullptr;
if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(pField))
ScGlobal::OpenURL( pURLField->GetURL(), pURLField->GetTargetFrame(), true );
return;
}
case SID_EDIT_HYPERLINK:
{
// Ensure the field is selected first
@@ -832,7 +823,6 @@ void ScEditShell::GetState( SfxItemSet& rSet )
}
break;
case SID_OPEN_HYPERLINK:
case SID_EDIT_HYPERLINK:
case SID_COPY_HYPERLINK_LOCATION:
case SID_REMOVE_HYPERLINK:
diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx
index 07d2d3a..5416422 100644
--- a/sc/source/ui/view/gridwin.cxx
+++ b/sc/source/ui/view/gridwin.cxx
@@ -5798,6 +5798,59 @@ static void lcl_SetEngineTextKeepingDefaults(const std::shared_ptr<ScFieldEditEn
}
}
static std::vector<std::unique_ptr<SvxFieldItem>> lcl_GetEditEngineFields(std::shared_ptr<ScFieldEditEngine> pEditEngine)
{
std::vector<std::unique_ptr<SvxFieldItem>> vFieldVect;
sal_Int32 nPara = pEditEngine->GetParagraphCount();
for (sal_Int32 nCurrPara = 0; nCurrPara < nPara; ++nCurrPara)
{
sal_Int16 nField = pEditEngine->GetFieldCount(nCurrPara);
for (sal_Int16 nCurrField = 0; nCurrField < nField; ++nCurrField)
{
EFieldInfo aFieldInfo = pEditEngine->GetFieldInfo(nCurrPara, nCurrField);
vFieldVect.push_back(std::move(aFieldInfo.pFieldItem));
}
}
return vFieldVect;
}
std::vector<UrlData> ScGridWindow::GetEditUrls(const ScAddress& rSelectedCell)
{
ScDocShell* pDocSh = mrViewData.GetDocShell();
ScDocument& rDoc = pDocSh->GetDocument();
SCCOL nPosX = rSelectedCell.Col();
SCROW nPosY = rSelectedCell.Row();
SCTAB nTab = rSelectedCell.Tab();
OUString sURL;
ScRefCellValue aCell;
std::vector<UrlData> vUrls;
if (!lcl_GetHyperlinkCell(rDoc, nPosX, nPosY, nTab, aCell, sURL))
return vUrls;
if (nPosX != rSelectedCell.Col())
return vUrls;
const ScPatternAttr* pPattern = rDoc.GetPattern( nPosX, nPosY, nTab );
std::shared_ptr<ScFieldEditEngine> pEngine = createEditEngine(pDocSh, *pPattern);
lcl_SetEngineTextKeepingDefaults(pEngine, rDoc, aCell, sURL);
std::vector<std::unique_ptr<SvxFieldItem>> vFieldItems = lcl_GetEditEngineFields(pEngine);
for (auto& pFieldItem : vFieldItems)
{
UrlData aData;
bool bIsUrl = extractURLInfo(pFieldItem.get(), &aData.aName, &aData.aUrl, &aData.aTarget);
if (bIsUrl && !aData.aUrl.isEmpty())
vUrls.push_back(aData);
}
return vUrls;
}
bool ScGridWindow::GetEditUrl( const Point& rPos,
OUString* pName, OUString* pUrl, OUString* pTarget )
{