tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / toolkit / source / controls / table / tablecontrol.cxx
blob7e609601722a1dab81dc65586c85e2ed2ceffd61
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <controls/table/tablecontrol.hxx>
22 #include "tablecontrol_impl.hxx"
23 #include "tabledatawindow.hxx"
25 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
26 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
28 #include <sal/log.hxx>
29 #include <comphelper/diagnose_ex.hxx>
30 #include <vcl/settings.hxx>
31 #include <vcl/vclevent.hxx>
33 using namespace ::com::sun::star::uno;
34 using ::com::sun::star::accessibility::XAccessible;
35 using namespace ::com::sun::star::accessibility;
37 namespace svt::table
41 namespace AccessibleEventId = ::com::sun::star::accessibility::AccessibleEventId;
44 //= TableControl
47 TableControl::TableControl( vcl::Window* _pParent, WinBits _nStyle )
48 :Control( _pParent, _nStyle )
49 ,m_pImpl( std::make_shared<TableControl_Impl>( *this ) )
51 TableDataWindow& rDataWindow = m_pImpl->getDataWindow();
52 rDataWindow.SetSelectHdl( LINK( this, TableControl, ImplSelectHdl ) );
54 // by default, use the background as determined by the style settings
55 const Color aWindowColor( GetSettings().GetStyleSettings().GetFieldColor() );
56 SetBackground( Wallpaper( aWindowColor ) );
57 GetOutDev()->SetFillColor( aWindowColor );
59 SetCompoundControl( true );
63 TableControl::~TableControl()
65 disposeOnce();
68 void TableControl::dispose()
70 CallEventListeners( VclEventId::ObjectDying );
72 m_pImpl->setModel( PTableModel() );
73 m_pImpl->disposeAccessible();
74 m_pImpl.reset();
75 Control::dispose();
79 void TableControl::GetFocus()
81 if ( !m_pImpl || !m_pImpl->getInputHandler()->GetFocus( *m_pImpl ) )
82 Control::GetFocus();
86 void TableControl::LoseFocus()
88 if ( !m_pImpl || !m_pImpl->getInputHandler()->LoseFocus( *m_pImpl ) )
89 Control::LoseFocus();
93 void TableControl::KeyInput( const KeyEvent& rKEvt )
95 if ( !m_pImpl->getInputHandler()->KeyInput( *m_pImpl, rKEvt ) )
96 Control::KeyInput( rKEvt );
97 else
99 if ( m_pImpl->isAccessibleAlive() )
101 m_pImpl->commitCellEvent( AccessibleEventId::STATE_CHANGED,
102 Any( AccessibleStateType::FOCUSED ),
103 Any()
105 // Huh? What the heck? Why do we unconditionally notify a STATE_CHANGE/FOCUSED after each and every
106 // (handled) key stroke?
108 m_pImpl->commitTableEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
109 Any(),
110 Any()
112 // ditto: Why do we notify this unconditionally? We should find the right place to notify the
113 // ACTIVE_DESCENDANT_CHANGED event.
114 // Also, we should check if STATE_CHANGED/FOCUSED is really necessary: finally, the children are
115 // transient, aren't they?
121 void TableControl::StateChanged( StateChangedType i_nStateChange )
123 Control::StateChanged( i_nStateChange );
125 // forward certain settings to the data window
126 switch ( i_nStateChange )
128 case StateChangedType::ControlFocus:
129 m_pImpl->invalidateSelectedRows();
130 break;
132 case StateChangedType::ControlBackground:
133 if ( IsControlBackground() )
134 getDataWindow().SetControlBackground( GetControlBackground() );
135 else
136 getDataWindow().SetControlBackground();
137 break;
139 case StateChangedType::ControlForeground:
140 if ( IsControlForeground() )
141 getDataWindow().SetControlForeground( GetControlForeground() );
142 else
143 getDataWindow().SetControlForeground();
144 break;
146 case StateChangedType::ControlFont:
147 if ( IsControlFont() )
148 getDataWindow().SetControlFont( GetControlFont() );
149 else
150 getDataWindow().SetControlFont();
151 break;
152 default:;
157 void TableControl::Resize()
159 Control::Resize();
160 m_pImpl->onResize();
164 void TableControl::SetModel( const PTableModel& _pModel )
166 m_pImpl->setModel( _pModel );
170 PTableModel TableControl::GetModel() const
172 return m_pImpl->getModel();
176 sal_Int32 TableControl::GetCurrentRow() const
178 return m_pImpl->getCurrentRow();
182 sal_Int32 TableControl::GetCurrentColumn() const
184 return m_pImpl->getCurrentColumn();
188 void TableControl::GoTo( ColPos _nColumn, RowPos _nRow )
190 m_pImpl->goTo( _nColumn, _nRow );
194 void TableControl::GoToCell(sal_Int32 _nColPos, sal_Int32 _nRowPos)
196 m_pImpl->goTo( _nColPos, _nRowPos );
200 sal_Int32 TableControl::GetSelectedRowCount() const
202 return sal_Int32( m_pImpl->getSelectedRowCount() );
206 sal_Int32 TableControl::GetSelectedRowIndex( sal_Int32 const i_selectionIndex ) const
208 return m_pImpl->getSelectedRowIndex( i_selectionIndex );
212 bool TableControl::IsRowSelected( sal_Int32 const i_rowIndex ) const
214 return m_pImpl->isRowSelected( i_rowIndex );
218 void TableControl::SelectRow( sal_Int32 const i_rowIndex, bool const i_select )
220 ENSURE_OR_RETURN_VOID( ( i_rowIndex >= 0 ) && ( i_rowIndex < m_pImpl->getModel()->getRowCount() ),
221 "TableControl::SelectRow: invalid row index!" );
223 if ( i_select )
225 if ( !m_pImpl->markRowAsSelected( i_rowIndex ) )
226 // nothing to do
227 return;
229 else
231 m_pImpl->markRowAsDeselected( i_rowIndex );
234 m_pImpl->invalidateRowRange( i_rowIndex, i_rowIndex );
235 Select();
239 void TableControl::SelectAllRows( bool const i_select )
241 if ( i_select )
243 if ( !m_pImpl->markAllRowsAsSelected() )
244 // nothing to do
245 return;
247 else
249 if ( !m_pImpl->markAllRowsAsDeselected() )
250 // nothing to do
251 return;
255 Invalidate();
256 // TODO: can't we do better than this, and invalidate only the rows which changed?
257 Select();
261 ITableControl& TableControl::getTableControlInterface()
263 return *m_pImpl;
267 SelectionEngine* TableControl::getSelEngine()
269 return m_pImpl->getSelEngine();
273 vcl::Window& TableControl::getDataWindow()
275 return m_pImpl->getDataWindow();
279 Reference< XAccessible > TableControl::CreateAccessible()
281 vcl::Window* pParent = GetAccessibleParentWindow();
282 ENSURE_OR_RETURN( pParent, "TableControl::CreateAccessible - parent not found", nullptr );
284 return m_pImpl->getAccessible( *pParent );
288 Reference<XAccessible> TableControl::CreateAccessibleControl( sal_Int32 )
290 SAL_WARN( "svtools", "TableControl::CreateAccessibleControl: to be overwritten!" );
291 return nullptr;
295 OUString TableControl::GetAccessibleObjectName( vcl::table::AccessibleTableControlObjType eObjType, sal_Int32 _nRow, sal_Int32 _nCol) const
297 OUString aRetText;
298 //Window* pWin;
299 switch( eObjType )
301 case vcl::table::AccessibleTableControlObjType::GRIDCONTROL:
302 aRetText = "Grid control";
303 break;
304 case vcl::table::AccessibleTableControlObjType::TABLE:
305 aRetText = "Grid control";
306 break;
307 case vcl::table::AccessibleTableControlObjType::ROWHEADERBAR:
308 aRetText = "RowHeaderBar";
309 break;
310 case vcl::table::AccessibleTableControlObjType::COLUMNHEADERBAR:
311 aRetText = "ColumnHeaderBar";
312 break;
313 case vcl::table::AccessibleTableControlObjType::TABLECELL:
314 //the name of the cell consists of column name and row name if defined
315 //if the name is equal to cell content, it'll be read twice
316 if(GetModel()->hasColumnHeaders())
318 aRetText = GetColumnName(_nCol) + " , ";
320 if(GetModel()->hasRowHeaders())
322 aRetText += GetRowName(_nRow) + " , ";
324 //aRetText = GetAccessibleCellText(_nRow, _nCol);
325 break;
326 case vcl::table::AccessibleTableControlObjType::ROWHEADERCELL:
327 aRetText = GetRowName(_nRow);
328 break;
329 case vcl::table::AccessibleTableControlObjType::COLUMNHEADERCELL:
330 aRetText = GetColumnName(_nCol);
331 break;
332 default:
333 OSL_FAIL("GridControl::GetAccessibleName: invalid enum!");
335 return aRetText;
339 OUString TableControl::GetAccessibleObjectDescription( vcl::table::AccessibleTableControlObjType eObjType ) const
341 OUString aRetText;
342 switch( eObjType )
344 case vcl::table::AccessibleTableControlObjType::GRIDCONTROL:
345 aRetText = "Grid control description";
346 break;
347 case vcl::table::AccessibleTableControlObjType::TABLE:
348 aRetText = "TABLE description";
349 break;
350 case vcl::table::AccessibleTableControlObjType::ROWHEADERBAR:
351 aRetText = "ROWHEADERBAR description";
352 break;
353 case vcl::table::AccessibleTableControlObjType::COLUMNHEADERBAR:
354 aRetText = "COLUMNHEADERBAR description";
355 break;
356 case vcl::table::AccessibleTableControlObjType::TABLECELL:
357 // the description of the cell consists of column name and row name if defined
358 // if the name is equal to cell content, it'll be read twice
359 if ( GetModel()->hasColumnHeaders() )
361 aRetText = GetColumnName( GetCurrentColumn() ) + " , ";
363 if ( GetModel()->hasRowHeaders() )
365 aRetText += GetRowName( GetCurrentRow() );
367 break;
368 case vcl::table::AccessibleTableControlObjType::ROWHEADERCELL:
369 aRetText = "ROWHEADERCELL description";
370 break;
371 case vcl::table::AccessibleTableControlObjType::COLUMNHEADERCELL:
372 aRetText = "COLUMNHEADERCELL description";
373 break;
375 return aRetText;
379 OUString TableControl::GetRowName( sal_Int32 _nIndex) const
381 OUString sRowName;
382 GetModel()->getRowHeading( _nIndex ) >>= sRowName;
383 return sRowName;
387 OUString TableControl::GetColumnName( sal_Int32 _nIndex) const
389 return GetModel()->getColumnModel(_nIndex)->getName();
393 OUString TableControl::GetAccessibleCellText( sal_Int32 _nRowPos, sal_Int32 _nColPos) const
395 return m_pImpl->getCellContentAsString( _nRowPos, _nColPos );
399 void TableControl::FillAccessibleStateSet(
400 sal_Int64& rStateSet,
401 vcl::table::AccessibleTableControlObjType eObjType ) const
403 switch( eObjType )
405 case vcl::table::AccessibleTableControlObjType::GRIDCONTROL:
406 case vcl::table::AccessibleTableControlObjType::TABLE:
408 rStateSet |= AccessibleStateType::FOCUSABLE;
410 if ( m_pImpl->getSelEngine()->GetSelectionMode() == SelectionMode::Multiple )
411 rStateSet |= AccessibleStateType::MULTI_SELECTABLE;
413 if ( HasChildPathFocus() )
414 rStateSet |= AccessibleStateType::FOCUSED;
416 if ( IsActive() )
417 rStateSet |= AccessibleStateType::ACTIVE;
419 if ( m_pImpl->getDataWindow().IsEnabled() )
421 rStateSet |= AccessibleStateType::ENABLED;
422 rStateSet |= AccessibleStateType::SENSITIVE;
425 if ( IsReallyVisible() )
426 rStateSet |= AccessibleStateType::VISIBLE;
428 if ( eObjType == vcl::table::AccessibleTableControlObjType::TABLE )
429 rStateSet |= AccessibleStateType::MANAGES_DESCENDANTS;
430 break;
432 case vcl::table::AccessibleTableControlObjType::ROWHEADERBAR:
433 rStateSet |= AccessibleStateType::VISIBLE;
434 rStateSet |= AccessibleStateType::MANAGES_DESCENDANTS;
435 break;
437 case vcl::table::AccessibleTableControlObjType::COLUMNHEADERBAR:
438 rStateSet |= AccessibleStateType::VISIBLE;
439 rStateSet |= AccessibleStateType::MANAGES_DESCENDANTS;
440 break;
442 case vcl::table::AccessibleTableControlObjType::TABLECELL:
444 rStateSet |= AccessibleStateType::FOCUSABLE;
445 if ( HasChildPathFocus() )
446 rStateSet |= AccessibleStateType::FOCUSED;
447 rStateSet |= AccessibleStateType::ACTIVE;
448 rStateSet |= AccessibleStateType::TRANSIENT;
449 rStateSet |= AccessibleStateType::SELECTABLE;
450 rStateSet |= AccessibleStateType::VISIBLE;
451 rStateSet |= AccessibleStateType::SHOWING;
452 if ( IsRowSelected( GetCurrentRow() ) )
453 // Hmm? Wouldn't we expect the affected row to be a parameter to this function?
454 rStateSet |= AccessibleStateType::SELECTED;
456 break;
458 case vcl::table::AccessibleTableControlObjType::ROWHEADERCELL:
459 rStateSet |= AccessibleStateType::VISIBLE;
460 rStateSet |= AccessibleStateType::TRANSIENT;
461 break;
463 case vcl::table::AccessibleTableControlObjType::COLUMNHEADERCELL:
464 rStateSet |= AccessibleStateType::VISIBLE;
465 break;
469 void TableControl::commitCellEventIfAccessibleAlive( sal_Int16 const i_eventID, const Any& i_newValue, const Any& i_oldValue )
471 if ( m_pImpl->isAccessibleAlive() )
472 m_pImpl->commitCellEvent( i_eventID, i_newValue, i_oldValue );
475 void TableControl::commitTableEventIfAccessibleAlive( sal_Int16 const i_eventID, const Any& i_newValue, const Any& i_oldValue )
477 if ( m_pImpl->isAccessibleAlive() )
478 m_pImpl->commitTableEvent( i_eventID, i_newValue, i_oldValue );
481 AbsoluteScreenPixelRectangle TableControl::GetWindowExtentsAbsolute() const
483 return Control::GetWindowExtentsAbsolute();
486 tools::Rectangle TableControl::GetWindowExtentsRelative(const vcl::Window& rRelativeWindow) const
488 return Control::GetWindowExtentsRelative( rRelativeWindow );
491 void TableControl::GrabFocus()
493 Control::GrabFocus();
496 Reference< XAccessible > TableControl::GetAccessible()
498 return Control::GetAccessible();
501 vcl::Window* TableControl::GetAccessibleParentWindow() const
503 return Control::GetAccessibleParentWindow();
506 vcl::Window* TableControl::GetWindowInstance()
508 return this;
512 bool TableControl::HasRowHeader()
514 return GetModel()->hasRowHeaders();
518 bool TableControl::HasColHeader()
520 return GetModel()->hasColumnHeaders();
524 sal_Int32 TableControl::GetAccessibleControlCount() const
526 // TC_TABLE is always defined, no matter whether empty or not
527 sal_Int32 count = 1;
528 if ( GetModel()->hasRowHeaders() )
529 ++count;
530 if ( GetModel()->hasColumnHeaders() )
531 ++count;
532 return count;
536 bool TableControl::ConvertPointToControlIndex( sal_Int32& _rnIndex, const Point& _rPoint )
538 sal_Int32 nRow = m_pImpl->getRowAtPoint( _rPoint );
539 sal_Int32 nCol = m_pImpl->getColAtPoint( _rPoint );
540 _rnIndex = nRow * GetColumnCount() + nCol;
541 return nRow >= 0;
545 sal_Int32 TableControl::GetRowCount() const
547 return GetModel()->getRowCount();
551 sal_Int32 TableControl::GetColumnCount() const
553 return GetModel()->getColumnCount();
557 bool TableControl::ConvertPointToCellAddress( sal_Int32& _rnRow, sal_Int32& _rnColPos, const Point& _rPoint )
559 _rnRow = m_pImpl->getRowAtPoint( _rPoint );
560 _rnColPos = m_pImpl->getColAtPoint( _rPoint );
561 return _rnRow >= 0;
565 void TableControl::FillAccessibleStateSetForCell( sal_Int64& _rStateSet, sal_Int32 _nRow, sal_uInt16 ) const
567 if ( IsRowSelected( _nRow ) )
568 _rStateSet |= AccessibleStateType::SELECTED;
569 if ( HasChildPathFocus() )
570 _rStateSet |= AccessibleStateType::FOCUSED;
571 else // only transient when column is not focused
572 _rStateSet |= AccessibleStateType::TRANSIENT;
574 _rStateSet |= AccessibleStateType::VISIBLE;
575 _rStateSet |= AccessibleStateType::SHOWING;
576 _rStateSet |= AccessibleStateType::ENABLED;
577 _rStateSet |= AccessibleStateType::SENSITIVE;
578 _rStateSet |= AccessibleStateType::ACTIVE;
582 tools::Rectangle TableControl::GetFieldCharacterBounds(sal_Int32,sal_Int32,sal_Int32 nIndex)
584 return GetCharacterBounds(nIndex);
588 sal_Int32 TableControl::GetFieldIndexAtPoint(sal_Int32,sal_Int32,const Point& _rPoint)
590 return GetIndexForPoint(_rPoint);
594 tools::Rectangle TableControl::calcHeaderRect(bool _bIsColumnBar )
596 return m_pImpl->calcHeaderRect( !_bIsColumnBar );
600 tools::Rectangle TableControl::calcHeaderCellRect( bool _bIsColumnBar, sal_Int32 nPos )
602 return m_pImpl->calcHeaderCellRect( _bIsColumnBar, nPos );
606 tools::Rectangle TableControl::calcTableRect()
608 return m_pImpl->calcTableRect();
612 tools::Rectangle TableControl::calcCellRect( sal_Int32 _nRowPos, sal_Int32 _nColPos )
614 return m_pImpl->calcCellRect( _nRowPos, _nColPos );
618 IMPL_LINK_NOARG(TableControl, ImplSelectHdl, LinkParamNone*, void)
620 Select();
624 void TableControl::Select()
626 ImplCallEventListenersAndHandler( VclEventId::TableRowSelect, nullptr );
628 if ( m_pImpl->isAccessibleAlive() )
630 m_pImpl->commitAccessibleEvent( AccessibleEventId::SELECTION_CHANGED );
632 m_pImpl->commitTableEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, Any(), Any() );
633 // TODO: why do we notify this when the *selection* changed? Shouldn't we find a better place for this,
634 // actually, when the active descendant, i.e. the current cell, *really* changed?
638 } // namespace svt::table
641 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */