diff options
author | Jim Raykowski <raykowj@gmail.com> | 2023-09-22 16:35:05 -0800 |
---|---|---|
committer | Jim Raykowski <raykowj@gmail.com> | 2023-10-03 06:50:02 +0200 |
commit | c603d37223d4f7c3594515fb2bbac22015bc146b (patch) | |
tree | 6f2798bf6b43ca943055ff79f85bac0157dc5234 /sw | |
parent | 9389102ee5e6adbb0f8b10f8aee60d1899d91d27 (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>
Diffstat (limited to 'sw')
-rw-r--r-- | sw/inc/view.hxx | 16 | ||||
-rw-r--r-- | sw/source/core/access/AccessibilityIssue.cxx | 86 | ||||
-rw-r--r-- | sw/source/uibase/uiview/view.cxx | 104 |
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) |