From b5d2845f291e5a37ae459229cc5f54240cb8d067 Mon Sep 17 00:00:00 2001 From: DietmarSchwertberger Date: Sat, 2 Mar 2024 22:05:00 +0100 Subject: [PATCH 01/19] implement basic accessibility support for wxGrid --- include/wx/generic/grid.h | 91 ++++++ src/generic/grid.cpp | 651 +++++++++++++++++++++++++++++++++++++- src/generic/gridsel.cpp | 4 + 3 files changed, 745 insertions(+), 1 deletion(-) diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index aeb6363957c0..386bac3c6984 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -120,6 +120,11 @@ class wxGridRowOperations; class wxGridColumnOperations; class wxGridDirectionOperations; +#if wxUSE_ACCESSIBILITY +class WXDLLIMPEXP_FWD_CORE wxGridAccessible; +class WXDLLIMPEXP_FWD_CORE wxGridCellAccessible; +#endif // wxUSE_ACCESSIBILITY + // ---------------------------------------------------------------------------- // macros @@ -2411,6 +2416,13 @@ class WXDLLIMPEXP_CORE wxGrid : public wxScrolledCanvas // implementation only void CancelMouseCapture(); +#if wxUSE_ACCESSIBILITY + virtual wxAccessible* CreateAccessible() override; + virtual bool Show(bool show) override; + virtual void SetName(const wxString &name) override; + virtual bool Reparent(wxWindowBase *newParent) override; +#endif // wxUSE_ACCESSIBILITY + protected: virtual wxSize DoGetBestSize() const override; virtual void DoEnable(bool enable) override; @@ -2769,6 +2781,11 @@ class WXDLLIMPEXP_CORE wxGrid : public wxScrolledCanvas friend class wxGridHeaderColumn; friend class wxGridHeaderCtrl; +#if wxUSE_ACCESSIBILITY + friend class wxGridAccessible; + friend class wxGridCellAccessible; +#endif // wxUSE_ACCESSIBILITY + private: // This is called from both Create() and OnDPIChanged() to (re)initialize // the values in pixels, which depend on the current DPI. @@ -3467,5 +3484,79 @@ extern const int wxEVT_GRID_CHANGE_SEL_LABEL; #endif +#if wxUSE_ACCESSIBILITY +//----------------------------------------------------------------------------- +// accessibility support for whole grid and per cell +//----------------------------------------------------------------------------- + +class WXDLLIMPEXP_CORE wxGridAccessible: public wxWindowAccessible +{ +public: + wxGridAccessible(wxGrid* win); + virtual ~wxGridAccessible(); + + virtual wxAccStatus HitTest(const wxPoint& pt, int* childId, + wxAccessible** childObject) override; + + virtual wxAccStatus GetLocation(wxRect& rect, int elementId) override; + + virtual wxAccStatus GetName(int childId, wxString* name) override; + + virtual wxAccStatus GetChildCount(int* childCount) override; + + virtual wxAccStatus GetChild(int childId, wxAccessible** child) override; + + virtual wxAccStatus GetRole(int childId, wxAccRole* role) override; + + virtual wxAccStatus GetState(int childId, long* state) override; + + virtual wxAccStatus GetValue(int childId, wxString* strValue) override; + + virtual wxAccStatus GetFocus(int* childId, wxAccessible** child) override; + +private: + wxGridCellAccessible *m_gridCellAccessible; + + int wxGridAccessible::GetChildId(wxGrid* grid, int row, int col, + bool isRowHeader, bool isColHeader); +}; + +class WXDLLIMPEXP_CORE wxGridCellAccessible: public wxAccessible +{ +public: + wxGridCellAccessible(wxGrid* win, int childId); + + virtual wxAccStatus HitTest(const wxPoint& pt, int* childId, + wxAccessible** childObject) override; + + virtual wxAccStatus GetLocation(wxRect& rect, int elementId) override; + + virtual wxAccStatus GetName(int childId, wxString* name) override; + + virtual wxAccStatus GetChildCount(int* childCount) override; + + virtual wxAccStatus GetChild(int childId, wxAccessible** child) override; + + virtual wxAccStatus GetParent(wxAccessible** parent) override; + + virtual wxAccStatus GetRole(int childId, wxAccRole* role) override; + + virtual wxAccStatus GetState(int childId, long* state) override; + + virtual wxAccStatus GetValue(int childId, wxString* strValue) override; + + virtual wxAccStatus GetFocus(int* childId, wxAccessible** child) override; + +private: + int m_childId; + int m_row; + int m_col; + bool m_isRowHeader; + bool m_isColHeader; + friend class wxGridAccessible; + void DoGetLocation(wxGrid* grid, wxRect& rect); +}; +#endif // wxUSE_ACCESSIBILITY + #endif // wxUSE_GRID #endif // _WX_GENERIC_GRID_H_ diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 0f5b7123d4ef..0b2382c97d5e 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -2695,6 +2695,11 @@ wxGrid::~wxGrid() delete m_setFixedRows; delete m_setFixedCols; + +#if wxUSE_ACCESSIBILITY + SetAccessible(nullptr); + wxAccessible::NotifyEvent(wxACC_EVENT_OBJECT_DESTROY, this, wxOBJID_CLIENT, wxACC_SELF); +#endif // wxUSE_ACCESSIBILITY } // @@ -2777,6 +2782,10 @@ void wxGrid::Create() m_labelTextColour = m_rowLabelWin->GetForegroundColour(); InitPixelFields(); + +#if wxUSE_ACCESSIBILITY + wxAccessible::NotifyEvent(wxACC_EVENT_OBJECT_CREATE, this, wxOBJID_CLIENT, wxACC_SELF); +#endif // wxUSE_ACCESSIBILITY } void wxGrid::InitPixelFields() @@ -6241,6 +6250,21 @@ bool wxGrid::SetCurrentCell( const wxGridCellCoords& coords ) RefreshBlock(coords, coords); +#if wxUSE_ACCESSIBILITY + int numCols = GetNumberCols(); + if ( m_rowLabelWidth ) + numCols++; + int row = coords.GetRow(); + if ( m_colLabelHeight ) + row++; + int objectId = numCols*row + coords.GetCol() + 1; + if ( m_rowLabelWidth ) + objectId++; + wxAccessible::NotifyEvent(wxACC_EVENT_OBJECT_SELECTIONWITHIN, this, wxOBJID_CLIENT, wxACC_SELF); + wxAccessible::NotifyEvent(wxACC_EVENT_OBJECT_FOCUS, this, wxOBJID_CLIENT, objectId); + printf("\nwxGrid::SetCurrentCell -> sending wxACC_EVENT_OBJECT_FOCUS %d and wxACC_EVENT_OBJECT_SELECTIONWITHIN %x\n", objectId, (int)this); +#endif // wxUSE_ACCESSIBILITY + return true; } @@ -7293,7 +7317,9 @@ void wxGrid::ForceRefresh() void wxGrid::DoEnable(bool enable) { wxScrolledCanvas::DoEnable(enable); - +#if wxUSE_ACCESSIBILITY + wxAccessible::NotifyEvent(wxACC_EVENT_OBJECT_STATECHANGE, this, wxOBJID_CLIENT, wxACC_SELF); +#endif // wxUSE_ACCESSIBILITY Refresh(false /* don't erase background */); } @@ -11019,6 +11045,44 @@ void wxGrid::SetRowSizes(const wxGridSizesInfo& sizeInfo) DoSetSizes(sizeInfo, wxGridRowOperations()); } +#if wxUSE_ACCESSIBILITY + +bool wxGrid::Show(bool show) +{ + bool changed = wxWindow::Show(show); + if ( changed ) + { + wxAccessible::NotifyEvent(show ? wxACC_EVENT_OBJECT_SHOW : wxACC_EVENT_OBJECT_HIDE, + this, wxOBJID_CLIENT, wxACC_SELF); + } + + return changed; +} + +void wxGrid::SetName(const wxString &name) +{ + wxWindow::SetName(name); + wxAccessible::NotifyEvent(wxACC_EVENT_OBJECT_NAMECHANGE, this, wxOBJID_CLIENT, wxACC_SELF); +} + +bool wxGrid::Reparent(wxWindowBase *newParent) +{ + bool changed = wxWindowBase::Reparent(newParent); + if ( changed ) + { + wxAccessible::NotifyEvent(wxACC_EVENT_OBJECT_PARENTCHANGE, this, wxOBJID_CLIENT, wxACC_SELF); + } + + return changed; +} + +wxAccessible* wxGrid::CreateAccessible() +{ + return new wxGridAccessible(this); +} + +#endif // wxUSE_ACCESSIBILITY + wxGridSizesInfo::wxGridSizesInfo(int defSize, const wxArrayInt& allSizes) { m_sizeDefault = defSize; @@ -11337,4 +11401,589 @@ wxGetContentRect(wxSize contentSize, return contentRect; } + +#if wxUSE_ACCESSIBILITY + +//----------------------------------------------------------------------------- +// wxGridAccessible +//----------------------------------------------------------------------------- + +wxGridAccessible::wxGridAccessible(wxGrid* win) + : wxWindowAccessible(win) +{ + m_gridCellAccessible = nullptr; +} + +wxGridAccessible::~wxGridAccessible() +{ + if ( m_gridCellAccessible ) + { + delete m_gridCellAccessible; + m_gridCellAccessible = nullptr; + } +} + +// helper to convert row / col into child object id +// error handling is not required here +int wxGridAccessible::GetChildId(wxGrid* grid, int row, int col, bool isRowHeader, bool isColHeader) +{ + int childId = 0; + int numberCols = grid->GetNumberCols(); + if ( grid->m_rowLabelWidth ) + numberCols++; + + if ( isColHeader && isRowHeader ) + childId = 1; + else if ( isColHeader ) + { + childId = col + 1; + if ( grid->m_rowLabelWidth ) + childId++; + } + else if ( isRowHeader ) + { + childId = row * numberCols + 1; + if ( grid->m_colLabelHeight ) + childId += numberCols; + } + else + { + childId = row * numberCols + col + 1; + if ( grid->m_colLabelHeight ) + childId += numberCols; + if ( grid->m_rowLabelWidth ) + childId++; + } + return childId; +} + +// Can return either a child object, or an integer +// representing the child element, starting from 1. +wxAccStatus wxGridAccessible::HitTest(const wxPoint& pt, int* childId, wxAccessible** childObject) +{ + wxGrid* grid = wxDynamicCast(GetWindow(), wxGrid); + wxCHECK(grid, wxACC_FAIL); + + wxPoint pos = grid->ScreenToClient(pt); + + if ( grid->HitTest(pos) != wxHT_WINDOW_INSIDE ) + { + *childId = wxACC_SELF; + return wxACC_OK; + } + + // this one is reduced by the sizes of the labels + wxPoint gridPos = pos; + gridPos.x -= grid->m_rowLabelWidth; + gridPos.y -= grid->m_colLabelHeight; + + // depending on window type, the unscrolled position x and/or y will be picked + wxPoint unscrolledPos = grid->CalcUnscrolledPosition(gridPos); + + // pick the correct scrolled or unscrolled x/y values and calculate row, col etc. + // merged cells are not handled + int row = -1, col = -1; + bool isColHeader = false, isRowHeader = false; + + if ( grid->m_gridWin->GetRect().Contains(pos) ) + { + // x and y scrolling + row = grid->YToRow(unscrolledPos.y, false, nullptr); + col = grid->XToCol(unscrolledPos.x, false, nullptr); + } + else if ( grid->m_frozenCornerGridWin && grid->m_frozenCornerGridWin->GetRect().Contains(pos) ) + { + // fixed, no scrolling + row = grid->YToRow(gridPos.y, false, nullptr); + col = grid->XToCol(gridPos.x, false, nullptr); + } + else if ( grid->m_frozenRowGridWin && grid->m_frozenRowGridWin->GetRect().Contains(pos) ) + { + // only x scrolling + row = grid->YToRow(gridPos.y, false, nullptr); + col = grid->XToCol(unscrolledPos.x, false, nullptr); + } + else if ( grid->m_frozenColGridWin && grid->m_frozenColGridWin->GetRect().Contains(pos) ) + { + // only y scrolling + row = grid->YToRow(unscrolledPos.y, false, nullptr); + col = grid->XToCol(gridPos.x, false, nullptr); + } + else if ( grid->m_cornerLabelWin && grid->m_cornerLabelWin->GetRect().Contains(pos) ) + { + // on corner label, fixed, no scrolling + isColHeader = isRowHeader = true; + } + else if ( grid->m_rowLabelWin && grid->m_rowLabelWin->GetRect().Contains(pos) ) + { + // on row labels, only y scrolling + isRowHeader = true; + row = grid->YToRow(unscrolledPos.y, false, nullptr); + } + else if ( grid->m_rowFrozenLabelWin && grid->m_rowFrozenLabelWin->GetRect().Contains(pos) ) + { + // on frozen row labels, no scrolling + isRowHeader = true; + row = grid->YToRow(gridPos.y, false, nullptr); + } + else if ( grid->m_colLabelWin && grid->m_colLabelWin->GetRect().Contains(pos) ) + { + // on col labels, only x scrolling + isColHeader = true; + col = grid->XToCol(unscrolledPos.x, false, nullptr); + } + else if ( grid->m_colFrozenLabelWin && grid->m_colFrozenLabelWin->GetRect().Contains(pos) ) + { + // on frozen col labels, no scrolling + isColHeader = true; + col = grid->XToCol(gridPos.x, false, nullptr); + } + + if ( ( !isRowHeader && col == -1 ) || ( !isColHeader && row == -1 ) ) + { + // not over label or grid cell, but over the grid + *childId = wxACC_SELF; + *childObject = this; + return wxACC_OK; + } + + *childId = GetChildId(grid, row, col, isRowHeader, isColHeader); + + return wxACC_OK; +} + +// Returns the rectangle for this object (id = 0) +wxAccStatus wxGridAccessible::GetLocation(wxRect& rect, int childId) +{ + wxGrid* grid = wxDynamicCast(GetWindow(), wxGrid); + wxCHECK( grid, wxACC_FAIL ); + + if ( childId != wxACC_SELF ) + return wxACC_NOT_IMPLEMENTED; + + rect = grid->GetScreenRect(); + + return wxACC_OK; +} + +// Gets the name of the specified object. +wxAccStatus wxGridAccessible::GetName(int childId, wxString* name) +{ + wxGrid* grid = wxDynamicCast(GetWindow(), wxGrid); + wxCHECK( grid, wxACC_FAIL ); + + if ( childId != wxACC_SELF ) + return wxACC_NOT_IMPLEMENTED; + + *name = grid->GetName(); + + return wxACC_OK; +} + +// Gets the number of children. +wxAccStatus wxGridAccessible::GetChildCount(int* childCount) +{ + wxGrid* grid = wxDynamicCast(GetWindow(), wxGrid); + wxCHECK( grid, wxACC_FAIL ); + + int numberCols = grid->GetNumberCols(); + int numberRows = grid->GetNumberRows(); + if (grid->m_colLabelHeight) + numberRows++; + if (grid->m_rowLabelWidth) + numberCols++; + + *childCount = numberRows * numberCols; + + return wxACC_OK; +} + +// Gets the specified child (starting from 1). +// If *child is null and return value is wxACC_OK, this means that the child +// is a simple element and not an accessible object. +wxAccStatus wxGridAccessible::GetChild(int childId, wxAccessible** child) +{ + wxGrid* grid = wxDynamicCast(GetWindow(), wxGrid); + wxCHECK( grid, wxACC_FAIL ); + + if ( childId == wxACC_SELF ) + { + *child = this; + } + else + { + if ( !m_gridCellAccessible || m_gridCellAccessible->m_childId!=childId) + { + delete m_gridCellAccessible; + m_gridCellAccessible = new wxGridCellAccessible(grid, childId); + } + *child = m_gridCellAccessible; + } + return wxACC_OK; +} + +// Returns a role constant. +wxAccStatus wxGridAccessible::GetRole(int childId, wxAccRole* role) +{ + wxGrid* grid = wxDynamicCast(GetWindow(), wxGrid); + wxCHECK( grid, wxACC_FAIL ); + + if ( childId == wxACC_SELF ) + *role = wxROLE_SYSTEM_TABLE; + else + *role = wxROLE_SYSTEM_CELL; + + return wxACC_OK; +} + +// Returns a state constant. +wxAccStatus wxGridAccessible::GetState(int childId, long* state) +{ + wxGrid* grid = wxDynamicCast(GetWindow(), wxGrid); + wxCHECK( grid, wxACC_FAIL ); + + if ( childId > 0 ) + return wxACC_NOT_IMPLEMENTED; + + long st = 0; + if ( !grid->IsEnabled() ) + st |= wxACC_STATE_SYSTEM_UNAVAILABLE; + if ( !grid->IsShown() ) + st |= wxACC_STATE_SYSTEM_INVISIBLE; + + if( grid->IsFocusable() ) + st |= wxACC_STATE_SYSTEM_FOCUSABLE; + + // this needs to be returned such that a child below is recognized as focused + // (check for cursorRow and cursorCol being != -1?) + if ( grid->HasFocus() ) + st |= wxACC_STATE_SYSTEM_FOCUSED; + + *state = st; + return wxACC_OK; +} + +// Returns a localized string representing the value for the object. +wxAccStatus wxGridAccessible::GetValue(int childId, wxString* strValue) +{ + + wxGrid* grid = wxDynamicCast(GetWindow(), wxGrid); + wxCHECK( grid, wxACC_FAIL ); + + if ( childId != wxACC_SELF ) + return wxACC_NOT_IMPLEMENTED; + + // we don't have a value for the grid + return wxACC_NOT_SUPPORTED; +} + +// Gets the window with the keyboard focus. +// If childId is 0 and child is null, no object in this subhierarchy has the focus. +// If this object has the focus, child should be 'this'. +wxAccStatus wxGridAccessible::GetFocus(int* childId, wxAccessible** child) +{ + wxGrid* grid = wxDynamicCast(GetWindow(), wxGrid); + wxCHECK( grid, wxACC_FAIL ); + + if ( grid->HasFocus() ) + { + wxGridCellCoords coord = grid->GetGridCursorCoords(); + if ( coord == wxGridNoCellCoords ) + { + *childId = wxACC_SELF; + *child = this; + } + else + { + *child = nullptr; + *childId = GetChildId(grid, coord.GetRow(), coord.GetCol(), false, false); + } + } + else + { + *childId = 0; + *child = nullptr; + } + + return wxACC_OK; +} + + +//----------------------------------------------------------------------------- +// wxGridCellAccessible +//----------------------------------------------------------------------------- + +wxGridCellAccessible::wxGridCellAccessible(wxGrid* grid, int childId) + : wxAccessible(grid) +{ + m_childId = childId; + + // calculate row, col, isRowHeader, isColHeader from childId + if ( childId == 1 && grid->m_colLabelHeight && grid->m_rowLabelWidth ) + { + m_row = m_col = -1; + m_isRowHeader = true; + m_isColHeader = true; + } + else + { + m_isRowHeader = m_isColHeader = false; + int numCols = grid->GetNumberCols(); + if ( grid->m_rowLabelWidth ) + numCols++; + m_row = (childId - 1) / numCols; + m_col = (childId - 1) % numCols; + if ( grid->m_rowLabelWidth ) + { + if ( m_col == 0 ) + { + m_col = -1; + m_isRowHeader = true; + } + else + m_col--; + } + if ( grid->m_colLabelHeight ) + { + if ( m_row == 0 ) + { + m_row = -1; + m_isColHeader = true; + } + else + m_row--; + } + } +} + +// Gets the parent +wxAccStatus wxGridCellAccessible::GetParent(wxAccessible** parent) +{ + wxGrid* grid = wxDynamicCast(GetWindow(), wxGrid); + wxCHECK(grid, wxACC_FAIL); + + *parent = grid->m_accessible; + return wxACC_OK; +} + +// Can return either a child object, or an integer +// representing the child element, starting from 1. +wxAccStatus wxGridCellAccessible::HitTest(const wxPoint& pt, int* childId, wxAccessible** childObject) +{ + wxGrid* grid = wxDynamicCast(GetWindow(), wxGrid); + wxCHECK( grid, wxACC_FAIL ); + + wxPoint pos = grid->ScreenToClient(pt); + wxRect cellRect; + DoGetLocation(grid, cellRect); + + if ( grid->HitTest(pos) != wxHT_WINDOW_INSIDE || !cellRect.Contains(pt) ) + { + *childId = wxACC_SELF; + return wxACC_OK; + } + + *childObject = this; + + return wxACC_OK; +} + +// helper to return the screen rectangle for this cell +void wxGridCellAccessible::DoGetLocation(wxGrid* grid, wxRect& rect) +{ + rect = grid->GetScreenRect(); + wxPoint unscrolledPos = grid->CalcScrolledPosition(rect.GetLeftTop()); + + if ( m_isColHeader ) + { + rect.height = grid->m_colLabelHeight; + } + else + { + if ( m_row >= grid->m_numFrozenRows ) + rect.y = unscrolledPos.y; + rect.y = rect.y + grid->m_colLabelHeight + grid->GetRowTop(m_row); + rect.height = grid->GetRowHeight(m_row); + } + if ( m_isRowHeader ) + rect.width = grid->m_rowLabelWidth; + else + { + if ( m_col >= grid->m_numFrozenCols ) + rect.x = unscrolledPos.x; + rect.x = rect.x + grid->m_rowLabelWidth + grid->GetColLeft(m_col); + rect.width = grid->GetColWidth(m_col); + } +} + +// Returns the rectangle for this object (id = 0) or a child element (id > 0). +wxAccStatus wxGridCellAccessible::GetLocation(wxRect& rect, int elementId) +{ + wxGrid* grid = wxDynamicCast(GetWindow(), wxGrid); + wxCHECK( grid, wxACC_FAIL ); + if ( elementId != wxACC_SELF ) + return wxACC_FAIL; + + DoGetLocation(grid, rect); + + return wxACC_OK; +} + +// Gets the name of the specified object. +wxAccStatus wxGridCellAccessible::GetName(int childId, wxString* name) +{ + wxGrid* grid = wxDynamicCast(GetWindow(), wxGrid); + wxCHECK( grid, wxACC_FAIL ); + + if ( childId != wxACC_SELF ) + return wxACC_FAIL; + + if ( m_isColHeader && m_isRowHeader ) + *name = _("Grid Corner"); + else if ( m_isColHeader ) + *name = wxString::Format(_("Column %s Header"), grid->GetColLabelValue(m_col)); + else if ( m_isRowHeader ) + *name = wxString::Format(_("Row %s Header"), grid->GetRowLabelValue(m_row)); + else + *name = wxString::Format(_("Row %s, Column %s"), + grid->GetRowLabelValue(m_row), grid->GetColLabelValue(m_col)); + + return wxACC_OK; +} + +// Gets the number of children. +wxAccStatus wxGridCellAccessible::GetChildCount(int* childCount) +{ + *childCount = 0; + return wxACC_OK; +} + +// Gets the specified child (starting from 1). +// If *child is NULL and return value is wxACC_OK, this means that the child +// is a simple element and not an accessible object. +wxAccStatus wxGridCellAccessible::GetChild(int childId, wxAccessible** child) +{ + if (childId != wxACC_SELF) + return wxACC_FAIL; + + *child = this; + return wxACC_OK; +} + +// Returns a role constant. +wxAccStatus wxGridCellAccessible::GetRole(int childId, wxAccRole* role) +{ + if ( childId != wxACC_SELF ) + return wxACC_FAIL; + + if ( m_isColHeader ) + *role = wxROLE_SYSTEM_COLUMNHEADER; + else if ( m_isRowHeader ) + *role = wxROLE_SYSTEM_ROWHEADER; + else + *role = wxROLE_SYSTEM_CELL; + + return wxACC_OK; +} + +// Returns a state constant. +wxAccStatus wxGridCellAccessible::GetState(int childId, long* state) +{ + wxGrid* grid = wxDynamicCast(GetWindow(), wxGrid); + wxCHECK( grid, wxACC_FAIL ); + if ( childId != wxACC_SELF ) + return wxACC_FAIL; + + long st = 0; + + if ( !grid->IsEnabled() ) + st |= wxACC_STATE_SYSTEM_UNAVAILABLE; + + if ( !m_isColHeader && !grid->IsRowShown(m_row) ) + st |= wxACC_STATE_SYSTEM_INVISIBLE; + else if ( !m_isRowHeader && !grid->IsColShown(m_col) ) + st |= wxACC_STATE_SYSTEM_INVISIBLE; + + if( grid->IsFocusable() ) + st |= wxACC_STATE_SYSTEM_FOCUSABLE; + + st |= wxACC_STATE_SYSTEM_SELECTABLE; + + const int cursorRow = grid->GetGridCursorRow(); + const int cursorCol = grid->GetGridCursorCol(); + + if ( !m_isColHeader && !m_isRowHeader && grid->HasFocus() && m_col==cursorCol && m_row==cursorRow) + st |= wxACC_STATE_SYSTEM_FOCUSED; + + // check selection and visibility + if ( m_isRowHeader && m_isColHeader ) + { + // check whether complete grid is selected? + } + else if ( m_isRowHeader ) + { + wxArrayInt selectedRows = grid->GetSelectedRows(); + if ( selectedRows.Index(m_row) != wxNOT_FOUND ) + st |= wxACC_STATE_SYSTEM_SELECTED; + } + else if ( m_isColHeader ) + { + wxArrayInt selectedCols = grid->GetSelectedCols(); + if ( selectedCols.Index(m_col) != wxNOT_FOUND ) + st |= wxACC_STATE_SYSTEM_SELECTED; + } + else + { + if ( grid->IsInSelection(m_row, m_col) ) + st |= wxACC_STATE_SYSTEM_SELECTED; + if ( grid->IsVisible(m_row, m_col, false) ) + st |= wxACC_STATE_SYSTEM_OFFSCREEN; + } + + *state = st; + return wxACC_OK; +} + +// Returns a localized string representing the value for the object or child. +wxAccStatus wxGridCellAccessible::GetValue(int childId, wxString* strValue) +{ + wxGrid* grid = wxDynamicCast(GetWindow(), wxGrid); + wxCHECK( grid, wxACC_FAIL ); + + if ( childId != wxACC_SELF ) + return wxACC_FAIL; + + if ( m_isColHeader && m_isRowHeader ) + *strValue = grid->GetCornerLabelValue(); + else if ( m_isColHeader ) + *strValue = grid->GetColLabelValue(m_col); + else if ( m_isRowHeader ) + *strValue = grid->GetRowLabelValue(m_row); + else + *strValue = grid->GetCellValue(m_row, m_col); + + return wxACC_OK; +} + +// Gets the window with the keyboard focus. +// If childId is 0 and child is NULL, no object in this subhierarchy has the focus. +// If this object has the focus, child should be 'this'. +wxAccStatus wxGridCellAccessible::GetFocus(int* childId, wxAccessible** child) +{ + wxGrid* grid = wxDynamicCast(GetWindow(), wxGrid); + wxCHECK( grid, wxACC_FAIL ); + + *childId = wxACC_SELF; + + const int cursorRow = grid->GetGridCursorRow(); + const int cursorCol = grid->GetGridCursorCol(); + + if ( !m_isColHeader && !m_isRowHeader && cursorRow == m_row && cursorCol == m_col ) + *child = this; + + return wxACC_OK; +} + +#endif // wxUSE_ACCESSIBILITY + #endif // wxUSE_GRID diff --git a/src/generic/gridsel.cpp b/src/generic/gridsel.cpp index 673c75cc67f8..27525d3a502e 100644 --- a/src/generic/gridsel.cpp +++ b/src/generic/gridsel.cpp @@ -867,6 +867,10 @@ wxGridSelection::Select(const wxGridBlockCoords& block, m_grid->RefreshBlock(block.GetTopLeft(), block.GetBottomRight()); } +#if wxUSE_ACCESSIBILITY + wxAccessible::NotifyEvent(wxACC_EVENT_OBJECT_SELECTIONWITHIN, m_grid, wxOBJID_CLIENT, wxACC_SELF); +#endif // wxUSE_ACCESSIBILITY + // Send Event, if not disabled. if ( eventType != wxEVT_NULL ) { From 4887f28cbe0ba0326dff4ddea490bcc024e4aec7 Mon Sep 17 00:00:00 2001 From: DietmarSchwertberger Date: Sat, 2 Mar 2024 22:31:39 +0100 Subject: [PATCH 02/19] remove white space --- include/wx/generic/grid.h | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index 386bac3c6984..c672a4406069 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -3499,19 +3499,12 @@ class WXDLLIMPEXP_CORE wxGridAccessible: public wxWindowAccessible wxAccessible** childObject) override; virtual wxAccStatus GetLocation(wxRect& rect, int elementId) override; - virtual wxAccStatus GetName(int childId, wxString* name) override; - virtual wxAccStatus GetChildCount(int* childCount) override; - virtual wxAccStatus GetChild(int childId, wxAccessible** child) override; - virtual wxAccStatus GetRole(int childId, wxAccRole* role) override; - virtual wxAccStatus GetState(int childId, long* state) override; - virtual wxAccStatus GetValue(int childId, wxString* strValue) override; - virtual wxAccStatus GetFocus(int* childId, wxAccessible** child) override; private: @@ -3530,21 +3523,13 @@ class WXDLLIMPEXP_CORE wxGridCellAccessible: public wxAccessible wxAccessible** childObject) override; virtual wxAccStatus GetLocation(wxRect& rect, int elementId) override; - virtual wxAccStatus GetName(int childId, wxString* name) override; - virtual wxAccStatus GetChildCount(int* childCount) override; - virtual wxAccStatus GetChild(int childId, wxAccessible** child) override; - virtual wxAccStatus GetParent(wxAccessible** parent) override; - virtual wxAccStatus GetRole(int childId, wxAccRole* role) override; - virtual wxAccStatus GetState(int childId, long* state) override; - virtual wxAccStatus GetValue(int childId, wxString* strValue) override; - virtual wxAccStatus GetFocus(int* childId, wxAccessible** child) override; private: From d5e0f2b3a4151bf1564f5997b758fe6e67a18742 Mon Sep 17 00:00:00 2001 From: DietmarSchwertberger Date: Sat, 2 Mar 2024 22:36:30 +0100 Subject: [PATCH 03/19] remove debug message --- src/generic/grid.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 0b2382c97d5e..499fee886171 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -6262,7 +6262,6 @@ bool wxGrid::SetCurrentCell( const wxGridCellCoords& coords ) objectId++; wxAccessible::NotifyEvent(wxACC_EVENT_OBJECT_SELECTIONWITHIN, this, wxOBJID_CLIENT, wxACC_SELF); wxAccessible::NotifyEvent(wxACC_EVENT_OBJECT_FOCUS, this, wxOBJID_CLIENT, objectId); - printf("\nwxGrid::SetCurrentCell -> sending wxACC_EVENT_OBJECT_FOCUS %d and wxACC_EVENT_OBJECT_SELECTIONWITHIN %x\n", objectId, (int)this); #endif // wxUSE_ACCESSIBILITY return true; From 61b47ac18bed62b8092c5eed6949829c355db6de Mon Sep 17 00:00:00 2001 From: DietmarSchwertberger Date: Sat, 2 Mar 2024 22:48:44 +0100 Subject: [PATCH 04/19] remove additional qualification --- include/wx/generic/grid.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index c672a4406069..3baa548d6ea9 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -3510,8 +3510,8 @@ class WXDLLIMPEXP_CORE wxGridAccessible: public wxWindowAccessible private: wxGridCellAccessible *m_gridCellAccessible; - int wxGridAccessible::GetChildId(wxGrid* grid, int row, int col, - bool isRowHeader, bool isColHeader); + int GetChildId(wxGrid* grid, int row, int col, + bool isRowHeader, bool isColHeader); }; class WXDLLIMPEXP_CORE wxGridCellAccessible: public wxAccessible From 6ea38f3a05944a37f63b826fe0baa5acb33bf165 Mon Sep 17 00:00:00 2001 From: DietmarSchwertberger Date: Sat, 2 Mar 2024 22:51:13 +0100 Subject: [PATCH 05/19] use nullptr --- src/generic/grid.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 499fee886171..b0e2f506179d 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -11858,7 +11858,7 @@ wxAccStatus wxGridCellAccessible::GetChildCount(int* childCount) } // Gets the specified child (starting from 1). -// If *child is NULL and return value is wxACC_OK, this means that the child +// If *child is nullptr and return value is wxACC_OK, this means that the child // is a simple element and not an accessible object. wxAccStatus wxGridCellAccessible::GetChild(int childId, wxAccessible** child) { @@ -11965,7 +11965,7 @@ wxAccStatus wxGridCellAccessible::GetValue(int childId, wxString* strValue) } // Gets the window with the keyboard focus. -// If childId is 0 and child is NULL, no object in this subhierarchy has the focus. +// If childId is 0 and child is nullptr, no object in this subhierarchy has the focus. // If this object has the focus, child should be 'this'. wxAccStatus wxGridCellAccessible::GetFocus(int* childId, wxAccessible** child) { From 3965a95a65ec95e754ac7f7b85d0fd0953195b12 Mon Sep 17 00:00:00 2001 From: DietmarSchwertberger Date: Sat, 2 Mar 2024 22:58:34 +0100 Subject: [PATCH 06/19] declare unused argument --- src/generic/grid.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index b0e2f506179d..c3d751378105 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -11663,7 +11663,7 @@ wxAccStatus wxGridAccessible::GetState(int childId, long* state) } // Returns a localized string representing the value for the object. -wxAccStatus wxGridAccessible::GetValue(int childId, wxString* strValue) +wxAccStatus wxGridAccessible::GetValue(int childId, wxString* WXUNUSED(strValue)) { wxGrid* grid = wxDynamicCast(GetWindow(), wxGrid); From 24e053c17d265423441fe1fc6ba5dc8bfac4bf13 Mon Sep 17 00:00:00 2001 From: DietmarSchwertberger Date: Sun, 3 Mar 2024 13:44:14 +0100 Subject: [PATCH 07/19] refactor, return different roles for headers --- include/wx/generic/grid.h | 3 - src/generic/grid.cpp | 148 ++++++++++++++++++++++---------------- 2 files changed, 86 insertions(+), 65 deletions(-) diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index 3baa548d6ea9..affc7b47f018 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -3509,9 +3509,6 @@ class WXDLLIMPEXP_CORE wxGridAccessible: public wxWindowAccessible private: wxGridCellAccessible *m_gridCellAccessible; - - int GetChildId(wxGrid* grid, int row, int col, - bool isRowHeader, bool isColHeader); }; class WXDLLIMPEXP_CORE wxGridCellAccessible: public wxAccessible diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index c3d751378105..df4e867c43ba 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -11404,31 +11404,17 @@ wxGetContentRect(wxSize contentSize, #if wxUSE_ACCESSIBILITY //----------------------------------------------------------------------------- -// wxGridAccessible +// helpers for wxGridAccessible and wxGridCellAccessible //----------------------------------------------------------------------------- -wxGridAccessible::wxGridAccessible(wxGrid* win) - : wxWindowAccessible(win) -{ - m_gridCellAccessible = nullptr; -} - -wxGridAccessible::~wxGridAccessible() -{ - if ( m_gridCellAccessible ) - { - delete m_gridCellAccessible; - m_gridCellAccessible = nullptr; - } -} - // helper to convert row / col into child object id // error handling is not required here -int wxGridAccessible::GetChildId(wxGrid* grid, int row, int col, bool isRowHeader, bool isColHeader) +static int GetChildId(wxGrid* grid, int row, int col, + bool isRowHeader, bool isColHeader) { int childId = 0; int numberCols = grid->GetNumberCols(); - if ( grid->m_rowLabelWidth ) + if ( grid->GetRowLabelSize() ) numberCols++; if ( isColHeader && isRowHeader ) @@ -11436,26 +11422,87 @@ int wxGridAccessible::GetChildId(wxGrid* grid, int row, int col, bool isRowHeade else if ( isColHeader ) { childId = col + 1; - if ( grid->m_rowLabelWidth ) + if ( grid->GetRowLabelSize() ) childId++; } else if ( isRowHeader ) { childId = row * numberCols + 1; - if ( grid->m_colLabelHeight ) + if ( grid->GetColLabelSize() ) childId += numberCols; } else { childId = row * numberCols + col + 1; - if ( grid->m_colLabelHeight ) + if ( grid->GetColLabelSize() ) childId += numberCols; - if ( grid->m_rowLabelWidth ) + if ( grid->GetRowLabelSize() ) childId++; } return childId; } +// helper to calculate row, col, isRowHeader, isColHeader from childId +static void GetRowCol(wxGrid* grid, int childId, int* row, int* col, + bool* isRowHeader, bool* isColHeader) +{ + if ( childId == 1 && grid->GetColLabelSize() && grid->GetRowLabelSize() ) + { + *row = *col = -1; + *isRowHeader = true; + *isColHeader = true; + } + else + { + *isRowHeader = *isColHeader = false; + int numCols = grid->GetNumberCols(); + if ( grid->GetRowLabelSize() ) + numCols++; + *row = (childId - 1) / numCols; + *col = (childId - 1) % numCols; + if ( grid->GetRowLabelSize() ) + { + if ( *col == 0 ) + { + *col = -1; + *isRowHeader = true; + } + else + (*col)--; + } + if ( grid->GetColLabelSize() ) + { + if ( *row == 0 ) + { + *row = -1; + *isColHeader = true; + } + else + (*row)--; + } + } +} + + +//----------------------------------------------------------------------------- +// wxGridAccessible +//----------------------------------------------------------------------------- + +wxGridAccessible::wxGridAccessible(wxGrid* win) + : wxWindowAccessible(win) +{ + m_gridCellAccessible = nullptr; +} + +wxGridAccessible::~wxGridAccessible() +{ + if ( m_gridCellAccessible ) + { + delete m_gridCellAccessible; + m_gridCellAccessible = nullptr; + } +} + // Can return either a child object, or an integer // representing the child element, starting from 1. wxAccStatus wxGridAccessible::HitTest(const wxPoint& pt, int* childId, wxAccessible** childObject) @@ -11628,9 +11675,22 @@ wxAccStatus wxGridAccessible::GetRole(int childId, wxAccRole* role) wxCHECK( grid, wxACC_FAIL ); if ( childId == wxACC_SELF ) + { *role = wxROLE_SYSTEM_TABLE; + } else - *role = wxROLE_SYSTEM_CELL; + { + // children can be cells or headers + int row, col; + bool isRowHeader, isColHeader; + GetRowCol(grid, childId, &row, &col, &isRowHeader, &isColHeader); + if ( isColHeader ) + *role = wxROLE_SYSTEM_COLUMNHEADER; + else if ( isRowHeader ) + *role = wxROLE_SYSTEM_ROWHEADER; + else + *role = wxROLE_SYSTEM_CELL; + } return wxACC_OK; } @@ -11716,43 +11776,7 @@ wxGridCellAccessible::wxGridCellAccessible(wxGrid* grid, int childId) : wxAccessible(grid) { m_childId = childId; - - // calculate row, col, isRowHeader, isColHeader from childId - if ( childId == 1 && grid->m_colLabelHeight && grid->m_rowLabelWidth ) - { - m_row = m_col = -1; - m_isRowHeader = true; - m_isColHeader = true; - } - else - { - m_isRowHeader = m_isColHeader = false; - int numCols = grid->GetNumberCols(); - if ( grid->m_rowLabelWidth ) - numCols++; - m_row = (childId - 1) / numCols; - m_col = (childId - 1) % numCols; - if ( grid->m_rowLabelWidth ) - { - if ( m_col == 0 ) - { - m_col = -1; - m_isRowHeader = true; - } - else - m_col--; - } - if ( grid->m_colLabelHeight ) - { - if ( m_row == 0 ) - { - m_row = -1; - m_isColHeader = true; - } - else - m_row--; - } - } + GetRowCol(grid, childId, &m_row, &m_col, &m_isRowHeader, &m_isColHeader); } // Gets the parent @@ -11816,11 +11840,11 @@ void wxGridCellAccessible::DoGetLocation(wxGrid* grid, wxRect& rect) } // Returns the rectangle for this object (id = 0) or a child element (id > 0). -wxAccStatus wxGridCellAccessible::GetLocation(wxRect& rect, int elementId) +wxAccStatus wxGridCellAccessible::GetLocation(wxRect& rect, int childId) { wxGrid* grid = wxDynamicCast(GetWindow(), wxGrid); wxCHECK( grid, wxACC_FAIL ); - if ( elementId != wxACC_SELF ) + if ( childId != wxACC_SELF ) return wxACC_FAIL; DoGetLocation(grid, rect); From c182baa3180f10503083d4107a23d976905a8464 Mon Sep 17 00:00:00 2001 From: DietmarSchwertberger Date: Mon, 13 May 2024 21:08:01 +0200 Subject: [PATCH 08/19] combine coordinate and value into GetName --- include/wx/generic/grid.h | 2 ++ src/generic/grid.cpp | 55 +++++++++++++++++++++++++++++---------- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index affc7b47f018..f51e7c6a9304 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -3535,6 +3535,8 @@ class WXDLLIMPEXP_CORE wxGridCellAccessible: public wxAccessible int m_col; bool m_isRowHeader; bool m_isColHeader; + bool m_isSameRow; + bool m_isSameCol; friend class wxGridAccessible; void DoGetLocation(wxGrid* grid, wxRect& rect); }; diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index df4e867c43ba..24e3c5055794 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -11658,10 +11658,33 @@ wxAccStatus wxGridAccessible::GetChild(int childId, wxAccessible** child) } else { - if ( !m_gridCellAccessible || m_gridCellAccessible->m_childId!=childId) + if ( !m_gridCellAccessible ) { + m_gridCellAccessible = new wxGridCellAccessible(grid, childId); + } + else if ( m_gridCellAccessible->m_childId != childId ) + { + // pass on the information whether the cell is on the same row or + // column than the previous one to avoid redundant coordinate info + int previousRow = m_gridCellAccessible->m_row; + int previousCol = m_gridCellAccessible->m_col; + int previousRowHeader = m_gridCellAccessible->m_isRowHeader; + int previousColHeader = m_gridCellAccessible->m_isColHeader; delete m_gridCellAccessible; m_gridCellAccessible = new wxGridCellAccessible(grid, childId); + if ( m_gridCellAccessible->m_row == previousRow && + m_gridCellAccessible->m_isColHeader == previousColHeader ) + { + m_gridCellAccessible->m_isSameRow = true; + printf("same row\n"); + } + if ( m_gridCellAccessible->m_col == previousCol && + m_gridCellAccessible->m_isRowHeader == previousRowHeader ) + { + m_gridCellAccessible->m_isSameCol = true; + printf("same column\n"); + } + } *child = m_gridCellAccessible; } @@ -11777,6 +11800,7 @@ wxGridCellAccessible::wxGridCellAccessible(wxGrid* grid, int childId) { m_childId = childId; GetRowCol(grid, childId, &m_row, &m_col, &m_isRowHeader, &m_isColHeader); + m_isSameRow = m_isSameCol = false; } // Gets the parent @@ -11861,15 +11885,25 @@ wxAccStatus wxGridCellAccessible::GetName(int childId, wxString* name) if ( childId != wxACC_SELF ) return wxACC_FAIL; + // combine coordinate info and value, as JAWS will not handle Name and Value if ( m_isColHeader && m_isRowHeader ) *name = _("Grid Corner"); else if ( m_isColHeader ) *name = wxString::Format(_("Column %s Header"), grid->GetColLabelValue(m_col)); else if ( m_isRowHeader ) *name = wxString::Format(_("Row %s Header"), grid->GetRowLabelValue(m_row)); + else if ( m_isSameRow ) + *name = wxString::Format(_("Column %s: %s"), + grid->GetColLabelValue(m_col), + grid->GetCellValue(m_row, m_col)); + else if ( m_isSameCol ) + *name = wxString::Format(_("Row %s: %s"), + grid->GetRowLabelValue(m_row), + grid->GetCellValue(m_row, m_col)); else - *name = wxString::Format(_("Row %s, Column %s"), - grid->GetRowLabelValue(m_row), grid->GetColLabelValue(m_col)); + *name = wxString::Format(_("Row %s, Column %s: %s"), + grid->GetRowLabelValue(m_row), grid->GetColLabelValue(m_col), + grid->GetCellValue(m_row, m_col)); return wxACC_OK; } @@ -11961,6 +11995,8 @@ wxAccStatus wxGridCellAccessible::GetState(int childId, long* state) st |= wxACC_STATE_SYSTEM_SELECTED; if ( grid->IsVisible(m_row, m_col, false) ) st |= wxACC_STATE_SYSTEM_OFFSCREEN; + if ( grid->IsReadOnly(m_row, m_col) ) + st |= wxACC_STATE_SYSTEM_READONLY; } *state = st; @@ -11975,17 +12011,8 @@ wxAccStatus wxGridCellAccessible::GetValue(int childId, wxString* strValue) if ( childId != wxACC_SELF ) return wxACC_FAIL; - - if ( m_isColHeader && m_isRowHeader ) - *strValue = grid->GetCornerLabelValue(); - else if ( m_isColHeader ) - *strValue = grid->GetColLabelValue(m_col); - else if ( m_isRowHeader ) - *strValue = grid->GetRowLabelValue(m_row); - else - *strValue = grid->GetCellValue(m_row, m_col); - - return wxACC_OK; + // GetName now returns coordinate and value info at the same time + return wxACC_NOT_IMPLEMENTED; } // Gets the window with the keyboard focus. From 46c906d546d6bdf4dacc435c1ef0e17fab823b7b Mon Sep 17 00:00:00 2001 From: DietmarSchwertberger Date: Mon, 20 May 2024 13:55:08 +0200 Subject: [PATCH 09/19] move wxGridAccessible to private header --- include/wx/generic/grid.h | 57 ----------------------------- include/wx/generic/private/grid.h | 59 +++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 57 deletions(-) diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index f51e7c6a9304..537437d60234 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -3484,63 +3484,6 @@ extern const int wxEVT_GRID_CHANGE_SEL_LABEL; #endif -#if wxUSE_ACCESSIBILITY -//----------------------------------------------------------------------------- -// accessibility support for whole grid and per cell -//----------------------------------------------------------------------------- - -class WXDLLIMPEXP_CORE wxGridAccessible: public wxWindowAccessible -{ -public: - wxGridAccessible(wxGrid* win); - virtual ~wxGridAccessible(); - - virtual wxAccStatus HitTest(const wxPoint& pt, int* childId, - wxAccessible** childObject) override; - - virtual wxAccStatus GetLocation(wxRect& rect, int elementId) override; - virtual wxAccStatus GetName(int childId, wxString* name) override; - virtual wxAccStatus GetChildCount(int* childCount) override; - virtual wxAccStatus GetChild(int childId, wxAccessible** child) override; - virtual wxAccStatus GetRole(int childId, wxAccRole* role) override; - virtual wxAccStatus GetState(int childId, long* state) override; - virtual wxAccStatus GetValue(int childId, wxString* strValue) override; - virtual wxAccStatus GetFocus(int* childId, wxAccessible** child) override; - -private: - wxGridCellAccessible *m_gridCellAccessible; -}; - -class WXDLLIMPEXP_CORE wxGridCellAccessible: public wxAccessible -{ -public: - wxGridCellAccessible(wxGrid* win, int childId); - - virtual wxAccStatus HitTest(const wxPoint& pt, int* childId, - wxAccessible** childObject) override; - - virtual wxAccStatus GetLocation(wxRect& rect, int elementId) override; - virtual wxAccStatus GetName(int childId, wxString* name) override; - virtual wxAccStatus GetChildCount(int* childCount) override; - virtual wxAccStatus GetChild(int childId, wxAccessible** child) override; - virtual wxAccStatus GetParent(wxAccessible** parent) override; - virtual wxAccStatus GetRole(int childId, wxAccRole* role) override; - virtual wxAccStatus GetState(int childId, long* state) override; - virtual wxAccStatus GetValue(int childId, wxString* strValue) override; - virtual wxAccStatus GetFocus(int* childId, wxAccessible** child) override; - -private: - int m_childId; - int m_row; - int m_col; - bool m_isRowHeader; - bool m_isColHeader; - bool m_isSameRow; - bool m_isSameCol; - friend class wxGridAccessible; - void DoGetLocation(wxGrid* grid, wxRect& rect); -}; -#endif // wxUSE_ACCESSIBILITY #endif // wxUSE_GRID #endif // _WX_GENERIC_GRID_H_ diff --git a/include/wx/generic/private/grid.h b/include/wx/generic/private/grid.h index d58f0dc10157..7c6986af0c60 100644 --- a/include/wx/generic/private/grid.h +++ b/include/wx/generic/private/grid.h @@ -1282,5 +1282,64 @@ TryGetValueAsDate(wxDateTime& result, } // namespace wxGridPrivate + +#if wxUSE_ACCESSIBILITY +//----------------------------------------------------------------------------- +// accessibility support for whole grid and per cell +//----------------------------------------------------------------------------- + +class WXDLLIMPEXP_CORE wxGridAccessible : public wxWindowAccessible +{ +public: + explicit wxGridAccessible(wxGrid* win); + virtual ~wxGridAccessible(); + + virtual wxAccStatus HitTest(const wxPoint& pt, int* childId, + wxAccessible** childObject) override; + + virtual wxAccStatus GetLocation(wxRect& rect, int elementId) override; + virtual wxAccStatus GetName(int childId, wxString* name) override; + virtual wxAccStatus GetChildCount(int* childCount) override; + virtual wxAccStatus GetChild(int childId, wxAccessible** child) override; + virtual wxAccStatus GetRole(int childId, wxAccRole* role) override; + virtual wxAccStatus GetState(int childId, long* state) override; + virtual wxAccStatus GetValue(int childId, wxString* strValue) override; + virtual wxAccStatus GetFocus(int* childId, wxAccessible** child) override; + +private: + wxGridCellAccessible* m_gridCellAccessible; +}; + +class WXDLLIMPEXP_CORE wxGridCellAccessible : public wxAccessible +{ +public: + wxGridCellAccessible(wxGrid* win, int childId); + + virtual wxAccStatus HitTest(const wxPoint& pt, int* childId, + wxAccessible** childObject) override; + + virtual wxAccStatus GetLocation(wxRect& rect, int elementId) override; + virtual wxAccStatus GetName(int childId, wxString* name) override; + virtual wxAccStatus GetChildCount(int* childCount) override; + virtual wxAccStatus GetChild(int childId, wxAccessible** child) override; + virtual wxAccStatus GetParent(wxAccessible** parent) override; + virtual wxAccStatus GetRole(int childId, wxAccRole* role) override; + virtual wxAccStatus GetState(int childId, long* state) override; + virtual wxAccStatus GetValue(int childId, wxString* strValue) override; + virtual wxAccStatus GetFocus(int* childId, wxAccessible** child) override; + +private: + int m_childId; + int m_row; + int m_col; + bool m_isRowHeader; + bool m_isColHeader; + bool m_isSameRow; + bool m_isSameCol; + friend class wxGridAccessible; + void DoGetLocation(wxGrid* grid, wxRect& rect); +}; +#endif // wxUSE_ACCESSIBILITY + #endif // wxUSE_GRID #endif // _WX_GENERIC_GRID_PRIVATE_H_ From c5582129cfe3727cb55170387a3e60a79171862d Mon Sep 17 00:00:00 2001 From: DietmarSchwertberger Date: Mon, 20 May 2024 14:59:06 +0200 Subject: [PATCH 10/19] replace m_row/m_col etc. with m_coords --- include/wx/generic/private/grid.h | 10 +- src/generic/grid.cpp | 155 +++++++++++++----------------- 2 files changed, 72 insertions(+), 93 deletions(-) diff --git a/include/wx/generic/private/grid.h b/include/wx/generic/private/grid.h index 7c6986af0c60..85087ff2d1e6 100644 --- a/include/wx/generic/private/grid.h +++ b/include/wx/generic/private/grid.h @@ -1330,12 +1330,10 @@ class WXDLLIMPEXP_CORE wxGridCellAccessible : public wxAccessible private: int m_childId; - int m_row; - int m_col; - bool m_isRowHeader; - bool m_isColHeader; - bool m_isSameRow; - bool m_isSameCol; + // row and / or col can be -1 for column or row header + wxGridCellCoords m_coords; + bool m_isSameRow = false; + bool m_isSameCol = false; friend class wxGridAccessible; void DoGetLocation(wxGrid* grid, wxRect& rect); }; diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 24e3c5055794..97d9f57b755d 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -11409,23 +11409,22 @@ wxGetContentRect(wxSize contentSize, // helper to convert row / col into child object id // error handling is not required here -static int GetChildId(wxGrid* grid, int row, int col, - bool isRowHeader, bool isColHeader) +static int GetChildId(wxGrid* grid, int row, int col) { int childId = 0; int numberCols = grid->GetNumberCols(); if ( grid->GetRowLabelSize() ) numberCols++; - if ( isColHeader && isRowHeader ) + if ( row == -1 && col == -1 ) childId = 1; - else if ( isColHeader ) + else if ( row == -1 ) { childId = col + 1; if ( grid->GetRowLabelSize() ) childId++; } - else if ( isRowHeader ) + else if ( col == -1 ) { childId = row * numberCols + 1; if ( grid->GetColLabelSize() ) @@ -11443,44 +11442,35 @@ static int GetChildId(wxGrid* grid, int row, int col, } // helper to calculate row, col, isRowHeader, isColHeader from childId -static void GetRowCol(wxGrid* grid, int childId, int* row, int* col, - bool* isRowHeader, bool* isColHeader) +wxGridCellCoords GetRowCol(wxGrid* grid, int childId) { - if ( childId == 1 && grid->GetColLabelSize() && grid->GetRowLabelSize() ) - { - *row = *col = -1; - *isRowHeader = true; - *isColHeader = true; - } - else + wxGridCellCoords coords; + + if ( childId != 1 || !grid->GetColLabelSize() || !grid->GetRowLabelSize() ) { - *isRowHeader = *isColHeader = false; int numCols = grid->GetNumberCols(); if ( grid->GetRowLabelSize() ) numCols++; - *row = (childId - 1) / numCols; - *col = (childId - 1) % numCols; + int row = (childId - 1) / numCols; + int col = (childId - 1) % numCols; if ( grid->GetRowLabelSize() ) { - if ( *col == 0 ) - { - *col = -1; - *isRowHeader = true; - } + if ( col == 0 ) + col = -1; else - (*col)--; + col--; } if ( grid->GetColLabelSize() ) { - if ( *row == 0 ) - { - *row = -1; - *isColHeader = true; - } + if ( row == 0 ) + row = -1; else - (*row)--; + row--; } + coords.SetCol(col); + coords.SetRow(row); } + return coords; } @@ -11593,7 +11583,12 @@ wxAccStatus wxGridAccessible::HitTest(const wxPoint& pt, int* childId, wxAccessi return wxACC_OK; } - *childId = GetChildId(grid, row, col, isRowHeader, isColHeader); + if ( isRowHeader ) + col = -1; + if ( isColHeader ) + row = -1; + + *childId = GetChildId(grid, row, col); return wxACC_OK; } @@ -11666,25 +11661,17 @@ wxAccStatus wxGridAccessible::GetChild(int childId, wxAccessible** child) { // pass on the information whether the cell is on the same row or // column than the previous one to avoid redundant coordinate info - int previousRow = m_gridCellAccessible->m_row; - int previousCol = m_gridCellAccessible->m_col; - int previousRowHeader = m_gridCellAccessible->m_isRowHeader; - int previousColHeader = m_gridCellAccessible->m_isColHeader; + wxGridCellCoords previous_coords = m_gridCellAccessible->m_coords; delete m_gridCellAccessible; m_gridCellAccessible = new wxGridCellAccessible(grid, childId); - if ( m_gridCellAccessible->m_row == previousRow && - m_gridCellAccessible->m_isColHeader == previousColHeader ) + if ( m_gridCellAccessible->m_coords.GetRow() == previous_coords.GetRow() ) { m_gridCellAccessible->m_isSameRow = true; - printf("same row\n"); } - if ( m_gridCellAccessible->m_col == previousCol && - m_gridCellAccessible->m_isRowHeader == previousRowHeader ) + if ( m_gridCellAccessible->m_coords.GetCol() == previous_coords.GetCol() ) { m_gridCellAccessible->m_isSameCol = true; - printf("same column\n"); } - } *child = m_gridCellAccessible; } @@ -11704,12 +11691,10 @@ wxAccStatus wxGridAccessible::GetRole(int childId, wxAccRole* role) else { // children can be cells or headers - int row, col; - bool isRowHeader, isColHeader; - GetRowCol(grid, childId, &row, &col, &isRowHeader, &isColHeader); - if ( isColHeader ) + wxGridCellCoords coords = GetRowCol(grid, childId); + if ( coords.GetRow() == -1 ) *role = wxROLE_SYSTEM_COLUMNHEADER; - else if ( isRowHeader ) + else if ( coords.GetCol() == -1 ) *role = wxROLE_SYSTEM_ROWHEADER; else *role = wxROLE_SYSTEM_CELL; @@ -11778,7 +11763,7 @@ wxAccStatus wxGridAccessible::GetFocus(int* childId, wxAccessible** child) else { *child = nullptr; - *childId = GetChildId(grid, coord.GetRow(), coord.GetCol(), false, false); + *childId = GetChildId(grid, coord.GetRow(), coord.GetCol() ); } } else @@ -11799,7 +11784,7 @@ wxGridCellAccessible::wxGridCellAccessible(wxGrid* grid, int childId) : wxAccessible(grid) { m_childId = childId; - GetRowCol(grid, childId, &m_row, &m_col, &m_isRowHeader, &m_isColHeader); + m_coords = GetRowCol(grid, childId); m_isSameRow = m_isSameCol = false; } @@ -11841,25 +11826,27 @@ void wxGridCellAccessible::DoGetLocation(wxGrid* grid, wxRect& rect) rect = grid->GetScreenRect(); wxPoint unscrolledPos = grid->CalcScrolledPosition(rect.GetLeftTop()); - if ( m_isColHeader ) + int row = m_coords.GetRow(); + if ( row == -1 ) { rect.height = grid->m_colLabelHeight; } else { - if ( m_row >= grid->m_numFrozenRows ) + if ( row >= grid->m_numFrozenRows ) rect.y = unscrolledPos.y; - rect.y = rect.y + grid->m_colLabelHeight + grid->GetRowTop(m_row); - rect.height = grid->GetRowHeight(m_row); + rect.y = rect.y + grid->m_colLabelHeight + grid->GetRowTop(row); + rect.height = grid->GetRowHeight(row); } - if ( m_isRowHeader ) + int col = m_coords.GetCol(); + if ( col == -1 ) rect.width = grid->m_rowLabelWidth; else { - if ( m_col >= grid->m_numFrozenCols ) + if ( col >= grid->m_numFrozenCols ) rect.x = unscrolledPos.x; - rect.x = rect.x + grid->m_rowLabelWidth + grid->GetColLeft(m_col); - rect.width = grid->GetColWidth(m_col); + rect.x = rect.x + grid->m_rowLabelWidth + grid->GetColLeft(col); + rect.width = grid->GetColWidth(col); } } @@ -11886,24 +11873,24 @@ wxAccStatus wxGridCellAccessible::GetName(int childId, wxString* name) return wxACC_FAIL; // combine coordinate info and value, as JAWS will not handle Name and Value - if ( m_isColHeader && m_isRowHeader ) + if ( !m_coords ) *name = _("Grid Corner"); - else if ( m_isColHeader ) - *name = wxString::Format(_("Column %s Header"), grid->GetColLabelValue(m_col)); - else if ( m_isRowHeader ) - *name = wxString::Format(_("Row %s Header"), grid->GetRowLabelValue(m_row)); + else if ( m_coords.GetRow() == -1 ) + *name = wxString::Format(_("Column %s Header"), grid->GetColLabelValue(m_coords.GetCol())); + else if ( m_coords.GetCol() == -1 ) + *name = wxString::Format(_("Row %s Header"), grid->GetRowLabelValue(m_coords.GetCol())); else if ( m_isSameRow ) *name = wxString::Format(_("Column %s: %s"), - grid->GetColLabelValue(m_col), - grid->GetCellValue(m_row, m_col)); + grid->GetColLabelValue(m_coords.GetCol()), + grid->GetCellValue(m_coords)); else if ( m_isSameCol ) *name = wxString::Format(_("Row %s: %s"), - grid->GetRowLabelValue(m_row), - grid->GetCellValue(m_row, m_col)); + grid->GetRowLabelValue(m_coords.GetRow()), + grid->GetCellValue(m_coords)); else *name = wxString::Format(_("Row %s, Column %s: %s"), - grid->GetRowLabelValue(m_row), grid->GetColLabelValue(m_col), - grid->GetCellValue(m_row, m_col)); + grid->GetRowLabelValue(m_coords.GetRow()), grid->GetColLabelValue(m_coords.GetCol()), + grid->GetCellValue(m_coords)); return wxACC_OK; } @@ -11933,9 +11920,9 @@ wxAccStatus wxGridCellAccessible::GetRole(int childId, wxAccRole* role) if ( childId != wxACC_SELF ) return wxACC_FAIL; - if ( m_isColHeader ) + if ( m_coords.GetRow() == -1 ) *role = wxROLE_SYSTEM_COLUMNHEADER; - else if ( m_isRowHeader ) + else if ( m_coords.GetCol() == -1 ) *role = wxROLE_SYSTEM_ROWHEADER; else *role = wxROLE_SYSTEM_CELL; @@ -11956,9 +11943,9 @@ wxAccStatus wxGridCellAccessible::GetState(int childId, long* state) if ( !grid->IsEnabled() ) st |= wxACC_STATE_SYSTEM_UNAVAILABLE; - if ( !m_isColHeader && !grid->IsRowShown(m_row) ) + if ( m_coords.GetRow() != -1 && !grid->IsRowShown(m_coords.GetRow()) ) st |= wxACC_STATE_SYSTEM_INVISIBLE; - else if ( !m_isRowHeader && !grid->IsColShown(m_col) ) + else if ( m_coords.GetCol() != -1 && !grid->IsColShown(m_coords.GetCol()) ) st |= wxACC_STATE_SYSTEM_INVISIBLE; if( grid->IsFocusable() ) @@ -11966,36 +11953,33 @@ wxAccStatus wxGridCellAccessible::GetState(int childId, long* state) st |= wxACC_STATE_SYSTEM_SELECTABLE; - const int cursorRow = grid->GetGridCursorRow(); - const int cursorCol = grid->GetGridCursorCol(); - - if ( !m_isColHeader && !m_isRowHeader && grid->HasFocus() && m_col==cursorCol && m_row==cursorRow) + if ( grid->HasFocus() && grid->GetGridCursorCoords() == m_coords ) st |= wxACC_STATE_SYSTEM_FOCUSED; // check selection and visibility - if ( m_isRowHeader && m_isColHeader ) + if ( !m_coords ) { // check whether complete grid is selected? } - else if ( m_isRowHeader ) + else if ( m_coords.GetCol() == -1 ) { wxArrayInt selectedRows = grid->GetSelectedRows(); - if ( selectedRows.Index(m_row) != wxNOT_FOUND ) + if ( selectedRows.Index(m_coords.GetRow()) != wxNOT_FOUND ) st |= wxACC_STATE_SYSTEM_SELECTED; } - else if ( m_isColHeader ) + else if ( m_coords.GetRow() == -1 ) { wxArrayInt selectedCols = grid->GetSelectedCols(); - if ( selectedCols.Index(m_col) != wxNOT_FOUND ) + if ( selectedCols.Index(m_coords.GetCol()) != wxNOT_FOUND ) st |= wxACC_STATE_SYSTEM_SELECTED; } else { - if ( grid->IsInSelection(m_row, m_col) ) + if ( grid->IsInSelection(m_coords) ) st |= wxACC_STATE_SYSTEM_SELECTED; - if ( grid->IsVisible(m_row, m_col, false) ) + if ( grid->IsVisible(m_coords, false) ) st |= wxACC_STATE_SYSTEM_OFFSCREEN; - if ( grid->IsReadOnly(m_row, m_col) ) + if ( grid->IsReadOnly(m_coords.GetRow(), m_coords.GetCol()) ) st |= wxACC_STATE_SYSTEM_READONLY; } @@ -12025,10 +12009,7 @@ wxAccStatus wxGridCellAccessible::GetFocus(int* childId, wxAccessible** child) *childId = wxACC_SELF; - const int cursorRow = grid->GetGridCursorRow(); - const int cursorCol = grid->GetGridCursorCol(); - - if ( !m_isColHeader && !m_isRowHeader && cursorRow == m_row && cursorCol == m_col ) + if ( grid->GetGridCursorCoords() == m_coords ) *child = this; return wxACC_OK; From 5ad258fc91d22032b7afbff4ee6fdd0c42f93f69 Mon Sep 17 00:00:00 2001 From: DietmarSchwertberger Date: Mon, 20 May 2024 14:59:44 +0200 Subject: [PATCH 11/19] cleanup after review --- src/generic/grid.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 97d9f57b755d..c3402829e03c 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -11903,8 +11903,6 @@ wxAccStatus wxGridCellAccessible::GetChildCount(int* childCount) } // Gets the specified child (starting from 1). -// If *child is nullptr and return value is wxACC_OK, this means that the child -// is a simple element and not an accessible object. wxAccStatus wxGridCellAccessible::GetChild(int childId, wxAccessible** child) { if (childId != wxACC_SELF) @@ -11988,7 +11986,7 @@ wxAccStatus wxGridCellAccessible::GetState(int childId, long* state) } // Returns a localized string representing the value for the object or child. -wxAccStatus wxGridCellAccessible::GetValue(int childId, wxString* strValue) +wxAccStatus wxGridCellAccessible::GetValue(int childId, wxString* WXUNUSED(strValue)) { wxGrid* grid = wxDynamicCast(GetWindow(), wxGrid); wxCHECK( grid, wxACC_FAIL ); From c0208b92f5a74f8332443f8277e714dea318f827 Mon Sep 17 00:00:00 2001 From: DietmarSchwertberger Date: Mon, 20 May 2024 15:05:30 +0200 Subject: [PATCH 12/19] fix bug for row header --- src/generic/grid.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index c3402829e03c..ac5d2a074ef3 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -11878,7 +11878,7 @@ wxAccStatus wxGridCellAccessible::GetName(int childId, wxString* name) else if ( m_coords.GetRow() == -1 ) *name = wxString::Format(_("Column %s Header"), grid->GetColLabelValue(m_coords.GetCol())); else if ( m_coords.GetCol() == -1 ) - *name = wxString::Format(_("Row %s Header"), grid->GetRowLabelValue(m_coords.GetCol())); + *name = wxString::Format(_("Row %s Header"), grid->GetRowLabelValue(m_coords.GetRow())); else if ( m_isSameRow ) *name = wxString::Format(_("Column %s: %s"), grid->GetColLabelValue(m_coords.GetCol()), From 60c735d42e384d495413fffaf5c988ba9623a061 Mon Sep 17 00:00:00 2001 From: DietmarSchwertberger Date: Mon, 20 May 2024 16:01:04 +0200 Subject: [PATCH 13/19] use std::unique_ptr for reference to wxGridCellAccessible --- include/wx/generic/private/grid.h | 2 +- src/generic/grid.cpp | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/include/wx/generic/private/grid.h b/include/wx/generic/private/grid.h index 85087ff2d1e6..f52cb5345ba7 100644 --- a/include/wx/generic/private/grid.h +++ b/include/wx/generic/private/grid.h @@ -1307,7 +1307,7 @@ class WXDLLIMPEXP_CORE wxGridAccessible : public wxWindowAccessible virtual wxAccStatus GetFocus(int* childId, wxAccessible** child) override; private: - wxGridCellAccessible* m_gridCellAccessible; + std::unique_ptr m_gridCellAccessible; }; class WXDLLIMPEXP_CORE wxGridCellAccessible : public wxAccessible diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index ac5d2a074ef3..ad961e889102 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -11488,8 +11488,7 @@ wxGridAccessible::~wxGridAccessible() { if ( m_gridCellAccessible ) { - delete m_gridCellAccessible; - m_gridCellAccessible = nullptr; + m_gridCellAccessible.reset(); } } @@ -11655,15 +11654,14 @@ wxAccStatus wxGridAccessible::GetChild(int childId, wxAccessible** child) { if ( !m_gridCellAccessible ) { - m_gridCellAccessible = new wxGridCellAccessible(grid, childId); + m_gridCellAccessible.reset( new wxGridCellAccessible(grid, childId) ); } else if ( m_gridCellAccessible->m_childId != childId ) { // pass on the information whether the cell is on the same row or // column than the previous one to avoid redundant coordinate info wxGridCellCoords previous_coords = m_gridCellAccessible->m_coords; - delete m_gridCellAccessible; - m_gridCellAccessible = new wxGridCellAccessible(grid, childId); + m_gridCellAccessible.reset( new wxGridCellAccessible(grid, childId) ); if ( m_gridCellAccessible->m_coords.GetRow() == previous_coords.GetRow() ) { m_gridCellAccessible->m_isSameRow = true; @@ -11673,7 +11671,7 @@ wxAccStatus wxGridAccessible::GetChild(int childId, wxAccessible** child) m_gridCellAccessible->m_isSameCol = true; } } - *child = m_gridCellAccessible; + *child = m_gridCellAccessible.get(); } return wxACC_OK; } From 61101da9984e018b62dc90015b1f63fcf99c14dd Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 20 May 2024 15:50:25 +0200 Subject: [PATCH 14/19] Some minor cleanup Remove some redundant initializations. Remove dtor which is not needed any more. Make the member variables that never change const. --- include/wx/generic/private/grid.h | 7 +++++-- src/generic/grid.cpp | 20 +++++--------------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/include/wx/generic/private/grid.h b/include/wx/generic/private/grid.h index f52cb5345ba7..629cffb5730e 100644 --- a/include/wx/generic/private/grid.h +++ b/include/wx/generic/private/grid.h @@ -1329,14 +1329,17 @@ class WXDLLIMPEXP_CORE wxGridCellAccessible : public wxAccessible virtual wxAccStatus GetFocus(int* childId, wxAccessible** child) override; private: - int m_childId; + const int m_childId; // row and / or col can be -1 for column or row header - wxGridCellCoords m_coords; + const wxGridCellCoords m_coords; + bool m_isSameRow = false; bool m_isSameCol = false; + friend class wxGridAccessible; void DoGetLocation(wxGrid* grid, wxRect& rect); }; + #endif // wxUSE_ACCESSIBILITY #endif // wxUSE_GRID diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index ad961e889102..4aab43060715 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -11481,15 +11481,6 @@ wxGridCellCoords GetRowCol(wxGrid* grid, int childId) wxGridAccessible::wxGridAccessible(wxGrid* win) : wxWindowAccessible(win) { - m_gridCellAccessible = nullptr; -} - -wxGridAccessible::~wxGridAccessible() -{ - if ( m_gridCellAccessible ) - { - m_gridCellAccessible.reset(); - } } // Can return either a child object, or an integer @@ -11654,14 +11645,14 @@ wxAccStatus wxGridAccessible::GetChild(int childId, wxAccessible** child) { if ( !m_gridCellAccessible ) { - m_gridCellAccessible.reset( new wxGridCellAccessible(grid, childId) ); + m_gridCellAccessible.reset(new wxGridCellAccessible(grid, childId)); } else if ( m_gridCellAccessible->m_childId != childId ) { // pass on the information whether the cell is on the same row or // column than the previous one to avoid redundant coordinate info wxGridCellCoords previous_coords = m_gridCellAccessible->m_coords; - m_gridCellAccessible.reset( new wxGridCellAccessible(grid, childId) ); + m_gridCellAccessible.reset(new wxGridCellAccessible(grid, childId)); if ( m_gridCellAccessible->m_coords.GetRow() == previous_coords.GetRow() ) { m_gridCellAccessible->m_isSameRow = true; @@ -11779,11 +11770,10 @@ wxAccStatus wxGridAccessible::GetFocus(int* childId, wxAccessible** child) //----------------------------------------------------------------------------- wxGridCellAccessible::wxGridCellAccessible(wxGrid* grid, int childId) - : wxAccessible(grid) + : wxAccessible(grid), + m_childId{childId}, + m_coords{GetRowCol(grid, childId)} { - m_childId = childId; - m_coords = GetRowCol(grid, childId); - m_isSameRow = m_isSameCol = false; } // Gets the parent From d73a7ee5468eec366d1135f08e223a6e5b2cca41 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 20 May 2024 15:59:21 +0200 Subject: [PATCH 15/19] Rename child id-related functions to have more symmetric names Also add some comments. --- src/generic/grid.cpp | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 4aab43060715..f9a180e23f99 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -11407,32 +11407,39 @@ wxGetContentRect(wxSize contentSize, // helpers for wxGridAccessible and wxGridCellAccessible //----------------------------------------------------------------------------- -// helper to convert row / col into child object id -// error handling is not required here -static int GetChildId(wxGrid* grid, int row, int col) +namespace +{ + +// Helper for converting between grid coordinates and child IDs. +// +// Child IDs are 1-based and are used to identify individual cells in the grid +// in the top-down, left-to-right order. + +// Return the child ID corresponding to the given grid cell coordinates. +int ConvertCoordsToChildId(wxGrid* grid, wxGridCellCoords coords) { int childId = 0; int numberCols = grid->GetNumberCols(); if ( grid->GetRowLabelSize() ) numberCols++; - if ( row == -1 && col == -1 ) + if ( !coords ) childId = 1; - else if ( row == -1 ) + else if ( coords.GetRow() == -1 ) { - childId = col + 1; + childId = coords.GetCol() + 1; if ( grid->GetRowLabelSize() ) childId++; } - else if ( col == -1 ) + else if ( coords.GetCol() == -1 ) { - childId = row * numberCols + 1; + childId = coords.GetRow() * numberCols + 1; if ( grid->GetColLabelSize() ) childId += numberCols; } else { - childId = row * numberCols + col + 1; + childId = coords.GetRow() * numberCols + coords.GetCol() + 1; if ( grid->GetColLabelSize() ) childId += numberCols; if ( grid->GetRowLabelSize() ) @@ -11441,8 +11448,9 @@ static int GetChildId(wxGrid* grid, int row, int col) return childId; } -// helper to calculate row, col, isRowHeader, isColHeader from childId -wxGridCellCoords GetRowCol(wxGrid* grid, int childId) +// Get coordinates corresponding to the given child ID (see the converse +// function above). +wxGridCellCoords ConvertChildIdToCoords(wxGrid* grid, int childId) { wxGridCellCoords coords; @@ -11470,9 +11478,11 @@ wxGridCellCoords GetRowCol(wxGrid* grid, int childId) coords.SetCol(col); coords.SetRow(row); } + return coords; } +} // anonymous namespace //----------------------------------------------------------------------------- // wxGridAccessible @@ -11578,7 +11588,7 @@ wxAccStatus wxGridAccessible::HitTest(const wxPoint& pt, int* childId, wxAccessi if ( isColHeader ) row = -1; - *childId = GetChildId(grid, row, col); + *childId = ConvertCoordsToChildId(grid, wxGridCellCoords(row, col)); return wxACC_OK; } @@ -11680,7 +11690,7 @@ wxAccStatus wxGridAccessible::GetRole(int childId, wxAccRole* role) else { // children can be cells or headers - wxGridCellCoords coords = GetRowCol(grid, childId); + wxGridCellCoords coords = ConvertChildIdToCoords(grid, childId); if ( coords.GetRow() == -1 ) *role = wxROLE_SYSTEM_COLUMNHEADER; else if ( coords.GetCol() == -1 ) @@ -11752,7 +11762,7 @@ wxAccStatus wxGridAccessible::GetFocus(int* childId, wxAccessible** child) else { *child = nullptr; - *childId = GetChildId(grid, coord.GetRow(), coord.GetCol() ); + *childId = ConvertCoordsToChildId(grid, coord); } } else @@ -11772,7 +11782,7 @@ wxAccStatus wxGridAccessible::GetFocus(int* childId, wxAccessible** child) wxGridCellAccessible::wxGridCellAccessible(wxGrid* grid, int childId) : wxAccessible(grid), m_childId{childId}, - m_coords{GetRowCol(grid, childId)} + m_coords{ConvertChildIdToCoords(grid, childId)} { } From 5d7e768c69089d11cb3e9b9ac3c92a95ea416411 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 20 May 2024 16:11:15 +0200 Subject: [PATCH 16/19] Remove leftover wxGridAccessible dtor declaration This should have been part of the grandparent commit. --- include/wx/generic/private/grid.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/wx/generic/private/grid.h b/include/wx/generic/private/grid.h index 629cffb5730e..3e560d8b5e94 100644 --- a/include/wx/generic/private/grid.h +++ b/include/wx/generic/private/grid.h @@ -1292,7 +1292,6 @@ class WXDLLIMPEXP_CORE wxGridAccessible : public wxWindowAccessible { public: explicit wxGridAccessible(wxGrid* win); - virtual ~wxGridAccessible(); virtual wxAccStatus HitTest(const wxPoint& pt, int* childId, wxAccessible** childObject) override; From cc3b3e311d68bde4da975677435e299a5142f1b8 Mon Sep 17 00:00:00 2001 From: DietmarSchwertberger Date: Mon, 20 May 2024 18:54:21 +0200 Subject: [PATCH 17/19] space removed --- src/generic/grid.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index f9a180e23f99..3e61c2a06cc9 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -11723,7 +11723,7 @@ wxAccStatus wxGridAccessible::GetState(int childId, long* state) // this needs to be returned such that a child below is recognized as focused // (check for cursorRow and cursorCol being != -1?) if ( grid->HasFocus() ) - st |= wxACC_STATE_SYSTEM_FOCUSED; + st |= wxACC_STATE_SYSTEM_FOCUSED; *state = st; return wxACC_OK; From 0a78a0381d0d63bb9e4bfe2645c43008b2fd8c0f Mon Sep 17 00:00:00 2001 From: DietmarSchwertberger Date: Mon, 20 May 2024 18:55:42 +0200 Subject: [PATCH 18/19] aovid unlikely case of division by zero --- src/generic/grid.cpp | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 3e61c2a06cc9..aadf79276a23 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -11459,24 +11459,27 @@ wxGridCellCoords ConvertChildIdToCoords(wxGrid* grid, int childId) int numCols = grid->GetNumberCols(); if ( grid->GetRowLabelSize() ) numCols++; - int row = (childId - 1) / numCols; - int col = (childId - 1) % numCols; - if ( grid->GetRowLabelSize() ) - { - if ( col == 0 ) - col = -1; - else - col--; - } - if ( grid->GetColLabelSize() ) - { - if ( row == 0 ) - row = -1; - else - row--; + if ( numCols ) { + // actually, numCols == 0 should not happen + int row = (childId - 1) / numCols; + int col = (childId - 1) % numCols; + if ( grid->GetRowLabelSize() ) + { + if ( col == 0 ) + col = -1; + else + col--; + } + if ( grid->GetColLabelSize() ) + { + if ( row == 0 ) + row = -1; + else + row--; + } + coords.SetCol(col); + coords.SetRow(row); } - coords.SetCol(col); - coords.SetRow(row); } return coords; From 14644c216df5c86dc23046eba251ea2d68629492 Mon Sep 17 00:00:00 2001 From: DietmarSchwertberger Date: Tue, 21 May 2024 20:05:28 +0200 Subject: [PATCH 19/19] insert check --- src/generic/grid.cpp | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index aadf79276a23..19be3fa88720 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -11459,27 +11459,25 @@ wxGridCellCoords ConvertChildIdToCoords(wxGrid* grid, int childId) int numCols = grid->GetNumberCols(); if ( grid->GetRowLabelSize() ) numCols++; - if ( numCols ) { - // actually, numCols == 0 should not happen - int row = (childId - 1) / numCols; - int col = (childId - 1) % numCols; - if ( grid->GetRowLabelSize() ) - { - if ( col == 0 ) - col = -1; - else - col--; - } - if ( grid->GetColLabelSize() ) - { - if ( row == 0 ) - row = -1; - else - row--; - } - coords.SetCol(col); - coords.SetRow(row); + wxCHECK_MSG(numCols, coords, "childId invalid for empty grid"); + int row = (childId - 1) / numCols; + int col = (childId - 1) % numCols; + if ( grid->GetRowLabelSize() ) + { + if ( col == 0 ) + col = -1; + else + col--; + } + if ( grid->GetColLabelSize() ) + { + if ( row == 0 ) + row = -1; + else + row--; } + coords.SetCol(col); + coords.SetRow(row); } return coords;