Bump version to 5.0-14
[LibreOffice.git] / svtools / source / table / tablecontrol.cxx
blob1b5ffdef5a32b2a129bbfc23130e963ad33f30d3
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 "table/tablecontrol.hxx"
22 #include "tablegeometry.hxx"
23 #include "tablecontrol_impl.hxx"
24 #include "tabledatawindow.hxx"
26 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
27 #include <com/sun/star/accessibility/AccessibleRole.hpp>
28 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
30 #include <tools/diagnose_ex.h>
31 #include <vcl/settings.hxx>
33 using namespace ::com::sun::star::uno;
34 using ::com::sun::star::accessibility::XAccessible;
35 using namespace ::com::sun::star::accessibility;
36 using namespace ::com::sun::star::lang;
37 using namespace utl;
39 namespace svt { namespace table
43 namespace AccessibleEventId = ::com::sun::star::accessibility::AccessibleEventId;
46 //= TableControl
49 TableControl::TableControl( vcl::Window* _pParent, WinBits _nStyle )
50 :Control( _pParent, _nStyle )
51 ,m_pImpl( new TableControl_Impl( *this ) )
53 TableDataWindow& rDataWindow = m_pImpl->getDataWindow();
54 rDataWindow.SetSelectHdl( LINK( this, TableControl, ImplSelectHdl ) );
56 // by default, use the background as determined by the style settings
57 const Color aWindowColor( GetSettings().GetStyleSettings().GetFieldColor() );
58 SetBackground( Wallpaper( aWindowColor ) );
59 SetFillColor( aWindowColor );
61 SetCompoundControl( true );
65 TableControl::~TableControl()
67 disposeOnce();
70 void TableControl::dispose()
72 CallEventListeners( VCLEVENT_OBJECT_DYING );
74 m_pImpl->setModel( PTableModel() );
75 m_pImpl->disposeAccessible();
76 m_pImpl.reset();
77 Control::dispose();
81 void TableControl::GetFocus()
83 if ( !m_pImpl || !m_pImpl->getInputHandler()->GetFocus( *m_pImpl ) )
84 Control::GetFocus();
88 void TableControl::LoseFocus()
90 if ( !m_pImpl || !m_pImpl->getInputHandler()->LoseFocus( *m_pImpl ) )
91 Control::LoseFocus();
95 void TableControl::KeyInput( const KeyEvent& rKEvt )
97 if ( !m_pImpl->getInputHandler()->KeyInput( *m_pImpl, rKEvt ) )
98 Control::KeyInput( rKEvt );
99 else
101 if ( m_pImpl->isAccessibleAlive() )
103 m_pImpl->commitCellEvent( AccessibleEventId::STATE_CHANGED,
104 makeAny( AccessibleStateType::FOCUSED ),
105 Any()
107 // Huh? What the heck? Why do we unconditionally notify a STATE_CHANGE/FOCUSED after each and every
108 // (handled) key stroke?
110 m_pImpl->commitTableEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
111 Any(),
112 Any()
114 // ditto: Why do we notify this unconditionally? We should find the right place to notify the
115 // ACTIVE_DESCENDANT_CHANGED event.
116 // Also, we should check if STATE_CHANGED/FOCUSED is really necessary: finally, the children are
117 // transient, aren't they?
124 void TableControl::StateChanged( StateChangedType i_nStateChange )
126 Control::StateChanged( i_nStateChange );
128 // forward certain settings to the data window
129 switch ( i_nStateChange )
131 case StateChangedType::ControlFocus:
132 m_pImpl->invalidateSelectedRows();
133 break;
135 case StateChangedType::ControlBackground:
136 if ( IsControlBackground() )
137 getDataWindow().SetControlBackground( GetControlBackground() );
138 else
139 getDataWindow().SetControlBackground();
140 break;
142 case StateChangedType::ControlForeground:
143 if ( IsControlForeground() )
144 getDataWindow().SetControlForeground( GetControlForeground() );
145 else
146 getDataWindow().SetControlForeground();
147 break;
149 case StateChangedType::ControlFont:
150 if ( IsControlFont() )
151 getDataWindow().SetControlFont( GetControlFont() );
152 else
153 getDataWindow().SetControlFont();
154 break;
155 default:;
160 void TableControl::Resize()
162 Control::Resize();
163 m_pImpl->onResize();
167 void TableControl::SetModel( PTableModel _pModel )
169 m_pImpl->setModel( _pModel );
173 PTableModel TableControl::GetModel() const
175 return m_pImpl->getModel();
179 sal_Int32 TableControl::GetCurrentRow() const
181 return m_pImpl->getCurrentRow();
185 sal_Int32 TableControl::GetCurrentColumn() const
187 return m_pImpl->getCurrentColumn();
191 bool TableControl::GoTo( ColPos _nColumn, RowPos _nRow )
193 return m_pImpl->goTo( _nColumn, _nRow );
197 bool TableControl::GoToCell(sal_Int32 _nColPos, sal_Int32 _nRowPos)
199 return m_pImpl->goTo( _nColPos, _nRowPos );
203 sal_Int32 TableControl::GetSelectedRowCount() const
205 return sal_Int32( m_pImpl->getSelectedRowCount() );
209 sal_Int32 TableControl::GetSelectedRowIndex( sal_Int32 const i_selectionIndex ) const
211 return sal_Int32( m_pImpl->getSelectedRowIndex( i_selectionIndex ) );
215 bool TableControl::IsRowSelected( sal_Int32 const i_rowIndex ) const
217 return m_pImpl->isRowSelected( i_rowIndex );
221 void TableControl::SelectRow( RowPos const i_rowIndex, bool const i_select )
223 ENSURE_OR_RETURN_VOID( ( i_rowIndex >= 0 ) && ( i_rowIndex < m_pImpl->getModel()->getRowCount() ),
224 "TableControl::SelectRow: invalid row index!" );
226 if ( i_select )
228 if ( !m_pImpl->markRowAsSelected( i_rowIndex ) )
229 // nothing to do
230 return;
232 else
234 m_pImpl->markRowAsDeselected( i_rowIndex );
237 m_pImpl->invalidateRowRange( i_rowIndex, i_rowIndex );
238 Select();
242 void TableControl::SelectAllRows( bool const i_select )
244 if ( i_select )
246 if ( !m_pImpl->markAllRowsAsSelected() )
247 // nothing to do
248 return;
250 else
252 if ( !m_pImpl->markAllRowsAsDeselected() )
253 // nothing to do
254 return;
258 Invalidate();
259 // TODO: can't we do better than this, and invalidate only the rows which changed?
260 Select();
264 ITableControl& TableControl::getTableControlInterface()
266 return *m_pImpl;
270 SelectionEngine* TableControl::getSelEngine()
272 return m_pImpl->getSelEngine();
276 vcl::Window& TableControl::getDataWindow()
278 return m_pImpl->getDataWindow();
282 Reference< XAccessible > TableControl::CreateAccessible()
284 vcl::Window* pParent = GetAccessibleParentWindow();
285 ENSURE_OR_RETURN( pParent, "TableControl::CreateAccessible - parent not found", NULL );
287 return m_pImpl->getAccessible( *pParent );
291 Reference<XAccessible> TableControl::CreateAccessibleControl( sal_Int32 _nIndex )
293 (void)_nIndex;
294 DBG_ASSERT( false, "TableControl::CreateAccessibleControl: to be overwritten!" );
295 return NULL;
299 OUString TableControl::GetAccessibleObjectName( AccessibleTableControlObjType eObjType, sal_Int32 _nRow, sal_Int32 _nCol) const
301 OUString aRetText;
302 //Window* pWin;
303 switch( eObjType )
305 case TCTYPE_GRIDCONTROL:
306 aRetText = "Grid control";
307 break;
308 case TCTYPE_TABLE:
309 aRetText = "Grid conrol";
310 break;
311 case TCTYPE_ROWHEADERBAR:
312 aRetText = "RowHeaderBar";
313 break;
314 case TCTYPE_COLUMNHEADERBAR:
315 aRetText = "ColumnHeaderBar";
316 break;
317 case TCTYPE_TABLECELL:
318 //the name of the cell constists of column name and row name if defined
319 //if the name is equal to cell content, it'll be read twice
320 if(GetModel()->hasColumnHeaders())
322 aRetText = GetColumnName(_nCol) + " , ";
324 if(GetModel()->hasRowHeaders())
326 aRetText += GetRowName(_nRow) + " , ";
328 //aRetText = GetAccessibleCellText(_nRow, _nCol);
329 break;
330 case TCTYPE_ROWHEADERCELL:
331 aRetText = GetRowName(_nRow);
332 break;
333 case TCTYPE_COLUMNHEADERCELL:
334 aRetText = GetColumnName(_nCol);
335 break;
336 default:
337 OSL_FAIL("GridControl::GetAccessibleName: invalid enum!");
339 return aRetText;
343 OUString TableControl::GetAccessibleObjectDescription( AccessibleTableControlObjType eObjType, sal_Int32 ) const
345 OUString aRetText;
346 switch( eObjType )
348 case TCTYPE_GRIDCONTROL:
349 aRetText = "Grid control description";
350 break;
351 case TCTYPE_TABLE:
352 aRetText = "TABLE description";
353 break;
354 case TCTYPE_ROWHEADERBAR:
355 aRetText = "ROWHEADERBAR description";
356 break;
357 case TCTYPE_COLUMNHEADERBAR:
358 aRetText = "COLUMNHEADERBAR description";
359 break;
360 case TCTYPE_TABLECELL:
361 // the description of the cell consists of column name and row name if defined
362 // if the name is equal to cell content, it'll be read twice
363 if ( GetModel()->hasColumnHeaders() )
365 aRetText = GetColumnName( GetCurrentColumn() ) + " , ";
367 if ( GetModel()->hasRowHeaders() )
369 aRetText += GetRowName( GetCurrentRow() );
371 break;
372 case TCTYPE_ROWHEADERCELL:
373 aRetText = "ROWHEADERCELL description";
374 break;
375 case TCTYPE_COLUMNHEADERCELL:
376 aRetText = "COLUMNHEADERCELL description";
377 break;
379 return aRetText;
383 OUString TableControl::GetRowDescription( sal_Int32 _nRow) const
385 (void)_nRow;
386 return OUString( "row description" );
390 OUString TableControl::GetRowName( sal_Int32 _nIndex) const
392 OUString sRowName;
393 GetModel()->getRowHeading( _nIndex ) >>= sRowName;
394 return sRowName;
398 OUString TableControl::GetColumnDescription( sal_uInt16 _nColumn) const
400 (void)_nColumn;
401 return OUString( "col description" );
405 OUString TableControl::GetColumnName( sal_Int32 _nIndex) const
407 return GetModel()->getColumnModel(_nIndex)->getName();
411 ::com::sun::star::uno::Any TableControl::GetCellContent( sal_Int32 _nRowPos, sal_Int32 _nColPos ) const
413 Any aCellContent;
414 GetModel()->getCellContent( _nColPos, _nRowPos, aCellContent );
415 return aCellContent;
419 OUString TableControl::GetAccessibleCellText( sal_Int32 _nRowPos, sal_Int32 _nColPos) const
421 return m_pImpl->getCellContentAsString( _nRowPos, _nColPos );
425 void TableControl::FillAccessibleStateSet(
426 ::utl::AccessibleStateSetHelper& rStateSet,
427 AccessibleTableControlObjType eObjType ) const
429 switch( eObjType )
431 case TCTYPE_GRIDCONTROL:
432 case TCTYPE_TABLE:
434 rStateSet.AddState( AccessibleStateType::FOCUSABLE );
436 if ( m_pImpl->getSelEngine()->GetSelectionMode() == MULTIPLE_SELECTION )
437 rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE);
439 if ( HasChildPathFocus() )
440 rStateSet.AddState( AccessibleStateType::FOCUSED );
442 if ( IsActive() )
443 rStateSet.AddState( AccessibleStateType::ACTIVE );
445 if ( m_pImpl->getDataWindow().IsEnabled() )
447 rStateSet.AddState( AccessibleStateType::ENABLED );
448 rStateSet.AddState( AccessibleStateType::SENSITIVE );
451 if ( IsReallyVisible() )
452 rStateSet.AddState( AccessibleStateType::VISIBLE );
454 if ( eObjType == TCTYPE_TABLE )
455 rStateSet.AddState( AccessibleStateType::MANAGES_DESCENDANTS );
456 break;
458 case TCTYPE_ROWHEADERBAR:
459 rStateSet.AddState( AccessibleStateType::VISIBLE );
460 rStateSet.AddState( AccessibleStateType::MANAGES_DESCENDANTS );
461 break;
463 case TCTYPE_COLUMNHEADERBAR:
464 rStateSet.AddState( AccessibleStateType::VISIBLE );
465 rStateSet.AddState( AccessibleStateType::MANAGES_DESCENDANTS );
466 break;
468 case TCTYPE_TABLECELL:
470 rStateSet.AddState( AccessibleStateType::FOCUSABLE );
471 if ( HasChildPathFocus() )
472 rStateSet.AddState( AccessibleStateType::FOCUSED );
473 rStateSet.AddState( AccessibleStateType::ACTIVE );
474 rStateSet.AddState( AccessibleStateType::TRANSIENT );
475 rStateSet.AddState( AccessibleStateType::SELECTABLE);
476 rStateSet.AddState( AccessibleStateType::VISIBLE );
477 rStateSet.AddState( AccessibleStateType::SHOWING );
478 if ( IsRowSelected( GetCurrentRow() ) )
479 // Hmm? Wouldn't we expect the affected row to be a parameter to this function?
480 rStateSet.AddState( AccessibleStateType::SELECTED );
482 break;
484 case TCTYPE_ROWHEADERCELL:
485 rStateSet.AddState( AccessibleStateType::VISIBLE );
486 rStateSet.AddState( AccessibleStateType::TRANSIENT );
487 break;
489 case TCTYPE_COLUMNHEADERCELL:
490 rStateSet.AddState( AccessibleStateType::VISIBLE );
491 break;
496 void TableControl::commitCellEventIfAccessibleAlive( sal_Int16 const i_eventID, const Any& i_newValue, const Any& i_oldValue )
498 if ( m_pImpl->isAccessibleAlive() )
499 m_pImpl->commitCellEvent( i_eventID, i_newValue, i_oldValue );
503 void TableControl::commitTableEventIfAccessibleAlive( sal_Int16 const i_eventID, const Any& i_newValue, const Any& i_oldValue )
505 if ( m_pImpl->isAccessibleAlive() )
506 m_pImpl->commitTableEvent( i_eventID, i_newValue, i_oldValue );
510 Rectangle TableControl::GetWindowExtentsRelative( vcl::Window *pRelativeWindow ) const
512 return Control::GetWindowExtentsRelative( pRelativeWindow );
516 void TableControl::GrabFocus()
518 Control::GrabFocus();
522 Reference< XAccessible > TableControl::GetAccessible( bool bCreate )
524 return Control::GetAccessible( bCreate );
528 vcl::Window* TableControl::GetAccessibleParentWindow() const
530 return Control::GetAccessibleParentWindow();
534 vcl::Window* TableControl::GetWindowInstance()
536 return this;
540 bool TableControl::HasRowHeader()
542 return GetModel()->hasRowHeaders();
546 bool TableControl::HasColHeader()
548 return GetModel()->hasColumnHeaders();
552 sal_Int32 TableControl::GetAccessibleControlCount() const
554 // TC_TABLE is always defined, no matter whether empty or not
555 sal_Int32 count = 1;
556 if ( GetModel()->hasRowHeaders() )
557 ++count;
558 if ( GetModel()->hasColumnHeaders() )
559 ++count;
560 return count;
564 bool TableControl::ConvertPointToControlIndex( sal_Int32& _rnIndex, const Point& _rPoint )
566 sal_Int32 nRow = m_pImpl->getRowAtPoint( _rPoint );
567 sal_Int32 nCol = m_pImpl->getColAtPoint( _rPoint );
568 _rnIndex = nRow * GetColumnCount() + nCol;
569 return nRow >= 0;
573 long TableControl::GetRowCount() const
575 return GetModel()->getRowCount();
579 long TableControl::GetColumnCount() const
581 return GetModel()->getColumnCount();
585 bool TableControl::HasRowHeader() const
587 return GetModel()->hasRowHeaders();
591 bool TableControl::ConvertPointToCellAddress( sal_Int32& _rnRow, sal_Int32& _rnColPos, const Point& _rPoint )
593 _rnRow = m_pImpl->getRowAtPoint( _rPoint );
594 _rnColPos = m_pImpl->getColAtPoint( _rPoint );
595 return _rnRow >= 0;
599 void TableControl::FillAccessibleStateSetForCell( ::utl::AccessibleStateSetHelper& _rStateSet, sal_Int32 _nRow, sal_uInt16 _nColumnPos ) const
601 if ( IsRowSelected( _nRow ) )
602 _rStateSet.AddState( AccessibleStateType::SELECTED );
603 if ( HasChildPathFocus() )
604 _rStateSet.AddState( AccessibleStateType::FOCUSED );
605 else // only transient when column is not focused
606 _rStateSet.AddState( AccessibleStateType::TRANSIENT );
608 _rStateSet.AddState( AccessibleStateType::VISIBLE );
609 _rStateSet.AddState( AccessibleStateType::SHOWING );
610 _rStateSet.AddState( AccessibleStateType::ENABLED );
611 _rStateSet.AddState( AccessibleStateType::SENSITIVE );
612 _rStateSet.AddState( AccessibleStateType::ACTIVE );
614 (void)_nColumnPos;
618 Rectangle TableControl::GetFieldCharacterBounds(sal_Int32 _nRow,sal_Int32 _nColumnPos,sal_Int32 nIndex)
620 (void)_nRow;
621 (void)_nColumnPos;
622 return GetCharacterBounds(nIndex);
626 sal_Int32 TableControl::GetFieldIndexAtPoint(sal_Int32 _nRow,sal_Int32 _nColumnPos,const Point& _rPoint)
628 (void)_nRow;
629 (void)_nColumnPos;
630 return GetIndexForPoint(_rPoint);
634 Rectangle TableControl::calcHeaderRect(bool _bIsColumnBar, bool _bOnScreen)
636 (void)_bOnScreen;
637 return m_pImpl->calcHeaderRect( !_bIsColumnBar );
641 Rectangle TableControl::calcHeaderCellRect( bool _bIsColumnBar, sal_Int32 nPos )
643 return m_pImpl->calcHeaderCellRect( _bIsColumnBar, nPos );
647 Rectangle TableControl::calcTableRect(bool _bOnScreen)
649 (void)_bOnScreen;
650 return m_pImpl->calcTableRect();
654 Rectangle TableControl::calcCellRect( sal_Int32 _nRowPos, sal_Int32 _nColPos )
656 return m_pImpl->calcCellRect( _nRowPos, _nColPos );
660 IMPL_LINK_NOARG(TableControl, ImplSelectHdl)
662 Select();
663 return 1;
667 void TableControl::Select()
669 ImplCallEventListenersAndHandler( VCLEVENT_TABLEROW_SELECT, m_pImpl->getSelectHandler(), this );
671 if ( m_pImpl->isAccessibleAlive() )
673 m_pImpl->commitAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() );
675 m_pImpl->commitTableEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, Any(), Any() );
676 // TODO: why do we notify this when the *selection* changed? Shouldn't we find a better place for this,
677 // actually, when the active descendant, i.e. the current cell, *really* changed?
681 }} // namespace svt::table
684 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */