LibreOffice Module toolkit (master) 1
tablecontrol.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
21
22#include "tablecontrol_impl.hxx"
23#include "tabledatawindow.hxx"
24
25#include <com/sun/star/accessibility/AccessibleStateType.hpp>
26#include <com/sun/star/accessibility/AccessibleEventId.hpp>
27
28#include <sal/log.hxx>
30#include <vcl/settings.hxx>
31#include <vcl/vclevent.hxx>
32
33using namespace ::com::sun::star::uno;
34using ::com::sun::star::accessibility::XAccessible;
35using namespace ::com::sun::star::accessibility;
36using namespace ::com::sun::star::lang;
37
38namespace svt::table
39{
40
41
42 namespace AccessibleEventId = ::com::sun::star::accessibility::AccessibleEventId;
43
44
45 //= TableControl
46
47
49 :Control( _pParent, _nStyle )
51 {
52 TableDataWindow& rDataWindow = m_pImpl->getDataWindow();
53 rDataWindow.SetSelectHdl( LINK( this, TableControl, ImplSelectHdl ) );
54
55 // by default, use the background as determined by the style settings
56 const Color aWindowColor( GetSettings().GetStyleSettings().GetFieldColor() );
57 SetBackground( Wallpaper( aWindowColor ) );
58 GetOutDev()->SetFillColor( aWindowColor );
59
60 SetCompoundControl( true );
61 }
62
63
65 {
67 }
68
70 {
71 CallEventListeners( VclEventId::ObjectDying );
72
73 m_pImpl->setModel( PTableModel() );
74 m_pImpl->disposeAccessible();
75 m_pImpl.reset();
77 }
78
79
81 {
82 if ( !m_pImpl || !m_pImpl->getInputHandler()->GetFocus( *m_pImpl ) )
84 }
85
86
88 {
89 if ( !m_pImpl || !m_pImpl->getInputHandler()->LoseFocus( *m_pImpl ) )
91 }
92
93
94 void TableControl::KeyInput( const KeyEvent& rKEvt )
95 {
96 if ( !m_pImpl->getInputHandler()->KeyInput( *m_pImpl, rKEvt ) )
97 Control::KeyInput( rKEvt );
98 else
99 {
100 if ( m_pImpl->isAccessibleAlive() )
101 {
102 m_pImpl->commitCellEvent( AccessibleEventId::STATE_CHANGED,
103 Any( AccessibleStateType::FOCUSED ),
104 Any()
105 );
106 // Huh? What the heck? Why do we unconditionally notify a STATE_CHANGE/FOCUSED after each and every
107 // (handled) key stroke?
108
109 m_pImpl->commitTableEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
110 Any(),
111 Any()
112 );
113 // ditto: Why do we notify this unconditionally? We should find the right place to notify the
114 // ACTIVE_DESCENDANT_CHANGED event.
115 // Also, we should check if STATE_CHANGED/FOCUSED is really necessary: finally, the children are
116 // transient, aren't they?
117 }
118 }
119 }
120
121
123 {
124 Control::StateChanged( i_nStateChange );
125
126 // forward certain settings to the data window
127 switch ( i_nStateChange )
128 {
129 case StateChangedType::ControlFocus:
130 m_pImpl->invalidateSelectedRows();
131 break;
132
133 case StateChangedType::ControlBackground:
134 if ( IsControlBackground() )
136 else
138 break;
139
140 case StateChangedType::ControlForeground:
141 if ( IsControlForeground() )
143 else
145 break;
146
147 case StateChangedType::ControlFont:
148 if ( IsControlFont() )
150 else
152 break;
153 default:;
154 }
155 }
156
157
159 {
161 m_pImpl->onResize();
162 }
163
164
165 void TableControl::SetModel( const PTableModel& _pModel )
166 {
167 m_pImpl->setModel( _pModel );
168 }
169
170
172 {
173 return m_pImpl->getModel();
174 }
175
176
178 {
179 return m_pImpl->getCurrentRow();
180 }
181
182
184 {
185 return m_pImpl->getCurrentColumn();
186 }
187
188
189 void TableControl::GoTo( ColPos _nColumn, RowPos _nRow )
190 {
191 m_pImpl->goTo( _nColumn, _nRow );
192 }
193
194
195 void TableControl::GoToCell(sal_Int32 _nColPos, sal_Int32 _nRowPos)
196 {
197 m_pImpl->goTo( _nColPos, _nRowPos );
198 }
199
200
202 {
203 return sal_Int32( m_pImpl->getSelectedRowCount() );
204 }
205
206
207 sal_Int32 TableControl::GetSelectedRowIndex( sal_Int32 const i_selectionIndex ) const
208 {
209 return m_pImpl->getSelectedRowIndex( i_selectionIndex );
210 }
211
212
213 bool TableControl::IsRowSelected( sal_Int32 const i_rowIndex ) const
214 {
215 return m_pImpl->isRowSelected( i_rowIndex );
216 }
217
218
219 void TableControl::SelectRow( sal_Int32 const i_rowIndex, bool const i_select )
220 {
221 ENSURE_OR_RETURN_VOID( ( i_rowIndex >= 0 ) && ( i_rowIndex < m_pImpl->getModel()->getRowCount() ),
222 "TableControl::SelectRow: invalid row index!" );
223
224 if ( i_select )
225 {
226 if ( !m_pImpl->markRowAsSelected( i_rowIndex ) )
227 // nothing to do
228 return;
229 }
230 else
231 {
232 m_pImpl->markRowAsDeselected( i_rowIndex );
233 }
234
235 m_pImpl->invalidateRowRange( i_rowIndex, i_rowIndex );
236 Select();
237 }
238
239
240 void TableControl::SelectAllRows( bool const i_select )
241 {
242 if ( i_select )
243 {
244 if ( !m_pImpl->markAllRowsAsSelected() )
245 // nothing to do
246 return;
247 }
248 else
249 {
250 if ( !m_pImpl->markAllRowsAsDeselected() )
251 // nothing to do
252 return;
253 }
254
255
256 Invalidate();
257 // TODO: can't we do better than this, and invalidate only the rows which changed?
258 Select();
259 }
260
261
263 {
264 return *m_pImpl;
265 }
266
267
269 {
270 return m_pImpl->getSelEngine();
271 }
272
273
275 {
276 return m_pImpl->getDataWindow();
277 }
278
279
280 Reference< XAccessible > TableControl::CreateAccessible()
281 {
283 ENSURE_OR_RETURN( pParent, "TableControl::CreateAccessible - parent not found", nullptr );
284
285 return m_pImpl->getAccessible( *pParent );
286 }
287
288
289 Reference<XAccessible> TableControl::CreateAccessibleControl( sal_Int32 )
290 {
291 SAL_WARN( "svtools", "TableControl::CreateAccessibleControl: to be overwritten!" );
292 return nullptr;
293 }
294
295
296 OUString TableControl::GetAccessibleObjectName( vcl::table::AccessibleTableControlObjType eObjType, sal_Int32 _nRow, sal_Int32 _nCol) const
297 {
298 OUString aRetText;
299 //Window* pWin;
300 switch( eObjType )
301 {
303 aRetText = "Grid control";
304 break;
306 aRetText = "Grid control";
307 break;
309 aRetText = "RowHeaderBar";
310 break;
312 aRetText = "ColumnHeaderBar";
313 break;
315 //the name of the cell consists of column name and row name if defined
316 //if the name is equal to cell content, it'll be read twice
317 if(GetModel()->hasColumnHeaders())
318 {
319 aRetText = GetColumnName(_nCol) + " , ";
320 }
321 if(GetModel()->hasRowHeaders())
322 {
323 aRetText += GetRowName(_nRow) + " , ";
324 }
325 //aRetText = GetAccessibleCellText(_nRow, _nCol);
326 break;
328 aRetText = GetRowName(_nRow);
329 break;
331 aRetText = GetColumnName(_nCol);
332 break;
333 default:
334 OSL_FAIL("GridControl::GetAccessibleName: invalid enum!");
335 }
336 return aRetText;
337 }
338
339
341 {
342 OUString aRetText;
343 switch( eObjType )
344 {
346 aRetText = "Grid control description";
347 break;
349 aRetText = "TABLE description";
350 break;
352 aRetText = "ROWHEADERBAR description";
353 break;
355 aRetText = "COLUMNHEADERBAR description";
356 break;
358 // the description of the cell consists of column name and row name if defined
359 // if the name is equal to cell content, it'll be read twice
360 if ( GetModel()->hasColumnHeaders() )
361 {
362 aRetText = GetColumnName( GetCurrentColumn() ) + " , ";
363 }
364 if ( GetModel()->hasRowHeaders() )
365 {
366 aRetText += GetRowName( GetCurrentRow() );
367 }
368 break;
370 aRetText = "ROWHEADERCELL description";
371 break;
373 aRetText = "COLUMNHEADERCELL description";
374 break;
375 }
376 return aRetText;
377 }
378
379
380 OUString TableControl::GetRowName( sal_Int32 _nIndex) const
381 {
382 OUString sRowName;
383 GetModel()->getRowHeading( _nIndex ) >>= sRowName;
384 return sRowName;
385 }
386
387
388 OUString TableControl::GetColumnName( sal_Int32 _nIndex) const
389 {
390 return GetModel()->getColumnModel(_nIndex)->getName();
391 }
392
393
394 OUString TableControl::GetAccessibleCellText( sal_Int32 _nRowPos, sal_Int32 _nColPos) const
395 {
396 return m_pImpl->getCellContentAsString( _nRowPos, _nColPos );
397 }
398
399
401 sal_Int64& rStateSet,
403 {
404 switch( eObjType )
405 {
408
409 rStateSet |= AccessibleStateType::FOCUSABLE;
410
411 if ( m_pImpl->getSelEngine()->GetSelectionMode() == SelectionMode::Multiple )
412 rStateSet |= AccessibleStateType::MULTI_SELECTABLE;
413
414 if ( HasChildPathFocus() )
415 rStateSet |= AccessibleStateType::FOCUSED;
416
417 if ( IsActive() )
418 rStateSet |= AccessibleStateType::ACTIVE;
419
420 if ( m_pImpl->getDataWindow().IsEnabled() )
421 {
422 rStateSet |= AccessibleStateType::ENABLED;
423 rStateSet |= AccessibleStateType::SENSITIVE;
424 }
425
426 if ( IsReallyVisible() )
427 rStateSet |= AccessibleStateType::VISIBLE;
428
429 if ( eObjType == vcl::table::TCTYPE_TABLE )
430 rStateSet |= AccessibleStateType::MANAGES_DESCENDANTS;
431 break;
432
434 rStateSet |= AccessibleStateType::VISIBLE;
435 rStateSet |= AccessibleStateType::MANAGES_DESCENDANTS;
436 break;
437
439 rStateSet |= AccessibleStateType::VISIBLE;
440 rStateSet |= AccessibleStateType::MANAGES_DESCENDANTS;
441 break;
442
444 {
445 rStateSet |= AccessibleStateType::FOCUSABLE;
446 if ( HasChildPathFocus() )
447 rStateSet |= AccessibleStateType::FOCUSED;
448 rStateSet |= AccessibleStateType::ACTIVE;
449 rStateSet |= AccessibleStateType::TRANSIENT;
450 rStateSet |= AccessibleStateType::SELECTABLE;
451 rStateSet |= AccessibleStateType::VISIBLE;
452 rStateSet |= AccessibleStateType::SHOWING;
453 if ( IsRowSelected( GetCurrentRow() ) )
454 // Hmm? Wouldn't we expect the affected row to be a parameter to this function?
455 rStateSet |= AccessibleStateType::SELECTED;
456 }
457 break;
458
460 rStateSet |= AccessibleStateType::VISIBLE;
461 rStateSet |= AccessibleStateType::TRANSIENT;
462 break;
463
465 rStateSet |= AccessibleStateType::VISIBLE;
466 break;
467 }
468 }
469
470 void TableControl::commitCellEventIfAccessibleAlive( sal_Int16 const i_eventID, const Any& i_newValue, const Any& i_oldValue )
471 {
472 if ( m_pImpl->isAccessibleAlive() )
473 m_pImpl->commitCellEvent( i_eventID, i_newValue, i_oldValue );
474 }
475
476 void TableControl::commitTableEventIfAccessibleAlive( sal_Int16 const i_eventID, const Any& i_newValue, const Any& i_oldValue )
477 {
478 if ( m_pImpl->isAccessibleAlive() )
479 m_pImpl->commitTableEvent( i_eventID, i_newValue, i_oldValue );
480 }
481
483 {
485 }
486
488 {
489 return Control::GetWindowExtentsRelative( rRelativeWindow );
490 }
491
493 {
495 }
496
497 Reference< XAccessible > TableControl::GetAccessible()
498 {
499 return Control::GetAccessible();
500 }
501
503 {
505 }
506
508 {
509 return this;
510 }
511
512
514 {
515 return GetModel()->hasRowHeaders();
516 }
517
518
520 {
521 return GetModel()->hasColumnHeaders();
522 }
523
524
526 {
527 // TC_TABLE is always defined, no matter whether empty or not
528 sal_Int32 count = 1;
529 if ( GetModel()->hasRowHeaders() )
530 ++count;
531 if ( GetModel()->hasColumnHeaders() )
532 ++count;
533 return count;
534 }
535
536
537 bool TableControl::ConvertPointToControlIndex( sal_Int32& _rnIndex, const Point& _rPoint )
538 {
539 sal_Int32 nRow = m_pImpl->getRowAtPoint( _rPoint );
540 sal_Int32 nCol = m_pImpl->getColAtPoint( _rPoint );
541 _rnIndex = nRow * GetColumnCount() + nCol;
542 return nRow >= 0;
543 }
544
545
547 {
548 return GetModel()->getRowCount();
549 }
550
551
553 {
554 return GetModel()->getColumnCount();
555 }
556
557
558 bool TableControl::ConvertPointToCellAddress( sal_Int32& _rnRow, sal_Int32& _rnColPos, const Point& _rPoint )
559 {
560 _rnRow = m_pImpl->getRowAtPoint( _rPoint );
561 _rnColPos = m_pImpl->getColAtPoint( _rPoint );
562 return _rnRow >= 0;
563 }
564
565
566 void TableControl::FillAccessibleStateSetForCell( sal_Int64& _rStateSet, sal_Int32 _nRow, sal_uInt16 ) const
567 {
568 if ( IsRowSelected( _nRow ) )
569 _rStateSet |= AccessibleStateType::SELECTED;
570 if ( HasChildPathFocus() )
571 _rStateSet |= AccessibleStateType::FOCUSED;
572 else // only transient when column is not focused
573 _rStateSet |= AccessibleStateType::TRANSIENT;
574
575 _rStateSet |= AccessibleStateType::VISIBLE;
576 _rStateSet |= AccessibleStateType::SHOWING;
577 _rStateSet |= AccessibleStateType::ENABLED;
578 _rStateSet |= AccessibleStateType::SENSITIVE;
579 _rStateSet |= AccessibleStateType::ACTIVE;
580 }
581
582
583 tools::Rectangle TableControl::GetFieldCharacterBounds(sal_Int32,sal_Int32,sal_Int32 nIndex)
584 {
586 }
587
588
589 sal_Int32 TableControl::GetFieldIndexAtPoint(sal_Int32,sal_Int32,const Point& _rPoint)
590 {
591 return GetIndexForPoint(_rPoint);
592 }
593
594
596 {
597 return m_pImpl->calcHeaderRect( !_bIsColumnBar );
598 }
599
600
601 tools::Rectangle TableControl::calcHeaderCellRect( bool _bIsColumnBar, sal_Int32 nPos )
602 {
603 return m_pImpl->calcHeaderCellRect( _bIsColumnBar, nPos );
604 }
605
606
608 {
609 return m_pImpl->calcTableRect();
610 }
611
612
613 tools::Rectangle TableControl::calcCellRect( sal_Int32 _nRowPos, sal_Int32 _nColPos )
614 {
615 return m_pImpl->calcCellRect( _nRowPos, _nColPos );
616 }
617
618
620 {
621 Select();
622 }
623
624
626 {
627 ImplCallEventListenersAndHandler( VclEventId::TableRowSelect, nullptr );
628
629 if ( m_pImpl->isAccessibleAlive() )
630 {
631 m_pImpl->commitAccessibleEvent( AccessibleEventId::SELECTION_CHANGED );
632
633 m_pImpl->commitTableEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, Any(), Any() );
634 // TODO: why do we notify this when the *selection* changed? Shouldn't we find a better place for this,
635 // actually, when the active descendant, i.e. the current cell, *really* changed?
636 }
637 }
638
639} // namespace svt::table
640
641
642/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
tools::Long GetIndexForPoint(const Point &rPoint) const
bool ImplCallEventListenersAndHandler(VclEventId nEvent, std::function< void()> const &callHandler)
virtual void StateChanged(StateChangedType nStateChange) override
virtual void Resize() override
void CallEventListeners(VclEventId nEvent, void *pData=nullptr)
tools::Rectangle GetCharacterBounds(tools::Long nIndex) const
virtual void dispose() override
void SetFillColor()
defines a callback interface to be implemented by a concrete table control
a basic control which manages table-like data, i.e.
void SetModel(const PTableModel &_pModel)
sets a new table model
virtual sal_Int32 GetFieldIndexAtPoint(sal_Int32 _nRow, sal_Int32 _nColumnPos, const Point &_rPoint) override
virtual sal_Int32 GetSelectedRowCount() const override
virtual OUString GetAccessibleObjectName(vcl::table::AccessibleTableControlObjType eObjType, sal_Int32 _nRow, sal_Int32 _nCol) const override
virtual bool HasColHeader() override
virtual sal_Int32 GetAccessibleControlCount() const override
virtual vcl::Window * GetAccessibleParentWindow() const override
sal_Int32 GetCurrentRow() const override
retrieves the current row
virtual void SelectAllRows(bool const i_select) override
sal_Int32 GetCurrentColumn() const override
retrieves the current column
virtual bool HasRowHeader() override
virtual tools::Rectangle calcHeaderRect(bool _bIsColumnBar) override
virtual css::uno::Reference< css::accessibility::XAccessible > GetAccessible() override
virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessibleControl(sal_Int32 _nIndex) override
virtual bool IsRowSelected(sal_Int32 const i_rowIndex) const override
virtual tools::Rectangle calcHeaderCellRect(bool _bIsColumnBar, sal_Int32 nPos) override
virtual tools::Rectangle calcCellRect(sal_Int32 _nRowPos, sal_Int32 _nColPos) override
virtual void FillAccessibleStateSet(sal_Int64 &rStateSet, vcl::table::AccessibleTableControlObjType eObjType) const override
virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override
Creates and returns the accessible object of the whole GridControl.
virtual sal_Int32 GetColumnCount() const override
virtual OUString GetAccessibleObjectDescription(vcl::table::AccessibleTableControlObjType eObjType) const override
virtual sal_Int32 GetSelectedRowIndex(sal_Int32 const i_selectionIndex) const override
virtual sal_Int32 GetRowCount() const override
virtual OUString GetRowName(sal_Int32 _nIndex) const override
virtual void GoToCell(sal_Int32 _nColumnPos, sal_Int32 _nRow) override
virtual void FillAccessibleStateSetForCell(sal_Int64 &_rStateSet, sal_Int32 _nRow, sal_uInt16 _nColumnPos) const override
virtual vcl::Window * GetWindowInstance() override
virtual tools::Rectangle GetWindowExtentsAbsolute() const override
virtual void SelectRow(sal_Int32 const i_rowIndex, bool const i_select) override
virtual tools::Rectangle GetFieldCharacterBounds(sal_Int32 _nRow, sal_Int32 _nColumnPos, sal_Int32 nIndex) override
virtual void LoseFocus() override
PTableModel GetModel() const
retrieves the current table model
virtual void KeyInput(const KeyEvent &rKEvt) override
virtual tools::Rectangle calcTableRect() override
virtual tools::Rectangle GetWindowExtentsRelative(const vcl::Window &rRelativeWindow) const override
virtual bool ConvertPointToControlIndex(sal_Int32 &_rnIndex, const Point &_rPoint) override
ITableControl & getTableControlInterface()
virtual OUString GetAccessibleCellText(sal_Int32 _nRowPos, sal_Int32 _nColPos) const override
SelectionEngine * getSelEngine()
after removing a row, updates the vector which contains the selected rows if the row,...
vcl::Window & getDataWindow()
virtual ~TableControl() override
void GoTo(ColPos _nColumnPos, RowPos _nRow)
activates the cell at the given position
void commitTableEventIfAccessibleAlive(sal_Int16 const i_eventID, const css::uno::Any &i_newValue, const css::uno::Any &i_oldValue)
virtual void Resize() override
virtual void GetFocus() override
virtual void dispose() override
virtual void GrabFocus() override
std::shared_ptr< TableControl_Impl > m_pImpl
void commitCellEventIfAccessibleAlive(sal_Int16 const i_eventID, const css::uno::Any &i_newValue, const css::uno::Any &i_oldValue)
virtual void StateChanged(StateChangedType i_nStateChange) override
virtual OUString GetColumnName(sal_Int32 _nIndex) const override
TableControl(vcl::Window *_pParent, WinBits _nStyle)
virtual bool ConvertPointToCellAddress(sal_Int32 &_rnRow, sal_Int32 &_rnColPos, const Point &_rPoint) override
the window containing the content area (including headers) of a table control
void SetSelectHdl(const Link< LinkParamNone *, void > &rLink)
tools::Rectangle GetWindowExtentsAbsolute() const
bool IsReallyVisible() const
virtual void GetFocus()
void SetControlForeground()
bool HasChildPathFocus(bool bSystemWindow=false) const
bool IsControlFont() const
void SetControlFont()
const Color & GetControlForeground() const
void GrabFocus()
void SetControlBackground()
vcl::Window * GetAccessibleParentWindow() const
bool IsControlForeground() const
const AllSettings & GetSettings() const
virtual void KeyInput(const KeyEvent &rKEvt)
vcl::Font GetControlFont() const
::OutputDevice const * GetOutDev() const
css::uno::Reference< css::accessibility::XAccessible > GetAccessible(bool bCreate=true)
bool IsControlBackground() const
virtual void LoseFocus()
const Color & GetControlBackground() const
void Invalidate(InvalidateFlags nFlags=InvalidateFlags::NONE)
tools::Rectangle GetWindowExtentsRelative(const vcl::Window &rRelativeWindow) const
bool IsActive() const
void SetCompoundControl(bool bCompound)
void SetBackground()
#define ENSURE_OR_RETURN(c, m, r)
#define ENSURE_OR_RETURN_VOID(c, m)
sal_Int32 nIndex
sal_uInt16 nPos
#define SAL_WARN(area, stream)
std::shared_ptr< T > make_shared(Args &&... args)
IMPL_LINK_NOARG(TableControl, ImplSelectHdl, LinkParamNone *, void)
sal_Int32 RowPos
a value denoting a row position within a table
Definition: tabletypes.hxx:34
std::shared_ptr< ITableModel > PTableModel
Definition: tablemodel.hxx:448
sal_Int32 ColPos
a value denoting a column position within a table
Definition: tabletypes.hxx:32
AccessibleTableControlObjType
StateChangedType
sal_Int64 WinBits