1 /*************************************************************************
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 * Copyright 2009 by Sun Microsystems, Inc.
6 * OpenOffice.org - a multi-platform office productivity suite
8 * This file is part of OpenOffice.org.
10 * OpenOffice.org is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License version 3
12 * only, as published by the Free Software Foundation.
14 * OpenOffice.org is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License version 3 for more details
18 * (a copy is included in the LICENSE file that accompanied this code).
20 * You should have received a copy of the GNU Lesser General Public License
21 * version 3 along with OpenOffice.org. If not, see
22 * <http://www.openoffice.org/license.html>
23 * for a copy of the LGPLv3 License.
24 ************************************************************************/
26 // MARKER(update_precomp.py): autogen include statement, do not remove
27 #include "precompiled_svtools.hxx"
29 #include "svtools/table/tablecontrol.hxx"
30 #include "svtools/table/defaultinputhandler.hxx"
31 #include "svtools/table/tablemodel.hxx"
32 #include "tablecontrol_impl.hxx"
33 #include "tablegeometry.hxx"
34 #include "svtools/table/tabledatawindow.hxx"
36 #include <vcl/scrbar.hxx>
37 #include <vcl/seleng.hxx>
42 //........................................................................
43 namespace svt
{ namespace table
45 //........................................................................
47 //====================================================================
49 //====================================================================
53 IAbstractTableControl
& m_rTable
;
56 TempHideCursor( IAbstractTableControl
& _rTable
)
59 m_rTable
.hideCursor();
63 m_rTable
.showCursor();
67 //====================================================================
69 //====================================================================
70 /** default implementation of an ->ITableModel, used as fallback when no
73 Instances of this class are static in any way, and provide the least
74 necessary default functionality for a table model.
76 class EmptyTableModel
: public ITableModel
83 // ITableModel overridables
84 virtual TableSize
getColumnCount() const
88 virtual TableSize
getRowCount() const
92 virtual bool hasColumnHeaders() const
96 virtual bool hasRowHeaders() const
100 virtual void setRowHeaders(bool _bRowHeaders
)
104 virtual void setColumnHeaders(bool _bColumnHeaders
)
106 (void)_bColumnHeaders
;
108 void setColumnCount(TableSize _nColCount
)
112 void setRowCount(TableSize _nRowCount
)
116 virtual bool isCellEditable( ColPos col
, RowPos row
) const
122 virtual void addTableModelListener( const PTableModelListener
& listener
)
127 virtual void removeTableModelListener( const PTableModelListener
& listener
)
132 virtual PColumnModel
getColumnModel( ColPos column
)
134 DBG_ERROR( "EmptyTableModel::getColumnModel: invalid call!" );
136 return PColumnModel();
138 virtual PColumnModel
getColumnModelByID( ColumnID id
)
140 DBG_ERROR( "EmptyTableModel::getColumnModel: invalid call!" );
142 return PColumnModel();
144 virtual PTableRenderer
getRenderer() const
146 return PTableRenderer();
148 virtual PTableInputHandler
getInputHandler() const
150 return PTableInputHandler();
152 virtual TableMetrics
getRowHeight() const
156 virtual void setRowHeight(TableMetrics _nRowHeight
)
160 virtual TableMetrics
getColumnHeaderHeight() const
164 virtual TableMetrics
getRowHeaderWidth() const
168 virtual ScrollbarVisibility
getVerticalScrollbarVisibility(int overAllHeight
, int actHeight
) const
172 return ScrollbarShowNever
;
174 virtual ScrollbarVisibility
getHorizontalScrollbarVisibility(int overAllWidth
, int actWidth
) const
178 return ScrollbarShowNever
;
180 virtual void setCellContent(std::vector
<std::vector
<rtl::OUString
> > pCellEntryType
)
182 (void)pCellEntryType
;
184 virtual std::vector
<std::vector
<rtl::OUString
> > getCellContent()
186 std::vector
<rtl::OUString
> cCC
;
187 cCC
.push_back(rtl::OUString::createFromAscii(""));
188 std::vector
<std::vector
<rtl::OUString
> > cC
;
192 virtual void setRowHeaderName(std::vector
<rtl::OUString
> pCellEntryType
)
194 (void)pCellEntryType
;
196 virtual std::vector
<rtl::OUString
> getRowHeaderName()
198 std::vector
<rtl::OUString
> cCC
;
199 cCC
.push_back(rtl::OUString::createFromAscii(""));
205 //====================================================================
206 //= TableControl_Impl
207 //====================================================================
208 DBG_NAME( TableControl_Impl
)
211 //====================================================================
212 //= SuspendInvariants
213 //====================================================================
214 class SuspendInvariants
217 const TableControl_Impl
& m_rTable
;
218 sal_Int32 m_nSuspendFlags
;
221 SuspendInvariants( const TableControl_Impl
& _rTable
, sal_Int32 _nSuspendFlags
)
223 ,m_nSuspendFlags( _nSuspendFlags
)
225 DBG_ASSERT( ( m_rTable
.m_nRequiredInvariants
& m_nSuspendFlags
) == m_nSuspendFlags
,
226 "SuspendInvariants: cannot suspend what is already suspended!" );
227 const_cast< TableControl_Impl
& >( m_rTable
).m_nRequiredInvariants
&= ~m_nSuspendFlags
;
231 const_cast< TableControl_Impl
& >( m_rTable
).m_nRequiredInvariants
|= m_nSuspendFlags
;
234 #define DBG_SUSPEND_INV( flags ) \
235 SuspendInvariants aSuspendInv( *this, flags );
237 #define DBG_SUSPEND_INV( flags )
241 //====================================================================
242 const char* TableControl_Impl_checkInvariants( const void* _pInstance
)
244 return static_cast< const TableControl_Impl
* >( _pInstance
)->impl_checkInvariants();
249 template< typename SCALAR_TYPE
>
250 bool lcl_checkLimitsExclusive( SCALAR_TYPE _nValue
, SCALAR_TYPE _nMin
, SCALAR_TYPE _nMax
)
252 return ( _nValue
> _nMin
) && ( _nValue
< _nMax
);
255 template< typename SCALAR_TYPE
>
256 bool lcl_checkLimitsExclusive_OrDefault_OrFallback( SCALAR_TYPE _nValue
, SCALAR_TYPE _nMin
, SCALAR_TYPE _nMax
,
257 PTableModel _pModel
, SCALAR_TYPE _nDefaultOrFallback
)
260 return _nValue
== _nDefaultOrFallback
;
261 if ( _nMax
<= _nMin
)
262 return _nDefaultOrFallback
== _nValue
;
263 return lcl_checkLimitsExclusive( _nValue
, _nMin
, _nMax
);
267 //--------------------------------------------------------------------
268 const sal_Char
* TableControl_Impl::impl_checkInvariants() const
271 return "no model, not even an EmptyTableModel";
273 if ( !m_pDataWindow
)
274 return "invalid data window!";
276 if ( m_pModel
->getColumnCount() != m_nColumnCount
)
277 return "column counts are inconsistent!";
279 if ( m_pModel
->getRowCount() != m_nRowCount
)
280 return "row counts are inconsistent!";
282 if ( ( m_nCurColumn
!= COL_INVALID
) && !m_aColumnWidthsPixel
.empty() && ( m_nCurColumn
< 0 ) || ( m_nCurColumn
>= (ColPos
)m_aColumnWidthsPixel
.size() ) )
283 return "current column is invalid!";
285 if ( m_aColumnWidthsPixel
.size() != m_aAccColumnWidthsPixel
.size() )
286 return "columnd width caches are inconsistent!";
288 if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nTopRow
, (RowPos
)-1, m_nRowCount
, getModel(), (RowPos
)0 ) )
289 return "invalid top row value!";
291 if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nCurRow
, (RowPos
)-1, m_nRowCount
, getModel(), ROW_INVALID
) )
292 return "invalid current row value!";
294 if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nLeftColumn
, (ColPos
)-1, m_nColumnCount
, getModel(), (ColPos
)0 ) )
295 return "invalid current column value!";
297 if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nCurColumn
, (ColPos
)-1, m_nColumnCount
, getModel(), COL_INVALID
) )
298 return "invalid current column value!";
300 if ( m_pInputHandler
!= m_pModel
->getInputHandler() )
301 return "input handler is not the model-provided one!";
303 // m_nColHeaderHeightPixel consistent with the model's value?
305 TableMetrics nHeaderHeight
= m_pModel
->hasColumnHeaders() ? m_pModel
->getColumnHeaderHeight() : 0;
306 nHeaderHeight
= m_rAntiImpl
.LogicToPixel( Size( 0, nHeaderHeight
), MAP_100TH_MM
).Height();
307 if ( nHeaderHeight
!= m_nColHeaderHeightPixel
)
308 return "column header heights are inconsistent!";
311 bool isDummyModel
= dynamic_cast< const EmptyTableModel
* >( m_pModel
.get() ) != NULL
;
314 TableMetrics nRowHeight
= m_pModel
->getRowHeight();
315 nRowHeight
= m_rAntiImpl
.LogicToPixel( Size( 0, nRowHeight
), MAP_100TH_MM
).Height();
316 if ( nRowHeight
!= m_nRowHeightPixel
)
317 return "row heights are inconsistent!";
320 // m_nRowHeaderWidthPixel consistent with the model's value?
322 TableMetrics nHeaderWidth
= m_pModel
->hasRowHeaders() ? m_pModel
->getRowHeaderWidth() : 0;
323 nHeaderWidth
= m_rAntiImpl
.LogicToPixel( Size( nHeaderWidth
, 0 ), MAP_100TH_MM
).Width();
324 if ( nHeaderWidth
!= m_nRowHeaderWidthPixel
)
325 return "row header widths are inconsistent!";
328 // TODO: check m_aColumnWidthsPixel and m_aAccColumnWidthsPixel
330 if ( m_nCursorHidden
< 0 )
331 return "invalid hidden count for the cursor!";
333 if ( ( m_nRequiredInvariants
& INV_SCROLL_POSITION
) && m_pVScroll
)
335 DBG_SUSPEND_INV( INV_SCROLL_POSITION
);
336 // prevent infinite recursion
338 if ( m_pVScroll
->GetThumbPos() != m_nTopRow
)
339 return "vertical scroll bar |position| is incorrect!";
340 if ( m_pVScroll
->GetRange().Max() != m_nRowCount
)
341 return "vertical scroll bar |range| is incorrect!";
342 if ( m_pVScroll
->GetVisibleSize() != impl_getVisibleRows( false ) )
343 return "vertical scroll bar |visible size| is incorrect!";
346 if ( ( m_nRequiredInvariants
& INV_SCROLL_POSITION
) && m_pHScroll
)
348 DBG_SUSPEND_INV( INV_SCROLL_POSITION
);
349 // prevent infinite recursion
351 if ( m_pHScroll
->GetThumbPos() != m_nLeftColumn
)
352 return "horizontal scroll bar |position| is incorrect!";
353 if ( m_pHScroll
->GetRange().Max() != m_nColumnCount
)
354 return "horizontal scroll bar |range| is incorrect!";
355 if ( m_pHScroll
->GetVisibleSize() != impl_getVisibleColumns( false ) )
356 return "horizontal scroll bar |visible size| is incorrect!";
363 #define DBG_CHECK_ME() \
364 DBG_CHKTHIS( TableControl_Impl, TableControl_Impl_checkInvariants )
366 //--------------------------------------------------------------------
367 TableControl_Impl::TableControl_Impl( TableControl
& _rAntiImpl
)
368 :m_rAntiImpl ( _rAntiImpl
)
369 ,m_pModel ( new EmptyTableModel
)
371 ,m_nRowHeightPixel ( 15 )
372 ,m_nColHeaderHeightPixel( 0 )
373 ,m_nRowHeaderWidthPixel ( 0 )
374 ,m_nColumnCount ( 0 )
376 ,m_nCurColumn ( COL_INVALID
)
377 ,m_nCurRow ( ROW_INVALID
)
380 ,m_nCursorHidden ( 1 )
381 ,m_pDataWindow ( new TableDataWindow( *this ) )
384 ,m_pScrollCorner ( NULL
)
387 ,m_pTableFunctionSet ( new TableFunctionSet(this ) )
390 ,m_nRequiredInvariants ( INV_SCROLL_POSITION
)
393 DBG_CTOR( TableControl_Impl
, TableControl_Impl_checkInvariants
);
394 m_pSelEngine
= new SelectionEngine(m_pDataWindow
, m_pTableFunctionSet
);
395 m_pSelEngine
->SetSelectionMode(SINGLE_SELECTION
);
396 m_pDataWindow
->SetPosPixel( Point( 0, 0 ) );
397 m_pDataWindow
->Show();
400 //--------------------------------------------------------------------
401 TableControl_Impl::~TableControl_Impl()
403 DBG_DTOR( TableControl_Impl
, TableControl_Impl_checkInvariants
);
405 DELETEZ( m_pVScroll
);
406 DELETEZ( m_pHScroll
);
407 DELETEZ( m_pScrollCorner
);
408 DELETEZ( m_pTableFunctionSet
);
409 DELETEZ( m_pSelEngine
);
410 DELETEZ( m_pDataWindow
);
413 //--------------------------------------------------------------------
414 PTableModel
TableControl_Impl::getModel() const
416 if ( dynamic_cast< const EmptyTableModel
* >( m_pModel
.get() ) != NULL
)
417 // if it's an EmptyTableModel, pretend that there is no model
418 return PTableModel();
423 //--------------------------------------------------------------------
424 void TableControl_Impl::setModel( PTableModel _pModel
)
428 TempHideCursor
aHideCursor( *this );
430 // TODO: revoke as table listener from the model
434 m_pModel
.reset( new EmptyTableModel
);
436 // TODO: register as table listener
437 //m_pModel->addTableModelListener(PTableModelListener(m_pTableModelListener));
438 m_nCurRow
= ROW_INVALID
;
439 m_nCurColumn
= COL_INVALID
;
441 // recalc some model-dependent cached info
442 impl_ni_updateCachedModelValues();
444 // completely invalidate
445 m_rAntiImpl
.Invalidate();
447 // reset cursor to (0,0)
448 if ( m_nRowCount
) m_nCurRow
= 0;
449 if ( m_nColumnCount
) m_nCurColumn
= 0;
452 //--------------------------------------------------------------------
453 void TableControl_Impl::impl_getAllVisibleCellsArea( Rectangle
& _rCellArea
) const
457 _rCellArea
.Left() = 0;
458 _rCellArea
.Top() = 0;
460 // determine the right-most border of the last column which is
461 // at least partially visible
462 _rCellArea
.Right() = m_nRowHeaderWidthPixel
;
463 if ( !m_aAccColumnWidthsPixel
.empty() )
465 // the number of pixels which are scroll out of the left hand
466 // side of the window
467 long nScrolledOutLeft
= m_nLeftColumn
== 0 ? 0 : m_aAccColumnWidthsPixel
[ m_nLeftColumn
- 1 ];
469 ArrayOfLong::const_reverse_iterator loop
= m_aAccColumnWidthsPixel
.rbegin();
472 _rCellArea
.Right() = *loop
++ - nScrolledOutLeft
+ m_nRowHeaderWidthPixel
;
474 while ( ( loop
!= m_aAccColumnWidthsPixel
.rend() )
475 && ( *loop
- nScrolledOutLeft
>= _rCellArea
.Right() )
478 // so far, _rCellArea.Right() denotes the first pixel *after* the cell area
479 --_rCellArea
.Right();
481 // determine the last row which is at least partially visible
482 _rCellArea
.Bottom() =
483 m_nColHeaderHeightPixel
484 + impl_getVisibleRows( true ) * m_nRowHeightPixel
488 //--------------------------------------------------------------------
489 void TableControl_Impl::impl_getAllVisibleDataCellArea( Rectangle
& _rCellArea
) const
493 impl_getAllVisibleCellsArea( _rCellArea
);
494 _rCellArea
.Left() = m_nRowHeaderWidthPixel
;
495 _rCellArea
.Top() = m_nColHeaderHeightPixel
;
498 //--------------------------------------------------------------------
499 void TableControl_Impl::impl_ni_updateCachedModelValues()
501 m_nRowHeightPixel
= 15;
502 m_nColHeaderHeightPixel
= 0;
503 m_nRowHeaderWidthPixel
= 0;
504 m_pInputHandler
.reset();
505 m_nColumnCount
= m_nRowCount
= 0;
507 m_nRowHeightPixel
= m_rAntiImpl
.LogicToPixel( Size( 0, m_pModel
->getRowHeight() ), MAP_100TH_MM
).Height();
508 if ( m_pModel
->hasColumnHeaders() )
509 m_nColHeaderHeightPixel
= m_rAntiImpl
.LogicToPixel( Size( 0, m_pModel
->getColumnHeaderHeight() ), MAP_100TH_MM
).Height();
510 if ( m_pModel
->hasRowHeaders() )
511 m_nRowHeaderWidthPixel
= m_rAntiImpl
.LogicToPixel( Size( m_pModel
->getRowHeaderWidth(), 0 ), MAP_100TH_MM
).Width();
513 impl_ni_updateColumnWidths();
515 m_pInputHandler
= m_pModel
->getInputHandler();
516 if ( !m_pInputHandler
)
517 m_pInputHandler
.reset( new DefaultInputHandler
);
519 m_nColumnCount
= m_pModel
->getColumnCount();
520 m_nRowCount
= m_pModel
->getRowCount();
523 //--------------------------------------------------------------------
524 void TableControl_Impl::impl_ni_updateColumnWidths()
526 m_aColumnWidthsPixel
.resize( 0 );
527 m_aAccColumnWidthsPixel
.resize( 0 );
531 TableSize colCount
= m_pModel
->getColumnCount();
532 m_aColumnWidthsPixel
.reserve( colCount
);
533 m_aAccColumnWidthsPixel
.reserve( colCount
);
534 long accumulatedPixelWidth
= 0;
535 for ( ColPos col
= 0; col
< colCount
; ++col
)
537 PColumnModel pColumn
= m_pModel
->getColumnModel( col
);
538 DBG_ASSERT( !!pColumn
, "TableControl_Impl::impl_ni_updateColumnWidths: invalid column returned by the model!" );
542 TableMetrics colWidth
= pColumn
->getWidth();
543 DBG_ASSERT( ( colWidth
== COLWIDTH_FIT_TO_VIEW
) || ( colWidth
> 0 ),
544 "TableControl_Impl::impl_ni_updateColumnWidths: invalid column width!" );
547 if ( colWidth
== COLWIDTH_FIT_TO_VIEW
)
550 DBG_ERROR( "TableControl_Impl::impl_ni_updateColumnWidths: COLWIDTH_FIT_TO_VIEW not implemented, yet!" );
554 pixelWidth
= m_rAntiImpl
.LogicToPixel( Size( colWidth
, 0 ), MAP_100TH_MM
).Width();
557 m_aColumnWidthsPixel
.push_back( pixelWidth
);
559 m_aAccColumnWidthsPixel
.push_back( accumulatedPixelWidth
+= pixelWidth
);
563 //--------------------------------------------------------------------
566 //................................................................
567 /// determines whether a scrollbar is needed for the given values
568 bool lcl_determineScrollbarNeed( ScrollbarVisibility _eVisibility
,
569 long _nVisibleUnits
, long _nRange
)
571 if ( _eVisibility
== ScrollbarShowNever
)
573 if ( _eVisibility
== ScrollbarShowAlways
)
575 return _nVisibleUnits
> _nRange
;
578 //................................................................
579 void lcl_setButtonRepeat( Window
& _rWindow
, ULONG _nDelay
)
581 AllSettings aSettings
= _rWindow
.GetSettings();
582 MouseSettings aMouseSettings
= aSettings
.GetMouseSettings();
584 aMouseSettings
.SetButtonRepeat( _nDelay
);
585 aSettings
.SetMouseSettings( aMouseSettings
);
587 _rWindow
.SetSettings( aSettings
, TRUE
);
590 //................................................................
591 void lcl_updateScrollbar( Window
& _rParent
, ScrollBar
*& _rpBar
,
592 ScrollbarVisibility _eVisibility
, long _nVisibleUnits
,
593 long _nPosition
, long _nLineSize
, long _nRange
,
594 bool _bHorizontal
, const Link
& _rScrollHandler
)
596 // do we need the scrollbar?
597 bool bNeedBar
= lcl_determineScrollbarNeed( _eVisibility
, _nVisibleUnits
, _nRange
);
599 // do we currently have the scrollbar?
600 bool bHaveBar
= _rpBar
!= NULL
;
602 // do we need to correct the scrollbar visibility?
603 if ( bHaveBar
&& !bNeedBar
)
607 else if ( !bHaveBar
&& bNeedBar
)
609 _rpBar
= new ScrollBar(
611 WB_DRAG
| ( _bHorizontal
? WB_HSCROLL
: WB_VSCROLL
)
613 _rpBar
->SetScrollHdl( _rScrollHandler
);
614 // get some speed into the scrolling ....
615 lcl_setButtonRepeat( *_rpBar
, 0 );
620 _rpBar
->SetRange( Range( 0, _nRange
) );
621 _rpBar
->SetVisibleSize( _nVisibleUnits
);
622 _rpBar
->SetPageSize( _nVisibleUnits
);
623 _rpBar
->SetLineSize( _nLineSize
);
624 _rpBar
->SetThumbPos( _nPosition
);
629 //................................................................
630 /** returns the number of rows fitting into the given range,
631 for the given row height. Partially fitting rows are counted, too, if the
632 respective parameter says so.
634 TableSize
lcl_getRowsFittingInto( long _nOverallHeight
, long _nRowHeightPixel
, bool _bAcceptPartialRow
= false )
636 return _bAcceptPartialRow
637 ? ( _nOverallHeight
+ ( _nRowHeightPixel
- 1 ) ) / _nRowHeightPixel
638 : _nOverallHeight
/ _nRowHeightPixel
;
641 //................................................................
642 /** returns the number of columns fitting into the given area,
643 with the first visible column as given. Partially fitting columns are counted, too,
644 if the respective parameter says so.
646 TableSize
lcl_getColumnsVisibleWithin( const Rectangle
& _rArea
, ColPos _nFirstVisibleColumn
,
647 const TableControl_Impl
& _rControl
, bool _bAcceptPartialRow
)
649 TableSize visibleColumns
= 0;
650 TableColumnGeometry
aColumn( _rControl
, _rArea
, _nFirstVisibleColumn
);
651 while ( aColumn
.isValid() )
653 if ( !_bAcceptPartialRow
)
654 if ( aColumn
.getRect().Right() > _rArea
.Right() )
655 // this column is only partially visible, and this is not allowed
661 return visibleColumns
;
666 //--------------------------------------------------------------------
667 void TableControl_Impl::impl_ni_updateScrollbars()
669 TempHideCursor
aHideCursor( *this );
671 // the width/height of a scrollbar, needed several times below
672 long nScrollbarMetrics
= m_rAntiImpl
.GetSettings().GetStyleSettings().GetScrollBarSize();
673 if ( m_rAntiImpl
.IsZoom() )
674 nScrollbarMetrics
= (long)( nScrollbarMetrics
* (double)m_rAntiImpl
.GetZoom() );
676 // determine the playground for the data cells (excluding headers)
677 // TODO: what if the control is smaller than needed for the headers/scrollbars?
678 Rectangle
aDataCellPlayground( Point( 0, 0 ), m_rAntiImpl
.GetOutputSizePixel() );
679 aDataCellPlayground
.Left() = m_nRowHeaderWidthPixel
;
680 aDataCellPlayground
.Top() = m_nColHeaderHeightPixel
;
682 // do we need a vertical scrollbar?
683 bool bFirstRoundVScrollNeed
= false;
684 if ( lcl_determineScrollbarNeed(
685 m_pModel
->getVerticalScrollbarVisibility(aDataCellPlayground
.GetHeight(), m_nRowHeightPixel
*m_nRowCount
),
686 lcl_getRowsFittingInto( aDataCellPlayground
.GetHeight(), m_nRowHeightPixel
),
689 aDataCellPlayground
.Right() -= nScrollbarMetrics
;
690 bFirstRoundVScrollNeed
= true;
692 // do we need a horizontal scrollbar?
693 if ( lcl_determineScrollbarNeed(
694 m_pModel
->getHorizontalScrollbarVisibility(aDataCellPlayground
.GetWidth(), m_aAccColumnWidthsPixel
[m_nColumnCount
-1]),
695 lcl_getColumnsVisibleWithin( aDataCellPlayground
, m_nLeftColumn
, *this, false ),
698 aDataCellPlayground
.Bottom() -= nScrollbarMetrics
;
700 // now that we just found that we need a horizontal scrollbar,
701 // the need for a vertical one may have changed, since the horizontal
702 // SB might just occupy enough space so that not all rows do fit
704 if ( !bFirstRoundVScrollNeed
&& lcl_determineScrollbarNeed(
705 m_pModel
->getVerticalScrollbarVisibility(aDataCellPlayground
.GetHeight(),m_nRowHeightPixel
*m_nRowCount
),
706 lcl_getRowsFittingInto( aDataCellPlayground
.GetHeight(), m_nRowHeightPixel
),
709 aDataCellPlayground
.Right() -= nScrollbarMetrics
;
714 Size regionWithoutHeader
= m_rAntiImpl
.PixelToLogic(Size(aDataCellPlayground
.Right() - aDataCellPlayground
.Left(),0),MAP_100TH_MM
);
715 TableMetrics nColWidth
= regionWithoutHeader
.Width()/m_nColumnCount
;
716 for ( ColPos col
= 0; col
< m_nColumnCount
; ++col
)
717 m_pModel
->getColumnModel(col
)->setWidth(nColWidth
);
718 m_rAntiImpl
.SetModel(m_pModel
);
721 // create or destroy the vertical scrollbar, as needed
725 m_pModel
->getVerticalScrollbarVisibility(aDataCellPlayground
.GetHeight(),m_nRowHeightPixel
*m_nRowCount
),
726 lcl_getRowsFittingInto( aDataCellPlayground
.GetHeight(), m_nRowHeightPixel
),
728 m_nTopRow
, // current position
730 m_nRowCount
, // range
732 LINK( this, TableControl_Impl
, OnScroll
) // scroll handler
737 Rectangle
aScrollbarArea(
738 Point( aDataCellPlayground
.Right() + 1, 0 ),
739 Size( nScrollbarMetrics
, aDataCellPlayground
.Bottom() + 1 )
741 m_pVScroll
->SetPosSizePixel(
742 aScrollbarArea
.TopLeft(), aScrollbarArea
.GetSize() );
745 // create or destroy the horizontal scrollbar, as needed
749 m_pModel
->getHorizontalScrollbarVisibility(aDataCellPlayground
.GetWidth(), m_aAccColumnWidthsPixel
[m_nColumnCount
-1]),
750 lcl_getColumnsVisibleWithin( aDataCellPlayground
, m_nLeftColumn
, *this, false ),
752 m_nLeftColumn
, // current position
754 m_nColumnCount
, // range
756 LINK( this, TableControl_Impl
, OnScroll
) // scroll handler
761 Rectangle
aScrollbarArea(
762 Point( 0, aDataCellPlayground
.Bottom() + 1 ),
763 Size( aDataCellPlayground
.Right() + 1, nScrollbarMetrics
)
765 m_pHScroll
->SetPosSizePixel(
766 aScrollbarArea
.TopLeft(), aScrollbarArea
.GetSize() );
769 // the corner window connecting the two scrollbars in the lower right corner
770 bool bHaveScrollCorner
= NULL
!= m_pScrollCorner
;
771 bool bNeedScrollCorner
= ( NULL
!= m_pHScroll
) && ( NULL
!= m_pVScroll
);
772 if ( bHaveScrollCorner
&& !bNeedScrollCorner
)
774 DELETEZ( m_pScrollCorner
);
776 else if ( !bHaveScrollCorner
&& bNeedScrollCorner
)
778 m_pScrollCorner
= new ScrollBarBox( &m_rAntiImpl
);
779 m_pScrollCorner
->SetSizePixel( Size( nScrollbarMetrics
, nScrollbarMetrics
) );
780 m_pScrollCorner
->SetPosPixel( Point( aDataCellPlayground
.Right() + 1, aDataCellPlayground
.Bottom() + 1 ) );
781 m_pScrollCorner
->Show();
784 // resize the data window
785 m_pDataWindow
->SetSizePixel( Size(
786 aDataCellPlayground
.GetWidth() + m_nRowHeaderWidthPixel
,
787 aDataCellPlayground
.GetHeight() + m_nColHeaderHeightPixel
791 //--------------------------------------------------------------------
792 void TableControl_Impl::onResize()
795 impl_ni_updateScrollbars();
796 //Rectangle aAllCells;
797 // impl_getAllVisibleCellsArea( aAllCells );
798 //m_pSelEngine->SetVisibleArea(aAllCells);
801 //--------------------------------------------------------------------
802 void TableControl_Impl::doPaintContent( const Rectangle
& _rUpdateRect
)
809 PTableRenderer pRenderer
= getModel()->getRenderer();
810 DBG_ASSERT( !!pRenderer
, "TableDataWindow::Paint: invalid renderer!" );
814 // our current style settings, to be passed to the renderer
815 const StyleSettings
& rStyle
= m_rAntiImpl
.GetSettings().GetStyleSettings();
817 // the area occupied by all (at least partially) visible cells, including
819 Rectangle aAllCellsWithHeaders
;
820 impl_getAllVisibleCellsArea( aAllCellsWithHeaders
);
822 m_nRowCount
= m_pModel
->getRowCount();
823 // ............................
824 // draw the header column area
825 if ( getModel()->hasColumnHeaders() )
827 TableRowGeometry
aHeaderRow( *this, Rectangle( Point( 0, 0 ),
828 aAllCellsWithHeaders
.BottomRight() ), ROW_COL_HEADERS
);
829 pRenderer
->PaintHeaderArea(
830 *m_pDataWindow
, aHeaderRow
.getRect(), true, false, rStyle
832 // Note that strictly, aHeaderRow.getRect() also contains the intersection between column
833 // and row header area. However, below we go to paint this intersection, again,
834 // so this hopefully doesn't hurt if we already paint it here.
836 for ( TableCellGeometry
aCell( aHeaderRow
, m_nLeftColumn
);
841 if ( _rUpdateRect
.GetIntersection( aCell
.getRect() ).IsEmpty() )
844 bool isActiveColumn
= ( aCell
.getColumn() == getCurColumn() );
845 bool isSelectedColumn
= false;
846 pRenderer
->PaintColumnHeader( aCell
.getColumn(), isActiveColumn
, isSelectedColumn
,
847 *m_pDataWindow
, aCell
.getRect(), rStyle
);
851 // the area occupied by the row header, if any
852 Rectangle aRowHeaderArea
;
853 if ( getModel()->hasRowHeaders() )
855 aRowHeaderArea
= aAllCellsWithHeaders
;
856 aRowHeaderArea
.Right() = m_nRowHeaderWidthPixel
- 1;
857 aRowHeaderArea
.Bottom() = m_nRowHeightPixel
* m_nRowCount
+ m_nColHeaderHeightPixel
- 1;
858 pRenderer
->PaintHeaderArea(
859 *m_pDataWindow
, aRowHeaderArea
, false, true, rStyle
861 // Note that strictly, aRowHeaderArea also contains the intersection between column
862 // and row header area. However, below we go to paint this intersection, again,
863 // so this hopefully doesn't hurt if we already paint it here.
865 if ( getModel()->hasColumnHeaders() )
867 TableCellGeometry
aIntersection( *this, Rectangle( Point( 0, 0 ),
868 aAllCellsWithHeaders
.BottomRight() ), COL_ROW_HEADERS
, ROW_COL_HEADERS
);
869 pRenderer
->PaintHeaderArea(
870 *m_pDataWindow
, aIntersection
.getRect(), true, true, rStyle
875 // ............................
876 // draw the table content row by row
878 TableSize colCount
= getModel()->getColumnCount();
881 Rectangle aAllDataCellsArea
;
882 impl_getAllVisibleDataCellArea( aAllDataCellsArea
);
884 //get the vector, which contains row vectors, each containing the data for the cells in this row
885 std::vector
<std::vector
<rtl::OUString
> > aCellContent
= m_pModel
->getCellContent();
886 //if the vector is empty, fill it with empty data, so the table can be painted
887 if(aCellContent
.empty())
889 std::vector
<rtl::OUString
> emptyCells
;
890 while(m_nRowCount
!=0)
892 aCellContent
.push_back(emptyCells
);
896 std::vector
<std::vector
<rtl::OUString
> >::iterator it
= aCellContent
.begin()+m_nTopRow
;
897 //get the vector, which contains the row header titles
898 std::vector
<rtl::OUString
> aRowHeaderContent
;
899 ::std::vector
<rtl::OUString
>::iterator itRowName
= aRowHeaderContent
.begin();
901 if(m_pModel
->hasRowHeaders())
903 aRowHeaderContent
= m_pModel
->getRowHeaderName();
904 //if the vector is empty, fill it with empty strings, so the table can be painted
905 if(aRowHeaderContent
.empty())
907 while(m_nRowCount
!=0)
909 aRowHeaderContent
.push_back(rtl::OUString::createFromAscii(""));
913 itRowName
= aRowHeaderContent
.begin()+m_nTopRow
;
915 for ( TableRowGeometry
aRowIterator( *this, aAllCellsWithHeaders
, getTopRow() );
916 aRowIterator
.isValid();
917 aRowIterator
.moveDown() )
919 if ( _rUpdateRect
.GetIntersection( aRowIterator
.getRect() ).IsEmpty() )
921 if(m_pModel
->hasRowHeaders())
926 bool isActiveRow
= ( aRowIterator
.getRow() == getCurRow() );
927 bool isSelectedRow
= false;
928 if(!m_nRowSelected
.empty())
930 for(std::vector
<RowPos
>::iterator itSel
=m_nRowSelected
.begin();
931 itSel
!=m_nRowSelected
.end();++itSel
)
933 if(*itSel
== aRowIterator
.getRow())
934 isSelectedRow
= true;
937 std::vector
<rtl::OUString
> aCellData
;
938 if(it
!= aCellContent
.end())
943 ::std::vector
<rtl::OUString
>::iterator iter
= aCellData
.begin()+m_nLeftColumn
;
945 // give the redenderer a chance to prepare the row
946 pRenderer
->PrepareRow( aRowIterator
.getRow(), isActiveRow
, isSelectedRow
,
947 *m_pDataWindow
, aRowIterator
.getRect().GetIntersection( aAllDataCellsArea
), rStyle
);
949 // paint the row header
950 if ( m_pModel
->hasRowHeaders() )
952 rtl::OUString rowHeaderName
;
953 if(itRowName
!= aRowHeaderContent
.end())
955 rowHeaderName
= *itRowName
;
958 Rectangle
aCurrentRowHeader( aRowHeaderArea
.GetIntersection( aRowIterator
.getRect() ) );
959 pRenderer
->PaintRowHeader( isActiveRow
, isSelectedRow
, *m_pDataWindow
, aCurrentRowHeader
,
960 rStyle
, rowHeaderName
);
965 // paint all cells in this row
966 for ( TableCellGeometry
aCell( aRowIterator
, m_nLeftColumn
);
971 // if ( _rUpdateRect.GetIntersection( aCell.getRect() ).IsEmpty() )
974 //bool isActiveCell = isActiveRow && ( aCell.getColumn() == getCurColumn() );
975 bool isSelectedColumn
= false;
976 rtl::OUString cellData
;
977 if(aCellData
.empty())
978 cellData
=rtl::OUString::createFromAscii("");
979 else if(iter
!= aCellData
.end())
984 pRenderer
->PaintCell( aCell
.getColumn(), isSelectedRow
|| isSelectedColumn
, isActiveRow
,
985 *m_pDataWindow
, aCell
.getRect(), rStyle
, cellData
);
990 //--------------------------------------------------------------------
991 void TableControl_Impl::hideCursor()
995 if ( ++m_nCursorHidden
== 1 )
996 impl_ni_doSwitchCursor( false );
999 //--------------------------------------------------------------------
1000 void TableControl_Impl::showCursor()
1004 DBG_ASSERT( m_nCursorHidden
> 0, "TableControl_Impl::showCursor: cursor not hidden!" );
1005 if ( --m_nCursorHidden
== 0 )
1006 impl_ni_doSwitchCursor( true );
1009 //--------------------------------------------------------------------
1010 bool TableControl_Impl::dispatchAction( TableControlAction _eAction
)
1014 bool bSuccess
= false;
1019 if(m_pSelEngine
->GetSelectionMode() == SINGLE_SELECTION
)
1021 //if other rows already selected, deselect them
1022 if(m_nRowSelected
.size()>0)
1024 for(std::vector
<RowPos
>::iterator it
=m_nRowSelected
.begin();
1025 it
!=m_nRowSelected
.end();++it
)
1027 invalidateSelectedRow(*it
,rCells
);
1028 m_pDataWindow
->Invalidate(rCells
);
1030 m_nRowSelected
.clear();
1032 if(m_nCurRow
< m_nRowCount
-1)
1035 m_nRowSelected
.push_back(m_nCurRow
);
1038 m_nRowSelected
.push_back(m_nCurRow
);
1039 invalidateSelectedRow(m_nCurRow
, rCells
);
1040 ensureVisible(m_nCurColumn
,m_nCurRow
,false);
1045 if ( m_nCurRow
< m_nRowCount
- 1 )
1046 bSuccess
= goTo( m_nCurColumn
, m_nCurRow
+ 1 );
1051 if(m_pSelEngine
->GetSelectionMode() == SINGLE_SELECTION
)
1053 if(m_nRowSelected
.size()>0)
1055 for(std::vector
<RowPos
>::iterator it
=m_nRowSelected
.begin();
1056 it
!=m_nRowSelected
.end();++it
)
1058 invalidateSelectedRow(*it
,rCells
);
1059 m_pDataWindow
->Invalidate(rCells
);
1061 m_nRowSelected
.clear();
1066 m_nRowSelected
.push_back(m_nCurRow
);
1067 invalidateSelectedRow(m_nCurRow
, rCells
);
1071 m_nRowSelected
.push_back(m_nCurRow
);
1072 invalidateSelectedRow(m_nCurRow
, rCells
);
1074 ensureVisible(m_nCurColumn
,m_nCurRow
,false);
1079 if ( m_nCurRow
> 0 )
1080 bSuccess
= goTo( m_nCurColumn
, m_nCurRow
- 1 );
1084 if ( m_nCurColumn
> 0 )
1085 bSuccess
= goTo( m_nCurColumn
- 1, m_nCurRow
);
1087 if ( ( m_nCurColumn
== 0) && ( m_nCurRow
> 0 ) )
1088 bSuccess
= goTo( m_nColumnCount
- 1, m_nCurRow
- 1 );
1092 if ( m_nCurColumn
< m_nColumnCount
- 1 )
1093 bSuccess
= goTo( m_nCurColumn
+ 1, m_nCurRow
);
1095 if ( ( m_nCurColumn
== m_nColumnCount
- 1 ) && ( m_nCurRow
< m_nRowCount
- 1 ) )
1096 bSuccess
= goTo( 0, m_nCurRow
+ 1 );
1099 case cursorToLineStart
:
1100 bSuccess
= goTo( 0, m_nCurRow
);
1103 case cursorToLineEnd
:
1104 bSuccess
= goTo( m_nColumnCount
- 1, m_nCurRow
);
1107 case cursorToFirstLine
:
1108 bSuccess
= goTo( m_nCurColumn
, 0 );
1111 case cursorToLastLine
:
1112 bSuccess
= goTo( m_nCurColumn
, m_nRowCount
- 1 );
1117 RowPos nNewRow
= ::std::max( (RowPos
)0, m_nCurRow
- impl_getVisibleRows( false ) );
1118 bSuccess
= goTo( m_nCurColumn
, nNewRow
);
1122 case cursorPageDown
:
1124 RowPos nNewRow
= ::std::min( m_nRowCount
- 1, m_nCurRow
+ impl_getVisibleRows( false ) );
1125 bSuccess
= goTo( m_nCurColumn
, nNewRow
);
1130 bSuccess
= goTo( 0, 0 );
1133 case cursorBottomRight
:
1134 bSuccess
= goTo( m_nColumnCount
- 1, m_nRowCount
- 1 );
1137 case cursorSelectRow
:
1139 if(m_pSelEngine
->GetSelectionMode() == NO_SELECTION
)
1140 return bSuccess
= false;
1141 //pos is the position of the current row in the vector of selected rows, if current row is selected
1142 int pos
= getRowSelectedNumber(m_nRowSelected
, m_nCurRow
);
1143 //if current row is selected, it should be deselected, when ALT+SPACE are pressed
1145 m_nRowSelected
.erase(m_nRowSelected
.begin()+pos
);
1146 //else select the row->put it in the vector
1148 m_nRowSelected
.push_back(m_nCurRow
);
1149 invalidateSelectedRow(m_nCurRow
, rCells
);
1153 case cursorSelectRowUp
:
1155 if(m_pSelEngine
->GetSelectionMode() == NO_SELECTION
)
1156 return bSuccess
= false;
1157 else if(m_pSelEngine
->GetSelectionMode() == SINGLE_SELECTION
)
1159 //if there are other selected rows, deselect them
1164 //there are other selected rows
1165 if(m_nRowSelected
.size()>0)
1167 //the anchor wasn't set -> a region is not selected, that's why clear all selection
1168 //and select the current row
1171 for(std::vector
<RowPos
>::iterator it
=m_nRowSelected
.begin();
1172 it
!=m_nRowSelected
.end();++it
)
1174 invalidateSelectedRow(*it
,rCells
);
1175 m_pDataWindow
->Invalidate(rCells
);
1177 m_nRowSelected
.clear();
1178 m_nRowSelected
.push_back(m_nCurRow
);
1179 invalidateSelectedRow(m_nCurRow
, rCells
);
1183 //a region is already selected, prevRow is last selected row and the row above - nextRow - should be selected
1184 int prevRow
= getRowSelectedNumber(m_nRowSelected
, m_nCurRow
);
1185 int nextRow
= getRowSelectedNumber(m_nRowSelected
, m_nCurRow
-1);
1188 //if m_nCurRow isn't the upper one, can move up, otherwise not
1192 return bSuccess
= true;
1193 //if nextRow already selected, deselect it, otherwise select it
1194 if(m_nRowSelected
[nextRow
] == m_nCurRow
)
1196 m_nRowSelected
.erase(m_nRowSelected
.begin()+prevRow
);
1197 invalidateSelectedRow(m_nCurRow
+1, rCells
);
1201 m_nRowSelected
.push_back(m_nCurRow
);
1202 invalidateSelectedRow(m_nCurRow
, rCells
);
1209 //if nothing is selected and the current row isn't the upper one
1210 //select the current and one row above
1211 //otherwise select only the upper row
1214 m_nRowSelected
.push_back(m_nCurRow
);
1216 m_nRowSelected
.push_back(m_nCurRow
);
1217 invalidateSelectedRegion(m_nCurRow
+1, m_nCurRow
, rCells
);
1221 m_nRowSelected
.push_back(m_nCurRow
);
1222 invalidateSelectedRow(m_nCurRow
, rCells
);
1225 m_pSelEngine
->SetAnchor(TRUE
);
1226 m_nAnchor
= m_nCurRow
;
1227 ensureVisible(m_nCurColumn
, m_nCurRow
, false);
1232 case cursorSelectRowDown
:
1234 if(m_pSelEngine
->GetSelectionMode() == NO_SELECTION
)
1236 else if(m_pSelEngine
->GetSelectionMode() == SINGLE_SELECTION
)
1242 if(m_nRowSelected
.size()>0)
1244 //the anchor wasn't set -> a region is not selected, that's why clear all selection
1245 //and select the current row
1248 for(std::vector
<RowPos
>::iterator it
=m_nRowSelected
.begin();
1249 it
!=m_nRowSelected
.end();++it
)
1251 invalidateSelectedRow(*it
,rCells
);
1252 m_pDataWindow
->Invalidate(rCells
);
1254 m_nRowSelected
.clear();
1255 m_nRowSelected
.push_back(m_nCurRow
);
1256 invalidateSelectedRow(m_nCurRow
, rCells
);
1260 //a region is already selected, prevRow is last selected row and the row beneath - nextRow - should be selected
1261 int prevRow
= getRowSelectedNumber(m_nRowSelected
, m_nCurRow
);
1262 int nextRow
= getRowSelectedNumber(m_nRowSelected
, m_nCurRow
+1);
1265 //if m_nCurRow isn't the last one, can move down, otherwise not
1266 if(m_nCurRow
<m_nRowCount
)
1269 return bSuccess
= true;
1270 //if net row already selected, deselect it, otherwise select it
1271 if(m_nRowSelected
[nextRow
] == m_nCurRow
)
1273 m_nRowSelected
.erase(m_nRowSelected
.begin()+prevRow
);
1274 invalidateSelectedRow(m_nCurRow
-1, rCells
);
1278 m_nRowSelected
.push_back(m_nCurRow
);
1279 invalidateSelectedRow(m_nCurRow
, rCells
);
1286 //there wasn't any selection, select curennt and row beneath, otherwise onlyrow beneath
1287 if(m_nCurRow
<m_nRowCount
-1)
1289 m_nRowSelected
.push_back(m_nCurRow
);
1291 m_nRowSelected
.push_back(m_nCurRow
);
1292 invalidateSelectedRegion(m_nCurRow
-1, m_nCurRow
, rCells
);
1296 m_nRowSelected
.push_back(m_nCurRow
);
1297 invalidateSelectedRow(m_nCurRow
, rCells
);
1300 m_pSelEngine
->SetAnchor(TRUE
);
1301 m_nAnchor
= m_nCurRow
;
1302 ensureVisible(m_nCurColumn
, m_nCurRow
, false);
1307 case cursorSelectRowAreaTop
:
1309 if(m_pSelEngine
->GetSelectionMode() == NO_SELECTION
)
1311 else if(m_pSelEngine
->GetSelectionMode() == SINGLE_SELECTION
)
1315 //select the region between the current and the upper row
1316 RowPos iter
= m_nCurRow
;
1317 invalidateSelectedRegion(m_nCurRow
, 0, rCells
);
1318 //put the rows in vector
1321 if(!isRowSelected(m_nRowSelected
, iter
))
1322 m_nRowSelected
.push_back(iter
);
1326 m_nAnchor
= m_nCurRow
;
1327 m_pSelEngine
->SetAnchor(TRUE
);
1328 ensureVisible(m_nCurColumn
, 0, false);
1333 case cursorSelectRowAreaBottom
:
1335 if(m_pSelEngine
->GetSelectionMode() == NO_SELECTION
)
1336 return bSuccess
= false;
1337 else if(m_pSelEngine
->GetSelectionMode() == SINGLE_SELECTION
)
1338 return bSuccess
= false;
1339 //select the region between the current and the last row
1340 RowPos iter
= m_nCurRow
;
1341 invalidateSelectedRegion(m_nCurRow
, m_nRowCount
-1, rCells
);
1342 //put the rows in the vector
1343 while(iter
<=m_nRowCount
)
1345 if(!isRowSelected(m_nRowSelected
, iter
))
1346 m_nRowSelected
.push_back(iter
);
1349 m_nCurRow
= m_nRowCount
-1;
1350 m_nAnchor
= m_nCurRow
;
1351 m_pSelEngine
->SetAnchor(TRUE
);
1352 ensureVisible(m_nCurColumn
, m_nRowCount
, false);
1357 DBG_ERROR( "TableControl_Impl::dispatchAction: unsupported action!" );
1362 //--------------------------------------------------------------------
1363 void TableControl_Impl::impl_ni_doSwitchCursor( bool _bShow
)
1365 PTableRenderer pRenderer
= !!m_pModel
? m_pModel
->getRenderer() : PTableRenderer();
1368 Rectangle aCellRect
;
1369 impl_getCellRect( m_nCurColumn
, m_nCurRow
, aCellRect
);
1371 // const StyleSettings& rStyle = m_rAntiImpl.GetSettings().GetStyleSettings();
1374 pRenderer
->ShowCellCursor( *m_pDataWindow
, aCellRect
);
1378 pRenderer
->HideCellCursor( *m_pDataWindow
, aCellRect
);
1383 //--------------------------------------------------------------------
1384 void TableControl_Impl::impl_getCellRect( ColPos _nColumn
, RowPos _nRow
, Rectangle
& _rCellRect
) const
1389 || ( COL_INVALID
== _nColumn
)
1390 || ( ROW_INVALID
== _nRow
)
1393 _rCellRect
.SetEmpty();
1397 DBG_ASSERT( ( _nColumn
>= 0 ) && ( _nColumn
< m_pModel
->getColumnCount() ),
1398 "TableControl_Impl::impl_getCellRect: invalid column index!" );
1399 DBG_ASSERT( ( _nRow
>= 0 ) && ( _nRow
< m_pModel
->getRowCount() ),
1400 "TableControl_Impl::impl_getCellRect: invalid row index!" );
1402 Rectangle aAllCells
;
1403 impl_getAllVisibleCellsArea( aAllCells
);
1405 TableCellGeometry
aCell( *this, aAllCells
, _nColumn
, _nRow
);
1406 _rCellRect
= aCell
.getRect();
1408 //-------------------------------------------------------------------------------
1409 RowPos
TableControl_Impl::getCurrentRow(const Point
& rPoint
)
1412 Rectangle rCellRect
;
1413 RowPos newRowPos
= -2;//-1 is HeaderRow
1414 ColPos newColPos
= 0;
1415 //To Do: when only row position needed, the second loop isn't necessary, Please proove this!!!
1416 for(int i
=0;i
<m_nRowCount
;i
++)
1418 for(int j
=-1;j
<m_nColumnCount
;j
++)
1420 impl_getCellRect(j
,i
,rCellRect
);
1421 if((rPoint
.X() >= rCellRect
.Left() && rPoint
.X() <= rCellRect
.Right()) && rPoint
.Y() >= rCellRect
.Top() && rPoint
.Y() <= rCellRect
.Bottom())
1428 m_nCurColumn
= newColPos
;
1435 //-------------------------------------------------------------------------------
1436 void TableControl_Impl::setCursorAtCurrentCell(const Point
& rPoint
)
1440 Rectangle rCellRect
;
1441 RowPos newRowPos
= -2;//-1 is HeaderRow
1442 ColPos newColPos
= 0;
1443 //To Do: when only row position needed, the second loop isn't necessary, Please proove this!!!
1444 for(int i
=0;i
<m_nRowCount
;i
++)
1446 for(int j
=-1;j
<m_nColumnCount
;j
++)
1448 impl_getCellRect(j
,i
,rCellRect
);
1449 if((rPoint
.X() >= rCellRect
.Left() && rPoint
.X() <= rCellRect
.Right()) && rPoint
.Y() >= rCellRect
.Top() && rPoint
.Y() <= rCellRect
.Bottom())
1452 m_nCurRow
= newRowPos
;
1457 m_nCurColumn
= newColPos
;
1464 //-------------------------------------------------------------------------------
1465 void TableControl_Impl::invalidateSelectedRegion(RowPos _nPrevRow
, RowPos _nCurRow
, Rectangle
& _rCellRect
)
1468 Rectangle aAllCells
;
1469 //get the visible area of the table control and set the Left and right border of the region to be repainted
1470 impl_getAllVisibleCellsArea( aAllCells
);
1471 _rCellRect
.Left() = aAllCells
.Left();
1472 _rCellRect
.Right() = aAllCells
.Right();
1474 //if only one row is selected
1475 if(_nPrevRow
== _nCurRow
)
1477 impl_getCellRect(m_nCurColumn
,_nCurRow
,rCells
);
1478 _rCellRect
.Top()=rCells
.Top();
1479 _rCellRect
.Bottom()=rCells
.Bottom();
1481 //if the region is above the current row
1482 else if(_nPrevRow
< _nCurRow
)
1484 impl_getCellRect(m_nCurColumn
,_nPrevRow
,rCells
);
1485 _rCellRect
.Top()=rCells
.Top();
1486 impl_getCellRect(m_nCurColumn
,_nCurRow
,rCells
);
1487 _rCellRect
.Bottom()=rCells
.Bottom();
1489 //if the region is beneath the current row
1492 impl_getCellRect(m_nCurColumn
,_nCurRow
,rCells
);
1493 _rCellRect
.Top()=rCells
.Top();
1494 impl_getCellRect(m_nCurColumn
,_nPrevRow
,rCells
);
1495 _rCellRect
.Bottom()=rCells
.Bottom();
1497 m_pDataWindow
->Invalidate(_rCellRect
);
1500 //-------------------------------------------------------------------------------
1501 //To Do: not really needed, because in method above one row can be invalidate. Please Prove this!!!
1502 void TableControl_Impl::invalidateSelectedRow(RowPos _nCurRow
, Rectangle
& _rCellRect
)
1505 Rectangle aAllCells
;
1506 impl_getAllVisibleCellsArea( aAllCells
);
1507 _rCellRect
.Left() = aAllCells
.Left();
1508 _rCellRect
.Right() = aAllCells
.Right();
1510 impl_getCellRect(m_nCurColumn
,_nCurRow
,rCells
);
1511 _rCellRect
.Top()=rCells
.Top();
1512 _rCellRect
.Bottom()=rCells
.Bottom();
1513 m_pDataWindow
->Invalidate(_rCellRect
);
1515 //-------------------------------------------------------------------------------
1516 //this method is to be called, when a new row is added
1517 void TableControl_Impl::invalidateRow(RowPos _nRowPos
, Rectangle
& _rCellRect
)
1520 TempHideCursor
aHideCursor( *this );
1521 impl_getAllVisibleCellsArea( _rCellRect
);
1522 TableRowGeometry
_rRow( *this, _rCellRect
, _nRowPos
);
1523 impl_ni_updateScrollbars();
1524 m_pDataWindow
->Invalidate(_rRow
.getRect());
1527 //-------------------------------------------------------------------------------
1528 std::vector
<RowPos
> TableControl_Impl::getSelectedRows()
1530 return m_nRowSelected
;
1533 void TableControl_Impl::removeSelectedRow(RowPos _nRowPos
)
1536 //if the row is selected, remove it from the selection vector
1537 if(isRowSelected(m_nRowSelected
, _nRowPos
))
1539 if(m_nRowSelected
.size()>1)
1540 m_nRowSelected
.erase(m_nRowSelected
.begin()+_nRowPos
);
1542 m_nRowSelected
.clear();
1544 //after removing a row, row positions must be updated, so selected rows could stay selected
1545 if(m_nRowSelected
.size()>1)
1547 for(std::vector
<RowPos
>::iterator it
=m_nRowSelected
.begin();it
!=m_nRowSelected
.end();++it
)
1550 m_nRowSelected
[i
]=*it
-1;
1557 m_nCurRow
= _nRowPos
-1;
1559 //-------------------------------------------------------------------------------
1560 void TableControl_Impl::invalidateRows(RowPos _nRowStart
, Rectangle
& _rCellRect
)
1565 /*TempHideCursor aHideCursor(*this);
1566 Rectangle aAllCells;
1567 impl_getAllVisibleCellsArea( aAllCells );
1568 TableRowGeometry _rRow( *this, aAllCells, _nRowStart);
1569 _rCellRect = _rRow.getRect();
1571 impl_getCellRect(m_nCurColumn,m_nRowCount,rCells1);
1572 _rCellRect.Bottom() = rCells1.Bottom();*/
1573 /*if(_nRowStart != _nRowEnd)
1575 TableRowGeometry _rRow( *this, aAllCells, _nRowEnd);
1576 _rCellRect.Bottom() = _rRow.getRect().Bottom();
1579 //_rCellRect.Right() = aAllCells.Right();
1580 //_rCellRect.Left() = aAllCells.Left();
1581 //Rectangle rCells1;
1582 //impl_getCellRect(m_nCurColumn,_nRowStart,rCells1);
1583 //_rCellRect.Top()=rCells1.Top();
1584 //Rectangle rCells2;
1585 //impl_getCellRect(m_nCurColumn,_nRowEnd,rCells2);
1586 //_rCellRect.Bottom()=rCells2.Bottom();
1587 impl_ni_updateScrollbars();
1588 //m_pDataWindow->Invalidate(_rCellRect);
1589 m_pDataWindow
->Invalidate();
1593 //-------------------------------------------------------------------------------
1594 bool TableControl_Impl::isClickInVisibleArea(const Point
& rPoint
)
1597 long nScrollbarMetrics
= m_rAntiImpl
.GetSettings().GetStyleSettings().GetScrollBarSize();
1598 //clickable area is in the visible table control area without the scrollbars
1599 Rectangle
aDataCellPlayground( Point( 0, 0 ), m_rAntiImpl
.GetOutputSizePixel() );
1600 aDataCellPlayground
.Top() = m_nColHeaderHeightPixel
;
1601 aDataCellPlayground
.Right() -= nScrollbarMetrics
;
1602 aDataCellPlayground
.Bottom() -= nScrollbarMetrics
;
1603 if((rPoint
.X() >= aDataCellPlayground
.Left() && rPoint
.X() <= aDataCellPlayground
.Right()) && rPoint
.Y() >= aDataCellPlayground
.Top() && rPoint
.Y() <= aDataCellPlayground
.Bottom())
1610 //--------------------------------------------------------------------
1611 TableSize
TableControl_Impl::impl_getVisibleRows( bool _bAcceptPartialRow
) const
1615 DBG_ASSERT( m_pDataWindow
, "TableControl_Impl::impl_getVisibleRows: no data window!" );
1617 return lcl_getRowsFittingInto(
1618 m_pDataWindow
->GetOutputSizePixel().Height() - m_nColHeaderHeightPixel
,
1624 //--------------------------------------------------------------------
1625 TableSize
TableControl_Impl::impl_getVisibleColumns( bool _bAcceptPartialRow
) const
1629 DBG_ASSERT( m_pDataWindow
, "TableControl_Impl::impl_getVisibleColumns: no data window!" );
1631 return lcl_getColumnsVisibleWithin(
1632 Rectangle( Point( 0, 0 ), m_pDataWindow
->GetOutputSizePixel() ),
1639 //--------------------------------------------------------------------
1640 bool TableControl_Impl::goTo( ColPos _nColumn
, RowPos _nRow
)
1644 // TODO: give veto listeners a chance
1646 if ( ( _nColumn
< -1 ) || ( _nColumn
>= m_nColumnCount
)
1647 || ( _nRow
< -1 ) || ( _nRow
>= m_nRowCount
)
1651 TempHideCursor
aHideCursor( *this );
1652 m_nCurColumn
= _nColumn
;
1655 // ensure that the new cell is visible
1656 ensureVisible( m_nCurColumn
, m_nCurRow
, false );
1658 // TODO: invalidate all and new column/row header, if present, to enforce
1660 //if(!m_nRowSelected.empty())
1662 // Rectangle rCells;
1663 // for(std::vector<RowPos>::iterator it=m_nRowSelected.begin();
1664 // it!=m_nRowSelected.end();++it)
1666 // invalidateSelectedRow(*it,rCells);
1668 // m_nRowSelected.clear();
1670 // TODO: notify listeners about new position
1674 //--------------------------------------------------------------------
1675 void TableControl_Impl::ensureVisible( ColPos _nColumn
, RowPos _nRow
, bool _bAcceptPartialVisibility
)
1678 DBG_ASSERT( ( _nColumn
>= 0 ) && ( _nColumn
< m_nColumnCount
)
1679 && ( _nRow
>= 0 ) && ( _nRow
< m_nRowCount
),
1680 "TableControl_Impl::ensureVisible: invalid coordinates!" );
1682 TempHideCursor
aHideCursor( *this );
1684 if ( _nColumn
< m_nLeftColumn
)
1685 impl_ni_ScrollColumns( _nColumn
- m_nLeftColumn
);
1688 TableSize nVisibleColumns
= impl_getVisibleColumns( _bAcceptPartialVisibility
);
1689 if ( _nColumn
> m_nLeftColumn
+ nVisibleColumns
- 1 )
1691 impl_ni_ScrollColumns( _nColumn
- ( m_nLeftColumn
+ nVisibleColumns
- 1 ) );
1692 // TODO: since not all columns have the same width, this might in theory result
1693 // in the column still not being visible.
1697 if ( _nRow
< m_nTopRow
)
1698 impl_ni_ScrollRows( _nRow
- m_nTopRow
);
1701 TableSize nVisibleRows
= impl_getVisibleRows( _bAcceptPartialVisibility
);
1702 if ( _nRow
> m_nTopRow
+ nVisibleRows
- 1 )
1703 impl_ni_ScrollRows( _nRow
- ( m_nTopRow
+ nVisibleRows
- 1 ) );
1707 //--------------------------------------------------------------------
1708 TableSize
TableControl_Impl::impl_ni_ScrollRows( TableSize _nRowDelta
)
1710 // compute new top row
1713 ::std::min( (RowPos
)( m_nTopRow
+ _nRowDelta
), (RowPos
)( m_nRowCount
- 1 ) ),
1717 RowPos nOldTopRow
= m_nTopRow
;
1718 m_nTopRow
= nNewTopRow
;
1720 // if updates are enabled currently, scroll the viewport
1721 if ( m_rAntiImpl
.IsUpdateMode() && ( m_nTopRow
!= nOldTopRow
) )
1723 DBG_SUSPEND_INV( INV_SCROLL_POSITION
);
1724 TempHideCursor
aHideCursor( *this );
1725 // TODO: call a onStartScroll at our listener (or better an own onStartScroll,
1726 // which hides the cursor and then calls the listener)
1727 // Same for onEndScroll
1729 // scroll the view port, if possible
1730 long nPixelDelta
= m_nRowHeightPixel
* ( m_nTopRow
- nOldTopRow
);
1732 Rectangle
aDataArea( Point( 0, m_nColHeaderHeightPixel
), m_pDataWindow
->GetOutputSizePixel() );
1734 if ( m_pDataWindow
->GetBackground().IsScrollable()
1735 && abs( nPixelDelta
) < aDataArea
.GetHeight()
1738 m_pDataWindow
->Scroll( 0, (long)-nPixelDelta
, aDataArea
, SCROLL_CLIP
| SCROLL_UPDATE
);
1741 m_pDataWindow
->Invalidate( INVALIDATE_UPDATE
);
1743 // update the position at the vertical scrollbar
1744 m_pVScroll
->SetThumbPos( m_nTopRow
);
1747 return (TableSize
)( m_nTopRow
- nOldTopRow
);
1750 //--------------------------------------------------------------------
1751 TableSize
TableControl_Impl::impl_ni_ScrollColumns( TableSize _nColumnDelta
)
1753 // compute new left column
1754 ColPos nNewLeftColumn
=
1756 ::std::min( (ColPos
)( m_nLeftColumn
+ _nColumnDelta
), (ColPos
)( m_nColumnCount
- 1 ) ),
1760 ColPos nOldLeftColumn
= m_nLeftColumn
;
1761 m_nLeftColumn
= nNewLeftColumn
;
1763 // if updates are enabled currently, scroll the viewport
1764 if ( m_rAntiImpl
.IsUpdateMode() && ( m_nLeftColumn
!= nOldLeftColumn
) )
1766 DBG_SUSPEND_INV( INV_SCROLL_POSITION
);
1767 TempHideCursor
aHideCursor( *this );
1768 // TODO: call a onStartScroll at our listener (or better an own onStartScroll,
1769 // which hides the cursor and then calls the listener)
1770 // Same for onEndScroll
1772 // scroll the view port, if possible
1773 Rectangle
aDataArea( Point( m_nRowHeaderWidthPixel
, 0 ), m_pDataWindow
->GetOutputSizePixel() );
1776 ( m_nLeftColumn
> 0 ? m_aAccColumnWidthsPixel
[ m_nLeftColumn
- 1 ] : 0 )
1777 - ( nOldLeftColumn
> 0 ? m_aAccColumnWidthsPixel
[ nOldLeftColumn
- 1 ] : 0 );
1779 if ( m_pDataWindow
->GetBackground().IsScrollable()
1780 && abs( nPixelDelta
) < aDataArea
.GetWidth()
1783 m_pDataWindow
->Scroll( (long)-nPixelDelta
, 0, aDataArea
, SCROLL_CLIP
| SCROLL_UPDATE
);
1786 m_pDataWindow
->Invalidate( INVALIDATE_UPDATE
);
1788 // update the position at the horizontal scrollbar
1789 m_pHScroll
->SetThumbPos( m_nLeftColumn
);
1792 return (TableSize
)( m_nLeftColumn
- nOldLeftColumn
);
1795 SelectionEngine
* TableControl_Impl::getSelEngine()
1797 return m_pSelEngine
;
1799 TableDataWindow
* TableControl_Impl::getDataWindow()
1801 return m_pDataWindow
;
1803 BOOL
TableControl_Impl::isRowSelected(::std::vector
<RowPos
> selectedRows
, RowPos current
)
1805 for(::std::vector
<RowPos
>::iterator it
=selectedRows
.begin();
1806 it
!=selectedRows
.end();++it
)
1814 int TableControl_Impl::getRowSelectedNumber(::std::vector
<RowPos
> selectedRows
, RowPos current
)
1818 for(std::vector
<RowPos
>::iterator it
=selectedRows
.begin();it
!=selectedRows
.end();++it
)
1827 void TableControl_Impl::setCellContent(CellEntryType
* pCellEntryType
)
1829 (void)pCellEntryType
;
1832 //--------------------------------------------------------------------
1833 IMPL_LINK( TableControl_Impl
, OnScroll
, ScrollBar
*, _pScrollbar
)
1835 DBG_ASSERT( ( _pScrollbar
== m_pVScroll
) || ( _pScrollbar
== m_pHScroll
),
1836 "TableControl_Impl::OnScroll: where did this come from?" );
1838 if ( _pScrollbar
== m_pVScroll
)
1839 impl_ni_ScrollRows( _pScrollbar
->GetDelta() );
1841 impl_ni_ScrollColumns( _pScrollbar
->GetDelta() );
1846 //---------------------------------------------------------------------------------------
1847 TableFunctionSet::TableFunctionSet(TableControl_Impl
* _pTableControl
):
1848 m_pTableControl( _pTableControl
)
1853 TableFunctionSet::~TableFunctionSet()
1857 void TableFunctionSet::BeginDrag()
1861 void TableFunctionSet::CreateAnchor()
1863 m_pTableControl
->m_nAnchor
= m_pTableControl
->m_nCurRow
;
1866 void TableFunctionSet::DestroyAnchor()
1868 m_pTableControl
->m_nAnchor
= -1;
1871 BOOL
TableFunctionSet::SetCursorAtPoint(const Point
& rPoint
, BOOL bDontSelectAtCursor
)
1873 BOOL bHandled
= FALSE
;
1875 //curRow is the row where the mouse click happened, m_nCurRow is the last selected row, before the mouse click
1876 RowPos curRow
= m_pTableControl
->getCurrentRow(rPoint
);
1879 if( bDontSelectAtCursor
)
1881 if(m_pTableControl
->m_nRowSelected
.size()>1)
1882 m_pTableControl
->m_pSelEngine
->AddAlways(TRUE
);
1885 else if(m_pTableControl
->m_nAnchor
== m_pTableControl
->m_nCurRow
)
1888 int diff
= m_pTableControl
->m_nCurRow
- curRow
;
1889 //bool isAlreadySelected = m_pTableControl->isRowSelected(m_pTableControl->m_nRowSelected, m_pTableControl->m_nAnchor);
1890 /* if(!isAlreadySelected && m_nCurrentRow != m_pTableControl->m_nCurRow)
1891 m_pTableControl->m_nRowSelected.push_back(m_nAnchor);*/
1892 //selected region lies above the last selection
1895 //put selected rows in vector
1896 while(m_pTableControl
->m_nAnchor
>=curRow
)
1898 bool isAlreadySelected
= m_pTableControl
->isRowSelected(m_pTableControl
->m_nRowSelected
, m_pTableControl
->m_nAnchor
);
1899 //if row isn't selected, put it in vector, otherwise don't put it there, because it will be twice there
1900 if(!isAlreadySelected
)
1901 m_pTableControl
->m_nRowSelected
.push_back(m_pTableControl
->m_nAnchor
);
1902 m_pTableControl
->m_nAnchor
--;
1905 m_pTableControl
->m_nAnchor
++;
1907 //selected region lies beneath the last selected row
1910 while(m_pTableControl
->m_nAnchor
<=curRow
)
1912 bool isAlreadySelected
= m_pTableControl
->isRowSelected(m_pTableControl
->m_nRowSelected
, m_pTableControl
->m_nAnchor
);
1913 if(!isAlreadySelected
)
1914 m_pTableControl
->m_nRowSelected
.push_back(m_pTableControl
->m_nAnchor
);
1915 m_pTableControl
->m_nAnchor
++;
1918 m_pTableControl
->m_nAnchor
--;
1920 m_pTableControl
->invalidateSelectedRegion(m_pTableControl
->m_nCurRow
, curRow
, rCells
);
1923 //no region selected
1926 if(m_pTableControl
->m_nRowSelected
.empty())
1928 m_pTableControl
->m_nRowSelected
.push_back(curRow
);
1932 if(m_pTableControl
->m_pSelEngine
->GetSelectionMode()==SINGLE_SELECTION
)
1935 m_pTableControl
->m_nRowSelected
.push_back(curRow
);
1939 bool isAlreadySelected
= m_pTableControl
->isRowSelected(m_pTableControl
->m_nRowSelected
, curRow
);
1940 if(!isAlreadySelected
)
1941 m_pTableControl
->m_nRowSelected
.push_back(curRow
);
1944 if(m_pTableControl
->m_nRowSelected
.size()>1 && m_pTableControl
->m_pSelEngine
->GetSelectionMode()!=SINGLE_SELECTION
)
1945 m_pTableControl
->m_pSelEngine
->AddAlways(TRUE
);
1946 m_pTableControl
->invalidateSelectedRow(curRow
,rCells
);
1949 m_pTableControl
->m_nCurRow
= curRow
;
1950 m_pTableControl
->ensureVisible(m_pTableControl
->m_nCurColumn
,m_pTableControl
->m_nCurRow
,false);
1954 BOOL
TableFunctionSet::IsSelectionAtPoint( const Point
& rPoint
)
1956 m_pTableControl
->m_pSelEngine
->AddAlways(FALSE
);
1957 if(m_pTableControl
->m_nRowSelected
.empty())
1961 RowPos curRow
= m_pTableControl
->getCurrentRow(rPoint
);
1962 m_pTableControl
->m_nAnchor
= -1;
1963 bool selected
= m_pTableControl
->isRowSelected(m_pTableControl
->m_nRowSelected
, curRow
);
1964 m_nCurrentRow
= curRow
;
1969 void TableFunctionSet::DeselectAtPoint( const Point
& rPoint
)
1975 for(std::vector
<RowPos
>::iterator it
=m_pTableControl
->m_nRowSelected
.begin();
1976 it
!=m_pTableControl
->m_nRowSelected
.end();++it
)
1978 if(*it
== m_nCurrentRow
)
1981 m_pTableControl
->invalidateSelectedRow(*it
,rCells
);
1985 m_pTableControl
->m_nRowSelected
.erase(m_pTableControl
->m_nRowSelected
.begin()+pos
);
1987 void TableFunctionSet::DeselectAll()
1989 if(!m_pTableControl
->m_nRowSelected
.empty())
1992 for(std::vector
<RowPos
>::iterator it
=m_pTableControl
->m_nRowSelected
.begin();
1993 it
!=m_pTableControl
->m_nRowSelected
.end();++it
)
1995 m_pTableControl
->invalidateSelectedRow(*it
,rCells
);
1997 m_pTableControl
->m_nRowSelected
.clear();
2001 //........................................................................
2002 } } // namespace svt::table
2003 //........................................................................