Update ooo320-m1
[ooovba.git] / svtools / source / table / tablecontrol_impl.cxx
blobd565f887416bd8b8799892079551f14b020d3939
1 /*************************************************************************
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
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>
39 #include <functional>
40 #include <stdlib.h>
42 //........................................................................
43 namespace svt { namespace table
45 //........................................................................
47 //====================================================================
48 //= TempHideCursor
49 //====================================================================
50 class TempHideCursor
52 private:
53 IAbstractTableControl& m_rTable;
55 public:
56 TempHideCursor( IAbstractTableControl& _rTable )
57 :m_rTable( _rTable )
59 m_rTable.hideCursor();
61 ~TempHideCursor()
63 m_rTable.showCursor();
67 //====================================================================
68 //= EmptyTableModel
69 //====================================================================
70 /** default implementation of an ->ITableModel, used as fallback when no
71 real model is present
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
78 public:
79 EmptyTableModel()
83 // ITableModel overridables
84 virtual TableSize getColumnCount() const
86 return 0;
88 virtual TableSize getRowCount() const
90 return 0;
92 virtual bool hasColumnHeaders() const
94 return false;
96 virtual bool hasRowHeaders() const
98 return false;
100 virtual void setRowHeaders(bool _bRowHeaders)
102 (void)_bRowHeaders;
104 virtual void setColumnHeaders(bool _bColumnHeaders)
106 (void)_bColumnHeaders;
108 void setColumnCount(TableSize _nColCount)
110 (void) _nColCount;
112 void setRowCount(TableSize _nRowCount)
114 (void)_nRowCount;
116 virtual bool isCellEditable( ColPos col, RowPos row ) const
118 (void)col;
119 (void)row;
120 return false;
122 virtual void addTableModelListener( const PTableModelListener& listener )
124 (void)listener;
125 // ignore
127 virtual void removeTableModelListener( const PTableModelListener& listener )
129 (void)listener;
130 // ignore
132 virtual PColumnModel getColumnModel( ColPos column )
134 DBG_ERROR( "EmptyTableModel::getColumnModel: invalid call!" );
135 (void)column;
136 return PColumnModel();
138 virtual PColumnModel getColumnModelByID( ColumnID id )
140 DBG_ERROR( "EmptyTableModel::getColumnModel: invalid call!" );
141 (void)id;
142 return PColumnModel();
144 virtual PTableRenderer getRenderer() const
146 return PTableRenderer();
148 virtual PTableInputHandler getInputHandler() const
150 return PTableInputHandler();
152 virtual TableMetrics getRowHeight() const
154 return 5 * 100;
156 virtual void setRowHeight(TableMetrics _nRowHeight)
158 (void)_nRowHeight;
160 virtual TableMetrics getColumnHeaderHeight() const
162 return 0;
164 virtual TableMetrics getRowHeaderWidth() const
166 return 0;
168 virtual ScrollbarVisibility getVerticalScrollbarVisibility(int overAllHeight, int actHeight) const
170 (void)overAllHeight;
171 (void)actHeight;
172 return ScrollbarShowNever;
174 virtual ScrollbarVisibility getHorizontalScrollbarVisibility(int overAllWidth, int actWidth) const
176 (void)overAllWidth;
177 (void)actWidth;
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;
189 cC.push_back(cCC);
190 return 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(""));
200 return cCC;
205 //====================================================================
206 //= TableControl_Impl
207 //====================================================================
208 DBG_NAME( TableControl_Impl )
210 #if DBG_UTIL
211 //====================================================================
212 //= SuspendInvariants
213 //====================================================================
214 class SuspendInvariants
216 private:
217 const TableControl_Impl& m_rTable;
218 sal_Int32 m_nSuspendFlags;
220 public:
221 SuspendInvariants( const TableControl_Impl& _rTable, sal_Int32 _nSuspendFlags )
222 :m_rTable( _rTable )
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;
229 ~SuspendInvariants()
231 const_cast< TableControl_Impl& >( m_rTable ).m_nRequiredInvariants |= m_nSuspendFlags;
234 #define DBG_SUSPEND_INV( flags ) \
235 SuspendInvariants aSuspendInv( *this, flags );
236 #else
237 #define DBG_SUSPEND_INV( flags )
238 #endif
240 #if DBG_UTIL
241 //====================================================================
242 const char* TableControl_Impl_checkInvariants( const void* _pInstance )
244 return static_cast< const TableControl_Impl* >( _pInstance )->impl_checkInvariants();
247 namespace
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 )
259 if ( !_pModel )
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
270 if ( !m_pModel )
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;
312 if ( !isDummyModel )
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!";
359 return NULL;
361 #endif
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 )
370 ,m_pInputHandler ( )
371 ,m_nRowHeightPixel ( 15 )
372 ,m_nColHeaderHeightPixel( 0 )
373 ,m_nRowHeaderWidthPixel ( 0 )
374 ,m_nColumnCount ( 0 )
375 ,m_nRowCount ( 0 )
376 ,m_nCurColumn ( COL_INVALID )
377 ,m_nCurRow ( ROW_INVALID )
378 ,m_nLeftColumn ( 0 )
379 ,m_nTopRow ( 0 )
380 ,m_nCursorHidden ( 1 )
381 ,m_pDataWindow ( new TableDataWindow( *this ) )
382 ,m_pVScroll ( NULL )
383 ,m_pHScroll ( NULL )
384 ,m_pScrollCorner ( NULL )
385 ,m_pSelEngine ( )
386 ,m_nRowSelected ( )
387 ,m_pTableFunctionSet ( new TableFunctionSet(this ) )
388 ,m_nAnchor (-1 )
389 #if DBG_UTIL
390 ,m_nRequiredInvariants ( INV_SCROLL_POSITION )
391 #endif
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();
420 return m_pModel;
423 //--------------------------------------------------------------------
424 void TableControl_Impl::setModel( PTableModel _pModel )
426 DBG_CHECK_ME();
428 TempHideCursor aHideCursor( *this );
430 // TODO: revoke as table listener from the model
432 m_pModel = _pModel;
433 if ( !m_pModel )
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
455 DBG_CHECK_ME();
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
485 - 1;
488 //--------------------------------------------------------------------
489 void TableControl_Impl::impl_getAllVisibleDataCellArea( Rectangle& _rCellArea ) const
491 DBG_CHECK_ME();
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 );
528 if ( !m_pModel )
529 return;
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!" );
539 if ( !pColumn )
540 continue;
542 TableMetrics colWidth = pColumn->getWidth();
543 DBG_ASSERT( ( colWidth == COLWIDTH_FIT_TO_VIEW ) || ( colWidth > 0 ),
544 "TableControl_Impl::impl_ni_updateColumnWidths: invalid column width!" );
546 long pixelWidth = 0;
547 if ( colWidth == COLWIDTH_FIT_TO_VIEW )
549 // TODO
550 DBG_ERROR( "TableControl_Impl::impl_ni_updateColumnWidths: COLWIDTH_FIT_TO_VIEW not implemented, yet!" );
552 else
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 //--------------------------------------------------------------------
564 namespace
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 )
572 return false;
573 if ( _eVisibility == ScrollbarShowAlways )
574 return true;
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 )
605 DELETEZ( _rpBar );
607 else if ( !bHaveBar && bNeedBar )
609 _rpBar = new ScrollBar(
610 &_rParent,
611 WB_DRAG | ( _bHorizontal ? WB_HSCROLL : WB_VSCROLL )
613 _rpBar->SetScrollHdl( _rScrollHandler );
614 // get some speed into the scrolling ....
615 lcl_setButtonRepeat( *_rpBar, 0 );
618 if ( _rpBar )
620 _rpBar->SetRange( Range( 0, _nRange ) );
621 _rpBar->SetVisibleSize( _nVisibleUnits );
622 _rpBar->SetPageSize( _nVisibleUnits );
623 _rpBar->SetLineSize( _nLineSize );
624 _rpBar->SetThumbPos( _nPosition );
625 _rpBar->Show();
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
656 break;
658 aColumn.moveRight();
659 ++visibleColumns;
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 ),
687 m_nRowCount ) )
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 ),
696 m_nColumnCount ) )
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
703 // anymore
704 if ( !bFirstRoundVScrollNeed && lcl_determineScrollbarNeed(
705 m_pModel->getVerticalScrollbarVisibility(aDataCellPlayground.GetHeight(),m_nRowHeightPixel*m_nRowCount),
706 lcl_getRowsFittingInto( aDataCellPlayground.GetHeight(), m_nRowHeightPixel ),
707 m_nRowCount ) )
709 aDataCellPlayground.Right() -= nScrollbarMetrics;
712 else
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
722 lcl_updateScrollbar(
723 m_rAntiImpl,
724 m_pVScroll,
725 m_pModel->getVerticalScrollbarVisibility(aDataCellPlayground.GetHeight(),m_nRowHeightPixel*m_nRowCount),
726 lcl_getRowsFittingInto( aDataCellPlayground.GetHeight(), m_nRowHeightPixel ),
727 // visible units
728 m_nTopRow, // current position
729 1, // line size
730 m_nRowCount, // range
731 false, // vertical
732 LINK( this, TableControl_Impl, OnScroll ) // scroll handler
734 // position it
735 if ( m_pVScroll )
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
746 lcl_updateScrollbar(
747 m_rAntiImpl,
748 m_pHScroll,
749 m_pModel->getHorizontalScrollbarVisibility(aDataCellPlayground.GetWidth(), m_aAccColumnWidthsPixel[m_nColumnCount-1]),
750 lcl_getColumnsVisibleWithin( aDataCellPlayground, m_nLeftColumn, *this, false ),
751 // visible units
752 m_nLeftColumn, // current position
753 1, // line size
754 m_nColumnCount, // range
755 true, // horizontal
756 LINK( this, TableControl_Impl, OnScroll ) // scroll handler
758 // position it
759 if ( m_pHScroll )
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
788 ) );
791 //--------------------------------------------------------------------
792 void TableControl_Impl::onResize()
794 DBG_CHECK_ME();
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 )
804 DBG_CHECK_ME();
806 if ( !getModel() )
807 return;
809 PTableRenderer pRenderer = getModel()->getRenderer();
810 DBG_ASSERT( !!pRenderer, "TableDataWindow::Paint: invalid renderer!" );
811 if ( !pRenderer )
812 return;
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
818 // headers
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 );
837 aCell.isValid();
838 aCell.moveRight()
841 if ( _rUpdateRect.GetIntersection( aCell.getRect() ).IsEmpty() )
842 continue;
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();
880 // paint all rows
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);
893 --m_nRowCount;
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(""));
910 --m_nRowCount;
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())
922 ++itRowName;
923 ++it;
924 continue;
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())
940 aCellData = *it;
941 ++it;
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;
956 ++itRowName;
958 Rectangle aCurrentRowHeader( aRowHeaderArea.GetIntersection( aRowIterator.getRect() ) );
959 pRenderer->PaintRowHeader( isActiveRow, isSelectedRow, *m_pDataWindow, aCurrentRowHeader,
960 rStyle, rowHeaderName );
962 if ( !colCount )
963 continue;
965 // paint all cells in this row
966 for ( TableCellGeometry aCell( aRowIterator, m_nLeftColumn );
967 aCell.isValid();
968 aCell.moveRight()
971 // if ( _rUpdateRect.GetIntersection( aCell.getRect() ).IsEmpty() )
972 // continue;
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())
981 cellData = *iter;
982 ++iter;
984 pRenderer->PaintCell( aCell.getColumn(), isSelectedRow || isSelectedColumn, isActiveRow,
985 *m_pDataWindow, aCell.getRect(), rStyle, cellData );
990 //--------------------------------------------------------------------
991 void TableControl_Impl::hideCursor()
993 DBG_CHECK_ME();
995 if ( ++m_nCursorHidden == 1 )
996 impl_ni_doSwitchCursor( false );
999 //--------------------------------------------------------------------
1000 void TableControl_Impl::showCursor()
1002 DBG_CHECK_ME();
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 )
1012 DBG_CHECK_ME();
1014 bool bSuccess = false;
1015 Rectangle rCells;
1016 switch ( _eAction )
1018 case cursorDown:
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)
1034 ++m_nCurRow;
1035 m_nRowSelected.push_back(m_nCurRow);
1037 else
1038 m_nRowSelected.push_back(m_nCurRow);
1039 invalidateSelectedRow(m_nCurRow, rCells);
1040 ensureVisible(m_nCurColumn,m_nCurRow,false);
1041 bSuccess = true;
1043 else
1045 if ( m_nCurRow < m_nRowCount - 1 )
1046 bSuccess = goTo( m_nCurColumn, m_nCurRow + 1 );
1048 break;
1050 case cursorUp:
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();
1063 if(m_nCurRow>0)
1065 --m_nCurRow;
1066 m_nRowSelected.push_back(m_nCurRow);
1067 invalidateSelectedRow(m_nCurRow, rCells);
1069 else
1071 m_nRowSelected.push_back(m_nCurRow);
1072 invalidateSelectedRow(m_nCurRow, rCells);
1074 ensureVisible(m_nCurColumn,m_nCurRow,false);
1075 bSuccess = true;
1077 else
1079 if ( m_nCurRow > 0 )
1080 bSuccess = goTo( m_nCurColumn, m_nCurRow - 1 );
1082 break;
1083 case cursorLeft:
1084 if ( m_nCurColumn > 0 )
1085 bSuccess = goTo( m_nCurColumn - 1, m_nCurRow );
1086 else
1087 if ( ( m_nCurColumn == 0) && ( m_nCurRow > 0 ) )
1088 bSuccess = goTo( m_nColumnCount - 1, m_nCurRow - 1 );
1089 break;
1091 case cursorRight:
1092 if ( m_nCurColumn < m_nColumnCount - 1 )
1093 bSuccess = goTo( m_nCurColumn + 1, m_nCurRow );
1094 else
1095 if ( ( m_nCurColumn == m_nColumnCount - 1 ) && ( m_nCurRow < m_nRowCount - 1 ) )
1096 bSuccess = goTo( 0, m_nCurRow + 1 );
1097 break;
1099 case cursorToLineStart:
1100 bSuccess = goTo( 0, m_nCurRow );
1101 break;
1103 case cursorToLineEnd:
1104 bSuccess = goTo( m_nColumnCount - 1, m_nCurRow );
1105 break;
1107 case cursorToFirstLine:
1108 bSuccess = goTo( m_nCurColumn, 0 );
1109 break;
1111 case cursorToLastLine:
1112 bSuccess = goTo( m_nCurColumn, m_nRowCount - 1 );
1113 break;
1115 case cursorPageUp:
1117 RowPos nNewRow = ::std::max( (RowPos)0, m_nCurRow - impl_getVisibleRows( false ) );
1118 bSuccess = goTo( m_nCurColumn, nNewRow );
1120 break;
1122 case cursorPageDown:
1124 RowPos nNewRow = ::std::min( m_nRowCount - 1, m_nCurRow + impl_getVisibleRows( false ) );
1125 bSuccess = goTo( m_nCurColumn, nNewRow );
1127 break;
1129 case cursorTopLeft:
1130 bSuccess = goTo( 0, 0 );
1131 break;
1133 case cursorBottomRight:
1134 bSuccess = goTo( m_nColumnCount - 1, m_nRowCount - 1 );
1135 break;
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
1144 if(pos>-1)
1145 m_nRowSelected.erase(m_nRowSelected.begin()+pos);
1146 //else select the row->put it in the vector
1147 else
1148 m_nRowSelected.push_back(m_nCurRow);
1149 invalidateSelectedRow(m_nCurRow, rCells);
1150 bSuccess = true;
1152 break;
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
1160 return false;
1162 else
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
1169 if(m_nAnchor==-1)
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);
1181 else
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);
1186 if(prevRow>-1)
1188 //if m_nCurRow isn't the upper one, can move up, otherwise not
1189 if(m_nCurRow>0)
1190 m_nCurRow--;
1191 else
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);
1199 else
1201 m_nRowSelected.push_back(m_nCurRow);
1202 invalidateSelectedRow(m_nCurRow, rCells);
1207 else
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
1212 if(m_nCurRow>0)
1214 m_nRowSelected.push_back(m_nCurRow);
1215 m_nCurRow--;
1216 m_nRowSelected.push_back(m_nCurRow);
1217 invalidateSelectedRegion(m_nCurRow+1, m_nCurRow, rCells);
1219 else
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);
1228 bSuccess = true;
1231 break;
1232 case cursorSelectRowDown:
1234 if(m_pSelEngine->GetSelectionMode() == NO_SELECTION)
1235 bSuccess = false;
1236 else if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
1238 bSuccess = false;
1240 else
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
1246 if(m_nAnchor==-1)
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);
1258 else
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);
1263 if(prevRow>-1)
1265 //if m_nCurRow isn't the last one, can move down, otherwise not
1266 if(m_nCurRow<m_nRowCount)
1267 m_nCurRow++;
1268 else
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);
1276 else
1278 m_nRowSelected.push_back(m_nCurRow);
1279 invalidateSelectedRow(m_nCurRow, rCells);
1284 else
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);
1290 m_nCurRow++;
1291 m_nRowSelected.push_back(m_nCurRow);
1292 invalidateSelectedRegion(m_nCurRow-1, m_nCurRow, rCells);
1294 else
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);
1303 bSuccess = true;
1306 break;
1307 case cursorSelectRowAreaTop:
1309 if(m_pSelEngine->GetSelectionMode() == NO_SELECTION)
1310 bSuccess = false;
1311 else if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
1312 bSuccess = false;
1313 else
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
1319 while(iter>=0)
1321 if(!isRowSelected(m_nRowSelected, iter))
1322 m_nRowSelected.push_back(iter);
1323 --iter;
1325 m_nCurRow = 0;
1326 m_nAnchor = m_nCurRow;
1327 m_pSelEngine->SetAnchor(TRUE);
1328 ensureVisible(m_nCurColumn, 0, false);
1329 bSuccess = true;
1332 break;
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);
1347 ++iter;
1349 m_nCurRow = m_nRowCount-1;
1350 m_nAnchor = m_nCurRow;
1351 m_pSelEngine->SetAnchor(TRUE);
1352 ensureVisible(m_nCurColumn, m_nRowCount, false);
1353 bSuccess = true;
1355 break;
1356 default:
1357 DBG_ERROR( "TableControl_Impl::dispatchAction: unsupported action!" );
1359 return bSuccess;
1362 //--------------------------------------------------------------------
1363 void TableControl_Impl::impl_ni_doSwitchCursor( bool _bShow )
1365 PTableRenderer pRenderer = !!m_pModel ? m_pModel->getRenderer() : PTableRenderer();
1366 if ( !!pRenderer )
1368 Rectangle aCellRect;
1369 impl_getCellRect( m_nCurColumn, m_nCurRow, aCellRect );
1371 // const StyleSettings& rStyle = m_rAntiImpl.GetSettings().GetStyleSettings();
1372 if ( _bShow )
1374 pRenderer->ShowCellCursor( *m_pDataWindow, aCellRect);
1376 else
1378 pRenderer->HideCellCursor( *m_pDataWindow, aCellRect);
1383 //--------------------------------------------------------------------
1384 void TableControl_Impl::impl_getCellRect( ColPos _nColumn, RowPos _nRow, Rectangle& _rCellRect ) const
1386 DBG_CHECK_ME();
1388 if ( !m_pModel
1389 || ( COL_INVALID == _nColumn )
1390 || ( ROW_INVALID == _nRow )
1393 _rCellRect.SetEmpty();
1394 return;
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)
1411 DBG_CHECK_ME();
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())
1423 newRowPos = i;
1424 newColPos = j;
1425 if(newColPos == -1)
1426 m_nCurColumn = 0;
1427 else
1428 m_nCurColumn = newColPos;
1429 return newRowPos;
1433 return newRowPos;
1435 //-------------------------------------------------------------------------------
1436 void TableControl_Impl::setCursorAtCurrentCell(const Point& rPoint)
1438 DBG_CHECK_ME();
1439 hideCursor();
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())
1451 newRowPos = i;
1452 m_nCurRow = newRowPos;
1453 newColPos = j;
1454 if(newColPos == -1)
1455 m_nCurColumn = 0;
1456 else
1457 m_nCurColumn = newColPos;
1461 showCursor();
1464 //-------------------------------------------------------------------------------
1465 void TableControl_Impl::invalidateSelectedRegion(RowPos _nPrevRow, RowPos _nCurRow, Rectangle& _rCellRect)
1467 DBG_CHECK_ME();
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();
1473 Rectangle rCells;
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
1490 else
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)
1504 DBG_CHECK_ME();
1505 Rectangle aAllCells;
1506 impl_getAllVisibleCellsArea( aAllCells );
1507 _rCellRect.Left() = aAllCells.Left();
1508 _rCellRect.Right() = aAllCells.Right();
1509 Rectangle rCells;
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)
1519 //DBG_CHECK_ME();
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)
1535 int i =0;
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);
1541 else
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)
1549 if(*it > _nRowPos)
1550 m_nRowSelected[i]=*it-1;
1551 ++i;
1554 if(_nRowPos == 0)
1555 m_nCurRow = 0;
1556 else
1557 m_nCurRow = _nRowPos-1;
1559 //-------------------------------------------------------------------------------
1560 void TableControl_Impl::invalidateRows(RowPos _nRowStart, Rectangle& _rCellRect)
1562 //DBG_CHECK_ME();
1563 (void)_nRowStart;
1564 (void)_rCellRect;
1565 /*TempHideCursor aHideCursor(*this);
1566 Rectangle aAllCells;
1567 impl_getAllVisibleCellsArea( aAllCells );
1568 TableRowGeometry _rRow( *this, aAllCells, _nRowStart);
1569 _rCellRect = _rRow.getRect();
1570 Rectangle rCells1;
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)
1596 DBG_CHECK_ME();
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())
1605 return true;
1607 else
1608 return false;
1610 //--------------------------------------------------------------------
1611 TableSize TableControl_Impl::impl_getVisibleRows( bool _bAcceptPartialRow ) const
1613 DBG_CHECK_ME();
1615 DBG_ASSERT( m_pDataWindow, "TableControl_Impl::impl_getVisibleRows: no data window!" );
1617 return lcl_getRowsFittingInto(
1618 m_pDataWindow->GetOutputSizePixel().Height() - m_nColHeaderHeightPixel,
1619 m_nRowHeightPixel,
1620 _bAcceptPartialRow
1624 //--------------------------------------------------------------------
1625 TableSize TableControl_Impl::impl_getVisibleColumns( bool _bAcceptPartialRow ) const
1627 DBG_CHECK_ME();
1629 DBG_ASSERT( m_pDataWindow, "TableControl_Impl::impl_getVisibleColumns: no data window!" );
1631 return lcl_getColumnsVisibleWithin(
1632 Rectangle( Point( 0, 0 ), m_pDataWindow->GetOutputSizePixel() ),
1633 m_nLeftColumn,
1634 *this,
1635 _bAcceptPartialRow
1639 //--------------------------------------------------------------------
1640 bool TableControl_Impl::goTo( ColPos _nColumn, RowPos _nRow )
1642 DBG_CHECK_ME();
1644 // TODO: give veto listeners a chance
1646 if ( ( _nColumn < -1 ) || ( _nColumn >= m_nColumnCount )
1647 || ( _nRow < -1 ) || ( _nRow >= m_nRowCount )
1649 return false;
1651 TempHideCursor aHideCursor( *this );
1652 m_nCurColumn = _nColumn;
1653 m_nCurRow = _nRow;
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
1659 // re-painting them
1660 //if(!m_nRowSelected.empty())
1662 // Rectangle rCells;
1663 // for(std::vector<RowPos>::iterator it=m_nRowSelected.begin();
1664 // it!=m_nRowSelected.end();++it)
1665 // {
1666 // invalidateSelectedRow(*it,rCells);
1667 // }
1668 // m_nRowSelected.clear();
1670 // TODO: notify listeners about new position
1671 return true;
1674 //--------------------------------------------------------------------
1675 void TableControl_Impl::ensureVisible( ColPos _nColumn, RowPos _nRow, bool _bAcceptPartialVisibility )
1677 DBG_CHECK_ME();
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 );
1686 else
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 );
1699 else
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
1711 RowPos nNewTopRow =
1712 ::std::max(
1713 ::std::min( (RowPos)( m_nTopRow + _nRowDelta ), (RowPos)( m_nRowCount - 1 ) ),
1714 (RowPos)0
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 );
1740 else
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 =
1755 ::std::max(
1756 ::std::min( (ColPos)( m_nLeftColumn + _nColumnDelta ), (ColPos)( m_nColumnCount - 1 ) ),
1757 (ColPos)0
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() );
1775 long nPixelDelta =
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 );
1785 else
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)
1808 if(*it == current)
1809 return TRUE;
1811 return FALSE;
1814 int TableControl_Impl::getRowSelectedNumber(::std::vector<RowPos> selectedRows, RowPos current)
1816 int pos = -1;
1817 int i = 0;
1818 for(std::vector<RowPos>::iterator it=selectedRows.begin();it!=selectedRows.end();++it)
1820 if(*it == current)
1821 return pos = i;
1822 ++i;
1824 return pos;
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() );
1840 else
1841 impl_ni_ScrollColumns( _pScrollbar->GetDelta() );
1843 return 0L;
1846 //---------------------------------------------------------------------------------------
1847 TableFunctionSet::TableFunctionSet(TableControl_Impl* _pTableControl):
1848 m_pTableControl( _pTableControl)
1849 ,m_nCurrentRow (-2)
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;
1874 Rectangle rCells;
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);
1877 if(curRow == -2)
1878 return FALSE;
1879 if( bDontSelectAtCursor )
1881 if(m_pTableControl->m_nRowSelected.size()>1)
1882 m_pTableControl->m_pSelEngine->AddAlways(TRUE);
1883 bHandled = TRUE;
1885 else if(m_pTableControl->m_nAnchor == m_pTableControl->m_nCurRow)
1887 //selecting region,
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
1893 if( diff >= 0)
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--;
1903 diff--;
1905 m_pTableControl->m_nAnchor++;
1907 //selected region lies beneath the last selected row
1908 else
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++;
1916 diff++;
1918 m_pTableControl->m_nAnchor--;
1920 m_pTableControl->invalidateSelectedRegion(m_pTableControl->m_nCurRow, curRow, rCells);
1921 bHandled = TRUE;
1923 //no region selected
1924 else
1926 if(m_pTableControl->m_nRowSelected.empty())
1928 m_pTableControl->m_nRowSelected.push_back(curRow);
1930 else
1932 if(m_pTableControl->m_pSelEngine->GetSelectionMode()==SINGLE_SELECTION)
1934 DeselectAll();
1935 m_pTableControl->m_nRowSelected.push_back(curRow);
1937 else
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);
1947 bHandled = TRUE;
1949 m_pTableControl->m_nCurRow = curRow;
1950 m_pTableControl->ensureVisible(m_pTableControl->m_nCurColumn,m_pTableControl->m_nCurRow,false);
1951 return bHandled;
1954 BOOL TableFunctionSet::IsSelectionAtPoint( const Point& rPoint )
1956 m_pTableControl->m_pSelEngine->AddAlways(FALSE);
1957 if(m_pTableControl->m_nRowSelected.empty())
1958 return FALSE;
1959 else
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;
1965 return selected;
1969 void TableFunctionSet::DeselectAtPoint( const Point& rPoint )
1971 (void)rPoint;
1972 long pos = 0;
1973 long i = 0;
1974 Rectangle rCells;
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)
1980 pos = i;
1981 m_pTableControl->invalidateSelectedRow(*it,rCells);
1983 ++i;
1985 m_pTableControl->m_nRowSelected.erase(m_pTableControl->m_nRowSelected.begin()+pos);
1987 void TableFunctionSet::DeselectAll()
1989 if(!m_pTableControl->m_nRowSelected.empty())
1991 Rectangle rCells;
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 //........................................................................