toolkit/inc/controls/table/defaultinputhandler.hxx | 1 toolkit/inc/controls/table/tablecontrolinterface.hxx | 12 ---- toolkit/source/controls/svtxgridcontrol.cxx | 4 - toolkit/source/controls/table/defaultinputhandler.cxx | 45 ------------------ toolkit/source/controls/table/tablecontrol.cxx | 43 ++++++++++++++++- toolkit/source/controls/table/tablecontrol_impl.hxx | 14 +++++ 6 files changed, 57 insertions(+), 62 deletions(-)
New commits: commit 6fc13fb03bc96eda65b91fd65ada26a162437404 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Thu Jan 23 15:01:15 2025 +0100 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Fri Jan 24 07:37:51 2025 +0100 toolkit: Move TableControl key input logic into that class Move logic from DefaultInputHandler::KeyInput into the only caller, TableControl::KeyInput. Drop ITableControl::dispatchAction from that interface as TableControl is now the only caller and that one knows that it's TableControl::m_pImpl is a TableControl_Impl. Change-Id: I0445ce10f8abee17ab6e4895aba5adf42974721b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/180662 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/toolkit/inc/controls/table/defaultinputhandler.hxx b/toolkit/inc/controls/table/defaultinputhandler.hxx index 51610b4b5d2d..40acc4a7a809 100644 --- a/toolkit/inc/controls/table/defaultinputhandler.hxx +++ b/toolkit/inc/controls/table/defaultinputhandler.hxx @@ -44,7 +44,6 @@ namespace svt::table bool MouseMove(ITableControl& _rControl, const MouseEvent& rMEvt); bool MouseButtonDown(ITableControl& _rControl, const MouseEvent& rMEvt); bool MouseButtonUp(ITableControl& _rControl, const MouseEvent& rMEvt); - static bool KeyInput(ITableControl& _rControl, const KeyEvent& rKEvt); private: bool delegateMouseEvent( ITableControl& i_control, const MouseEvent& i_event, diff --git a/toolkit/inc/controls/table/tablecontrolinterface.hxx b/toolkit/inc/controls/table/tablecontrolinterface.hxx index ee9a52785471..e5ff0cd88303 100644 --- a/toolkit/inc/controls/table/tablecontrolinterface.hxx +++ b/toolkit/inc/controls/table/tablecontrolinterface.hxx @@ -163,18 +163,6 @@ namespace svt::table */ virtual void showCursor() = 0; - /** dispatches an action to the table control - - @return - <TRUE/> if the action could be dispatched successfully, <FALSE/> otherwise. Usual - failure conditions include some other instance vetoing the action, or impossibility - to execute the action at all (for instance moving up one row when already positioned - on the very first row). - - @see TableControlAction - */ - virtual bool dispatchAction( TableControlAction _eAction ) = 0; - /** returns selection engine*/ virtual SelectionEngine* getSelEngine() = 0; diff --git a/toolkit/source/controls/table/defaultinputhandler.cxx b/toolkit/source/controls/table/defaultinputhandler.cxx index ef6e250547f8..ba00f0bb9384 100644 --- a/toolkit/source/controls/table/defaultinputhandler.cxx +++ b/toolkit/source/controls/table/defaultinputhandler.cxx @@ -114,51 +114,6 @@ namespace svt::table return delegateMouseEvent( i_tableControl, i_event, &MouseFunction::handleMouseUp ); } - - bool DefaultInputHandler::KeyInput( ITableControl& _rControl, const KeyEvent& rKEvt ) - { - bool bHandled = false; - - const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode(); - sal_uInt16 nKeyCode = rKeyCode.GetCode(); - - struct ActionMapEntry - { - sal_uInt16 nKeyCode; - sal_uInt16 nKeyModifier; - TableControlAction eAction; - } - static const aKnownActions[] = { - { KEY_DOWN, 0, TableControlAction::cursorDown }, - { KEY_UP, 0, TableControlAction::cursorUp }, - { KEY_LEFT, 0, TableControlAction::cursorLeft }, - { KEY_RIGHT, 0, TableControlAction::cursorRight }, - { KEY_HOME, 0, TableControlAction::cursorToLineStart }, - { KEY_END, 0, TableControlAction::cursorToLineEnd }, - { KEY_PAGEUP, 0, TableControlAction::cursorPageUp }, - { KEY_PAGEDOWN, 0, TableControlAction::cursorPageDown }, - { KEY_PAGEUP, KEY_MOD1, TableControlAction::cursorToFirstLine }, - { KEY_PAGEDOWN, KEY_MOD1, TableControlAction::cursorToLastLine }, - { KEY_HOME, KEY_MOD1, TableControlAction::cursorTopLeft }, - { KEY_END, KEY_MOD1, TableControlAction::cursorBottomRight }, - { KEY_SPACE, KEY_MOD1, TableControlAction::cursorSelectRow }, - { KEY_UP, KEY_SHIFT, TableControlAction::cursorSelectRowUp }, - { KEY_DOWN, KEY_SHIFT, TableControlAction::cursorSelectRowDown }, - { KEY_END, KEY_SHIFT, TableControlAction::cursorSelectRowAreaBottom }, - { KEY_HOME, KEY_SHIFT, TableControlAction::cursorSelectRowAreaTop } - }; - for (const ActionMapEntry& rAction : aKnownActions) - { - if ( ( rAction.nKeyCode == nKeyCode ) && ( rAction.nKeyModifier == rKeyCode.GetModifier() ) ) - { - bHandled = _rControl.dispatchAction( rAction.eAction ); - break; - } - } - - return bHandled; - } - } // namespace svt::table diff --git a/toolkit/source/controls/table/tablecontrol.cxx b/toolkit/source/controls/table/tablecontrol.cxx index bde7d9788126..c5b5ef1c6b78 100644 --- a/toolkit/source/controls/table/tablecontrol.cxx +++ b/toolkit/source/controls/table/tablecontrol.cxx @@ -96,7 +96,48 @@ namespace svt::table void TableControl::KeyInput( const KeyEvent& rKEvt ) { - if (!m_pImpl || !DefaultInputHandler::KeyInput(*m_pImpl, rKEvt)) + bool bHandled = false; + if (m_pImpl) + { + const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode(); + sal_uInt16 nKeyCode = rKeyCode.GetCode(); + + struct ActionMapEntry + { + sal_uInt16 nKeyCode; + sal_uInt16 nKeyModifier; + TableControlAction eAction; + } + static const aKnownActions[] = { + { KEY_DOWN, 0, TableControlAction::cursorDown }, + { KEY_UP, 0, TableControlAction::cursorUp }, + { KEY_LEFT, 0, TableControlAction::cursorLeft }, + { KEY_RIGHT, 0, TableControlAction::cursorRight }, + { KEY_HOME, 0, TableControlAction::cursorToLineStart }, + { KEY_END, 0, TableControlAction::cursorToLineEnd }, + { KEY_PAGEUP, 0, TableControlAction::cursorPageUp }, + { KEY_PAGEDOWN, 0, TableControlAction::cursorPageDown }, + { KEY_PAGEUP, KEY_MOD1, TableControlAction::cursorToFirstLine }, + { KEY_PAGEDOWN, KEY_MOD1, TableControlAction::cursorToLastLine }, + { KEY_HOME, KEY_MOD1, TableControlAction::cursorTopLeft }, + { KEY_END, KEY_MOD1, TableControlAction::cursorBottomRight }, + { KEY_SPACE, KEY_MOD1, TableControlAction::cursorSelectRow }, + { KEY_UP, KEY_SHIFT, TableControlAction::cursorSelectRowUp }, + { KEY_DOWN, KEY_SHIFT, TableControlAction::cursorSelectRowDown }, + { KEY_END, KEY_SHIFT, TableControlAction::cursorSelectRowAreaBottom }, + { KEY_HOME, KEY_SHIFT, TableControlAction::cursorSelectRowAreaTop } + }; + for (const ActionMapEntry& rAction : aKnownActions) + { + if ((rAction.nKeyCode == nKeyCode) && (rAction.nKeyModifier == rKeyCode.GetModifier())) + { + bHandled = m_pImpl->dispatchAction(rAction.eAction); + break; + } + } + } + + if (!bHandled) Control::KeyInput( rKEvt ); else { diff --git a/toolkit/source/controls/table/tablecontrol_impl.hxx b/toolkit/source/controls/table/tablecontrol_impl.hxx index db17ef85fdfe..a2fc6ec873d7 100644 --- a/toolkit/source/controls/table/tablecontrol_impl.hxx +++ b/toolkit/source/controls/table/tablecontrol_impl.hxx @@ -244,7 +244,19 @@ namespace svt::table // ITableControl virtual void hideCursor() override; virtual void showCursor() override; - virtual bool dispatchAction( TableControlAction _eAction ) override; + + /** dispatches an action to the table control + + @return + <TRUE/> if the action could be dispatched successfully, <FALSE/> otherwise. Usual + failure conditions include some other instance vetoing the action, or impossibility + to execute the action at all (for instance moving up one row when already positioned + on the very first row). + + @see TableControlAction + */ + virtual bool dispatchAction(TableControlAction _eAction); + virtual SelectionEngine* getSelEngine() override; virtual PTableModel getModel() const override; virtual ColPos getCurrentColumn() const override; commit 57906dde339a71eee87437ae2d11c7474c03befd Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Thu Jan 23 14:37:07 2025 +0100 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Fri Jan 24 07:37:43 2025 +0100 tdf#164783 toolkit a11y: Only send event for current cell if there's one TableControl::commitCellEventIfAccessibleAlive sends an event on the currently selected/active cell. So only call it in SVTXGridControl::ProcessWindowEvent when there is one. Use TableControl::GetCurrentRow and TableControl::GetCurrentColumn to check that, which return a special value (of -2) for the case there is no active cell. For TableControl::GetCurrentRow: /** retrieves the current row The current row is the one which contains the active cell. @return the row index of the active cell, or ->ROW_INVALID if there is no active cell, e.g. because the table does not contain any rows or columns. */ sal_Int32 GetCurrentRow() const override; The previous check whether the table has any rows was insufficient and resulted in an invalid attempt to access vector elements at negative indices. For the tdf#164783 scenario: /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/debug/vector:508: In function: reference std::vector<rtl::Reference<accessibility::AccessibleGridControlTableCell>>::operator[](size_type) [_Tp = rtl::Reference<accessibility::AccessibleGridControlTableCell>, _Allocator = std::allocator<rtl::Reference<accessibility::AccessibleGridControlTableCell>>] Error: attempt to subscript container with out-of-bounds index -6, but container only holds 60 elements. Objects involved in the operation: sequence "this" @ 0x5638c74e2350 { type = std::debug::vector<rtl::Reference<accessibility::AccessibleGridControlTableCell>, std::allocator<rtl::Reference<accessibility::AccessibleGridControlTableCell> > >; } /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/debug/vector:508: In function: reference std::vector<rtl::Reference<accessibility::AccessibleGridControlTableCell>>::operator[](size_type) [_Tp = rtl::Reference<accessibility::AccessibleGridControlTableCell>, _Allocator = std::allocator<rtl::Reference<accessibility::AccessibleGridControlTableCell>>] Error: attempt to subscript container with out-of-bounds index -6, but container only holds 60 elements. Objects involved in the operation: sequence "this" @ 0x5638c74e2350 { type = std::debug::vector<rtl::Reference<accessibility::AccessibleGridControlTableCell>, std::allocator<rtl::Reference<accessibility::AccessibleGridControlTableCell> > >; } sequence "this" @ 0x5638c74e2350 { type = std::debug::vector<rtl::Reference<accessibility::AccessibleGridControlTableCell>, std::allocator<rtl::Reference<accessibility::AccessibleGridControlTableCell> > >; } Fatal exception: Signal 6 Stack: #0 sal::backtrace_get(unsigned int) at .../libreoffice/sal/osl/unx/backtraceapi.cxx:42 #1 (anonymous namespace)::printStack(int) at .../libreoffice/sal/osl/unx/signal.cxx:289 #2 (anonymous namespace)::callSystemHandler(int, siginfo_t*, void*) at .../libreoffice/sal/osl/unx/signal.cxx:330 #3 (anonymous namespace)::signalHandlerFunction(int, siginfo_t*, void*) at .../libreoffice/sal/osl/unx/signal.cxx:427 #4 /lib/x86_64-linux-gnu/libc.so.6(+0x3fda0) [0x7f7544649da0] #5 __pthread_kill_implementation at ./nptl/pthread_kill.c:44 (discriminator 1) #6 raise at ./signal/../sysdeps/posix/raise.c:27 #7 abort at ./stdlib/abort.c:81 #8 std::__throw_bad_exception() in /lib/x86_64-linux-gnu/libstdc++.so.6 #9 std::__debug::vector<rtl::Reference<accessibility::AccessibleGridControlTableCell>, std::allocator<rtl::Reference<accessibility::AccessibleGridControlTableCell>>>::operator[](unsigned long) at /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/debug/vector:508 #10 accessibility::AccessibleGridControlTable::getAccessibleChild(long) at .../libreoffice/vcl/source/accessibility/AccessibleGridControlTable.cxx:66 #11 accessibility::AccessibleGridControlTable::getAccessibleCellAt(int, int) at .../libreoffice/vcl/source/accessibility/AccessibleGridControlTable.cxx:191 #12 accessibility::AccessibleGridControl::commitCellEvent(short, com::sun::star::uno::Any const&, com::sun::star::uno::Any const&) at .../libreoffice/vcl/source/accessibility/AccessibleGridControl.cxx:272 #13 accessibility::AccessibleGridControlAccess::commitCellEvent(short, com::sun::star::uno::Any const&, com::sun::star::uno::Any const&) at .../libreoffice/vcl/inc/accessibility/AccessibleGridControl.hxx:197 #14 svt::table::TableControl_Impl::commitCellEvent(short, com::sun::star::uno::Any const&, com::sun::star::uno::Any const&) at .../libreoffice/toolkit/source/controls/table/tablecontrol_impl.cxx:2304 #15 svt::table::TableControl::commitCellEventIfAccessibleAlive(short, com::sun::star::uno::Any const&, com::sun::star::uno::Any const&) at .../libreoffice/toolkit/source/controls/table/tablecontrol.cxx:470 #16 SVTXGridControl::ProcessWindowEvent(VclWindowEvent const&) at .../libreoffice/toolkit/source/controls/svtxgridcontrol.cxx:823 #17 VCLXWindow::WindowEventListener(VclWindowEvent&) at .../libreoffice/toolkit/source/awt/vclxwindow.cxx:390 #18 VCLXWindow::LinkStubWindowEventListener(void*, VclWindowEvent&) at .../libreoffice/toolkit/source/awt/vclxwindow.cxx:383 #19 Link<VclWindowEvent&, void>::Call(VclWindowEvent&) const at .../libreoffice/include/tools/link.hxx:101 #20 vcl::Window::CallEventListeners(VclEventId, void*) at .../libreoffice/vcl/source/window/event.cxx:262 #21 Control::CallEventListeners(VclEventId, void*) at .../libreoffice/vcl/source/control/ctrl.cxx:298 #22 Control::ImplCallEventListenersAndHandler(VclEventId, std::function<void ()> const&) at .../libreoffice/vcl/source/control/ctrl.cxx:305 #23 Control::EventNotify(NotifyEvent&) at .../libreoffice/vcl/source/control/ctrl.cxx:247 #24 vcl::Window::CompatNotify(NotifyEvent&) at .../libreoffice/vcl/source/window/window.cxx:3943 #25 vcl::Window::LoseFocus() at .../libreoffice/vcl/source/window/window.cxx:1861 #26 svt::table::TableControl::LoseFocus() at .../libreoffice/toolkit/source/controls/table/tablecontrol.cxx:94 #27 vcl::Window::CompatLoseFocus() at .../libreoffice/vcl/source/window/window.cxx:3912 #28 vcl::Window::ImplAsyncFocusHdl(void*) at .../libreoffice/vcl/source/window/winproc.cxx:2127 #29 vcl::Window::LinkStubImplAsyncFocusHdl(void*, void*) at .../libreoffice/vcl/source/window/winproc.cxx:2033 #30 Link<void*, void>::Call(void*) const at .../libreoffice/include/tools/link.hxx:101 #31 ImplHandleUserEvent(ImplSVEvent*) at .../libreoffice/vcl/source/window/winproc.cxx:2288 #32 ImplWindowFrameProc(vcl::Window*, SalEvent, void const*) at .../libreoffice/vcl/source/window/winproc.cxx:2849 #33 SalFrame::CallCallback(SalEvent, void const*) const at .../libreoffice/vcl/inc/salframe.hxx:311 #34 SalGenericDisplay::ProcessEvent(SalUserEventList::SalUserEvent) at .../libreoffice/vcl/unx/generic/app/gendisp.cxx:67 #35 SalUserEventList::DispatchUserEvents(bool)::$_0::operator()() const at .../libreoffice/vcl/source/app/salusereventlist.cxx:119 #36 SalUserEventList::DispatchUserEvents(bool) at .../libreoffice/vcl/source/app/salusereventlist.cxx:120 #37 SalGenericDisplay::DispatchInternalEvent(bool) at .../libreoffice/vcl/unx/generic/app/gendisp.cxx:51 #38 call_userEventFn(void*) at .../libreoffice/vcl/unx/gtk3/gtkdata.cxx:827 #39 /lib/x86_64-linux-gnu/libglib-2.0.so.0(+0x5a81f) [0x7f7536f0b81f] #40 /lib/x86_64-linux-gnu/libglib-2.0.so.0(+0x5ca57) [0x7f7536f0da57] #41 g_main_loop_run in /lib/x86_64-linux-gnu/libglib-2.0.so.0 ... Change-Id: Iafed90e6985cf2c05d65be5f74334f58b369d945 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/180661 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/toolkit/source/controls/svtxgridcontrol.cxx b/toolkit/source/controls/svtxgridcontrol.cxx index 6cd34bef8bca..74036177d8ab 100644 --- a/toolkit/source/controls/svtxgridcontrol.cxx +++ b/toolkit/source/controls/svtxgridcontrol.cxx @@ -790,7 +790,7 @@ void SVTXGridControl::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent { // TODO: this doesn't belong here. It belongs into the TableControl/_Impl, so A11Y also // works when the control is used outside the UNO context - if ( pTable->GetRowCount()>0 ) + if (pTable->GetCurrentRow() != ROW_INVALID && pTable->GetCurrentColumn() != COL_INVALID) { pTable->commitCellEventIfAccessibleAlive( AccessibleEventId::STATE_CHANGED, @@ -818,7 +818,7 @@ void SVTXGridControl::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent { // TODO: this doesn't belong here. It belongs into the TableControl/_Impl, so A11Y also // works when the control is used outside the UNO context - if ( pTable->GetRowCount()>0 ) + if (pTable->GetCurrentRow() != ROW_INVALID && pTable->GetCurrentColumn() != COL_INVALID) { pTable->commitCellEventIfAccessibleAlive( AccessibleEventId::STATE_CHANGED,