summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Raykowski <raykowj@gmail.com>2023-09-22 16:35:05 -0800
committerJim Raykowski <raykowj@gmail.com>2023-10-03 06:50:02 +0200
commitc603d37223d4f7c3594515fb2bbac22015bc146b (patch)
tree6f2798bf6b43ca943055ff79f85bac0157dc5234
parent9389102ee5e6adbb0f8b10f8aee60d1899d91d27 (diff)
tdf#157370 Bring A11y issue to attention in the document view
when issue is clicked on in the A11y sidebar Change-Id: I9122e608e88568fa2deeee91b6cf4616b0f61db8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157200 Tested-by: Jenkins Reviewed-by: Jim Raykowski <raykowj@gmail.com>
-rw-r--r--sw/inc/view.hxx16
-rw-r--r--sw/source/core/access/AccessibilityIssue.cxx86
-rw-r--r--sw/source/uibase/uiview/view.cxx104
3 files changed, 205 insertions, 1 deletions
diff --git a/sw/inc/view.hxx b/sw/inc/view.hxx
index dee2363dedd9..c6add7e23364 100644
--- a/sw/inc/view.hxx
+++ b/sw/inc/view.hxx
@@ -32,6 +32,8 @@
#include "swtypes.hxx"
#include "shellid.hxx"
+#include <svx/sdr/overlay/overlayobject.hxx>
+
class SwTextFormatColl;
class SwPageDesc;
class SwFrameFormat;
@@ -68,6 +70,7 @@ enum class SotExchangeDest;
class SwCursorShell;
enum class SvxSearchCmd;
enum class SelectionType : sal_Int32;
+class SwNode;
namespace com::sun::star::view { class XSelectionSupplier; }
namespace sfx2 { class FileDialogHelper; }
@@ -716,6 +719,19 @@ public:
virtual std::optional<OString> getLOKPayload(int nType, int nViewId) const override;
bool IsHighlightCharDF() { return m_bIsHighlightCharDF; }
+
+private:
+ AutoTimer m_aBringToAttentionBlinkTimer;
+ size_t m_nBringToAttentionBlinkTimeOutsRemaining;
+
+ std::unique_ptr<sdr::overlay::OverlayObject> m_xBringToAttentionOverlayObject;
+
+ DECL_LINK(BringToAttentionBlinkTimerHdl, Timer*, void);
+
+public:
+ void BringToAttention(std::vector<basegfx::B2DRange>&& aRanges = {});
+ void BringToAttention(const tools::Rectangle& rRect);
+ void BringToAttention(const SwNode* pNode);
};
inline tools::Long SwView::GetXScroll() const
diff --git a/sw/source/core/access/AccessibilityIssue.cxx b/sw/source/core/access/AccessibilityIssue.cxx
index 6ec39238cda9..8056408a5b02 100644
--- a/sw/source/core/access/AccessibilityIssue.cxx
+++ b/sw/source/core/access/AccessibilityIssue.cxx
@@ -28,6 +28,11 @@
#include <svx/svdpage.hxx>
#include <svx/svxdlg.hxx>
+#include <svx/svdview.hxx>
+#include <flyfrm.hxx>
+#include <txatbase.hxx>
+#include <txtfrm.hxx>
+
namespace sw
{
AccessibilityIssue::AccessibilityIssue(sfx::AccessibilityIssueID eIssueID)
@@ -75,6 +80,21 @@ void AccessibilityIssue::gotoIssue() const
{
SwWrtShell* pWrtShell = TempIssueObject.m_pDoc->GetDocShell()->GetWrtShell();
bool bSelected = pWrtShell->GotoFly(TempIssueObject.m_sObjectID, FLYCNTTYPE_ALL, true);
+
+ // bring issue to attention
+ if (bSelected)
+ {
+ if (const SwFlyFrameFormat* pFlyFormat
+ = m_pDoc->FindFlyByName(TempIssueObject.m_sObjectID, SwNodeType::NONE))
+ {
+ if (SwFlyFrame* pFlyFrame
+ = SwIterator<SwFlyFrame, SwFormat>(*pFlyFormat).First())
+ {
+ pWrtShell->GetView().BringToAttention(pFlyFrame->getFrameArea().SVRect());
+ }
+ }
+ }
+
if (bSelected && pWrtShell->IsFrameSelected())
{
pWrtShell->HideCursor();
@@ -82,8 +102,19 @@ void AccessibilityIssue::gotoIssue() const
}
if (!bSelected && TempIssueObject.m_eIssueObject == IssueObject::TEXTFRAME)
+ {
pWrtShell->GotoDrawingObject(TempIssueObject.m_sObjectID);
+ // bring issue to attention
+ if (SdrPage* pPage
+ = pWrtShell->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0))
+ {
+ if (SdrObject* pObj = pPage->GetObjByName(TempIssueObject.m_sObjectID))
+ {
+ pWrtShell->GetView().BringToAttention(pObj->GetLogicRect());
+ }
+ }
+ }
if (comphelper::LibreOfficeKit::isActive())
pWrtShell->ShowCursor();
}
@@ -94,6 +125,17 @@ void AccessibilityIssue::gotoIssue() const
if (pWrtShell->IsFrameSelected())
pWrtShell->LeaveSelFrameMode();
pWrtShell->GotoDrawingObject(TempIssueObject.m_sObjectID);
+
+ // bring issue to attention
+ if (SdrPage* pPage
+ = pWrtShell->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0))
+ {
+ if (SdrObject* pObj = pPage->GetObjByName(TempIssueObject.m_sObjectID))
+ {
+ pWrtShell->GetView().BringToAttention(pObj->GetLogicRect());
+ }
+ }
+
if (comphelper::LibreOfficeKit::isActive())
pWrtShell->ShowCursor();
}
@@ -107,6 +149,17 @@ void AccessibilityIssue::gotoIssue() const
if (!bIsDesignMode)
pWrtShell->GetView().GetFormShell()->SetDesignMode(true);
pWrtShell->GotoDrawingObject(TempIssueObject.m_sObjectID);
+
+ // bring issue to attention
+ if (SdrPage* pPage
+ = pWrtShell->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0))
+ {
+ if (SdrObject* pObj = pPage->GetObjByName(TempIssueObject.m_sObjectID))
+ {
+ pWrtShell->GetView().BringToAttention(pObj->GetLogicRect());
+ }
+ }
+
if (comphelper::LibreOfficeKit::isActive())
pWrtShell->ShowCursor();
}
@@ -116,6 +169,17 @@ void AccessibilityIssue::gotoIssue() const
{
SwWrtShell* pWrtShell = TempIssueObject.m_pDoc->GetDocShell()->GetWrtShell();
pWrtShell->GotoTable(TempIssueObject.m_sObjectID);
+
+ // bring issue to attention
+ if (SwTable* pTmpTable = SwTable::FindTable(
+ TempIssueObject.m_pDoc->FindTableFormatByName(TempIssueObject.m_sObjectID)))
+ {
+ if (SwTableNode* pTableNode = pTmpTable->GetTableNode())
+ {
+ pWrtShell->GetView().BringToAttention(pTableNode);
+ }
+ }
+
if (comphelper::LibreOfficeKit::isActive())
pWrtShell->ShowCursor();
}
@@ -133,6 +197,10 @@ void AccessibilityIssue::gotoIssue() const
pPaM->SetMark();
*pPaM->GetMark() = aMark;
pWrtShell->EndAllAction();
+
+ // bring issue to attention
+ pWrtShell->GetView().BringToAttention(pContentNode);
+
if (comphelper::LibreOfficeKit::isActive())
pWrtShell->ShowCursor();
}
@@ -141,7 +209,25 @@ void AccessibilityIssue::gotoIssue() const
{
SwWrtShell* pWrtShell = TempIssueObject.m_pDoc->GetDocShell()->GetWrtShell();
if (TempIssueObject.m_pTextFootnote)
+ {
pWrtShell->GotoFootnoteAnchor(*TempIssueObject.m_pTextFootnote);
+
+ // bring issue to attention
+ const SwTextNode& rTextNode = TempIssueObject.m_pTextFootnote->GetTextNode();
+ if (SwTextFrame* pFrame
+ = static_cast<SwTextFrame*>(rTextNode.getLayoutFrame(pWrtShell->GetLayout())))
+ {
+ auto nStart = TempIssueObject.m_pTextFootnote->GetStart();
+ auto nEnd = nStart + 1;
+ SwPosition aStartPos(rTextNode, nStart), aEndPos(rTextNode, nEnd);
+ SwRect aStartCharRect, aEndCharRect;
+ pFrame->GetCharRect(aStartCharRect, aStartPos);
+ pFrame->GetCharRect(aEndCharRect, aEndPos);
+ tools::Rectangle aRect(aStartCharRect.Left() - 50, aStartCharRect.Top(),
+ aEndCharRect.Right() + 50, aStartCharRect.Bottom());
+ pWrtShell->GetView().BringToAttention(aRect);
+ }
+ }
if (comphelper::LibreOfficeKit::isActive())
pWrtShell->ShowCursor();
}
diff --git a/sw/source/uibase/uiview/view.cxx b/sw/source/uibase/uiview/view.cxx
index 0e998a57fa71..85138778bf65 100644
--- a/sw/source/uibase/uiview/view.cxx
+++ b/sw/source/uibase/uiview/view.cxx
@@ -111,6 +111,14 @@
#include <svtools/embedhlp.hxx>
#include <tools/UnitConversion.hxx>
+#include <svx/sdr/overlay/overlayselection.hxx>
+#include <svx/sdr/overlay/overlayobject.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/svdview.hxx>
+#include <node2lay.hxx>
+#include <cntfrm.hxx>
+
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
@@ -795,7 +803,9 @@ SwView::SwView(SfxViewFrame& _rFrame, SfxViewShell* pOldSh)
m_bIsPreviewDoubleClick(false),
m_bMakeSelectionVisible(false),
m_bForceChangesToolbar(true),
- m_nLOKPageUpDownOffset(0)
+ m_nLOKPageUpDownOffset(0),
+ m_aBringToAttentionBlinkTimer("SwView m_aBringToAttentionBlinkTimer"),
+ m_nBringToAttentionBlinkTimeOutsRemaining(0)
{
static bool bRequestDoubleBuffering = getenv("VCL_DOUBLEBUFFERING_ENABLE");
if (bRequestDoubleBuffering)
@@ -1099,6 +1109,10 @@ SwView::SwView(SfxViewFrame& _rFrame, SfxViewShell* pOldSh)
if (!bFuzzing)
GetViewFrame().GetWindow().AddChildEventListener(LINK(this, SwView, WindowChildEventListener));
+
+ m_aBringToAttentionBlinkTimer.SetInvokeHandler(
+ LINK(this, SwView, BringToAttentionBlinkTimerHdl));
+ m_aBringToAttentionBlinkTimer.SetTimeout(350);
}
SwViewGlueDocShell::SwViewGlueDocShell(SwView& rView, SwDocShell& rDocSh)
@@ -1991,6 +2005,94 @@ bool SwView::IsDataSourceAvailable(const OUString sDataSourceName)
return xDatabaseContext->hasByName(sDataSourceName);
}
+void SwView::BringToAttention(std::vector<basegfx::B2DRange>&& aRanges)
+{
+ m_nBringToAttentionBlinkTimeOutsRemaining = 0;
+ m_aBringToAttentionBlinkTimer.Stop();
+ if (aRanges.empty())
+ m_xBringToAttentionOverlayObject.reset();
+ else
+ {
+ m_xBringToAttentionOverlayObject.reset(
+ new sdr::overlay::OverlaySelection(sdr::overlay::OverlayType::Invert,
+ Color(), std::move(aRanges),
+ true /*unused for Invert type*/));
+ m_nBringToAttentionBlinkTimeOutsRemaining = 4;
+ m_aBringToAttentionBlinkTimer.Start();
+ }
+}
+
+void SwView::BringToAttention(const tools::Rectangle& rRect)
+{
+ std::vector<basegfx::B2DRange> aRanges{ basegfx::B2DRange(rRect.Left(), rRect.Top(),
+ rRect.Right(), rRect.Bottom()) };
+ BringToAttention(std::move(aRanges));
+}
+
+void SwView::BringToAttention(const SwNode* pNode)
+{
+ if (!pNode)
+ return;
+
+ std::vector<basegfx::B2DRange> aRanges;
+ const SwFrame* pFrame;
+ if (pNode->IsContentNode())
+ {
+ pFrame = pNode->GetContentNode()->getLayoutFrame(GetWrtShell().GetLayout());
+ }
+ else
+ {
+ // section and table nodes
+ SwNode2Layout aTmp(*pNode, pNode->GetIndex() - 1);
+ pFrame = aTmp.NextFrame();
+ }
+ while (pFrame)
+ {
+ const SwRect& rFrameRect = pFrame->getFrameArea();
+ if (!rFrameRect.IsEmpty())
+ aRanges.emplace_back(rFrameRect.Left(), rFrameRect.Top() + pFrame->GetTopMargin(),
+ rFrameRect.Right(), rFrameRect.Bottom());
+ if (!pFrame->IsFlowFrame())
+ break;
+ const SwFlowFrame* pFollow = SwFlowFrame::CastFlowFrame(pFrame)->GetFollow();
+ if (!pFollow)
+ break;
+ pFrame = &pFollow->GetFrame();
+ }
+ BringToAttention(std::move(aRanges));
+}
+
+IMPL_LINK_NOARG(SwView, BringToAttentionBlinkTimerHdl, Timer*, void)
+{
+ if (GetDrawView() && m_xBringToAttentionOverlayObject)
+ {
+ if (SdrView* pView = GetDrawView())
+ {
+ if (SdrPaintWindow* pPaintWindow = pView->GetPaintWindow(0))
+ {
+ const rtl::Reference<sdr::overlay::OverlayManager>& xOverlayManager
+ = pPaintWindow->GetOverlayManager();
+ if (m_nBringToAttentionBlinkTimeOutsRemaining % 2 == 0)
+ xOverlayManager->add(*m_xBringToAttentionOverlayObject);
+ else
+ xOverlayManager->remove(*m_xBringToAttentionOverlayObject);
+ --m_nBringToAttentionBlinkTimeOutsRemaining;
+ }
+ else
+ m_nBringToAttentionBlinkTimeOutsRemaining = 0;
+ }
+ else
+ m_nBringToAttentionBlinkTimeOutsRemaining = 0;
+ }
+ else
+ m_nBringToAttentionBlinkTimeOutsRemaining = 0;
+ if (m_nBringToAttentionBlinkTimeOutsRemaining == 0)
+ {
+ m_xBringToAttentionOverlayObject.reset();
+ m_aBringToAttentionBlinkTimer.Stop();
+ }
+}
+
namespace sw {
void InitPrintOptionsFromApplication(SwPrintData & o_rData, bool const bWeb)