1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 "svtools/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>
32 using namespace ::com::sun::star::uno
;
33 using ::com::sun::star::accessibility::XAccessible
;
34 using namespace ::com::sun::star::accessibility
;
35 using namespace ::com::sun::star::lang
;
37 //......................................................................................................................
38 namespace svt
{ namespace table
40 //......................................................................................................................
42 namespace AccessibleEventId
= ::com::sun::star::accessibility::AccessibleEventId
;
44 //==================================================================================================================
46 //==================================================================================================================
47 // -----------------------------------------------------------------------------------------------------------------
48 TableControl::TableControl( Window
* _pParent
, WinBits _nStyle
)
49 :Control( _pParent
, _nStyle
)
50 ,m_pImpl( new TableControl_Impl( *this ) )
52 TableDataWindow
& rDataWindow
= m_pImpl
->getDataWindow();
53 rDataWindow
.SetSelectHdl( LINK( this, TableControl
, ImplSelectHdl
) );
55 // by default, use the background as determined by the style settings
56 const Color
aWindowColor( GetSettings().GetStyleSettings().GetFieldColor() );
57 SetBackground( Wallpaper( aWindowColor
) );
58 SetFillColor( aWindowColor
);
60 SetCompoundControl( true );
63 // -----------------------------------------------------------------------------------------------------------------
64 TableControl::~TableControl()
66 ImplCallEventListeners( VCLEVENT_OBJECT_DYING
);
68 m_pImpl
->setModel( PTableModel() );
69 m_pImpl
->disposeAccessible();
73 // -----------------------------------------------------------------------------------------------------------------
74 void TableControl::GetFocus()
76 if ( !m_pImpl
->getInputHandler()->GetFocus( *m_pImpl
) )
80 // -----------------------------------------------------------------------------------------------------------------
81 void TableControl::LoseFocus()
83 if ( !m_pImpl
->getInputHandler()->LoseFocus( *m_pImpl
) )
87 // -----------------------------------------------------------------------------------------------------------------
88 void TableControl::KeyInput( const KeyEvent
& rKEvt
)
90 if ( !m_pImpl
->getInputHandler()->KeyInput( *m_pImpl
, rKEvt
) )
91 Control::KeyInput( rKEvt
);
94 if ( m_pImpl
->isAccessibleAlive() )
96 m_pImpl
->commitCellEvent( AccessibleEventId::STATE_CHANGED
,
97 makeAny( AccessibleStateType::FOCUSED
),
100 // Huh? What the heck? Why do we unconditionally notify a STATE_CHANGE/FOCUSED after each and every
101 // (handled) key stroke?
103 m_pImpl
->commitTableEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED
,
107 // ditto: Why do we notify this unconditionally? We should find the right place to notify the
108 // ACTIVE_DESCENDANT_CHANGED event.
109 // Also, we should check if STATE_CHANGED/FOCUSED is really necessary: finally, the children are
110 // transient, aren't they?
116 // -----------------------------------------------------------------------------------------------------------------
117 void TableControl::StateChanged( StateChangedType i_nStateChange
)
119 Control::StateChanged( i_nStateChange
);
121 // forward certain settings to the data window
122 switch ( i_nStateChange
)
124 case STATE_CHANGE_CONTROL_FOCUS
:
125 m_pImpl
->invalidateSelectedRows();
128 case STATE_CHANGE_CONTROLBACKGROUND
:
129 if ( IsControlBackground() )
130 getDataWindow().SetControlBackground( GetControlBackground() );
132 getDataWindow().SetControlBackground();
135 case STATE_CHANGE_CONTROLFOREGROUND
:
136 if ( IsControlForeground() )
137 getDataWindow().SetControlForeground( GetControlForeground() );
139 getDataWindow().SetControlForeground();
142 case STATE_CHANGE_CONTROLFONT
:
143 if ( IsControlFont() )
144 getDataWindow().SetControlFont( GetControlFont() );
146 getDataWindow().SetControlFont();
151 // -----------------------------------------------------------------------------------------------------------------
152 void TableControl::Resize()
158 // -----------------------------------------------------------------------------------------------------------------
159 void TableControl::SetModel( PTableModel _pModel
)
161 m_pImpl
->setModel( _pModel
);
164 // -----------------------------------------------------------------------------------------------------------------
165 PTableModel
TableControl::GetModel() const
167 return m_pImpl
->getModel();
170 // -----------------------------------------------------------------------------------------------------------------
171 sal_Int32
TableControl::GetCurrentRow() const
173 return m_pImpl
->getCurrentRow();
176 // -----------------------------------------------------------------------------------------------------------------
177 sal_Int32
TableControl::GetCurrentColumn() const
179 return m_pImpl
->getCurrentColumn();
182 // -----------------------------------------------------------------------------------------------------------------
183 bool TableControl::GoTo( ColPos _nColumn
, RowPos _nRow
)
185 return m_pImpl
->goTo( _nColumn
, _nRow
);
188 // -----------------------------------------------------------------------------------------------------------------
189 sal_Bool
TableControl::GoToCell(sal_Int32 _nColPos
, sal_Int32 _nRowPos
)
191 return m_pImpl
->goTo( _nColPos
, _nRowPos
);
194 //------------------------------------------------------------------------------------------------------------------
195 sal_Int32
TableControl::GetSelectedRowCount() const
197 return sal_Int32( m_pImpl
->getSelectedRowCount() );
200 //------------------------------------------------------------------------------------------------------------------
201 sal_Int32
TableControl::GetSelectedRowIndex( sal_Int32
const i_selectionIndex
) const
203 return sal_Int32( m_pImpl
->getSelectedRowIndex( i_selectionIndex
) );
206 //------------------------------------------------------------------------------------------------------------------
207 bool TableControl::IsRowSelected( sal_Int32
const i_rowIndex
) const
209 return m_pImpl
->isRowSelected( i_rowIndex
);
212 // -----------------------------------------------------------------------------------------------------------------
213 void TableControl::SelectRow( RowPos
const i_rowIndex
, bool const i_select
)
215 ENSURE_OR_RETURN_VOID( ( i_rowIndex
>= 0 ) && ( i_rowIndex
< m_pImpl
->getModel()->getRowCount() ),
216 "TableControl::SelectRow: invalid row index!" );
220 if ( !m_pImpl
->markRowAsSelected( i_rowIndex
) )
226 m_pImpl
->markRowAsDeselected( i_rowIndex
);
229 m_pImpl
->invalidateRowRange( i_rowIndex
, i_rowIndex
);
233 // -----------------------------------------------------------------------------------------------------------------
234 void TableControl::SelectAllRows( bool const i_select
)
238 if ( !m_pImpl
->markAllRowsAsSelected() )
244 if ( !m_pImpl
->markAllRowsAsDeselected() )
251 // TODO: can't we do better than this, and invalidate only the rows which changed?
255 // -----------------------------------------------------------------------------------------------------------------
256 ITableControl
& TableControl::getTableControlInterface()
261 // -----------------------------------------------------------------------------------------------------------------
262 SelectionEngine
* TableControl::getSelEngine()
264 return m_pImpl
->getSelEngine();
267 // -----------------------------------------------------------------------------------------------------------------
268 Window
& TableControl::getDataWindow()
270 return m_pImpl
->getDataWindow();
273 // -----------------------------------------------------------------------------------------------------------------
274 Reference
< XAccessible
> TableControl::CreateAccessible()
276 Window
* pParent
= GetAccessibleParentWindow();
277 ENSURE_OR_RETURN( pParent
, "TableControl::CreateAccessible - parent not found", NULL
);
279 return m_pImpl
->getAccessible( *pParent
);
282 // -----------------------------------------------------------------------------------------------------------------
283 Reference
<XAccessible
> TableControl::CreateAccessibleControl( sal_Int32 _nIndex
)
286 DBG_ASSERT( sal_False
, "TableControl::CreateAccessibleControl: to be overwritten!" );
290 // -----------------------------------------------------------------------------------------------------------------
291 OUString
TableControl::GetAccessibleObjectName( AccessibleTableControlObjType eObjType
, sal_Int32 _nRow
, sal_Int32 _nCol
) const
297 case TCTYPE_GRIDCONTROL
:
298 aRetText
= OUString( "Grid control" );
301 aRetText
= OUString( "Grid conrol" );
303 case TCTYPE_ROWHEADERBAR
:
304 aRetText
= OUString( "RowHeaderBar" );
306 case TCTYPE_COLUMNHEADERBAR
:
307 aRetText
= OUString( "ColumnHeaderBar" );
309 case TCTYPE_TABLECELL
:
310 //the name of the cell constists of column name and row name if defined
311 //if the name is equal to cell content, it'll be read twice
312 if(GetModel()->hasColumnHeaders())
314 aRetText
= GetColumnName(_nCol
);
315 aRetText
+= OUString::createFromAscii(" , ");
317 if(GetModel()->hasRowHeaders())
319 aRetText
+= GetRowName(_nRow
);
320 aRetText
+= OUString::createFromAscii(" , ");
322 //aRetText = GetAccessibleCellText(_nRow, _nCol);
324 case TCTYPE_ROWHEADERCELL
:
325 aRetText
= GetRowName(_nRow
);
327 case TCTYPE_COLUMNHEADERCELL
:
328 aRetText
= GetColumnName(_nCol
);
331 OSL_FAIL("GridControl::GetAccessibleName: invalid enum!");
336 //------------------------------------------------------------------------------------------------------------------
337 OUString
TableControl::GetAccessibleObjectDescription( AccessibleTableControlObjType eObjType
, sal_Int32
) const
342 case TCTYPE_GRIDCONTROL
:
343 aRetText
= OUString( "Grid control description" );
346 aRetText
= OUString( "TABLE description" );
348 case TCTYPE_ROWHEADERBAR
:
349 aRetText
= OUString( "ROWHEADERBAR description" );
351 case TCTYPE_COLUMNHEADERBAR
:
352 aRetText
= OUString( "COLUMNHEADERBAR description" );
354 case TCTYPE_TABLECELL
:
355 // the description of the cell consists of column name and row name if defined
356 // if the name is equal to cell content, it'll be read twice
357 if ( GetModel()->hasColumnHeaders() )
359 aRetText
= GetColumnName( GetCurrentColumn() );
360 aRetText
+= OUString::createFromAscii( " , " );
362 if ( GetModel()->hasRowHeaders() )
364 aRetText
+= GetRowName( GetCurrentRow() );
367 case TCTYPE_ROWHEADERCELL
:
368 aRetText
= OUString( "ROWHEADERCELL description" );
370 case TCTYPE_COLUMNHEADERCELL
:
371 aRetText
= OUString( "COLUMNHEADERCELL description" );
377 //------------------------------------------------------------------------------------------------------------------
378 OUString
TableControl::GetRowDescription( sal_Int32 _nRow
) const
381 return OUString( "row description" );
384 //------------------------------------------------------------------------------------------------------------------
385 OUString
TableControl::GetRowName( sal_Int32 _nIndex
) const
388 GetModel()->getRowHeading( _nIndex
) >>= sRowName
;
392 //------------------------------------------------------------------------------------------------------------------
393 OUString
TableControl::GetColumnDescription( sal_uInt16 _nColumn
) const
396 return OUString( "col description" );
399 //------------------------------------------------------------------------------------------------------------------
400 OUString
TableControl::GetColumnName( sal_Int32 _nIndex
) const
402 return GetModel()->getColumnModel(_nIndex
)->getName();
405 //------------------------------------------------------------------------------------------------------------------
406 ::com::sun::star::uno::Any
TableControl::GetCellContent( sal_Int32 _nRowPos
, sal_Int32 _nColPos
) const
409 GetModel()->getCellContent( _nColPos
, _nRowPos
, aCellContent
);
413 //------------------------------------------------------------------------------------------------------------------
414 OUString
TableControl::GetAccessibleCellText( sal_Int32 _nRowPos
, sal_Int32 _nColPos
) const
416 return m_pImpl
->getCellContentAsString( _nRowPos
, _nColPos
);
419 //------------------------------------------------------------------------------------------------------------------
420 void TableControl::FillAccessibleStateSet(
421 ::utl::AccessibleStateSetHelper
& rStateSet
,
422 AccessibleTableControlObjType eObjType
) const
426 case TCTYPE_GRIDCONTROL
:
429 rStateSet
.AddState( AccessibleStateType::FOCUSABLE
);
431 if ( m_pImpl
->getSelEngine()->GetSelectionMode() == MULTIPLE_SELECTION
)
432 rStateSet
.AddState( AccessibleStateType::MULTI_SELECTABLE
);
434 if ( HasChildPathFocus() )
435 rStateSet
.AddState( AccessibleStateType::FOCUSED
);
438 rStateSet
.AddState( AccessibleStateType::ACTIVE
);
440 if ( m_pImpl
->getDataWindow().IsEnabled() )
442 rStateSet
.AddState( AccessibleStateType::ENABLED
);
443 rStateSet
.AddState( AccessibleStateType::SENSITIVE
);
446 if ( IsReallyVisible() )
447 rStateSet
.AddState( AccessibleStateType::VISIBLE
);
449 if ( eObjType
== TCTYPE_TABLE
)
450 rStateSet
.AddState( AccessibleStateType::MANAGES_DESCENDANTS
);
453 case TCTYPE_ROWHEADERBAR
:
454 rStateSet
.AddState( AccessibleStateType::VISIBLE
);
455 rStateSet
.AddState( AccessibleStateType::MANAGES_DESCENDANTS
);
458 case TCTYPE_COLUMNHEADERBAR
:
459 rStateSet
.AddState( AccessibleStateType::VISIBLE
);
460 rStateSet
.AddState( AccessibleStateType::MANAGES_DESCENDANTS
);
463 case TCTYPE_TABLECELL
:
465 rStateSet
.AddState( AccessibleStateType::FOCUSABLE
);
466 if ( HasChildPathFocus() )
467 rStateSet
.AddState( AccessibleStateType::FOCUSED
);
468 rStateSet
.AddState( AccessibleStateType::ACTIVE
);
469 rStateSet
.AddState( AccessibleStateType::TRANSIENT
);
470 rStateSet
.AddState( AccessibleStateType::SELECTABLE
);
471 rStateSet
.AddState( AccessibleStateType::VISIBLE
);
472 rStateSet
.AddState( AccessibleStateType::SHOWING
);
473 if ( IsRowSelected( GetCurrentRow() ) )
474 // Hmm? Wouldn't we expect the affected row to be a parameter to this function?
475 rStateSet
.AddState( AccessibleStateType::SELECTED
);
479 case TCTYPE_ROWHEADERCELL
:
480 rStateSet
.AddState( AccessibleStateType::VISIBLE
);
481 rStateSet
.AddState( AccessibleStateType::TRANSIENT
);
484 case TCTYPE_COLUMNHEADERCELL
:
485 rStateSet
.AddState( AccessibleStateType::VISIBLE
);
490 //------------------------------------------------------------------------------------------------------------------
491 void TableControl::commitCellEventIfAccessibleAlive( sal_Int16
const i_eventID
, const Any
& i_newValue
, const Any
& i_oldValue
)
493 if ( m_pImpl
->isAccessibleAlive() )
494 m_pImpl
->commitCellEvent( i_eventID
, i_newValue
, i_oldValue
);
497 //------------------------------------------------------------------------------------------------------------------
498 void TableControl::commitTableEventIfAccessibleAlive( sal_Int16
const i_eventID
, const Any
& i_newValue
, const Any
& i_oldValue
)
500 if ( m_pImpl
->isAccessibleAlive() )
501 m_pImpl
->commitTableEvent( i_eventID
, i_newValue
, i_oldValue
);
504 //------------------------------------------------------------------------------------------------------------------
505 Rectangle
TableControl::GetWindowExtentsRelative( Window
*pRelativeWindow
) const
507 return Control::GetWindowExtentsRelative( pRelativeWindow
);
510 //------------------------------------------------------------------------------------------------------------------
511 void TableControl::GrabFocus()
513 Control::GrabFocus();
516 //------------------------------------------------------------------------------------------------------------------
517 Reference
< XAccessible
> TableControl::GetAccessible( sal_Bool bCreate
)
519 return Control::GetAccessible( bCreate
);
522 //------------------------------------------------------------------------------------------------------------------
523 Window
* TableControl::GetAccessibleParentWindow() const
525 return Control::GetAccessibleParentWindow();
528 //------------------------------------------------------------------------------------------------------------------
529 Window
* TableControl::GetWindowInstance()
534 //------------------------------------------------------------------------------------------------------------------
535 sal_Bool
TableControl::HasRowHeader()
537 return GetModel()->hasRowHeaders();
540 //------------------------------------------------------------------------------------------------------------------
541 sal_Bool
TableControl::HasColHeader()
543 return GetModel()->hasColumnHeaders();
546 //------------------------------------------------------------------------------------------------------------------
547 sal_Int32
TableControl::GetAccessibleControlCount() const
549 // TC_TABLE is always defined, no matter whether empty or not
551 if ( GetModel()->hasRowHeaders() )
553 if ( GetModel()->hasColumnHeaders() )
558 //------------------------------------------------------------------------------------------------------------------
559 sal_Bool
TableControl::ConvertPointToControlIndex( sal_Int32
& _rnIndex
, const Point
& _rPoint
)
561 sal_Int32 nRow
= m_pImpl
->getRowAtPoint( _rPoint
);
562 sal_Int32 nCol
= m_pImpl
->getColAtPoint( _rPoint
);
563 _rnIndex
= nRow
* GetColumnCount() + nCol
;
564 return nRow
>= 0 ? sal_True
: sal_False
;
567 //------------------------------------------------------------------------------------------------------------------
568 long TableControl::GetRowCount() const
570 return GetModel()->getRowCount();
573 //------------------------------------------------------------------------------------------------------------------
574 long TableControl::GetColumnCount() const
576 return GetModel()->getColumnCount();
579 //------------------------------------------------------------------------------------------------------------------
580 sal_Bool
TableControl::HasRowHeader() const
582 return GetModel()->hasRowHeaders();
585 //------------------------------------------------------------------------------------------------------------------
586 sal_Bool
TableControl::ConvertPointToCellAddress( sal_Int32
& _rnRow
, sal_Int32
& _rnColPos
, const Point
& _rPoint
)
588 _rnRow
= m_pImpl
->getRowAtPoint( _rPoint
);
589 _rnColPos
= m_pImpl
->getColAtPoint( _rPoint
);
590 return _rnRow
>= 0 ? sal_True
: sal_False
;
593 //------------------------------------------------------------------------------------------------------------------
594 void TableControl::FillAccessibleStateSetForCell( ::utl::AccessibleStateSetHelper
& _rStateSet
, sal_Int32 _nRow
, sal_uInt16 _nColumnPos
) const
596 if ( IsRowSelected( _nRow
) )
597 _rStateSet
.AddState( AccessibleStateType::SELECTED
);
598 if ( HasChildPathFocus() )
599 _rStateSet
.AddState( AccessibleStateType::FOCUSED
);
600 else // only transient when column is not focused
601 _rStateSet
.AddState( AccessibleStateType::TRANSIENT
);
603 _rStateSet
.AddState( AccessibleStateType::VISIBLE
);
604 _rStateSet
.AddState( AccessibleStateType::SHOWING
);
605 _rStateSet
.AddState( AccessibleStateType::ENABLED
);
606 _rStateSet
.AddState( AccessibleStateType::SENSITIVE
);
607 _rStateSet
.AddState( AccessibleStateType::ACTIVE
);
612 //------------------------------------------------------------------------------------------------------------------
613 Rectangle
TableControl::GetFieldCharacterBounds(sal_Int32 _nRow
,sal_Int32 _nColumnPos
,sal_Int32 nIndex
)
617 return GetCharacterBounds(nIndex
);
620 //------------------------------------------------------------------------------------------------------------------
621 sal_Int32
TableControl::GetFieldIndexAtPoint(sal_Int32 _nRow
,sal_Int32 _nColumnPos
,const Point
& _rPoint
)
625 return GetIndexForPoint(_rPoint
);
628 //------------------------------------------------------------------------------------------------------------------
629 Rectangle
TableControl::calcHeaderRect(sal_Bool _bIsColumnBar
,sal_Bool _bOnScreen
)
632 return m_pImpl
->calcHeaderRect( _bIsColumnBar
? false : true );
635 //------------------------------------------------------------------------------------------------------------------
636 Rectangle
TableControl::calcHeaderCellRect( sal_Bool _bIsColumnBar
, sal_Int32 nPos
)
638 return m_pImpl
->calcHeaderCellRect( _bIsColumnBar
, nPos
);
641 //------------------------------------------------------------------------------------------------------------------
642 Rectangle
TableControl::calcTableRect(sal_Bool _bOnScreen
)
645 return m_pImpl
->calcTableRect();
648 //------------------------------------------------------------------------------------------------------------------
649 Rectangle
TableControl::calcCellRect( sal_Int32 _nRowPos
, sal_Int32 _nColPos
)
651 return m_pImpl
->calcCellRect( _nRowPos
, _nColPos
);
654 //------------------------------------------------------------------------------------------------------------------
655 IMPL_LINK_NOARG(TableControl
, ImplSelectHdl
)
661 //------------------------------------------------------------------------------------------------------------------
662 void TableControl::Select()
664 ImplCallEventListenersAndHandler( VCLEVENT_TABLEROW_SELECT
, m_pImpl
->getSelectHandler(), this );
666 if ( m_pImpl
->isAccessibleAlive() )
668 m_pImpl
->commitAccessibleEvent( AccessibleEventId::SELECTION_CHANGED
, Any(), Any() );
670 m_pImpl
->commitTableEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED
, Any(), Any() );
671 // TODO: why do we notify this when the *selection* changed? Shouldn't we find a better place for this,
672 // actually, when the active descendant, i.e. the current cell, *really* changed?
676 }} // namespace svt::table
678 //......................................................................................................................
679 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */