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 .
21 #include "svtools/table/tablecontrol.hxx"
22 #include "svtools/table/defaultinputhandler.hxx"
23 #include "svtools/table/tablemodel.hxx"
25 #include "tabledatawindow.hxx"
26 #include "tablecontrol_impl.hxx"
27 #include "tablegeometry.hxx"
29 #include <com/sun/star/accessibility/XAccessible.hpp>
30 #include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
31 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
32 #include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
34 #include <comphelper/flagguard.hxx>
35 #include <vcl/scrbar.hxx>
36 #include <vcl/seleng.hxx>
37 #include <rtl/ref.hxx>
38 #include <vcl/image.hxx>
39 #include <tools/diagnose_ex.h>
44 #define MIN_COLUMN_WIDTH_PIXEL 4
46 //......................................................................................................................
47 namespace svt
{ namespace table
49 //......................................................................................................................
51 using ::com::sun::star::accessibility::AccessibleTableModelChange
;
52 using ::com::sun::star::uno::makeAny
;
53 using ::com::sun::star::uno::Any
;
54 using ::com::sun::star::accessibility::XAccessible
;
55 using ::com::sun::star::uno::Reference
;
57 namespace AccessibleEventId
= ::com::sun::star::accessibility::AccessibleEventId
;
58 namespace AccessibleTableModelChangeType
= ::com::sun::star::accessibility::AccessibleTableModelChangeType
;
60 //==================================================================================================================
62 //==================================================================================================================
66 ITableControl
& m_rTable
;
69 SuppressCursor( ITableControl
& _rTable
)
72 m_rTable
.hideCursor();
76 m_rTable
.showCursor();
80 //====================================================================
82 //====================================================================
83 /** default implementation of an ->ITableModel, used as fallback when no
86 Instances of this class are static in any way, and provide the least
87 necessary default functionality for a table model.
89 class EmptyTableModel
: public ITableModel
96 // ITableModel overridables
97 virtual TableSize
getColumnCount() const
101 virtual TableSize
getRowCount() const
105 virtual bool hasColumnHeaders() const
109 virtual bool hasRowHeaders() const
113 virtual bool isCellEditable( ColPos col
, RowPos row
) const
119 virtual PColumnModel
getColumnModel( ColPos column
)
121 OSL_FAIL( "EmptyTableModel::getColumnModel: invalid call!" );
123 return PColumnModel();
125 virtual PTableRenderer
getRenderer() const
127 return PTableRenderer();
129 virtual PTableInputHandler
getInputHandler() const
131 return PTableInputHandler();
133 virtual TableMetrics
getRowHeight() const
137 virtual void setRowHeight(TableMetrics _nRowHeight
)
141 virtual TableMetrics
getColumnHeaderHeight() const
145 virtual TableMetrics
getRowHeaderWidth() const
149 virtual ScrollbarVisibility
getVerticalScrollbarVisibility() const
151 return ScrollbarShowNever
;
153 virtual ScrollbarVisibility
getHorizontalScrollbarVisibility() const
155 return ScrollbarShowNever
;
157 virtual void addTableModelListener( const PTableModelListener
& i_listener
)
161 virtual void removeTableModelListener( const PTableModelListener
& i_listener
)
165 virtual ::boost::optional
< ::Color
> getLineColor() const
167 return ::boost::optional
< ::Color
>();
169 virtual ::boost::optional
< ::Color
> getHeaderBackgroundColor() const
171 return ::boost::optional
< ::Color
>();
173 virtual ::boost::optional
< ::Color
> getHeaderTextColor() const
175 return ::boost::optional
< ::Color
>();
177 virtual ::boost::optional
< ::Color
> getActiveSelectionBackColor() const
179 return ::boost::optional
< ::Color
>();
181 virtual ::boost::optional
< ::Color
> getInactiveSelectionBackColor() const
183 return ::boost::optional
< ::Color
>();
185 virtual ::boost::optional
< ::Color
> getActiveSelectionTextColor() const
187 return ::boost::optional
< ::Color
>();
189 virtual ::boost::optional
< ::Color
> getInactiveSelectionTextColor() const
191 return ::boost::optional
< ::Color
>();
193 virtual ::boost::optional
< ::Color
> getTextColor() const
195 return ::boost::optional
< ::Color
>();
197 virtual ::boost::optional
< ::Color
> getTextLineColor() const
199 return ::boost::optional
< ::Color
>();
201 virtual ::boost::optional
< ::std::vector
< ::Color
> > getRowBackgroundColors() const
203 return ::boost::optional
< ::std::vector
< ::Color
> >();
205 virtual ::com::sun::star::style::VerticalAlignment
getVerticalAlign() const
207 return com::sun::star::style::VerticalAlignment(0);
209 virtual ITableDataSort
* getSortAdapter()
213 virtual void getCellContent( ColPos
const i_col
, RowPos
const i_row
, ::com::sun::star::uno::Any
& o_cellContent
)
217 o_cellContent
.clear();
219 virtual void getCellToolTip( ColPos
const, RowPos
const, ::com::sun::star::uno::Any
& )
222 virtual Any
getRowHeading( RowPos
const i_rowPos
) const
230 //====================================================================
231 //= TableControl_Impl
232 //====================================================================
233 DBG_NAME( TableControl_Impl
)
236 //====================================================================
237 //= SuspendInvariants
238 //====================================================================
239 class SuspendInvariants
242 const TableControl_Impl
& m_rTable
;
243 sal_Int32 m_nSuspendFlags
;
246 SuspendInvariants( const TableControl_Impl
& _rTable
, sal_Int32 _nSuspendFlags
)
248 ,m_nSuspendFlags( _nSuspendFlags
)
250 //DBG_ASSERT( ( m_rTable.m_nRequiredInvariants & m_nSuspendFlags ) == m_nSuspendFlags,
251 // "SuspendInvariants: cannot suspend what is already suspended!" );
252 const_cast< TableControl_Impl
& >( m_rTable
).m_nRequiredInvariants
&= ~m_nSuspendFlags
;
256 const_cast< TableControl_Impl
& >( m_rTable
).m_nRequiredInvariants
|= m_nSuspendFlags
;
259 #define DBG_SUSPEND_INV( flags ) \
260 SuspendInvariants aSuspendInv( *this, flags );
262 #define DBG_SUSPEND_INV( flags )
266 //====================================================================
267 const char* TableControl_Impl_checkInvariants( const void* _pInstance
)
269 return static_cast< const TableControl_Impl
* >( _pInstance
)->impl_checkInvariants();
274 template< typename SCALAR_TYPE
>
275 bool lcl_checkLimitsExclusive( SCALAR_TYPE _nValue
, SCALAR_TYPE _nMin
, SCALAR_TYPE _nMax
)
277 return ( _nValue
> _nMin
) && ( _nValue
< _nMax
);
280 template< typename SCALAR_TYPE
>
281 bool lcl_checkLimitsExclusive_OrDefault_OrFallback( SCALAR_TYPE _nValue
, SCALAR_TYPE _nMin
, SCALAR_TYPE _nMax
,
282 PTableModel _pModel
, SCALAR_TYPE _nDefaultOrFallback
)
285 return _nValue
== _nDefaultOrFallback
;
286 if ( _nMax
<= _nMin
)
287 return _nDefaultOrFallback
== _nValue
;
288 return lcl_checkLimitsExclusive( _nValue
, _nMin
, _nMax
);
292 //------------------------------------------------------------------------------------------------------------------
293 const sal_Char
* TableControl_Impl::impl_checkInvariants() const
296 return "no model, not even an EmptyTableModel";
298 if ( !m_pDataWindow
)
299 return "invalid data window!";
301 if ( m_pModel
->getColumnCount() != m_nColumnCount
)
302 return "column counts are inconsistent!";
304 if ( m_pModel
->getRowCount() != m_nRowCount
)
305 return "row counts are inconsistent!";
307 if ( ( ( m_nCurColumn
!= COL_INVALID
) && !m_aColumnWidths
.empty() && ( m_nCurColumn
< 0 ) ) || ( m_nCurColumn
>= (ColPos
)m_aColumnWidths
.size() ) )
308 return "current column is invalid!";
310 if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nTopRow
, (RowPos
)-1, m_nRowCount
, getModel(), (RowPos
)0 ) )
311 return "invalid top row value!";
313 if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nCurRow
, (RowPos
)-1, m_nRowCount
, getModel(), ROW_INVALID
) )
314 return "invalid current row value!";
316 if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nLeftColumn
, (ColPos
)-1, m_nColumnCount
, getModel(), (ColPos
)0 ) )
317 return "invalid current column value!";
319 if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nCurColumn
, (ColPos
)-1, m_nColumnCount
, getModel(), COL_INVALID
) )
320 return "invalid current column value!";
322 if ( m_pInputHandler
!= m_pModel
->getInputHandler() )
323 return "input handler is not the model-provided one!";
325 // m_aSelectedRows should have reasonable content
327 if ( m_aSelectedRows
.size() > size_t( m_pModel
->getRowCount() ) )
328 return "there are more rows selected than actually exist";
329 for ( ::std::vector
< RowPos
>::const_iterator selRow
= m_aSelectedRows
.begin();
330 selRow
!= m_aSelectedRows
.end();
334 if ( ( *selRow
< 0 ) || ( *selRow
>= m_pModel
->getRowCount() ) )
335 return "a non-existent row is selected";
339 // m_nColHeaderHeightPixel consistent with the model's value?
341 TableMetrics nHeaderHeight
= m_pModel
->hasColumnHeaders() ? m_pModel
->getColumnHeaderHeight() : 0;
342 nHeaderHeight
= m_rAntiImpl
.LogicToPixel( Size( 0, nHeaderHeight
), MAP_APPFONT
).Height();
343 if ( nHeaderHeight
!= m_nColHeaderHeightPixel
)
344 return "column header heights are inconsistent!";
347 bool isDummyModel
= dynamic_cast< const EmptyTableModel
* >( m_pModel
.get() ) != NULL
;
350 TableMetrics nRowHeight
= m_pModel
->getRowHeight();
351 nRowHeight
= m_rAntiImpl
.LogicToPixel( Size( 0, nRowHeight
), MAP_APPFONT
).Height();
352 if ( nRowHeight
!= m_nRowHeightPixel
)
353 return "row heights are inconsistent!";
356 // m_nRowHeaderWidthPixel consistent with the model's value?
358 TableMetrics nHeaderWidth
= m_pModel
->hasRowHeaders() ? m_pModel
->getRowHeaderWidth() : 0;
359 nHeaderWidth
= m_rAntiImpl
.LogicToPixel( Size( nHeaderWidth
, 0 ), MAP_APPFONT
).Width();
360 if ( nHeaderWidth
!= m_nRowHeaderWidthPixel
)
361 return "row header widths are inconsistent!";
364 // m_aColumnWidths consistency
365 if ( size_t( m_nColumnCount
) != m_aColumnWidths
.size() )
366 return "wrong number of cached column widths";
368 for ( ColumnPositions::const_iterator col
= m_aColumnWidths
.begin();
369 col
!= m_aColumnWidths
.end();
372 if ( col
->getEnd() < col
->getStart() )
373 return "column widths: 'end' is expected to not be smaller than start";
375 ColumnPositions::const_iterator nextCol
= col
+ 1;
376 if ( nextCol
!= m_aColumnWidths
.end() )
377 if ( col
->getEnd() != nextCol
->getStart() )
378 return "column widths: one column's end should be the next column's start";
382 if ( m_nLeftColumn
< m_nColumnCount
)
383 if ( m_aColumnWidths
[ m_nLeftColumn
].getStart() != m_nRowHeaderWidthPixel
)
384 return "the left-most column should start immediately after the row header";
386 if ( m_nCursorHidden
< 0 )
387 return "invalid hidden count for the cursor!";
389 if ( ( m_nRequiredInvariants
& INV_SCROLL_POSITION
) && m_pVScroll
)
391 DBG_SUSPEND_INV( INV_SCROLL_POSITION
);
392 // prevent infinite recursion
394 if ( m_nLeftColumn
< 0 )
395 return "invalid left-most column index";
396 if ( m_pVScroll
->GetThumbPos() != m_nTopRow
)
397 return "vertical scroll bar |position| is incorrect!";
398 if ( m_pVScroll
->GetRange().Max() != m_nRowCount
)
399 return "vertical scroll bar |range| is incorrect!";
400 if ( m_pVScroll
->GetVisibleSize() != impl_getVisibleRows( false ) )
401 return "vertical scroll bar |visible size| is incorrect!";
404 if ( ( m_nRequiredInvariants
& INV_SCROLL_POSITION
) && m_pHScroll
)
406 DBG_SUSPEND_INV( INV_SCROLL_POSITION
);
407 // prevent infinite recursion
409 if ( m_pHScroll
->GetThumbPos() != m_nLeftColumn
)
410 return "horizontal scroll bar |position| is incorrect!";
411 if ( m_pHScroll
->GetRange().Max() != m_nColumnCount
)
412 return "horizontal scroll bar |range| is incorrect!";
413 if ( m_pHScroll
->GetVisibleSize() != impl_getVisibleColumns( false ) )
414 return "horizontal scroll bar |visible size| is incorrect!";
421 #define DBG_CHECK_ME() \
422 DBG_CHKTHIS( TableControl_Impl, TableControl_Impl_checkInvariants )
424 //------------------------------------------------------------------------------------------------------------------
425 TableControl_Impl::TableControl_Impl( TableControl
& _rAntiImpl
)
426 :m_rAntiImpl ( _rAntiImpl
)
427 ,m_pModel ( new EmptyTableModel
)
429 ,m_nRowHeightPixel ( 15 )
430 ,m_nColHeaderHeightPixel( 0 )
431 ,m_nRowHeaderWidthPixel ( 0 )
432 ,m_nColumnCount ( 0 )
434 ,m_bColumnsFit ( true )
435 ,m_nCurColumn ( COL_INVALID
)
436 ,m_nCurRow ( ROW_INVALID
)
439 ,m_nCursorHidden ( 1 )
440 ,m_pDataWindow ( new TableDataWindow( *this ) )
443 ,m_pScrollCorner ( NULL
)
446 ,m_pTableFunctionSet ( new TableFunctionSet( this ) )
448 ,m_bUpdatingColWidths ( false )
449 ,m_pAccessibleTable ( NULL
)
451 ,m_nRequiredInvariants ( INV_SCROLL_POSITION
)
454 DBG_CTOR( TableControl_Impl
, TableControl_Impl_checkInvariants
);
455 m_pSelEngine
= new SelectionEngine( m_pDataWindow
.get(), m_pTableFunctionSet
);
456 m_pSelEngine
->SetSelectionMode(SINGLE_SELECTION
);
457 m_pDataWindow
->SetPosPixel( Point( 0, 0 ) );
458 m_pDataWindow
->Show();
461 //------------------------------------------------------------------------------------------------------------------
462 TableControl_Impl::~TableControl_Impl()
464 DBG_DTOR( TableControl_Impl
, TableControl_Impl_checkInvariants
);
466 DELETEZ( m_pVScroll
);
467 DELETEZ( m_pHScroll
);
468 DELETEZ( m_pScrollCorner
);
469 DELETEZ( m_pTableFunctionSet
);
470 DELETEZ( m_pSelEngine
);
473 //------------------------------------------------------------------------------------------------------------------
474 void TableControl_Impl::setModel( PTableModel _pModel
)
478 SuppressCursor
aHideCursor( *this );
481 m_pModel
->removeTableModelListener( shared_from_this() );
485 m_pModel
.reset( new EmptyTableModel
);
487 m_pModel
->addTableModelListener( shared_from_this() );
489 m_nCurRow
= ROW_INVALID
;
490 m_nCurColumn
= COL_INVALID
;
492 // recalc some model-dependent cached info
493 impl_ni_updateCachedModelValues();
496 // completely invalidate
497 m_rAntiImpl
.Invalidate();
499 // reset cursor to (0,0)
500 if ( m_nRowCount
) m_nCurRow
= 0;
501 if ( m_nColumnCount
) m_nCurColumn
= 0;
504 //------------------------------------------------------------------------------------------------------------------
507 bool lcl_adjustSelectedRows( ::std::vector
< RowPos
>& io_selectionIndexes
, RowPos
const i_firstAffectedRowIndex
, TableSize
const i_offset
)
509 bool didChanges
= false;
510 for ( ::std::vector
< RowPos
>::iterator selPos
= io_selectionIndexes
.begin();
511 selPos
!= io_selectionIndexes
.end();
515 if ( *selPos
< i_firstAffectedRowIndex
)
524 //------------------------------------------------------------------------------------------------------------------
525 void TableControl_Impl::rowsInserted( RowPos i_first
, RowPos i_last
)
528 OSL_PRECOND( i_last
>= i_first
, "TableControl_Impl::rowsInserted: invalid row indexes!" );
530 TableSize
const insertedRows
= i_last
- i_first
+ 1;
532 // adjust selection, if necessary
533 bool const selectionChanged
= lcl_adjustSelectedRows( m_aSelectedRows
, i_first
, insertedRows
);
535 // adjust our cached row count
536 m_nRowCount
= m_pModel
->getRowCount();
538 // if the rows have been inserted before the current row, adjust this
539 if ( i_first
<= m_nCurRow
)
540 goTo( m_nCurColumn
, m_nCurRow
+ insertedRows
);
542 // relayout, since the scrollbar need might have changed
545 // notify A1YY events
546 if ( impl_isAccessibleAlive() )
548 impl_commitAccessibleEvent( AccessibleEventId::TABLE_MODEL_CHANGED
,
549 makeAny( AccessibleTableModelChange( AccessibleTableModelChangeType::INSERT
, i_first
, i_last
, 0, m_pModel
->getColumnCount() ) ),
555 invalidateRowRange( i_first
, ROW_INVALID
);
557 // call selection handlers, if necessary
558 if ( selectionChanged
)
559 m_rAntiImpl
.Select();
562 //------------------------------------------------------------------------------------------------------------------
563 void TableControl_Impl::rowsRemoved( RowPos i_first
, RowPos i_last
)
565 sal_Int32 firstRemovedRow
= i_first
;
566 sal_Int32 lastRemovedRow
= i_last
;
568 // adjust selection, if necessary
569 bool selectionChanged
= false;
572 selectionChanged
= markAllRowsAsDeselected();
575 lastRemovedRow
= m_nRowCount
- 1;
579 ENSURE_OR_RETURN_VOID( i_last
>= i_first
, "TableControl_Impl::rowsRemoved: illegal indexes!" );
581 for ( sal_Int32 row
= i_first
; row
<= i_last
; ++row
)
583 if ( markRowAsDeselected( row
) )
584 selectionChanged
= true;
587 if ( lcl_adjustSelectedRows( m_aSelectedRows
, i_last
+ 1, i_first
- i_last
- 1 ) )
588 selectionChanged
= true;
591 // adjust cached row count
592 m_nRowCount
= m_pModel
->getRowCount();
594 // adjust the current row, if it is larger than the row count now
595 if ( m_nCurRow
>= m_nRowCount
)
597 if ( m_nRowCount
> 0 )
598 goTo( m_nCurColumn
, m_nRowCount
- 1 );
601 m_nCurRow
= ROW_INVALID
;
605 else if ( m_nRowCount
== 0 )
611 // relayout, since the scrollbar need might have changed
614 // notify A11Y events
615 if ( impl_isAccessibleAlive() )
618 AccessibleEventId::TABLE_MODEL_CHANGED
,
619 makeAny( AccessibleTableModelChange(
620 AccessibleTableModelChangeType::DELETE
,
624 m_pModel
->getColumnCount()
630 // schedule a repaint
631 invalidateRowRange( firstRemovedRow
, ROW_INVALID
);
633 // call selection handlers, if necessary
634 if ( selectionChanged
)
635 m_rAntiImpl
.Select();
638 //------------------------------------------------------------------------------------------------------------------
639 void TableControl_Impl::columnInserted( ColPos
const i_colIndex
)
641 m_nColumnCount
= m_pModel
->getColumnCount();
644 m_rAntiImpl
.Invalidate();
646 OSL_UNUSED( i_colIndex
);
649 //------------------------------------------------------------------------------------------------------------------
650 void TableControl_Impl::columnRemoved( ColPos
const i_colIndex
)
652 m_nColumnCount
= m_pModel
->getColumnCount();
654 // adjust the current column, if it is larger than the column count now
655 if ( m_nCurColumn
>= m_nColumnCount
)
657 if ( m_nColumnCount
> 0 )
658 goTo( m_nCurColumn
- 1, m_nCurRow
);
660 m_nCurColumn
= COL_INVALID
;
665 m_rAntiImpl
.Invalidate();
667 OSL_UNUSED( i_colIndex
);
670 //------------------------------------------------------------------------------------------------------------------
671 void TableControl_Impl::allColumnsRemoved()
673 m_nColumnCount
= m_pModel
->getColumnCount();
676 m_rAntiImpl
.Invalidate();
679 //------------------------------------------------------------------------------------------------------------------
680 void TableControl_Impl::cellsUpdated( ColPos
const i_firstCol
, ColPos i_lastCol
, RowPos
const i_firstRow
, RowPos
const i_lastRow
)
682 invalidateRowRange( i_firstRow
, i_lastRow
);
684 OSL_UNUSED( i_firstCol
);
685 OSL_UNUSED( i_lastCol
);
688 //------------------------------------------------------------------------------------------------------------------
689 void TableControl_Impl::tableMetricsChanged()
691 impl_ni_updateCachedTableMetrics();
693 m_rAntiImpl
.Invalidate();
696 //------------------------------------------------------------------------------------------------------------------
697 void TableControl_Impl::impl_invalidateColumn( ColPos
const i_column
)
701 Rectangle
const aAllCellsArea( impl_getAllVisibleCellsArea() );
703 const TableColumnGeometry
aColumn( *this, aAllCellsArea
, i_column
);
704 if ( aColumn
.isValid() )
705 m_rAntiImpl
.Invalidate( aColumn
.getRect() );
708 //------------------------------------------------------------------------------------------------------------------
709 void TableControl_Impl::columnChanged( ColPos
const i_column
, ColumnAttributeGroup
const i_attributeGroup
)
711 ColumnAttributeGroup
nGroup( i_attributeGroup
);
712 if ( nGroup
& COL_ATTRS_APPEARANCE
)
714 impl_invalidateColumn( i_column
);
715 nGroup
&= ~COL_ATTRS_APPEARANCE
;
718 if ( nGroup
& COL_ATTRS_WIDTH
)
720 if ( !m_bUpdatingColWidths
)
722 impl_ni_relayout( i_column
);
723 invalidate( TableAreaAll
);
726 nGroup
&= ~COL_ATTRS_WIDTH
;
729 OSL_ENSURE( ( nGroup
== COL_ATTRS_NONE
) || ( i_attributeGroup
== COL_ATTRS_ALL
),
730 "TableControl_Impl::columnChanged: don't know how to handle this change!" );
733 //------------------------------------------------------------------------------------------------------------------
734 Rectangle
TableControl_Impl::impl_getAllVisibleCellsArea() const
738 Rectangle
aArea( Point( 0, 0 ), Size( 0, 0 ) );
740 // determine the right-most border of the last column which is
741 // at least partially visible
742 aArea
.Right() = m_nRowHeaderWidthPixel
;
743 if ( !m_aColumnWidths
.empty() )
745 // the number of pixels which are scrolled out of the left hand
746 // side of the window
747 const long nScrolledOutLeft
= m_nLeftColumn
== 0 ? 0 : m_aColumnWidths
[ m_nLeftColumn
- 1 ].getEnd();
749 ColumnPositions::const_reverse_iterator loop
= m_aColumnWidths
.rbegin();
752 aArea
.Right() = loop
->getEnd() - nScrolledOutLeft
+ m_nRowHeaderWidthPixel
;
755 while ( ( loop
!= m_aColumnWidths
.rend() )
756 && ( loop
->getEnd() - nScrolledOutLeft
>= aArea
.Right() )
759 // so far, aArea.Right() denotes the first pixel *after* the cell area
762 // determine the last row which is at least partially visible
764 m_nColHeaderHeightPixel
765 + impl_getVisibleRows( true ) * m_nRowHeightPixel
771 //------------------------------------------------------------------------------------------------------------------
772 Rectangle
TableControl_Impl::impl_getAllVisibleDataCellArea() const
776 Rectangle
aArea( impl_getAllVisibleCellsArea() );
777 aArea
.Left() = m_nRowHeaderWidthPixel
;
778 aArea
.Top() = m_nColHeaderHeightPixel
;
782 //------------------------------------------------------------------------------------------------------------------
783 void TableControl_Impl::impl_ni_updateCachedTableMetrics()
785 m_nRowHeightPixel
= m_rAntiImpl
.LogicToPixel( Size( 0, m_pModel
->getRowHeight() ), MAP_APPFONT
).Height();
787 m_nColHeaderHeightPixel
= 0;
788 if ( m_pModel
->hasColumnHeaders() )
789 m_nColHeaderHeightPixel
= m_rAntiImpl
.LogicToPixel( Size( 0, m_pModel
->getColumnHeaderHeight() ), MAP_APPFONT
).Height();
791 m_nRowHeaderWidthPixel
= 0;
792 if ( m_pModel
->hasRowHeaders() )
793 m_nRowHeaderWidthPixel
= m_rAntiImpl
.LogicToPixel( Size( m_pModel
->getRowHeaderWidth(), 0 ), MAP_APPFONT
).Width();
796 //------------------------------------------------------------------------------------------------------------------
797 void TableControl_Impl::impl_ni_updateCachedModelValues()
799 m_pInputHandler
= m_pModel
->getInputHandler();
800 if ( !m_pInputHandler
)
801 m_pInputHandler
.reset( new DefaultInputHandler
);
803 m_nColumnCount
= m_pModel
->getColumnCount();
804 if ( m_nLeftColumn
>= m_nColumnCount
)
805 m_nLeftColumn
= ( m_nColumnCount
> 0 ) ? m_nColumnCount
- 1 : 0;
807 m_nRowCount
= m_pModel
->getRowCount();
808 if ( m_nTopRow
>= m_nRowCount
)
809 m_nTopRow
= ( m_nRowCount
> 0 ) ? m_nRowCount
- 1 : 0;
811 impl_ni_updateCachedTableMetrics();
814 //------------------------------------------------------------------------------------------------------------------
817 //..............................................................................................................
818 /// determines whether a scrollbar is needed for the given values
819 bool lcl_determineScrollbarNeed( long const i_position
, ScrollbarVisibility
const i_visibility
,
820 long const i_availableSpace
, long const i_neededSpace
)
822 if ( i_visibility
== ScrollbarShowNever
)
824 if ( i_visibility
== ScrollbarShowAlways
)
826 if ( i_position
> 0 )
828 if ( i_availableSpace
>= i_neededSpace
)
833 //..............................................................................................................
834 void lcl_setButtonRepeat( Window
& _rWindow
, sal_uLong _nDelay
)
836 AllSettings aSettings
= _rWindow
.GetSettings();
837 MouseSettings aMouseSettings
= aSettings
.GetMouseSettings();
839 aMouseSettings
.SetButtonRepeat( _nDelay
);
840 aSettings
.SetMouseSettings( aMouseSettings
);
842 _rWindow
.SetSettings( aSettings
, sal_True
);
845 //..............................................................................................................
846 bool lcl_updateScrollbar( Window
& _rParent
, ScrollBar
*& _rpBar
,
847 bool const i_needBar
, long _nVisibleUnits
,
848 long _nPosition
, long _nLineSize
, long _nRange
,
849 bool _bHorizontal
, const Link
& _rScrollHandler
)
851 // do we currently have the scrollbar?
852 bool bHaveBar
= _rpBar
!= NULL
;
854 // do we need to correct the scrollbar visibility?
855 if ( bHaveBar
&& !i_needBar
)
857 if ( _rpBar
->IsTracking() )
858 _rpBar
->EndTracking();
861 else if ( !bHaveBar
&& i_needBar
)
863 _rpBar
= new ScrollBar(
865 WB_DRAG
| ( _bHorizontal
? WB_HSCROLL
: WB_VSCROLL
)
867 _rpBar
->SetScrollHdl( _rScrollHandler
);
868 // get some speed into the scrolling ....
869 lcl_setButtonRepeat( *_rpBar
, 0 );
874 _rpBar
->SetRange( Range( 0, _nRange
) );
875 _rpBar
->SetVisibleSize( _nVisibleUnits
);
876 _rpBar
->SetPageSize( _nVisibleUnits
);
877 _rpBar
->SetLineSize( _nLineSize
);
878 _rpBar
->SetThumbPos( _nPosition
);
882 return ( bHaveBar
!= i_needBar
);
885 //..............................................................................................................
886 /** returns the number of rows fitting into the given range,
887 for the given row height. Partially fitting rows are counted, too, if the
888 respective parameter says so.
890 TableSize
lcl_getRowsFittingInto( long _nOverallHeight
, long _nRowHeightPixel
, bool _bAcceptPartialRow
= false )
892 return _bAcceptPartialRow
893 ? ( _nOverallHeight
+ ( _nRowHeightPixel
- 1 ) ) / _nRowHeightPixel
894 : _nOverallHeight
/ _nRowHeightPixel
;
897 //..............................................................................................................
898 /** returns the number of columns fitting into the given area,
899 with the first visible column as given. Partially fitting columns are counted, too,
900 if the respective parameter says so.
902 TableSize
lcl_getColumnsVisibleWithin( const Rectangle
& _rArea
, ColPos _nFirstVisibleColumn
,
903 const TableControl_Impl
& _rControl
, bool _bAcceptPartialRow
)
905 TableSize visibleColumns
= 0;
906 TableColumnGeometry
aColumn( _rControl
, _rArea
, _nFirstVisibleColumn
);
907 while ( aColumn
.isValid() )
909 if ( !_bAcceptPartialRow
)
910 if ( aColumn
.getRect().Right() > _rArea
.Right() )
911 // this column is only partially visible, and this is not allowed
917 return visibleColumns
;
922 //------------------------------------------------------------------------------------------------------------------
923 long TableControl_Impl::impl_ni_calculateColumnWidths( ColPos
const i_assumeInflexibleColumnsUpToIncluding
,
924 bool const i_assumeVerticalScrollbar
, ::std::vector
< long >& o_newColWidthsPixel
) const
926 // the available horizontal space
927 long gridWidthPixel
= m_rAntiImpl
.GetOutputSizePixel().Width();
928 ENSURE_OR_RETURN( !!m_pModel
, "TableControl_Impl::impl_ni_calculateColumnWidths: not allowed without a model!", gridWidthPixel
);
929 if ( m_pModel
->hasRowHeaders() && ( gridWidthPixel
!= 0 ) )
931 gridWidthPixel
-= m_nRowHeaderWidthPixel
;
934 if ( i_assumeVerticalScrollbar
&& ( m_pModel
->getVerticalScrollbarVisibility() != ScrollbarShowNever
) )
936 long nScrollbarMetrics
= m_rAntiImpl
.GetSettings().GetStyleSettings().GetScrollBarSize();
937 gridWidthPixel
-= nScrollbarMetrics
;
940 // no need to do anything without columns
941 TableSize
const colCount
= m_pModel
->getColumnCount();
943 return gridWidthPixel
;
945 // collect some meta data for our columns:
946 // - their current (pixel) metrics
947 long accumulatedCurrentWidth
= 0;
948 ::std::vector
< long > currentColWidths
;
949 currentColWidths
.reserve( colCount
);
950 typedef ::std::vector
< ::std::pair
< long, long > > ColumnLimits
;
951 ColumnLimits effectiveColumnLimits
;
952 effectiveColumnLimits
.reserve( colCount
);
953 long accumulatedMinWidth
= 0;
954 long accumulatedMaxWidth
= 0;
955 // - their relative flexibility
956 ::std::vector
< ::sal_Int32
> columnFlexibilities
;
957 columnFlexibilities
.reserve( colCount
);
958 long flexibilityDenominator
= 0;
959 size_t flexibleColumnCount
= 0;
960 for ( ColPos col
= 0; col
< colCount
; ++col
)
962 PColumnModel
const pColumn
= m_pModel
->getColumnModel( col
);
963 ENSURE_OR_THROW( !!pColumn
, "invalid column returned by the model!" );
966 long const currentWidth
= appFontWidthToPixel( pColumn
->getWidth() );
967 currentColWidths
.push_back( currentWidth
);
970 accumulatedCurrentWidth
+= currentWidth
;
973 ::sal_Int32 flexibility
= pColumn
->getFlexibility();
974 OSL_ENSURE( flexibility
>= 0, "TableControl_Impl::impl_ni_calculateColumnWidths: a column's flexibility should be non-negative." );
975 if ( ( flexibility
< 0 ) // normalization
976 || ( !pColumn
->isResizable() ) // column not resizable => no auto-resize
977 || ( col
<= i_assumeInflexibleColumnsUpToIncluding
) // column shall be treated as inflexible => respec this
982 long effectiveMin
= currentWidth
, effectiveMax
= currentWidth
;
983 // if the column is not flexible, it will not be asked for min/max, but we assume the current width as limit then
984 if ( flexibility
> 0 )
986 long const minWidth
= appFontWidthToPixel( pColumn
->getMinWidth() );
988 effectiveMin
= minWidth
;
990 effectiveMin
= MIN_COLUMN_WIDTH_PIXEL
;
992 long const maxWidth
= appFontWidthToPixel( pColumn
->getMaxWidth() );
993 OSL_ENSURE( minWidth
<= maxWidth
, "TableControl_Impl::impl_ni_calculateColumnWidths: pretty undecided 'bout its width limits, this column!" );
994 if ( ( maxWidth
> 0 ) && ( maxWidth
>= minWidth
) )
995 effectiveMax
= maxWidth
;
997 effectiveMax
= gridWidthPixel
; // TODO: any better guess here?
999 if ( effectiveMin
== effectiveMax
)
1000 // if the min and the max are identical, this implies no flexibility at all
1004 columnFlexibilities
.push_back( flexibility
);
1005 flexibilityDenominator
+= flexibility
;
1006 if ( flexibility
> 0 )
1007 ++flexibleColumnCount
;
1009 effectiveColumnLimits
.push_back( ::std::pair
< long, long >( effectiveMin
, effectiveMax
) );
1010 accumulatedMinWidth
+= effectiveMin
;
1011 accumulatedMaxWidth
+= effectiveMax
;
1014 o_newColWidthsPixel
= currentColWidths
;
1015 if ( flexibilityDenominator
== 0 )
1017 // no column is flexible => don't adjust anything
1019 else if ( gridWidthPixel
> accumulatedCurrentWidth
)
1020 { // we have space to give away ...
1021 long distributePixel
= gridWidthPixel
- accumulatedCurrentWidth
;
1022 if ( gridWidthPixel
> accumulatedMaxWidth
)
1024 // ... but the column's maximal widths are still less than we have
1025 // => set them all to max
1026 for ( size_t i
= 0; i
< size_t( colCount
); ++i
)
1028 o_newColWidthsPixel
[i
] = effectiveColumnLimits
[i
].second
;
1033 bool startOver
= false;
1037 // distribute the remaining space amongst all columns with a positive flexibility
1038 for ( size_t i
=0; i
<o_newColWidthsPixel
.size() && !startOver
; ++i
)
1040 long const columnFlexibility
= columnFlexibilities
[i
];
1041 if ( columnFlexibility
== 0 )
1044 long newColWidth
= currentColWidths
[i
] + columnFlexibility
* distributePixel
/ flexibilityDenominator
;
1046 if ( newColWidth
> effectiveColumnLimits
[i
].second
)
1047 { // that was too much, we hit the col's maximum
1048 // set the new width to exactly this maximum
1049 newColWidth
= effectiveColumnLimits
[i
].second
;
1050 // adjust the flexibility denominator ...
1051 flexibilityDenominator
-= columnFlexibility
;
1052 columnFlexibilities
[i
] = 0;
1053 --flexibleColumnCount
;
1054 // ... and the remaining width ...
1055 long const difference
= newColWidth
- currentColWidths
[i
];
1056 distributePixel
-= difference
;
1057 // ... this way, we ensure that the width not taken up by this column is consumed by the other
1058 // flexible ones (if there are some)
1060 // and start over with the first column, since there might be earlier columns which need
1061 // to be recalculated now
1065 o_newColWidthsPixel
[i
] = newColWidth
;
1068 while ( startOver
);
1070 // are there pixels left (might be caused by rounding errors)?
1071 distributePixel
= gridWidthPixel
- ::std::accumulate( o_newColWidthsPixel
.begin(), o_newColWidthsPixel
.end(), 0 );
1072 while ( ( distributePixel
> 0 ) && ( flexibleColumnCount
> 0 ) )
1074 // yes => ignore relative flexibilities, and subsequently distribute single pixels to all flexible
1075 // columns which did not yet reach their maximum.
1076 for ( size_t i
=0; ( i
< o_newColWidthsPixel
.size() ) && ( distributePixel
> 0 ); ++i
)
1078 if ( columnFlexibilities
[i
] == 0 )
1081 OSL_ENSURE( o_newColWidthsPixel
[i
] <= effectiveColumnLimits
[i
].second
,
1082 "TableControl_Impl::impl_ni_calculateColumnWidths: inconsitency!" );
1083 if ( o_newColWidthsPixel
[i
] >= effectiveColumnLimits
[i
].first
)
1085 columnFlexibilities
[i
] = 0;
1086 --flexibleColumnCount
;
1090 ++o_newColWidthsPixel
[i
];
1096 else if ( gridWidthPixel
< accumulatedCurrentWidth
)
1097 { // we need to take away some space from the columns which allow it ...
1098 long takeAwayPixel
= accumulatedCurrentWidth
- gridWidthPixel
;
1099 if ( gridWidthPixel
< accumulatedMinWidth
)
1101 // ... but the column's minimal widths are still more than we have
1102 // => set them all to min
1103 for ( size_t i
= 0; i
< size_t( colCount
); ++i
)
1105 o_newColWidthsPixel
[i
] = effectiveColumnLimits
[i
].first
;
1110 bool startOver
= false;
1114 // take away the space we need from the columns with a positive flexibility
1115 for ( size_t i
=0; i
<o_newColWidthsPixel
.size() && !startOver
; ++i
)
1117 long const columnFlexibility
= columnFlexibilities
[i
];
1118 if ( columnFlexibility
== 0 )
1121 long newColWidth
= currentColWidths
[i
] - columnFlexibility
* takeAwayPixel
/ flexibilityDenominator
;
1123 if ( newColWidth
< effectiveColumnLimits
[i
].first
)
1124 { // that was too much, we hit the col's minimum
1125 // set the new width to exactly this minimum
1126 newColWidth
= effectiveColumnLimits
[i
].first
;
1127 // adjust the flexibility denominator ...
1128 flexibilityDenominator
-= columnFlexibility
;
1129 columnFlexibilities
[i
] = 0;
1130 --flexibleColumnCount
;
1131 // ... and the remaining width ...
1132 long const difference
= currentColWidths
[i
] - newColWidth
;
1133 takeAwayPixel
-= difference
;
1135 // and start over with the first column, since there might be earlier columns which need
1136 // to be recalculated now
1140 o_newColWidthsPixel
[i
] = newColWidth
;
1143 while ( startOver
);
1145 // are there pixels left (might be caused by rounding errors)?
1146 takeAwayPixel
= ::std::accumulate( o_newColWidthsPixel
.begin(), o_newColWidthsPixel
.end(), 0 ) - gridWidthPixel
;
1147 while ( ( takeAwayPixel
> 0 ) && ( flexibleColumnCount
> 0 ) )
1149 // yes => ignore relative flexibilities, and subsequently take away pixels from all flexible
1150 // columns which did not yet reach their minimum.
1151 for ( size_t i
=0; ( i
< o_newColWidthsPixel
.size() ) && ( takeAwayPixel
> 0 ); ++i
)
1153 if ( columnFlexibilities
[i
] == 0 )
1156 OSL_ENSURE( o_newColWidthsPixel
[i
] >= effectiveColumnLimits
[i
].first
,
1157 "TableControl_Impl::impl_ni_calculateColumnWidths: inconsitency!" );
1158 if ( o_newColWidthsPixel
[i
] <= effectiveColumnLimits
[i
].first
)
1160 columnFlexibilities
[i
] = 0;
1161 --flexibleColumnCount
;
1165 --o_newColWidthsPixel
[i
];
1172 return gridWidthPixel
;
1175 //------------------------------------------------------------------------------------------------------------------
1176 void TableControl_Impl::impl_ni_relayout( ColPos
const i_assumeInflexibleColumnsUpToIncluding
)
1178 ENSURE_OR_RETURN_VOID( !m_bUpdatingColWidths
, "TableControl_Impl::impl_ni_relayout: recursive call detected!" );
1180 m_aColumnWidths
.resize( 0 );
1184 ::comphelper::FlagRestorationGuard
const aWidthUpdateFlag( m_bUpdatingColWidths
, true );
1185 SuppressCursor
aHideCursor( *this );
1189 // 1. adjust column widths, leaving space for a vertical scrollbar
1190 // 2. determine need for a vertical scrollbar
1191 // - V-YES: all fine, result from 1. is still valid
1192 // - V-NO: result from 1. is still under consideration
1194 // 3. determine need for a horizontal scrollbar
1195 // - H-NO: all fine, result from 2. is still valid
1196 // - H-YES: reconsider need for a vertical scrollbar, if result of 2. was V-NO
1197 // - V-YES: all fine, result from 1. is still valid
1198 // - V-NO: redistribute the remaining space (if any) amongst all columns which allow it
1200 ::std::vector
< long > newWidthsPixel
;
1201 long gridWidthPixel
= impl_ni_calculateColumnWidths( i_assumeInflexibleColumnsUpToIncluding
, true, newWidthsPixel
);
1203 // the width/height of a scrollbar, needed several times below
1204 long const nScrollbarMetrics
= m_rAntiImpl
.GetSettings().GetStyleSettings().GetScrollBarSize();
1206 // determine the playground for the data cells (excluding headers)
1207 // TODO: what if the control is smaller than needed for the headers/scrollbars?
1208 Rectangle
aDataCellPlayground( Point( 0, 0 ), m_rAntiImpl
.GetOutputSizePixel() );
1209 aDataCellPlayground
.Left() = m_nRowHeaderWidthPixel
;
1210 aDataCellPlayground
.Top() = m_nColHeaderHeightPixel
;
1212 OSL_ENSURE( ( m_nRowCount
== m_pModel
->getRowCount() ) && ( m_nColumnCount
== m_pModel
->getColumnCount() ),
1213 "TableControl_Impl::impl_ni_relayout: how is this expected to work with invalid data?" );
1214 long const nAllColumnsWidth
= ::std::accumulate( newWidthsPixel
.begin(), newWidthsPixel
.end(), 0 );
1216 ScrollbarVisibility
const eVertScrollbar
= m_pModel
->getVerticalScrollbarVisibility();
1217 ScrollbarVisibility
const eHorzScrollbar
= m_pModel
->getHorizontalScrollbarVisibility();
1219 // do we need a vertical scrollbar?
1220 bool bNeedVerticalScrollbar
= lcl_determineScrollbarNeed(
1221 m_nTopRow
, eVertScrollbar
, aDataCellPlayground
.GetHeight(), m_nRowHeightPixel
* m_nRowCount
);
1222 bool bFirstRoundVScrollNeed
= false;
1223 if ( bNeedVerticalScrollbar
)
1225 aDataCellPlayground
.Right() -= nScrollbarMetrics
;
1226 bFirstRoundVScrollNeed
= true;
1229 // do we need a horizontal scrollbar?
1230 bool const bNeedHorizontalScrollbar
= lcl_determineScrollbarNeed(
1231 m_nLeftColumn
, eHorzScrollbar
, aDataCellPlayground
.GetWidth(), nAllColumnsWidth
);
1232 if ( bNeedHorizontalScrollbar
)
1234 aDataCellPlayground
.Bottom() -= nScrollbarMetrics
;
1236 // now that we just found that we need a horizontal scrollbar,
1237 // the need for a vertical one may have changed, since the horizontal
1238 // SB might just occupy enough space so that not all rows do fit
1240 if ( !bFirstRoundVScrollNeed
)
1242 bNeedVerticalScrollbar
= lcl_determineScrollbarNeed(
1243 m_nTopRow
, eVertScrollbar
, aDataCellPlayground
.GetHeight(), m_nRowHeightPixel
* m_nRowCount
);
1244 if ( bNeedVerticalScrollbar
)
1246 aDataCellPlayground
.Right() -= nScrollbarMetrics
;
1251 // the initial call to impl_ni_calculateColumnWidths assumed that we need a vertical scrollbar. If, by now,
1252 // we know that this is not the case, re-calculate the column widths.
1253 if ( !bNeedVerticalScrollbar
)
1254 gridWidthPixel
= impl_ni_calculateColumnWidths( i_assumeInflexibleColumnsUpToIncluding
, false, newWidthsPixel
);
1256 // update the column objects with the new widths we finally calculated
1257 TableSize
const colCount
= m_pModel
->getColumnCount();
1258 m_aColumnWidths
.reserve( colCount
);
1259 long accumulatedWidthPixel
= m_nRowHeaderWidthPixel
;
1260 bool anyColumnWidthChanged
= false;
1261 for ( ColPos col
= 0; col
< colCount
; ++col
)
1263 const long columnStart
= accumulatedWidthPixel
;
1264 const long columnEnd
= columnStart
+ newWidthsPixel
[col
];
1265 m_aColumnWidths
.push_back( MutableColumnMetrics( columnStart
, columnEnd
) );
1266 accumulatedWidthPixel
= columnEnd
;
1268 // and don't forget to forward this to the column models
1269 PColumnModel
const pColumn
= m_pModel
->getColumnModel( col
);
1270 ENSURE_OR_THROW( !!pColumn
, "invalid column returned by the model!" );
1272 long const oldColumnWidthAppFont
= pColumn
->getWidth();
1273 long const newColumnWidthAppFont
= pixelWidthToAppFont( newWidthsPixel
[col
] );
1274 pColumn
->setWidth( newColumnWidthAppFont
);
1276 anyColumnWidthChanged
|= ( oldColumnWidthAppFont
!= newColumnWidthAppFont
);
1279 // if the column widths changed, ensure everything is repainted
1280 if ( anyColumnWidthChanged
)
1281 invalidate( TableAreaAll
);
1283 // if the column resizing happened to leave some space at the right, but there are columns
1284 // scrolled out to the left, scroll them in
1285 while ( ( m_nLeftColumn
> 0 )
1286 && ( accumulatedWidthPixel
- m_aColumnWidths
[ m_nLeftColumn
- 1 ].getStart() <= gridWidthPixel
)
1292 // now adjust the column metrics, since they currently ignore the horizontal scroll position
1293 if ( m_nLeftColumn
> 0 )
1295 const long offsetPixel
= m_aColumnWidths
[ 0 ].getStart() - m_aColumnWidths
[ m_nLeftColumn
].getStart();
1296 for ( ColumnPositions::iterator colPos
= m_aColumnWidths
.begin();
1297 colPos
!= m_aColumnWidths
.end();
1301 colPos
->move( offsetPixel
);
1305 // show or hide the scrollbars as needed, and position the data window
1306 impl_ni_positionChildWindows( aDataCellPlayground
, bNeedVerticalScrollbar
, bNeedHorizontalScrollbar
);
1309 //------------------------------------------------------------------------------------------------------------------
1310 void TableControl_Impl::impl_ni_positionChildWindows( Rectangle
const & i_dataCellPlayground
,
1311 bool const i_verticalScrollbar
, bool const i_horizontalScrollbar
)
1313 long const nScrollbarMetrics
= m_rAntiImpl
.GetSettings().GetStyleSettings().GetScrollBarSize();
1315 // create or destroy the vertical scrollbar, as needed
1316 lcl_updateScrollbar(
1319 i_verticalScrollbar
,
1320 lcl_getRowsFittingInto( i_dataCellPlayground
.GetHeight(), m_nRowHeightPixel
),
1322 m_nTopRow
, // current position
1324 m_nRowCount
, // range
1326 LINK( this, TableControl_Impl
, OnScroll
) // scroll handler
1332 Rectangle
aScrollbarArea(
1333 Point( i_dataCellPlayground
.Right() + 1, 0 ),
1334 Size( nScrollbarMetrics
, i_dataCellPlayground
.Bottom() + 1 )
1336 m_pVScroll
->SetPosSizePixel(
1337 aScrollbarArea
.TopLeft(), aScrollbarArea
.GetSize() );
1340 // create or destroy the horizontal scrollbar, as needed
1341 lcl_updateScrollbar(
1344 i_horizontalScrollbar
,
1345 lcl_getColumnsVisibleWithin( i_dataCellPlayground
, m_nLeftColumn
, *this, false ),
1347 m_nLeftColumn
, // current position
1349 m_nColumnCount
, // range
1351 LINK( this, TableControl_Impl
, OnScroll
) // scroll handler
1357 TableSize
const nVisibleUnits
= lcl_getColumnsVisibleWithin( i_dataCellPlayground
, m_nLeftColumn
, *this, false );
1358 TableMetrics
const nRange
= m_nColumnCount
;
1359 if( m_nLeftColumn
+ nVisibleUnits
== nRange
- 1 )
1361 if ( m_aColumnWidths
[ nRange
- 1 ].getStart() - m_aColumnWidths
[ m_nLeftColumn
].getEnd() + m_aColumnWidths
[ nRange
-1 ].getWidth() > i_dataCellPlayground
.GetWidth() )
1363 m_pHScroll
->SetVisibleSize( nVisibleUnits
-1 );
1364 m_pHScroll
->SetPageSize( nVisibleUnits
- 1 );
1367 Rectangle
aScrollbarArea(
1368 Point( 0, i_dataCellPlayground
.Bottom() + 1 ),
1369 Size( i_dataCellPlayground
.Right() + 1, nScrollbarMetrics
)
1371 m_pHScroll
->SetPosSizePixel(
1372 aScrollbarArea
.TopLeft(), aScrollbarArea
.GetSize() );
1375 // the corner window connecting the two scrollbars in the lower right corner
1376 bool bHaveScrollCorner
= NULL
!= m_pScrollCorner
;
1377 bool bNeedScrollCorner
= ( NULL
!= m_pHScroll
) && ( NULL
!= m_pVScroll
);
1378 if ( bHaveScrollCorner
&& !bNeedScrollCorner
)
1380 DELETEZ( m_pScrollCorner
);
1382 else if ( !bHaveScrollCorner
&& bNeedScrollCorner
)
1384 m_pScrollCorner
= new ScrollBarBox( &m_rAntiImpl
);
1385 m_pScrollCorner
->SetSizePixel( Size( nScrollbarMetrics
, nScrollbarMetrics
) );
1386 m_pScrollCorner
->SetPosPixel( Point( i_dataCellPlayground
.Right() + 1, i_dataCellPlayground
.Bottom() + 1 ) );
1387 m_pScrollCorner
->Show();
1389 else if(bHaveScrollCorner
&& bNeedScrollCorner
)
1391 m_pScrollCorner
->SetPosPixel( Point( i_dataCellPlayground
.Right() + 1, i_dataCellPlayground
.Bottom() + 1 ) );
1392 m_pScrollCorner
->Show();
1395 // resize the data window
1396 m_pDataWindow
->SetSizePixel( Size(
1397 i_dataCellPlayground
.GetWidth() + m_nRowHeaderWidthPixel
,
1398 i_dataCellPlayground
.GetHeight() + m_nColHeaderHeightPixel
1402 //------------------------------------------------------------------------------------------------------------------
1403 void TableControl_Impl::onResize()
1408 checkCursorPosition();
1411 //------------------------------------------------------------------------------------------------------------------
1412 void TableControl_Impl::doPaintContent( const Rectangle
& _rUpdateRect
)
1418 PTableRenderer pRenderer
= getModel()->getRenderer();
1419 DBG_ASSERT( !!pRenderer
, "TableDataWindow::doPaintContent: invalid renderer!" );
1423 // our current style settings, to be passed to the renderer
1424 const StyleSettings
& rStyle
= m_rAntiImpl
.GetSettings().GetStyleSettings();
1425 m_nRowCount
= m_pModel
->getRowCount();
1426 // the area occupied by all (at least partially) visible cells, including
1428 Rectangle
const aAllCellsWithHeaders( impl_getAllVisibleCellsArea() );
1430 // ............................
1431 // draw the header column area
1432 if ( m_pModel
->hasColumnHeaders() )
1434 TableRowGeometry
const aHeaderRow( *this, Rectangle( Point( 0, 0 ),
1435 aAllCellsWithHeaders
.BottomRight() ), ROW_COL_HEADERS
);
1436 Rectangle
const aColRect(aHeaderRow
.getRect());
1437 pRenderer
->PaintHeaderArea(
1438 *m_pDataWindow
, aColRect
, true, false, rStyle
1440 // Note that strictly, aHeaderRow.getRect() also contains the intersection between column
1441 // and row header area. However, below we go to paint this intersection, again,
1442 // so this hopefully doesn't hurt if we already paint it here.
1444 for ( TableCellGeometry
aCell( aHeaderRow
, m_nLeftColumn
);
1449 if ( _rUpdateRect
.GetIntersection( aCell
.getRect() ).IsEmpty() )
1452 bool isActiveColumn
= ( aCell
.getColumn() == getCurrentColumn() );
1453 bool isSelectedColumn
= false;
1454 pRenderer
->PaintColumnHeader( aCell
.getColumn(), isActiveColumn
, isSelectedColumn
,
1455 *m_pDataWindow
, aCell
.getRect(), rStyle
);
1458 // the area occupied by the row header, if any
1459 Rectangle aRowHeaderArea
;
1460 if ( m_pModel
->hasRowHeaders() )
1462 aRowHeaderArea
= aAllCellsWithHeaders
;
1463 aRowHeaderArea
.Right() = m_nRowHeaderWidthPixel
- 1;
1465 TableSize
const nVisibleRows
= impl_getVisibleRows( true );
1466 TableSize nActualRows
= nVisibleRows
;
1467 if ( m_nTopRow
+ nActualRows
> m_nRowCount
)
1468 nActualRows
= m_nRowCount
- m_nTopRow
;
1469 aRowHeaderArea
.Bottom() = m_nColHeaderHeightPixel
+ m_nRowHeightPixel
* nActualRows
- 1;
1471 pRenderer
->PaintHeaderArea( *m_pDataWindow
, aRowHeaderArea
, false, true, rStyle
);
1472 // Note that strictly, aRowHeaderArea also contains the intersection between column
1473 // and row header area. However, below we go to paint this intersection, again,
1474 // so this hopefully doesn't hurt if we already paint it here.
1476 if ( m_pModel
->hasColumnHeaders() )
1478 TableCellGeometry
const aIntersection( *this, Rectangle( Point( 0, 0 ),
1479 aAllCellsWithHeaders
.BottomRight() ), COL_ROW_HEADERS
, ROW_COL_HEADERS
);
1480 Rectangle
const aInters( aIntersection
.getRect() );
1481 pRenderer
->PaintHeaderArea(
1482 *m_pDataWindow
, aInters
, true, true, rStyle
1487 // ............................
1488 // draw the table content row by row
1490 TableSize colCount
= getModel()->getColumnCount();
1493 Rectangle
const aAllDataCellsArea( impl_getAllVisibleDataCellArea() );
1494 for ( TableRowGeometry
aRowIterator( *this, aAllCellsWithHeaders
, getTopRow() );
1495 aRowIterator
.isValid();
1496 aRowIterator
.moveDown() )
1498 if ( _rUpdateRect
.GetIntersection( aRowIterator
.getRect() ).IsEmpty() )
1501 bool const isControlFocused
= m_rAntiImpl
.HasControlFocus();
1502 bool const isSelectedRow
= isRowSelected( aRowIterator
.getRow() );
1504 Rectangle
const aRect
= aRowIterator
.getRect().GetIntersection( aAllDataCellsArea
);
1506 // give the redenderer a chance to prepare the row
1507 pRenderer
->PrepareRow(
1508 aRowIterator
.getRow(), isControlFocused
, isSelectedRow
,
1509 *m_pDataWindow
, aRect
, rStyle
1512 // paint the row header
1513 if ( m_pModel
->hasRowHeaders() )
1515 const Rectangle
aCurrentRowHeader( aRowHeaderArea
.GetIntersection( aRowIterator
.getRect() ) );
1516 pRenderer
->PaintRowHeader( isControlFocused
, isSelectedRow
, *m_pDataWindow
, aCurrentRowHeader
,
1523 // paint all cells in this row
1524 for ( TableCellGeometry
aCell( aRowIterator
, m_nLeftColumn
);
1529 bool isSelectedColumn
= false;
1530 pRenderer
->PaintCell( aCell
.getColumn(), isSelectedRow
|| isSelectedColumn
, isControlFocused
,
1531 *m_pDataWindow
, aCell
.getRect(), rStyle
);
1535 //------------------------------------------------------------------------------------------------------------------
1536 void TableControl_Impl::hideCursor()
1540 if ( ++m_nCursorHidden
== 1 )
1541 impl_ni_doSwitchCursor( false );
1544 //------------------------------------------------------------------------------------------------------------------
1545 void TableControl_Impl::showCursor()
1549 DBG_ASSERT( m_nCursorHidden
> 0, "TableControl_Impl::showCursor: cursor not hidden!" );
1550 if ( --m_nCursorHidden
== 0 )
1551 impl_ni_doSwitchCursor( true );
1554 //------------------------------------------------------------------------------------------------------------------
1555 bool TableControl_Impl::dispatchAction( TableControlAction _eAction
)
1559 bool bSuccess
= false;
1560 bool selectionChanged
= false;
1565 if ( m_pSelEngine
->GetSelectionMode() == SINGLE_SELECTION
)
1567 //if other rows already selected, deselect them
1568 if(!m_aSelectedRows
.empty())
1570 invalidateSelectedRows();
1571 m_aSelectedRows
.clear();
1573 if ( m_nCurRow
< m_nRowCount
-1 )
1576 m_aSelectedRows
.push_back(m_nCurRow
);
1579 m_aSelectedRows
.push_back(m_nCurRow
);
1580 invalidateRow( m_nCurRow
);
1581 ensureVisible(m_nCurColumn
,m_nCurRow
,false);
1582 selectionChanged
= true;
1587 if ( m_nCurRow
< m_nRowCount
- 1 )
1588 bSuccess
= goTo( m_nCurColumn
, m_nCurRow
+ 1 );
1593 if(m_pSelEngine
->GetSelectionMode() == SINGLE_SELECTION
)
1595 if(!m_aSelectedRows
.empty())
1597 invalidateSelectedRows();
1598 m_aSelectedRows
.clear();
1603 m_aSelectedRows
.push_back(m_nCurRow
);
1604 invalidateRow( m_nCurRow
);
1608 m_aSelectedRows
.push_back(m_nCurRow
);
1609 invalidateRow( m_nCurRow
);
1611 ensureVisible(m_nCurColumn
,m_nCurRow
,false);
1612 selectionChanged
= true;
1617 if ( m_nCurRow
> 0 )
1618 bSuccess
= goTo( m_nCurColumn
, m_nCurRow
- 1 );
1622 if ( m_nCurColumn
> 0 )
1623 bSuccess
= goTo( m_nCurColumn
- 1, m_nCurRow
);
1625 if ( ( m_nCurColumn
== 0) && ( m_nCurRow
> 0 ) )
1626 bSuccess
= goTo( m_nColumnCount
- 1, m_nCurRow
- 1 );
1630 if ( m_nCurColumn
< m_nColumnCount
- 1 )
1631 bSuccess
= goTo( m_nCurColumn
+ 1, m_nCurRow
);
1633 if ( ( m_nCurColumn
== m_nColumnCount
- 1 ) && ( m_nCurRow
< m_nRowCount
- 1 ) )
1634 bSuccess
= goTo( 0, m_nCurRow
+ 1 );
1637 case cursorToLineStart
:
1638 bSuccess
= goTo( 0, m_nCurRow
);
1641 case cursorToLineEnd
:
1642 bSuccess
= goTo( m_nColumnCount
- 1, m_nCurRow
);
1645 case cursorToFirstLine
:
1646 bSuccess
= goTo( m_nCurColumn
, 0 );
1649 case cursorToLastLine
:
1650 bSuccess
= goTo( m_nCurColumn
, m_nRowCount
- 1 );
1655 RowPos nNewRow
= ::std::max( (RowPos
)0, m_nCurRow
- impl_getVisibleRows( false ) );
1656 bSuccess
= goTo( m_nCurColumn
, nNewRow
);
1660 case cursorPageDown
:
1662 RowPos nNewRow
= ::std::min( m_nRowCount
- 1, m_nCurRow
+ impl_getVisibleRows( false ) );
1663 bSuccess
= goTo( m_nCurColumn
, nNewRow
);
1668 bSuccess
= goTo( 0, 0 );
1671 case cursorBottomRight
:
1672 bSuccess
= goTo( m_nColumnCount
- 1, m_nRowCount
- 1 );
1675 case cursorSelectRow
:
1677 if(m_pSelEngine
->GetSelectionMode() == NO_SELECTION
)
1678 return bSuccess
= false;
1679 //pos is the position of the current row in the vector of selected rows, if current row is selected
1680 int pos
= getRowSelectedNumber(m_aSelectedRows
, m_nCurRow
);
1681 //if current row is selected, it should be deselected, when ALT+SPACE are pressed
1684 m_aSelectedRows
.erase(m_aSelectedRows
.begin()+pos
);
1685 if(m_aSelectedRows
.empty() && m_nAnchor
!= -1)
1688 //else select the row->put it in the vector
1690 m_aSelectedRows
.push_back(m_nCurRow
);
1691 invalidateRow( m_nCurRow
);
1692 selectionChanged
= true;
1696 case cursorSelectRowUp
:
1698 if(m_pSelEngine
->GetSelectionMode() == NO_SELECTION
)
1699 return bSuccess
= false;
1700 else if(m_pSelEngine
->GetSelectionMode() == SINGLE_SELECTION
)
1702 //if there are other selected rows, deselect them
1707 //there are other selected rows
1708 if(!m_aSelectedRows
.empty())
1710 //the anchor wasn't set -> a region is not selected, that's why clear all selection
1711 //and select the current row
1714 invalidateSelectedRows();
1715 m_aSelectedRows
.clear();
1716 m_aSelectedRows
.push_back(m_nCurRow
);
1717 invalidateRow( m_nCurRow
);
1721 //a region is already selected, prevRow is last selected row and the row above - nextRow - should be selected
1722 int prevRow
= getRowSelectedNumber(m_aSelectedRows
, m_nCurRow
);
1723 int nextRow
= getRowSelectedNumber(m_aSelectedRows
, m_nCurRow
-1);
1726 //if m_nCurRow isn't the upper one, can move up, otherwise not
1730 return bSuccess
= true;
1731 //if nextRow already selected, deselect it, otherwise select it
1732 if(nextRow
>-1 && m_aSelectedRows
[nextRow
] == m_nCurRow
)
1734 m_aSelectedRows
.erase(m_aSelectedRows
.begin()+prevRow
);
1735 invalidateRow( m_nCurRow
+ 1 );
1739 m_aSelectedRows
.push_back(m_nCurRow
);
1740 invalidateRow( m_nCurRow
);
1747 m_aSelectedRows
.push_back(m_nCurRow
);
1749 m_aSelectedRows
.push_back(m_nCurRow
);
1750 invalidateSelectedRegion( m_nCurRow
+1, m_nCurRow
);
1757 //if nothing is selected and the current row isn't the upper one
1758 //select the current and one row above
1759 //otherwise select only the upper row
1762 m_aSelectedRows
.push_back(m_nCurRow
);
1764 m_aSelectedRows
.push_back(m_nCurRow
);
1765 invalidateSelectedRegion( m_nCurRow
+1, m_nCurRow
);
1769 m_aSelectedRows
.push_back(m_nCurRow
);
1770 invalidateRow( m_nCurRow
);
1773 m_pSelEngine
->SetAnchor(sal_True
);
1774 m_nAnchor
= m_nCurRow
;
1775 ensureVisible(m_nCurColumn
, m_nCurRow
, false);
1776 selectionChanged
= true;
1781 case cursorSelectRowDown
:
1783 if(m_pSelEngine
->GetSelectionMode() == NO_SELECTION
)
1785 else if(m_pSelEngine
->GetSelectionMode() == SINGLE_SELECTION
)
1791 if(!m_aSelectedRows
.empty())
1793 //the anchor wasn't set -> a region is not selected, that's why clear all selection
1794 //and select the current row
1797 invalidateSelectedRows();
1798 m_aSelectedRows
.clear();
1799 m_aSelectedRows
.push_back(m_nCurRow
);
1800 invalidateRow( m_nCurRow
);
1804 //a region is already selected, prevRow is last selected row and the row beneath - nextRow - should be selected
1805 int prevRow
= getRowSelectedNumber(m_aSelectedRows
, m_nCurRow
);
1806 int nextRow
= getRowSelectedNumber(m_aSelectedRows
, m_nCurRow
+1);
1809 //if m_nCurRow isn't the last one, can move down, otherwise not
1810 if(m_nCurRow
<m_nRowCount
-1)
1813 return bSuccess
= true;
1814 //if next row already selected, deselect it, otherwise select it
1815 if(nextRow
>-1 && m_aSelectedRows
[nextRow
] == m_nCurRow
)
1817 m_aSelectedRows
.erase(m_aSelectedRows
.begin()+prevRow
);
1818 invalidateRow( m_nCurRow
- 1 );
1822 m_aSelectedRows
.push_back(m_nCurRow
);
1823 invalidateRow( m_nCurRow
);
1828 if(m_nCurRow
<m_nRowCount
-1)
1830 m_aSelectedRows
.push_back(m_nCurRow
);
1832 m_aSelectedRows
.push_back(m_nCurRow
);
1833 invalidateSelectedRegion( m_nCurRow
-1, m_nCurRow
);
1840 //there wasn't any selection, select current and row beneath, otherwise only row beneath
1841 if(m_nCurRow
<m_nRowCount
-1)
1843 m_aSelectedRows
.push_back(m_nCurRow
);
1845 m_aSelectedRows
.push_back(m_nCurRow
);
1846 invalidateSelectedRegion( m_nCurRow
-1, m_nCurRow
);
1850 m_aSelectedRows
.push_back(m_nCurRow
);
1851 invalidateRow( m_nCurRow
);
1854 m_pSelEngine
->SetAnchor(sal_True
);
1855 m_nAnchor
= m_nCurRow
;
1856 ensureVisible(m_nCurColumn
, m_nCurRow
, false);
1857 selectionChanged
= true;
1863 case cursorSelectRowAreaTop
:
1865 if(m_pSelEngine
->GetSelectionMode() == NO_SELECTION
)
1867 else if(m_pSelEngine
->GetSelectionMode() == SINGLE_SELECTION
)
1871 //select the region between the current and the upper row
1872 RowPos iter
= m_nCurRow
;
1873 invalidateSelectedRegion( m_nCurRow
, 0 );
1874 //put the rows in vector
1877 if ( !isRowSelected( iter
) )
1878 m_aSelectedRows
.push_back(iter
);
1882 m_nAnchor
= m_nCurRow
;
1883 m_pSelEngine
->SetAnchor(sal_True
);
1884 ensureVisible(m_nCurColumn
, 0, false);
1885 selectionChanged
= true;
1891 case cursorSelectRowAreaBottom
:
1893 if(m_pSelEngine
->GetSelectionMode() == NO_SELECTION
)
1894 return bSuccess
= false;
1895 else if(m_pSelEngine
->GetSelectionMode() == SINGLE_SELECTION
)
1896 return bSuccess
= false;
1897 //select the region between the current and the last row
1898 RowPos iter
= m_nCurRow
;
1899 invalidateSelectedRegion( m_nCurRow
, m_nRowCount
-1 );
1900 //put the rows in the vector
1901 while(iter
<=m_nRowCount
)
1903 if ( !isRowSelected( iter
) )
1904 m_aSelectedRows
.push_back(iter
);
1907 m_nCurRow
= m_nRowCount
-1;
1908 m_nAnchor
= m_nCurRow
;
1909 m_pSelEngine
->SetAnchor(sal_True
);
1910 ensureVisible(m_nCurColumn
, m_nRowCount
-1, false);
1911 selectionChanged
= true;
1916 OSL_FAIL( "TableControl_Impl::dispatchAction: unsupported action!" );
1920 if ( bSuccess
&& selectionChanged
)
1922 m_rAntiImpl
.Select();
1928 //------------------------------------------------------------------------------------------------------------------
1929 void TableControl_Impl::impl_ni_doSwitchCursor( bool _bShow
)
1931 PTableRenderer pRenderer
= !!m_pModel
? m_pModel
->getRenderer() : PTableRenderer();
1934 Rectangle aCellRect
;
1935 impl_getCellRect( m_nCurColumn
, m_nCurRow
, aCellRect
);
1937 pRenderer
->ShowCellCursor( *m_pDataWindow
, aCellRect
);
1939 pRenderer
->HideCellCursor( *m_pDataWindow
, aCellRect
);
1943 //------------------------------------------------------------------------------------------------------------------
1944 void TableControl_Impl::impl_getCellRect( ColPos _nColumn
, RowPos _nRow
, Rectangle
& _rCellRect
) const
1949 || ( COL_INVALID
== _nColumn
)
1950 || ( ROW_INVALID
== _nRow
)
1953 _rCellRect
.SetEmpty();
1957 TableCellGeometry
aCell( *this, impl_getAllVisibleCellsArea(), _nColumn
, _nRow
);
1958 _rCellRect
= aCell
.getRect();
1961 //------------------------------------------------------------------------------------------------------------------
1962 RowPos
TableControl_Impl::getRowAtPoint( const Point
& rPoint
) const
1965 return impl_getRowForAbscissa( rPoint
.Y() );
1968 //------------------------------------------------------------------------------------------------------------------
1969 ColPos
TableControl_Impl::getColAtPoint( const Point
& rPoint
) const
1972 return impl_getColumnForOrdinate( rPoint
.X() );
1975 //------------------------------------------------------------------------------------------------------------------
1976 TableCell
TableControl_Impl::hitTest( Point
const & i_point
) const
1978 TableCell
aCell( getColAtPoint( i_point
), getRowAtPoint( i_point
) );
1979 if ( aCell
.nColumn
> COL_ROW_HEADERS
)
1981 PColumnModel
const pColumn
= m_pModel
->getColumnModel( aCell
.nColumn
);
1982 MutableColumnMetrics
const & rColInfo( m_aColumnWidths
[ aCell
.nColumn
] );
1983 if ( ( rColInfo
.getEnd() - 3 <= i_point
.X() )
1984 && ( rColInfo
.getEnd() >= i_point
.X() )
1985 && pColumn
->isResizable()
1988 aCell
.eArea
= ColumnDivider
;
1994 //------------------------------------------------------------------------------------------------------------------
1995 ColumnMetrics
TableControl_Impl::getColumnMetrics( ColPos
const i_column
) const
1999 ENSURE_OR_RETURN( ( i_column
>= 0 ) && ( i_column
< m_pModel
->getColumnCount() ),
2000 "TableControl_Impl::getColumnMetrics: illegal column index!", ColumnMetrics() );
2001 return (ColumnMetrics
const &)m_aColumnWidths
[ i_column
];
2004 //------------------------------------------------------------------------------------------------------------------
2005 PTableModel
TableControl_Impl::getModel() const
2010 //------------------------------------------------------------------------------------------------------------------
2011 RowPos
TableControl_Impl::getCurrentColumn() const
2013 return m_nCurColumn
;
2016 //------------------------------------------------------------------------------------------------------------------
2017 RowPos
TableControl_Impl::getCurrentRow() const
2022 //------------------------------------------------------------------------------------------------------------------
2023 ::Size
TableControl_Impl::getTableSizePixel() const
2025 return m_pDataWindow
->GetOutputSizePixel();
2028 //------------------------------------------------------------------------------------------------------------------
2029 void TableControl_Impl::setPointer( Pointer
const & i_pointer
)
2032 m_pDataWindow
->SetPointer( i_pointer
);
2035 //------------------------------------------------------------------------------------------------------------------
2036 void TableControl_Impl::captureMouse()
2038 m_pDataWindow
->CaptureMouse();
2041 //------------------------------------------------------------------------------------------------------------------
2042 void TableControl_Impl::releaseMouse()
2044 m_pDataWindow
->ReleaseMouse();
2047 //------------------------------------------------------------------------------------------------------------------
2048 void TableControl_Impl::invalidate( TableArea
const i_what
)
2052 case TableAreaColumnHeaders
:
2053 m_pDataWindow
->Invalidate( calcHeaderRect( true ) );
2056 case TableAreaRowHeaders
:
2057 m_pDataWindow
->Invalidate( calcHeaderRect( false ) );
2060 case TableAreaDataArea
:
2061 m_pDataWindow
->Invalidate( impl_getAllVisibleDataCellArea() );
2065 m_pDataWindow
->Invalidate();
2070 //------------------------------------------------------------------------------------------------------------------
2071 long TableControl_Impl::pixelWidthToAppFont( long const i_pixels
) const
2073 return m_pDataWindow
->PixelToLogic( Size( i_pixels
, 0 ), MAP_APPFONT
).Width();
2076 //------------------------------------------------------------------------------------------------------------------
2077 long TableControl_Impl::appFontWidthToPixel( long const i_appFontUnits
) const
2079 return m_pDataWindow
->LogicToPixel( Size( i_appFontUnits
, 0 ), MAP_APPFONT
).Width();
2082 //------------------------------------------------------------------------------------------------------------------
2083 void TableControl_Impl::hideTracking()
2085 m_pDataWindow
->HideTracking();
2088 //------------------------------------------------------------------------------------------------------------------
2089 void TableControl_Impl::showTracking( Rectangle
const & i_location
, sal_uInt16
const i_flags
)
2091 m_pDataWindow
->ShowTracking( i_location
, i_flags
);
2094 //------------------------------------------------------------------------------------------------------------------
2095 bool TableControl_Impl::activateCell( ColPos
const i_col
, RowPos
const i_row
)
2098 return goTo( i_col
, i_row
);
2101 //------------------------------------------------------------------------------------------------------------------
2102 void TableControl_Impl::invalidateSelectedRegion( RowPos _nPrevRow
, RowPos _nCurRow
)
2105 // get the visible area of the table control and set the Left and right border of the region to be repainted
2106 Rectangle
const aAllCells( impl_getAllVisibleCellsArea() );
2108 Rectangle aInvalidateRect
;
2109 aInvalidateRect
.Left() = aAllCells
.Left();
2110 aInvalidateRect
.Right() = aAllCells
.Right();
2111 // if only one row is selected
2112 if ( _nPrevRow
== _nCurRow
)
2114 Rectangle aCellRect
;
2115 impl_getCellRect( m_nCurColumn
, _nCurRow
, aCellRect
);
2116 aInvalidateRect
.Top() = aCellRect
.Top();
2117 aInvalidateRect
.Bottom() = aCellRect
.Bottom();
2119 //if the region is above the current row
2120 else if(_nPrevRow
< _nCurRow
)
2122 Rectangle aCellRect
;
2123 impl_getCellRect( m_nCurColumn
, _nPrevRow
, aCellRect
);
2124 aInvalidateRect
.Top() = aCellRect
.Top();
2125 impl_getCellRect( m_nCurColumn
, _nCurRow
, aCellRect
);
2126 aInvalidateRect
.Bottom() = aCellRect
.Bottom();
2128 //if the region is beneath the current row
2131 Rectangle aCellRect
;
2132 impl_getCellRect( m_nCurColumn
, _nCurRow
, aCellRect
);
2133 aInvalidateRect
.Top() = aCellRect
.Top();
2134 impl_getCellRect( m_nCurColumn
, _nPrevRow
, aCellRect
);
2135 aInvalidateRect
.Bottom() = aCellRect
.Bottom();
2138 invalidateRect(aInvalidateRect
);
2141 void TableControl_Impl::invalidateRect(const Rectangle
&rInvalidateRect
)
2143 m_pDataWindow
->Invalidate( rInvalidateRect
,
2144 m_pDataWindow
->GetControlBackground().GetTransparency() ? INVALIDATE_TRANSPARENT
: 0 );
2147 //------------------------------------------------------------------------------------------------------------------
2148 void TableControl_Impl::invalidateSelectedRows()
2150 for ( ::std::vector
< RowPos
>::iterator selRow
= m_aSelectedRows
.begin();
2151 selRow
!= m_aSelectedRows
.end();
2155 invalidateRow( *selRow
);
2159 //------------------------------------------------------------------------------------------------------------------
2160 void TableControl_Impl::invalidateRowRange( RowPos
const i_firstRow
, RowPos
const i_lastRow
)
2162 RowPos
const firstRow
= i_firstRow
< m_nTopRow
? m_nTopRow
: i_firstRow
;
2163 RowPos
const lastVisibleRow
= m_nTopRow
+ impl_getVisibleRows( true ) - 1;
2164 RowPos
const lastRow
= ( ( i_lastRow
== ROW_INVALID
) || ( i_lastRow
> lastVisibleRow
) ) ? lastVisibleRow
: i_lastRow
;
2166 Rectangle aInvalidateRect
;
2168 Rectangle
const aVisibleCellsArea( impl_getAllVisibleCellsArea() );
2169 TableRowGeometry
aRow( *this, aVisibleCellsArea
, firstRow
, true );
2170 while ( aRow
.isValid() && ( aRow
.getRow() <= lastRow
) )
2172 aInvalidateRect
.Union( aRow
.getRect() );
2176 if ( i_lastRow
== ROW_INVALID
)
2177 aInvalidateRect
.Bottom() = m_pDataWindow
->GetOutputSizePixel().Height();
2179 invalidateRect(aInvalidateRect
);
2182 //------------------------------------------------------------------------------
2183 void TableControl_Impl::checkCursorPosition()
2187 TableSize nVisibleRows
= impl_getVisibleRows(true);
2188 TableSize nVisibleCols
= impl_getVisibleColumns(true);
2189 if ( ( m_nTopRow
+ nVisibleRows
> m_nRowCount
)
2190 && ( m_nRowCount
>= nVisibleRows
)
2200 if ( ( m_nLeftColumn
+ nVisibleCols
> m_nColumnCount
)
2201 && ( m_nColumnCount
>= nVisibleCols
)
2211 m_pDataWindow
->Invalidate();
2214 //--------------------------------------------------------------------
2215 TableSize
TableControl_Impl::impl_getVisibleRows( bool _bAcceptPartialRow
) const
2219 DBG_ASSERT( m_pDataWindow
, "TableControl_Impl::impl_getVisibleRows: no data window!" );
2221 return lcl_getRowsFittingInto(
2222 m_pDataWindow
->GetOutputSizePixel().Height() - m_nColHeaderHeightPixel
,
2228 //--------------------------------------------------------------------
2229 TableSize
TableControl_Impl::impl_getVisibleColumns( bool _bAcceptPartialCol
) const
2233 DBG_ASSERT( m_pDataWindow
, "TableControl_Impl::impl_getVisibleColumns: no data window!" );
2235 return lcl_getColumnsVisibleWithin(
2236 Rectangle( Point( 0, 0 ), m_pDataWindow
->GetOutputSizePixel() ),
2243 //--------------------------------------------------------------------
2244 bool TableControl_Impl::goTo( ColPos _nColumn
, RowPos _nRow
)
2248 // TODO: give veto listeners a chance
2250 if ( ( _nColumn
< 0 ) || ( _nColumn
>= m_nColumnCount
)
2251 || ( _nRow
< 0 ) || ( _nRow
>= m_nRowCount
)
2254 OSL_ENSURE( false, "TableControl_Impl::goTo: invalid row or column index!" );
2258 SuppressCursor
aHideCursor( *this );
2259 m_nCurColumn
= _nColumn
;
2262 // ensure that the new cell is visible
2263 ensureVisible( m_nCurColumn
, m_nCurRow
, false );
2267 //--------------------------------------------------------------------
2268 void TableControl_Impl::ensureVisible( ColPos _nColumn
, RowPos _nRow
, bool _bAcceptPartialVisibility
)
2271 DBG_ASSERT( ( _nColumn
>= 0 ) && ( _nColumn
< m_nColumnCount
)
2272 && ( _nRow
>= 0 ) && ( _nRow
< m_nRowCount
),
2273 "TableControl_Impl::ensureVisible: invalid coordinates!" );
2275 SuppressCursor
aHideCursor( *this );
2277 if ( _nColumn
< m_nLeftColumn
)
2278 impl_scrollColumns( _nColumn
- m_nLeftColumn
);
2281 TableSize nVisibleColumns
= impl_getVisibleColumns( _bAcceptPartialVisibility
);
2282 if ( _nColumn
> m_nLeftColumn
+ nVisibleColumns
- 1 )
2284 impl_scrollColumns( _nColumn
- ( m_nLeftColumn
+ nVisibleColumns
- 1 ) );
2285 // TODO: since not all columns have the same width, this might in theory result
2286 // in the column still not being visible.
2290 if ( _nRow
< m_nTopRow
)
2291 impl_scrollRows( _nRow
- m_nTopRow
);
2294 TableSize nVisibleRows
= impl_getVisibleRows( _bAcceptPartialVisibility
);
2295 if ( _nRow
> m_nTopRow
+ nVisibleRows
- 1 )
2296 impl_scrollRows( _nRow
- ( m_nTopRow
+ nVisibleRows
- 1 ) );
2300 //--------------------------------------------------------------------
2301 OUString
TableControl_Impl::getCellContentAsString( RowPos
const i_row
, ColPos
const i_col
)
2304 m_pModel
->getCellContent( i_col
, i_row
, aCellValue
);
2306 OUString sCellStringContent
;
2307 m_pModel
->getRenderer()->GetFormattedCellString( aCellValue
, i_col
, i_row
, sCellStringContent
);
2309 return sCellStringContent
;
2312 //--------------------------------------------------------------------
2313 TableSize
TableControl_Impl::impl_ni_ScrollRows( TableSize _nRowDelta
)
2315 // compute new top row
2318 ::std::min( (RowPos
)( m_nTopRow
+ _nRowDelta
), (RowPos
)( m_nRowCount
- 1 ) ),
2322 RowPos nOldTopRow
= m_nTopRow
;
2323 m_nTopRow
= nNewTopRow
;
2325 // if updates are enabled currently, scroll the viewport
2326 if ( m_nTopRow
!= nOldTopRow
)
2328 DBG_SUSPEND_INV( INV_SCROLL_POSITION
);
2329 SuppressCursor
aHideCursor( *this );
2330 // TODO: call a onStartScroll at our listener (or better an own onStartScroll,
2331 // which hides the cursor and then calls the listener)
2332 // Same for onEndScroll
2334 // scroll the view port, if possible
2335 long nPixelDelta
= m_nRowHeightPixel
* ( m_nTopRow
- nOldTopRow
);
2337 Rectangle
aDataArea( Point( 0, m_nColHeaderHeightPixel
), m_pDataWindow
->GetOutputSizePixel() );
2339 if ( m_pDataWindow
->GetBackground().IsScrollable()
2340 && abs( nPixelDelta
) < aDataArea
.GetHeight()
2343 m_pDataWindow
->Scroll( 0, (long)-nPixelDelta
, aDataArea
, SCROLL_CLIP
| SCROLL_UPDATE
| SCROLL_CHILDREN
);
2346 m_pDataWindow
->Invalidate( INVALIDATE_UPDATE
);
2348 // update the position at the vertical scrollbar
2349 if ( m_pVScroll
!= NULL
)
2350 m_pVScroll
->SetThumbPos( m_nTopRow
);
2353 // The scroll bar availaility might change when we scrolled.
2354 // For instance, imagine a view with 10 rows, if which 5 fit into the window, numbered 1 to 10.
2356 // - the user scroll to row number 6, so the last 5 rows are visible
2357 // - somebody remove the last 4 rows
2358 // - the user scroll to row number 5 being the top row, so the last two rows are visible
2359 // - somebody remove row number 6
2360 // - the user scroll to row number 1
2361 // => in this case, the need for the scrollbar vanishes immediately.
2362 if ( m_nTopRow
== 0 )
2363 m_rAntiImpl
.PostUserEvent( LINK( this, TableControl_Impl
, OnUpdateScrollbars
) );
2365 return (TableSize
)( m_nTopRow
- nOldTopRow
);
2368 //--------------------------------------------------------------------
2369 TableSize
TableControl_Impl::impl_scrollRows( TableSize
const i_rowDelta
)
2372 return impl_ni_ScrollRows( i_rowDelta
);
2375 //--------------------------------------------------------------------
2376 TableSize
TableControl_Impl::impl_ni_ScrollColumns( TableSize _nColumnDelta
)
2378 // compute new left column
2379 const ColPos nNewLeftColumn
=
2381 ::std::min( (ColPos
)( m_nLeftColumn
+ _nColumnDelta
), (ColPos
)( m_nColumnCount
- 1 ) ),
2385 const ColPos nOldLeftColumn
= m_nLeftColumn
;
2386 m_nLeftColumn
= nNewLeftColumn
;
2388 // if updates are enabled currently, scroll the viewport
2389 if ( m_nLeftColumn
!= nOldLeftColumn
)
2391 DBG_SUSPEND_INV( INV_SCROLL_POSITION
);
2392 SuppressCursor
aHideCursor( *this );
2393 // TODO: call a onStartScroll at our listener (or better an own onStartScroll,
2394 // which hides the cursor and then calls the listener)
2395 // Same for onEndScroll
2397 // scroll the view port, if possible
2398 const Rectangle
aDataArea( Point( m_nRowHeaderWidthPixel
, 0 ), m_pDataWindow
->GetOutputSizePixel() );
2401 m_aColumnWidths
[ nOldLeftColumn
].getStart()
2402 - m_aColumnWidths
[ m_nLeftColumn
].getStart();
2404 // update our column positions
2405 // Do this *before* scrolling, as SCROLL_UPDATE will trigger a paint, which already needs the correct
2406 // information in m_aColumnWidths
2407 for ( ColumnPositions::iterator colPos
= m_aColumnWidths
.begin();
2408 colPos
!= m_aColumnWidths
.end();
2412 colPos
->move( nPixelDelta
);
2415 // scroll the window content (if supported and possible), or invalidate the complete window
2416 if ( m_pDataWindow
->GetBackground().IsScrollable()
2417 && abs( nPixelDelta
) < aDataArea
.GetWidth()
2420 m_pDataWindow
->Scroll( nPixelDelta
, 0, aDataArea
, SCROLL_CLIP
| SCROLL_UPDATE
);
2423 m_pDataWindow
->Invalidate( INVALIDATE_UPDATE
);
2425 // update the position at the horizontal scrollbar
2426 if ( m_pHScroll
!= NULL
)
2427 m_pHScroll
->SetThumbPos( m_nLeftColumn
);
2430 // The scroll bar availaility might change when we scrolled. This is because we do not hide
2431 // the scrollbar when it is, in theory, unnecessary, but currently at a position > 0. In this case, it will
2432 // be auto-hidden when it's scrolled back to pos 0.
2433 if ( m_nLeftColumn
== 0 )
2434 m_rAntiImpl
.PostUserEvent( LINK( this, TableControl_Impl
, OnUpdateScrollbars
) );
2436 return (TableSize
)( m_nLeftColumn
- nOldLeftColumn
);
2439 //------------------------------------------------------------------------------------------------------------------
2440 TableSize
TableControl_Impl::impl_scrollColumns( TableSize
const i_columnDelta
)
2443 return impl_ni_ScrollColumns( i_columnDelta
);
2446 //------------------------------------------------------------------------------------------------------------------
2447 SelectionEngine
* TableControl_Impl::getSelEngine()
2449 return m_pSelEngine
;
2452 //------------------------------------------------------------------------------------------------------------------
2453 ScrollBar
* TableControl_Impl::getHorzScrollbar()
2458 //------------------------------------------------------------------------------------------------------------------
2459 ScrollBar
* TableControl_Impl::getVertScrollbar()
2464 //------------------------------------------------------------------------------------------------------------------
2465 bool TableControl_Impl::isRowSelected( RowPos i_row
) const
2467 return ::std::find( m_aSelectedRows
.begin(), m_aSelectedRows
.end(), i_row
) != m_aSelectedRows
.end();
2470 //------------------------------------------------------------------------------------------------------------------
2471 RowPos
TableControl_Impl::getSelectedRowIndex( size_t const i_selectionIndex
) const
2473 if ( i_selectionIndex
< m_aSelectedRows
.size() )
2474 return m_aSelectedRows
[ i_selectionIndex
];
2478 //------------------------------------------------------------------------------------------------------------------
2479 int TableControl_Impl::getRowSelectedNumber(const ::std::vector
<RowPos
>& selectedRows
, RowPos current
)
2481 std::vector
<RowPos
>::const_iterator it
= ::std::find(selectedRows
.begin(),selectedRows
.end(),current
);
2482 if ( it
!= selectedRows
.end() )
2484 return it
- selectedRows
.begin();
2489 //--------------------------------------------------------------------
2490 ColPos
TableControl_Impl::impl_getColumnForOrdinate( long const i_ordinate
) const
2494 if ( ( m_aColumnWidths
.empty() ) || ( i_ordinate
< 0 ) )
2497 if ( i_ordinate
< m_nRowHeaderWidthPixel
)
2498 return COL_ROW_HEADERS
;
2500 ColumnPositions::const_iterator lowerBound
= ::std::lower_bound(
2501 m_aColumnWidths
.begin(),
2502 m_aColumnWidths
.end(),
2503 MutableColumnMetrics(i_ordinate
+1, i_ordinate
+1),
2504 ColumnInfoPositionLess()
2506 if ( lowerBound
== m_aColumnWidths
.end() )
2508 // point is *behind* the start of the last column ...
2509 if ( i_ordinate
< m_aColumnWidths
.rbegin()->getEnd() )
2510 // ... but still before its end
2511 return m_nColumnCount
- 1;
2514 return lowerBound
- m_aColumnWidths
.begin();
2517 //--------------------------------------------------------------------
2518 RowPos
TableControl_Impl::impl_getRowForAbscissa( long const i_abscissa
) const
2522 if ( i_abscissa
< 0 )
2525 if ( i_abscissa
< m_nColHeaderHeightPixel
)
2526 return ROW_COL_HEADERS
;
2528 long const abscissa
= i_abscissa
- m_nColHeaderHeightPixel
;
2529 long const row
= m_nTopRow
+ abscissa
/ m_nRowHeightPixel
;
2530 return row
< m_pModel
->getRowCount() ? row
: ROW_INVALID
;
2533 //--------------------------------------------------------------------
2534 bool TableControl_Impl::markRowAsDeselected( RowPos
const i_rowIndex
)
2538 ::std::vector
< RowPos
>::iterator selPos
= ::std::find( m_aSelectedRows
.begin(), m_aSelectedRows
.end(), i_rowIndex
);
2539 if ( selPos
== m_aSelectedRows
.end() )
2542 m_aSelectedRows
.erase( selPos
);
2546 //--------------------------------------------------------------------
2547 bool TableControl_Impl::markRowAsSelected( RowPos
const i_rowIndex
)
2551 if ( isRowSelected( i_rowIndex
) )
2554 SelectionMode
const eSelMode
= getSelEngine()->GetSelectionMode();
2557 case SINGLE_SELECTION
:
2558 if ( !m_aSelectedRows
.empty() )
2560 OSL_ENSURE( m_aSelectedRows
.size() == 1, "TableControl::markRowAsSelected: SingleSelection with more than one selected element?" );
2561 m_aSelectedRows
[0] = i_rowIndex
;
2566 case MULTIPLE_SELECTION
:
2567 m_aSelectedRows
.push_back( i_rowIndex
);
2571 OSL_ENSURE( false, "TableControl_Impl::markRowAsSelected: unsupported selection mode!" );
2578 //--------------------------------------------------------------------
2579 bool TableControl_Impl::markAllRowsAsDeselected()
2581 if ( m_aSelectedRows
.empty() )
2584 m_aSelectedRows
.clear();
2588 //--------------------------------------------------------------------
2589 bool TableControl_Impl::markAllRowsAsSelected()
2593 SelectionMode
const eSelMode
= getSelEngine()->GetSelectionMode();
2594 ENSURE_OR_RETURN_FALSE( eSelMode
== MULTIPLE_SELECTION
, "TableControl_Impl::markAllRowsAsSelected: unsupported selection mode!" );
2596 if ( m_aSelectedRows
.size() == size_t( m_pModel
->getRowCount() ) )
2598 #if OSL_DEBUG_LEVEL > 0
2599 for ( TableSize row
= 0; row
< m_pModel
->getRowCount(); ++row
)
2601 OSL_ENSURE( isRowSelected( row
), "TableControl_Impl::markAllRowsAsSelected: inconsistency in the selected rows!" );
2604 // already all rows marked as selected
2608 m_aSelectedRows
.clear();
2609 for ( RowPos i
=0; i
< m_pModel
->getRowCount(); ++i
)
2610 m_aSelectedRows
.push_back(i
);
2615 //--------------------------------------------------------------------
2616 void TableControl_Impl::commitAccessibleEvent( sal_Int16
const i_eventID
, const Any
& i_newValue
, const Any
& i_oldValue
)
2618 impl_commitAccessibleEvent( i_eventID
, i_newValue
, i_oldValue
);
2621 //--------------------------------------------------------------------
2622 void TableControl_Impl::commitCellEvent( sal_Int16
const i_eventID
, const Any
& i_newValue
, const Any
& i_oldValue
)
2625 if ( impl_isAccessibleAlive() )
2626 m_pAccessibleTable
->commitCellEvent( i_eventID
, i_newValue
, i_oldValue
);
2629 //--------------------------------------------------------------------
2630 void TableControl_Impl::commitTableEvent( sal_Int16
const i_eventID
, const Any
& i_newValue
, const Any
& i_oldValue
)
2633 if ( impl_isAccessibleAlive() )
2634 m_pAccessibleTable
->commitTableEvent( i_eventID
, i_newValue
, i_oldValue
);
2637 //--------------------------------------------------------------------
2638 Rectangle
TableControl_Impl::calcHeaderRect(bool bColHeader
)
2640 Rectangle
const aRectTableWithHeaders( impl_getAllVisibleCellsArea() );
2641 Size
const aSizeTableWithHeaders( aRectTableWithHeaders
.GetSize() );
2643 return Rectangle( aRectTableWithHeaders
.TopLeft(), Size( aSizeTableWithHeaders
.Width(), m_nColHeaderHeightPixel
) );
2645 return Rectangle( aRectTableWithHeaders
.TopLeft(), Size( m_nRowHeaderWidthPixel
, aSizeTableWithHeaders
.Height() ) );
2648 //--------------------------------------------------------------------
2649 Rectangle
TableControl_Impl::calcHeaderCellRect( bool bColHeader
, sal_Int32 nPos
)
2651 Rectangle
const aHeaderRect
= calcHeaderRect( bColHeader
);
2652 TableCellGeometry
const aGeometry(
2654 bColHeader
? nPos
: COL_ROW_HEADERS
,
2655 bColHeader
? ROW_COL_HEADERS
: nPos
2657 return aGeometry
.getRect();
2660 //--------------------------------------------------------------------
2661 Rectangle
TableControl_Impl::calcTableRect()
2663 return impl_getAllVisibleDataCellArea();
2666 //--------------------------------------------------------------------
2667 Rectangle
TableControl_Impl::calcCellRect( sal_Int32 nRow
, sal_Int32 nCol
)
2669 Rectangle aCellRect
;
2670 impl_getCellRect( nRow
, nCol
, aCellRect
);
2674 //--------------------------------------------------------------------
2675 IMPL_LINK( TableControl_Impl
, OnUpdateScrollbars
, void*, /**/ )
2678 // TODO: can't we simply use lcl_updateScrollbar here, so the scrollbars ranges are updated, instead of
2679 // doing a complete re-layout?
2684 //--------------------------------------------------------------------
2685 IMPL_LINK( TableControl_Impl
, OnScroll
, ScrollBar
*, _pScrollbar
)
2687 DBG_ASSERT( ( _pScrollbar
== m_pVScroll
) || ( _pScrollbar
== m_pHScroll
),
2688 "TableControl_Impl::OnScroll: where did this come from?" );
2690 if ( _pScrollbar
== m_pVScroll
)
2691 impl_ni_ScrollRows( _pScrollbar
->GetDelta() );
2693 impl_ni_ScrollColumns( _pScrollbar
->GetDelta() );
2698 //------------------------------------------------------------------------------------------------------------------
2699 Reference
< XAccessible
> TableControl_Impl::getAccessible( Window
& i_parentWindow
)
2701 DBG_TESTSOLARMUTEX();
2702 if ( m_pAccessibleTable
== NULL
)
2704 Reference
< XAccessible
> const xAccParent
= i_parentWindow
.GetAccessible();
2705 if ( xAccParent
.is() )
2707 m_pAccessibleTable
= m_aFactoryAccess
.getFactory().createAccessibleTableControl(
2708 xAccParent
, m_rAntiImpl
2713 Reference
< XAccessible
> xAccessible
;
2714 if ( m_pAccessibleTable
)
2715 xAccessible
= m_pAccessibleTable
->getMyself();
2719 //------------------------------------------------------------------------------------------------------------------
2720 void TableControl_Impl::disposeAccessible()
2722 if ( m_pAccessibleTable
)
2723 m_pAccessibleTable
->dispose();
2724 m_pAccessibleTable
= NULL
;
2727 //------------------------------------------------------------------------------------------------------------------
2728 bool TableControl_Impl::impl_isAccessibleAlive() const
2731 return ( NULL
!= m_pAccessibleTable
) && m_pAccessibleTable
->isAlive();
2734 //------------------------------------------------------------------------------------------------------------------
2735 void TableControl_Impl::impl_commitAccessibleEvent( sal_Int16
const i_eventID
, Any
const & i_newValue
, Any
const & i_oldValue
)
2738 if ( impl_isAccessibleAlive() )
2739 m_pAccessibleTable
->commitEvent( i_eventID
, i_newValue
, i_oldValue
);
2742 //==================================================================================================================
2743 //= TableFunctionSet
2744 //==================================================================================================================
2745 //------------------------------------------------------------------------------------------------------------------
2746 TableFunctionSet::TableFunctionSet(TableControl_Impl
* _pTableControl
)
2747 :m_pTableControl( _pTableControl
)
2748 ,m_nCurrentRow( ROW_INVALID
)
2751 //------------------------------------------------------------------------------------------------------------------
2752 TableFunctionSet::~TableFunctionSet()
2755 //------------------------------------------------------------------------------------------------------------------
2756 void TableFunctionSet::BeginDrag()
2759 //------------------------------------------------------------------------------------------------------------------
2760 void TableFunctionSet::CreateAnchor()
2762 m_pTableControl
->setAnchor( m_pTableControl
->getCurRow() );
2765 //------------------------------------------------------------------------------------------------------------------
2766 void TableFunctionSet::DestroyAnchor()
2768 m_pTableControl
->setAnchor( ROW_INVALID
);
2771 //------------------------------------------------------------------------------------------------------------------
2772 sal_Bool
TableFunctionSet::SetCursorAtPoint(const Point
& rPoint
, sal_Bool bDontSelectAtCursor
)
2774 sal_Bool bHandled
= sal_False
;
2775 // newRow is the row which includes the point, getCurRow() is the last selected row, before the mouse click
2776 RowPos newRow
= m_pTableControl
->getRowAtPoint( rPoint
);
2777 if ( newRow
== ROW_COL_HEADERS
)
2778 newRow
= m_pTableControl
->getTopRow();
2780 ColPos newCol
= m_pTableControl
->getColAtPoint( rPoint
);
2781 if ( newCol
== COL_ROW_HEADERS
)
2782 newCol
= m_pTableControl
->getLeftColumn();
2784 if ( ( newRow
== ROW_INVALID
) || ( newCol
== COL_INVALID
) )
2787 if ( bDontSelectAtCursor
)
2789 if ( m_pTableControl
->getSelectedRowCount() > 1 )
2790 m_pTableControl
->getSelEngine()->AddAlways(sal_True
);
2791 bHandled
= sal_True
;
2793 else if ( m_pTableControl
->getAnchor() == m_pTableControl
->getCurRow() )
2796 int diff
= m_pTableControl
->getCurRow() - newRow
;
2797 //selected region lies above the last selection
2800 //put selected rows in vector
2801 while ( m_pTableControl
->getAnchor() >= newRow
)
2803 m_pTableControl
->markRowAsSelected( m_pTableControl
->getAnchor() );
2804 m_pTableControl
->setAnchor( m_pTableControl
->getAnchor() - 1 );
2807 m_pTableControl
->setAnchor( m_pTableControl
->getAnchor() + 1 );
2809 //selected region lies beneath the last selected row
2812 while ( m_pTableControl
->getAnchor() <= newRow
)
2814 m_pTableControl
->markRowAsSelected( m_pTableControl
->getAnchor() );
2815 m_pTableControl
->setAnchor( m_pTableControl
->getAnchor() + 1 );
2818 m_pTableControl
->setAnchor( m_pTableControl
->getAnchor() - 1 );
2820 m_pTableControl
->invalidateSelectedRegion( m_pTableControl
->getCurRow(), newRow
);
2821 bHandled
= sal_True
;
2823 //no region selected
2826 if ( !m_pTableControl
->hasRowSelection() )
2827 m_pTableControl
->markRowAsSelected( newRow
);
2830 if ( m_pTableControl
->getSelEngine()->GetSelectionMode() == SINGLE_SELECTION
)
2833 m_pTableControl
->markRowAsSelected( newRow
);
2837 m_pTableControl
->markRowAsSelected( newRow
);
2840 if ( m_pTableControl
->getSelectedRowCount() > 1 && m_pTableControl
->getSelEngine()->GetSelectionMode() != SINGLE_SELECTION
)
2841 m_pTableControl
->getSelEngine()->AddAlways(sal_True
);
2843 m_pTableControl
->invalidateRow( newRow
);
2844 bHandled
= sal_True
;
2846 m_pTableControl
->goTo( newCol
, newRow
);
2849 //------------------------------------------------------------------------------------------------------------------
2850 sal_Bool
TableFunctionSet::IsSelectionAtPoint( const Point
& rPoint
)
2852 m_pTableControl
->getSelEngine()->AddAlways(sal_False
);
2853 if ( !m_pTableControl
->hasRowSelection() )
2857 RowPos curRow
= m_pTableControl
->getRowAtPoint( rPoint
);
2858 m_pTableControl
->setAnchor( ROW_INVALID
);
2859 bool selected
= m_pTableControl
->isRowSelected( curRow
);
2860 m_nCurrentRow
= curRow
;
2864 //------------------------------------------------------------------------------------------------------------------
2865 void TableFunctionSet::DeselectAtPoint( const Point
& rPoint
)
2868 m_pTableControl
->invalidateRow( m_nCurrentRow
);
2869 m_pTableControl
->markRowAsDeselected( m_nCurrentRow
);
2872 //------------------------------------------------------------------------------------------------------------------
2873 void TableFunctionSet::DeselectAll()
2875 if ( m_pTableControl
->hasRowSelection() )
2877 for ( size_t i
=0; i
<m_pTableControl
->getSelectedRowCount(); ++i
)
2879 RowPos
const rowIndex
= m_pTableControl
->getSelectedRowIndex(i
);
2880 m_pTableControl
->invalidateRow( rowIndex
);
2883 m_pTableControl
->markAllRowsAsDeselected();
2887 //......................................................................................................................
2888 } } // namespace svt::table
2889 //......................................................................................................................
2891 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */