LCOV - code coverage report
Current view: top level - libreoffice/svtools/source/table - tablecontrol_impl.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 1 1169 0.1 %
Date: 2012-12-27 Functions: 2 138 1.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : 
      21             : #include "svtools/table/tablecontrol.hxx"
      22             : #include "svtools/table/defaultinputhandler.hxx"
      23             : #include "svtools/table/tablemodel.hxx"
      24             : 
      25             : #include "tabledatawindow.hxx"
      26             : #include "tablecontrol_impl.hxx"
      27             : #include "tablegeometry.hxx"
      28             : 
      29             : #include <com/sun/star/accessibility/XAccessible.hpp>
      30             : #include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
      31             : #include <com/sun/star/accessibility/AccessibleEventId.hpp>
      32             : #include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
      33             : 
      34             : #include <comphelper/flagguard.hxx>
      35             : #include <vcl/scrbar.hxx>
      36             : #include <vcl/seleng.hxx>
      37             : #include <rtl/ref.hxx>
      38             : #include <vcl/image.hxx>
      39             : #include <tools/diagnose_ex.h>
      40             : 
      41             : #include <functional>
      42             : #include <numeric>
      43             : 
      44             : #define MIN_COLUMN_WIDTH_PIXEL  4
      45             : 
      46             : //......................................................................................................................
      47             : namespace svt { namespace table
      48             : {
      49             : //......................................................................................................................
      50             : 
      51             :     /** === begin UNO using === **/
      52             :     using ::com::sun::star::accessibility::AccessibleTableModelChange;
      53             :     using ::com::sun::star::uno::makeAny;
      54             :     using ::com::sun::star::uno::Any;
      55             :     using ::com::sun::star::accessibility::XAccessible;
      56             :     using ::com::sun::star::uno::Reference;
      57             :     /** === end UNO using === **/
      58             :     namespace AccessibleEventId = ::com::sun::star::accessibility::AccessibleEventId;
      59             :     namespace AccessibleTableModelChangeType = ::com::sun::star::accessibility::AccessibleTableModelChangeType;
      60             : 
      61             :     //==================================================================================================================
      62             :     //= SuppressCursor
      63             :     //==================================================================================================================
      64             :     class SuppressCursor
      65             :     {
      66             :     private:
      67             :         ITableControl&  m_rTable;
      68             : 
      69             :     public:
      70           0 :         SuppressCursor( ITableControl& _rTable )
      71           0 :             :m_rTable( _rTable )
      72             :         {
      73           0 :             m_rTable.hideCursor();
      74           0 :         }
      75           0 :         ~SuppressCursor()
      76             :         {
      77           0 :             m_rTable.showCursor();
      78           0 :         }
      79             :     };
      80             : 
      81             :     //====================================================================
      82             :     //= EmptyTableModel
      83             :     //====================================================================
      84             :     /** default implementation of an ->ITableModel, used as fallback when no
      85             :         real model is present
      86             : 
      87             :         Instances of this class are static in any way, and provide the least
      88             :         necessary default functionality for a table model.
      89             :     */
      90           0 :     class EmptyTableModel : public ITableModel
      91             :     {
      92             :     public:
      93           0 :         EmptyTableModel()
      94           0 :         {
      95           0 :         }
      96             : 
      97             :         // ITableModel overridables
      98           0 :         virtual TableSize           getColumnCount() const
      99             :         {
     100           0 :             return 0;
     101             :         }
     102           0 :         virtual TableSize           getRowCount() const
     103             :         {
     104           0 :             return 0;
     105             :         }
     106           0 :         virtual bool                hasColumnHeaders() const
     107             :         {
     108           0 :             return false;
     109             :         }
     110           0 :         virtual bool                hasRowHeaders() const
     111             :         {
     112           0 :             return false;
     113             :         }
     114           0 :         virtual bool                isCellEditable( ColPos col, RowPos row ) const
     115             :         {
     116             :             (void)col;
     117             :             (void)row;
     118           0 :             return false;
     119             :         }
     120           0 :         virtual PColumnModel        getColumnModel( ColPos column )
     121             :         {
     122             :             OSL_FAIL( "EmptyTableModel::getColumnModel: invalid call!" );
     123             :             (void)column;
     124           0 :             return PColumnModel();
     125             :         }
     126           0 :         virtual PTableRenderer      getRenderer() const
     127             :         {
     128           0 :             return PTableRenderer();
     129             :         }
     130           0 :         virtual PTableInputHandler  getInputHandler() const
     131             :         {
     132           0 :             return PTableInputHandler();
     133             :         }
     134           0 :         virtual TableMetrics        getRowHeight() const
     135             :         {
     136           0 :             return 5 * 100;
     137             :         }
     138           0 :         virtual void setRowHeight(TableMetrics _nRowHeight)
     139             :         {
     140             :             (void)_nRowHeight;
     141           0 :         }
     142           0 :         virtual TableMetrics        getColumnHeaderHeight() const
     143             :         {
     144           0 :             return 0;
     145             :         }
     146           0 :         virtual TableMetrics        getRowHeaderWidth() const
     147             :         {
     148           0 :             return 0;
     149             :         }
     150           0 :         virtual ScrollbarVisibility getVerticalScrollbarVisibility() const
     151             :         {
     152           0 :             return ScrollbarShowNever;
     153             :         }
     154           0 :         virtual ScrollbarVisibility getHorizontalScrollbarVisibility() const
     155             :         {
     156           0 :             return ScrollbarShowNever;
     157             :         }
     158           0 :         virtual void addTableModelListener( const PTableModelListener& i_listener )
     159             :         {
     160             :             (void)i_listener;
     161           0 :         }
     162           0 :         virtual void removeTableModelListener( const PTableModelListener& i_listener )
     163             :         {
     164             :             (void)i_listener;
     165           0 :         }
     166           0 :         virtual ::boost::optional< ::Color > getLineColor() const
     167             :         {
     168           0 :             return ::boost::optional< ::Color >();
     169             :         }
     170           0 :         virtual ::boost::optional< ::Color > getHeaderBackgroundColor() const
     171             :         {
     172           0 :             return ::boost::optional< ::Color >();
     173             :         }
     174           0 :         virtual ::boost::optional< ::Color > getHeaderTextColor() const
     175             :         {
     176           0 :             return ::boost::optional< ::Color >();
     177             :         }
     178           0 :         virtual ::boost::optional< ::Color >    getActiveSelectionBackColor() const
     179             :         {
     180           0 :             return ::boost::optional< ::Color >();
     181             :         }
     182           0 :         virtual ::boost::optional< ::Color >    getInactiveSelectionBackColor() const
     183             :         {
     184           0 :             return ::boost::optional< ::Color >();
     185             :         }
     186           0 :         virtual ::boost::optional< ::Color >    getActiveSelectionTextColor() const
     187             :         {
     188           0 :             return ::boost::optional< ::Color >();
     189             :         }
     190           0 :         virtual ::boost::optional< ::Color >    getInactiveSelectionTextColor() const
     191             :         {
     192           0 :             return ::boost::optional< ::Color >();
     193             :         }
     194           0 :         virtual ::boost::optional< ::Color > getTextColor() const
     195             :         {
     196           0 :             return ::boost::optional< ::Color >();
     197             :         }
     198           0 :         virtual ::boost::optional< ::Color > getTextLineColor() const
     199             :         {
     200           0 :             return ::boost::optional< ::Color >();
     201             :         }
     202           0 :         virtual ::boost::optional< ::std::vector< ::Color > > getRowBackgroundColors() const
     203             :         {
     204           0 :             return ::boost::optional< ::std::vector< ::Color > >();
     205             :         }
     206           0 :         virtual ::com::sun::star::style::VerticalAlignment getVerticalAlign() const
     207             :         {
     208           0 :             return com::sun::star::style::VerticalAlignment(0);
     209             :         }
     210           0 :         virtual ITableDataSort* getSortAdapter()
     211             :         {
     212           0 :             return NULL;
     213             :         }
     214           0 :         virtual void getCellContent( ColPos const i_col, RowPos const i_row, ::com::sun::star::uno::Any& o_cellContent )
     215             :         {
     216             :             (void)i_row;
     217             :             (void)i_col;
     218           0 :             o_cellContent.clear();
     219           0 :         }
     220           0 :         virtual void getCellToolTip( ColPos const, RowPos const, ::com::sun::star::uno::Any& )
     221             :         {
     222           0 :         }
     223           0 :         virtual Any getRowHeading( RowPos const i_rowPos ) const
     224             :         {
     225             :             (void)i_rowPos;
     226           0 :             return Any();
     227             :         }
     228             :     };
     229             : 
     230             : 
     231             :     //====================================================================
     232             :     //= TableControl_Impl
     233             :     //====================================================================
     234             :     DBG_NAME( TableControl_Impl )
     235             : 
     236             : #if DBG_UTIL
     237             :     //====================================================================
     238             :     //= SuspendInvariants
     239             :     //====================================================================
     240             :     class SuspendInvariants
     241             :     {
     242             :     private:
     243             :         const TableControl_Impl&    m_rTable;
     244             :         sal_Int32                   m_nSuspendFlags;
     245             : 
     246             :     public:
     247             :         SuspendInvariants( const TableControl_Impl& _rTable, sal_Int32 _nSuspendFlags )
     248             :             :m_rTable( _rTable )
     249             :             ,m_nSuspendFlags( _nSuspendFlags )
     250             :         {
     251             :             //DBG_ASSERT( ( m_rTable.m_nRequiredInvariants & m_nSuspendFlags ) == m_nSuspendFlags,
     252             :             //    "SuspendInvariants: cannot suspend what is already suspended!" );
     253             :             const_cast< TableControl_Impl& >( m_rTable ).m_nRequiredInvariants &= ~m_nSuspendFlags;
     254             :         }
     255             :         ~SuspendInvariants()
     256             :         {
     257             :             const_cast< TableControl_Impl& >( m_rTable ).m_nRequiredInvariants |= m_nSuspendFlags;
     258             :         }
     259             :     };
     260             :     #define DBG_SUSPEND_INV( flags ) \
     261             :         SuspendInvariants aSuspendInv( *this, flags );
     262             : #else
     263             :     #define DBG_SUSPEND_INV( flags )
     264             : #endif
     265             : 
     266             : #if DBG_UTIL
     267             :     //====================================================================
     268             :     const char* TableControl_Impl_checkInvariants( const void* _pInstance )
     269             :     {
     270             :         return static_cast< const TableControl_Impl* >( _pInstance )->impl_checkInvariants();
     271             :     }
     272             : 
     273             :     namespace
     274             :     {
     275             :         template< typename SCALAR_TYPE >
     276             :         bool lcl_checkLimitsExclusive( SCALAR_TYPE _nValue, SCALAR_TYPE _nMin, SCALAR_TYPE _nMax )
     277             :         {
     278             :             return ( _nValue > _nMin ) && ( _nValue < _nMax );
     279             :         }
     280             : 
     281             :         template< typename SCALAR_TYPE >
     282             :         bool lcl_checkLimitsExclusive_OrDefault_OrFallback( SCALAR_TYPE _nValue, SCALAR_TYPE _nMin, SCALAR_TYPE _nMax,
     283             :             PTableModel _pModel, SCALAR_TYPE _nDefaultOrFallback )
     284             :         {
     285             :             if ( !_pModel )
     286             :                 return _nValue == _nDefaultOrFallback;
     287             :             if ( _nMax <= _nMin )
     288             :                 return _nDefaultOrFallback == _nValue;
     289             :             return lcl_checkLimitsExclusive( _nValue, _nMin, _nMax );
     290             :         }
     291             :     }
     292             : 
     293             :     //------------------------------------------------------------------------------------------------------------------
     294             :     const sal_Char* TableControl_Impl::impl_checkInvariants() const
     295             :     {
     296             :         if ( !m_pModel )
     297             :             return "no model, not even an EmptyTableModel";
     298             : 
     299             :         if ( !m_pDataWindow )
     300             :             return "invalid data window!";
     301             : 
     302             :         if ( m_pModel->getColumnCount() != m_nColumnCount )
     303             :             return "column counts are inconsistent!";
     304             : 
     305             :         if ( m_pModel->getRowCount() != m_nRowCount )
     306             :             return "row counts are inconsistent!";
     307             : 
     308             :         if ( ( ( m_nCurColumn != COL_INVALID ) && !m_aColumnWidths.empty() && ( m_nCurColumn < 0 ) ) || ( m_nCurColumn >= (ColPos)m_aColumnWidths.size() ) )
     309             :             return "current column is invalid!";
     310             : 
     311             :         if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nTopRow, (RowPos)-1, m_nRowCount, getModel(), (RowPos)0 ) )
     312             :             return "invalid top row value!";
     313             : 
     314             :         if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nCurRow, (RowPos)-1, m_nRowCount, getModel(), ROW_INVALID ) )
     315             :             return "invalid current row value!";
     316             : 
     317             :         if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nLeftColumn, (ColPos)-1, m_nColumnCount, getModel(), (ColPos)0 ) )
     318             :             return "invalid current column value!";
     319             : 
     320             :         if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nCurColumn, (ColPos)-1, m_nColumnCount, getModel(), COL_INVALID ) )
     321             :             return "invalid current column value!";
     322             : 
     323             :         if  ( m_pInputHandler != m_pModel->getInputHandler() )
     324             :             return "input handler is not the model-provided one!";
     325             : 
     326             :         // m_aSelectedRows should have reasonable content
     327             :         {
     328             :             if ( m_aSelectedRows.size() > size_t( m_pModel->getRowCount() ) )
     329             :                 return "there are more rows selected than actually exist";
     330             :             for (   ::std::vector< RowPos >::const_iterator selRow = m_aSelectedRows.begin();
     331             :                     selRow != m_aSelectedRows.end();
     332             :                     ++selRow
     333             :                 )
     334             :             {
     335             :                 if ( ( *selRow < 0 ) || ( *selRow >= m_pModel->getRowCount() ) )
     336             :                     return "a non-existent row is selected";
     337             :             }
     338             :         }
     339             : 
     340             :         // m_nColHeaderHeightPixel consistent with the model's value?
     341             :         {
     342             :             TableMetrics nHeaderHeight = m_pModel->hasColumnHeaders() ? m_pModel->getColumnHeaderHeight() : 0;
     343             :             nHeaderHeight = m_rAntiImpl.LogicToPixel( Size( 0, nHeaderHeight ), MAP_APPFONT ).Height();
     344             :             if ( nHeaderHeight != m_nColHeaderHeightPixel )
     345             :                 return "column header heights are inconsistent!";
     346             :         }
     347             : 
     348             :         bool isDummyModel = dynamic_cast< const EmptyTableModel* >( m_pModel.get() ) != NULL;
     349             :         if ( !isDummyModel )
     350             :         {
     351             :             TableMetrics nRowHeight = m_pModel->getRowHeight();
     352             :             nRowHeight = m_rAntiImpl.LogicToPixel( Size( 0, nRowHeight ), MAP_APPFONT).Height();
     353             :             if ( nRowHeight != m_nRowHeightPixel )
     354             :                 return "row heights are inconsistent!";
     355             :         }
     356             : 
     357             :         // m_nRowHeaderWidthPixel consistent with the model's value?
     358             :         {
     359             :             TableMetrics nHeaderWidth = m_pModel->hasRowHeaders() ? m_pModel->getRowHeaderWidth() : 0;
     360             :             nHeaderWidth = m_rAntiImpl.LogicToPixel( Size( nHeaderWidth, 0 ), MAP_APPFONT ).Width();
     361             :             if ( nHeaderWidth != m_nRowHeaderWidthPixel )
     362             :                 return "row header widths are inconsistent!";
     363             :         }
     364             : 
     365             :         // m_aColumnWidths consistency
     366             :         if ( size_t( m_nColumnCount ) != m_aColumnWidths.size() )
     367             :             return "wrong number of cached column widths";
     368             : 
     369             :         for (   ColumnPositions::const_iterator col = m_aColumnWidths.begin();
     370             :                 col != m_aColumnWidths.end();
     371             :             )
     372             :         {
     373             :             if ( col->getEnd() < col->getStart() )
     374             :                 return "column widths: 'end' is expected to not be smaller than start";
     375             : 
     376             :             ColumnPositions::const_iterator nextCol = col + 1;
     377             :             if ( nextCol != m_aColumnWidths.end() )
     378             :                 if ( col->getEnd() != nextCol->getStart() )
     379             :                     return "column widths: one column's end should be the next column's start";
     380             :             col = nextCol;
     381             :         }
     382             : 
     383             :         if ( m_nLeftColumn < m_nColumnCount )
     384             :             if ( m_aColumnWidths[ m_nLeftColumn ].getStart() != m_nRowHeaderWidthPixel )
     385             :                 return "the left-most column should start immediately after the row header";
     386             : 
     387             :         if ( m_nCursorHidden < 0 )
     388             :             return "invalid hidden count for the cursor!";
     389             : 
     390             :         if ( ( m_nRequiredInvariants & INV_SCROLL_POSITION ) && m_pVScroll )
     391             :         {
     392             :             DBG_SUSPEND_INV( INV_SCROLL_POSITION );
     393             :                 // prevent infinite recursion
     394             : 
     395             :             if ( m_nLeftColumn < 0 )
     396             :                 return "invalid left-most column index";
     397             :             if ( m_pVScroll->GetThumbPos() != m_nTopRow )
     398             :                 return "vertical scroll bar |position| is incorrect!";
     399             :             if ( m_pVScroll->GetRange().Max() != m_nRowCount )
     400             :                 return "vertical scroll bar |range| is incorrect!";
     401             :             if ( m_pVScroll->GetVisibleSize() != impl_getVisibleRows( false ) )
     402             :                 return "vertical scroll bar |visible size| is incorrect!";
     403             :         }
     404             : 
     405             :         if ( ( m_nRequiredInvariants & INV_SCROLL_POSITION ) && m_pHScroll )
     406             :         {
     407             :             DBG_SUSPEND_INV( INV_SCROLL_POSITION );
     408             :                 // prevent infinite recursion
     409             : 
     410             :             if ( m_pHScroll->GetThumbPos() != m_nLeftColumn )
     411             :                 return "horizontal scroll bar |position| is incorrect!";
     412             :             if ( m_pHScroll->GetRange().Max() != m_nColumnCount )
     413             :                 return "horizontal scroll bar |range| is incorrect!";
     414             :             if ( m_pHScroll->GetVisibleSize() != impl_getVisibleColumns( false ) )
     415             :                 return "horizontal scroll bar |visible size| is incorrect!";
     416             :         }
     417             : 
     418             :         return NULL;
     419             :     }
     420             : #endif
     421             : 
     422             : #define DBG_CHECK_ME() \
     423             :     DBG_CHKTHIS( TableControl_Impl, TableControl_Impl_checkInvariants )
     424             : 
     425             :     //------------------------------------------------------------------------------------------------------------------
     426           0 :     TableControl_Impl::TableControl_Impl( TableControl& _rAntiImpl )
     427             :         :m_rAntiImpl            ( _rAntiImpl                    )
     428           0 :         ,m_pModel               ( new EmptyTableModel           )
     429             :         ,m_pInputHandler        (                               )
     430             :         ,m_nRowHeightPixel      ( 15                            )
     431             :         ,m_nColHeaderHeightPixel( 0                             )
     432             :         ,m_nRowHeaderWidthPixel ( 0                             )
     433             :         ,m_nColumnCount         ( 0                             )
     434             :         ,m_nRowCount            ( 0                             )
     435             :         ,m_bColumnsFit          ( true                          )
     436             :         ,m_nCurColumn           ( COL_INVALID                   )
     437             :         ,m_nCurRow              ( ROW_INVALID                   )
     438             :         ,m_nLeftColumn          ( 0                             )
     439             :         ,m_nTopRow              ( 0                             )
     440             :         ,m_nCursorHidden        ( 1                             )
     441           0 :         ,m_pDataWindow          ( new TableDataWindow( *this )  )
     442             :         ,m_pVScroll             ( NULL                          )
     443             :         ,m_pHScroll             ( NULL                          )
     444             :         ,m_pScrollCorner        ( NULL                          )
     445             :         ,m_pSelEngine           (                               )
     446             :         ,m_aSelectedRows        (                               )
     447           0 :         ,m_pTableFunctionSet    ( new TableFunctionSet( this  ) )
     448             :         ,m_nAnchor              ( -1                            )
     449             :         ,m_bUpdatingColWidths   ( false                         )
     450           0 :         ,m_pAccessibleTable     ( NULL                          )
     451             : #if DBG_UTIL
     452             :         ,m_nRequiredInvariants ( INV_SCROLL_POSITION )
     453             : #endif
     454             :     {
     455             :         DBG_CTOR( TableControl_Impl, TableControl_Impl_checkInvariants );
     456           0 :         m_pSelEngine = new SelectionEngine( m_pDataWindow.get(), m_pTableFunctionSet );
     457           0 :         m_pSelEngine->SetSelectionMode(SINGLE_SELECTION);
     458           0 :         m_pDataWindow->SetPosPixel( Point( 0, 0 ) );
     459           0 :         m_pDataWindow->Show();
     460           0 :     }
     461             : 
     462             :     //------------------------------------------------------------------------------------------------------------------
     463           0 :     TableControl_Impl::~TableControl_Impl()
     464             :     {
     465             :         DBG_DTOR( TableControl_Impl, TableControl_Impl_checkInvariants );
     466             : 
     467           0 :         DELETEZ( m_pVScroll );
     468           0 :         DELETEZ( m_pHScroll );
     469           0 :         DELETEZ( m_pScrollCorner );
     470           0 :         DELETEZ( m_pTableFunctionSet );
     471           0 :         DELETEZ( m_pSelEngine );
     472           0 :     }
     473             : 
     474             :     //------------------------------------------------------------------------------------------------------------------
     475           0 :     void TableControl_Impl::setModel( PTableModel _pModel )
     476             :     {
     477             :         DBG_CHECK_ME();
     478             : 
     479           0 :         SuppressCursor aHideCursor( *this );
     480             : 
     481           0 :         if ( !!m_pModel )
     482           0 :             m_pModel->removeTableModelListener( shared_from_this() );
     483             : 
     484           0 :         m_pModel = _pModel;
     485           0 :         if ( !m_pModel)
     486           0 :             m_pModel.reset( new EmptyTableModel );
     487             : 
     488           0 :         m_pModel->addTableModelListener( shared_from_this() );
     489             : 
     490           0 :         m_nCurRow = ROW_INVALID;
     491           0 :         m_nCurColumn = COL_INVALID;
     492             : 
     493             :         // recalc some model-dependent cached info
     494           0 :         impl_ni_updateCachedModelValues();
     495           0 :         impl_ni_relayout();
     496             : 
     497             :         // completely invalidate
     498           0 :         m_rAntiImpl.Invalidate();
     499             : 
     500             :         // reset cursor to (0,0)
     501           0 :         if ( m_nRowCount ) m_nCurRow = 0;
     502           0 :         if ( m_nColumnCount ) m_nCurColumn = 0;
     503           0 :     }
     504             : 
     505             :     //------------------------------------------------------------------------------------------------------------------
     506             :     namespace
     507             :     {
     508           0 :         bool lcl_adjustSelectedRows( ::std::vector< RowPos >& io_selectionIndexes, RowPos const i_firstAffectedRowIndex, TableSize const i_offset )
     509             :         {
     510           0 :             bool didChanges = false;
     511           0 :             for (   ::std::vector< RowPos >::iterator selPos = io_selectionIndexes.begin();
     512           0 :                     selPos != io_selectionIndexes.end();
     513             :                     ++selPos
     514             :                 )
     515             :             {
     516           0 :                 if ( *selPos < i_firstAffectedRowIndex )
     517           0 :                     continue;
     518           0 :                 *selPos += i_offset;
     519           0 :                 didChanges = true;
     520             :             }
     521           0 :             return didChanges;
     522             :         }
     523             :     }
     524             : 
     525             :     //------------------------------------------------------------------------------------------------------------------
     526           0 :     void TableControl_Impl::rowsInserted( RowPos i_first, RowPos i_last )
     527             :     {
     528             :         DBG_CHECK_ME();
     529             :         OSL_PRECOND( i_last >= i_first, "TableControl_Impl::rowsInserted: invalid row indexes!" );
     530             : 
     531           0 :         TableSize const insertedRows = i_last - i_first + 1;
     532             : 
     533             :         // adjust selection, if necessary
     534           0 :         bool const selectionChanged = lcl_adjustSelectedRows( m_aSelectedRows, i_first, insertedRows );
     535             : 
     536             :         // adjust our cached row count
     537           0 :         m_nRowCount = m_pModel->getRowCount();
     538             : 
     539             :         // if the rows have been inserted before the current row, adjust this
     540           0 :         if ( i_first <= m_nCurRow )
     541           0 :             goTo( m_nCurColumn, m_nCurRow + insertedRows );
     542             : 
     543             :         // relayout, since the scrollbar need might have changed
     544           0 :         impl_ni_relayout();
     545             : 
     546             :         // notify A1YY events
     547           0 :         if ( impl_isAccessibleAlive() )
     548             :         {
     549             :             impl_commitAccessibleEvent( AccessibleEventId::TABLE_MODEL_CHANGED,
     550           0 :                 makeAny( AccessibleTableModelChange( AccessibleTableModelChangeType::INSERT, i_first, i_last, 0, m_pModel->getColumnCount() ) ),
     551             :                 Any()
     552           0 :             );
     553             :         }
     554             : 
     555             :         // schedule repaint
     556           0 :         invalidateRowRange( i_first, ROW_INVALID );
     557             : 
     558             :         // call selection handlers, if necessary
     559           0 :         if ( selectionChanged )
     560           0 :             m_rAntiImpl.Select();
     561           0 :     }
     562             : 
     563             :     //------------------------------------------------------------------------------------------------------------------
     564           0 :     void TableControl_Impl::rowsRemoved( RowPos i_first, RowPos i_last )
     565             :     {
     566           0 :         sal_Int32 firstRemovedRow = i_first;
     567           0 :         sal_Int32 lastRemovedRow = i_last;
     568             : 
     569             :         // adjust selection, if necessary
     570           0 :         bool selectionChanged = false;
     571           0 :         if ( i_first == -1 )
     572             :         {
     573           0 :             selectionChanged = markAllRowsAsDeselected();
     574             : 
     575           0 :             firstRemovedRow = 0;
     576           0 :             lastRemovedRow = m_nRowCount - 1;
     577             :         }
     578             :         else
     579             :         {
     580           0 :             ENSURE_OR_RETURN_VOID( i_last >= i_first, "TableControl_Impl::rowsRemoved: illegal indexes!" );
     581             : 
     582           0 :             for ( sal_Int32 row = i_first; row <= i_last; ++row )
     583             :             {
     584           0 :                 if ( markRowAsDeselected( row ) )
     585           0 :                     selectionChanged = true;
     586             :             }
     587             : 
     588           0 :             if ( lcl_adjustSelectedRows( m_aSelectedRows, i_last + 1, i_first - i_last - 1 ) )
     589           0 :                 selectionChanged = true;
     590             :         }
     591             : 
     592             :         // adjust cached row count
     593           0 :         m_nRowCount = m_pModel->getRowCount();
     594             : 
     595             :         // adjust the current row, if it is larger than the row count now
     596           0 :         if ( m_nCurRow >= m_nRowCount )
     597             :         {
     598           0 :             if ( m_nRowCount > 0 )
     599           0 :                 goTo( m_nCurColumn, m_nRowCount - 1 );
     600             :             else
     601           0 :                 m_nCurRow = ROW_INVALID;
     602             :         }
     603             : 
     604             :         // relayout, since the scrollbar need might have changed
     605           0 :         impl_ni_relayout();
     606             : 
     607             :         // notify A11Y events
     608           0 :         if ( impl_isAccessibleAlive() )
     609             :         {
     610             :             commitTableEvent(
     611             :                 AccessibleEventId::TABLE_MODEL_CHANGED,
     612             :                 makeAny( AccessibleTableModelChange(
     613             :                     AccessibleTableModelChangeType::DELETE,
     614             :                     firstRemovedRow,
     615             :                     lastRemovedRow,
     616             :                     0,
     617           0 :                     m_pModel->getColumnCount()
     618             :                 ) ),
     619             :                 Any()
     620           0 :             );
     621             :         }
     622             : 
     623             :         // schedule a repaint
     624           0 :         invalidateRowRange( firstRemovedRow, ROW_INVALID );
     625             : 
     626             :         // call selection handlers, if necessary
     627           0 :         if ( selectionChanged )
     628           0 :             m_rAntiImpl.Select();
     629             :     }
     630             : 
     631             :     //------------------------------------------------------------------------------------------------------------------
     632           0 :     void TableControl_Impl::columnInserted( ColPos const i_colIndex )
     633             :     {
     634           0 :         m_nColumnCount = m_pModel->getColumnCount();
     635           0 :         impl_ni_relayout();
     636             : 
     637           0 :         m_rAntiImpl.Invalidate();
     638             : 
     639             :         OSL_UNUSED( i_colIndex );
     640           0 :    }
     641             : 
     642             :     //------------------------------------------------------------------------------------------------------------------
     643           0 :     void TableControl_Impl::columnRemoved( ColPos const i_colIndex )
     644             :     {
     645           0 :         m_nColumnCount = m_pModel->getColumnCount();
     646             : 
     647             :         // adjust the current column, if it is larger than the column count now
     648           0 :         if ( m_nCurColumn >= m_nColumnCount )
     649             :         {
     650           0 :             if ( m_nColumnCount > 0 )
     651           0 :                 goTo( m_nCurColumn - 1, m_nCurRow );
     652             :             else
     653           0 :                 m_nCurColumn = COL_INVALID;
     654             :         }
     655             : 
     656           0 :         impl_ni_relayout();
     657             : 
     658           0 :         m_rAntiImpl.Invalidate();
     659             : 
     660             :         OSL_UNUSED( i_colIndex );
     661           0 :     }
     662             : 
     663             :     //------------------------------------------------------------------------------------------------------------------
     664           0 :     void TableControl_Impl::allColumnsRemoved()
     665             :     {
     666           0 :         m_nColumnCount = m_pModel->getColumnCount();
     667           0 :         impl_ni_relayout();
     668             : 
     669           0 :         m_rAntiImpl.Invalidate();
     670           0 :     }
     671             : 
     672             :     //------------------------------------------------------------------------------------------------------------------
     673           0 :     void TableControl_Impl::cellsUpdated( ColPos const i_firstCol, ColPos i_lastCol, RowPos const i_firstRow, RowPos const i_lastRow )
     674             :     {
     675           0 :         invalidateRowRange( i_firstRow, i_lastRow );
     676             : 
     677             :         OSL_UNUSED( i_firstCol );
     678             :         OSL_UNUSED( i_lastCol );
     679           0 :     }
     680             : 
     681             :     //------------------------------------------------------------------------------------------------------------------
     682           0 :     void TableControl_Impl::tableMetricsChanged()
     683             :     {
     684           0 :         impl_ni_updateCachedTableMetrics();
     685           0 :         impl_ni_relayout();
     686           0 :         m_rAntiImpl.Invalidate();
     687           0 :     }
     688             : 
     689             :     //------------------------------------------------------------------------------------------------------------------
     690           0 :     void TableControl_Impl::impl_invalidateColumn( ColPos const i_column )
     691             :     {
     692             :         DBG_CHECK_ME();
     693             : 
     694           0 :         Rectangle const aAllCellsArea( impl_getAllVisibleCellsArea() );
     695             : 
     696           0 :         const TableColumnGeometry aColumn( *this, aAllCellsArea, i_column );
     697           0 :         if ( aColumn.isValid() )
     698           0 :             m_rAntiImpl.Invalidate( aColumn.getRect() );
     699           0 :     }
     700             : 
     701             :     //------------------------------------------------------------------------------------------------------------------
     702           0 :     void TableControl_Impl::columnChanged( ColPos const i_column, ColumnAttributeGroup const i_attributeGroup )
     703             :     {
     704           0 :         ColumnAttributeGroup nGroup( i_attributeGroup );
     705           0 :         if ( nGroup & COL_ATTRS_APPEARANCE )
     706             :         {
     707           0 :             impl_invalidateColumn( i_column );
     708           0 :             nGroup &= ~COL_ATTRS_APPEARANCE;
     709             :         }
     710             : 
     711           0 :         if ( nGroup & COL_ATTRS_WIDTH )
     712             :         {
     713           0 :             if ( !m_bUpdatingColWidths )
     714             :             {
     715           0 :                 impl_ni_relayout( i_column );
     716           0 :                 invalidate( TableAreaAll );
     717             :             }
     718             : 
     719           0 :             nGroup &= ~COL_ATTRS_WIDTH;
     720             :         }
     721             : 
     722             :         OSL_ENSURE( ( nGroup == COL_ATTRS_NONE ) || ( i_attributeGroup == COL_ATTRS_ALL ),
     723             :             "TableControl_Impl::columnChanged: don't know how to handle this change!" );
     724           0 :     }
     725             : 
     726             :     //------------------------------------------------------------------------------------------------------------------
     727           0 :     Rectangle TableControl_Impl::impl_getAllVisibleCellsArea() const
     728             :     {
     729             :         DBG_CHECK_ME();
     730             : 
     731           0 :         Rectangle aArea( Point( 0, 0 ), Size( 0, 0 ) );
     732             : 
     733             :         // determine the right-most border of the last column which is
     734             :         // at least partially visible
     735           0 :         aArea.Right() = m_nRowHeaderWidthPixel;
     736           0 :         if ( !m_aColumnWidths.empty() )
     737             :         {
     738             :             // the number of pixels which are scrolled out of the left hand
     739             :             // side of the window
     740           0 :             const long nScrolledOutLeft = m_nLeftColumn == 0 ? 0 : m_aColumnWidths[ m_nLeftColumn - 1 ].getEnd();
     741             : 
     742           0 :             ColumnPositions::const_reverse_iterator loop = m_aColumnWidths.rbegin();
     743           0 :             do
     744             :             {
     745           0 :                 aArea.Right() = loop->getEnd() - nScrolledOutLeft + m_nRowHeaderWidthPixel;
     746           0 :                 ++loop;
     747             :             }
     748           0 :             while ( (   loop != m_aColumnWidths.rend() )
     749           0 :                  && (   loop->getEnd() - nScrolledOutLeft >= aArea.Right() )
     750             :                  );
     751             :         }
     752             :         // so far, aArea.Right() denotes the first pixel *after* the cell area
     753           0 :         --aArea.Right();
     754             : 
     755             :         // determine the last row which is at least partially visible
     756           0 :         aArea.Bottom() =
     757             :                 m_nColHeaderHeightPixel
     758           0 :             +   impl_getVisibleRows( true ) * m_nRowHeightPixel
     759           0 :             -   1;
     760             : 
     761           0 :         return aArea;
     762             :     }
     763             : 
     764             :     //------------------------------------------------------------------------------------------------------------------
     765           0 :     Rectangle TableControl_Impl::impl_getAllVisibleDataCellArea() const
     766             :     {
     767             :         DBG_CHECK_ME();
     768             : 
     769           0 :         Rectangle aArea( impl_getAllVisibleCellsArea() );
     770           0 :         aArea.Left() = m_nRowHeaderWidthPixel;
     771           0 :         aArea.Top() = m_nColHeaderHeightPixel;
     772           0 :         return aArea;
     773             :     }
     774             : 
     775             :     //------------------------------------------------------------------------------------------------------------------
     776           0 :     void TableControl_Impl::impl_ni_updateCachedTableMetrics()
     777             :     {
     778           0 :         m_nRowHeightPixel = m_rAntiImpl.LogicToPixel( Size( 0, m_pModel->getRowHeight() ), MAP_APPFONT ).Height();
     779             : 
     780           0 :         m_nColHeaderHeightPixel = 0;
     781           0 :         if ( m_pModel->hasColumnHeaders() )
     782           0 :            m_nColHeaderHeightPixel = m_rAntiImpl.LogicToPixel( Size( 0, m_pModel->getColumnHeaderHeight() ), MAP_APPFONT ).Height();
     783             : 
     784           0 :         m_nRowHeaderWidthPixel = 0;
     785           0 :         if ( m_pModel->hasRowHeaders() )
     786           0 :             m_nRowHeaderWidthPixel = m_rAntiImpl.LogicToPixel( Size( m_pModel->getRowHeaderWidth(), 0 ), MAP_APPFONT).Width();
     787           0 :     }
     788             : 
     789             :     //------------------------------------------------------------------------------------------------------------------
     790           0 :     void TableControl_Impl::impl_ni_updateCachedModelValues()
     791             :     {
     792           0 :         m_pInputHandler = m_pModel->getInputHandler();
     793           0 :         if ( !m_pInputHandler )
     794           0 :             m_pInputHandler.reset( new DefaultInputHandler );
     795             : 
     796           0 :         m_nColumnCount = m_pModel->getColumnCount();
     797           0 :         if ( m_nLeftColumn >= m_nColumnCount )
     798           0 :             m_nLeftColumn = ( m_nColumnCount > 0 ) ? m_nColumnCount - 1 : 0;
     799             : 
     800           0 :         m_nRowCount = m_pModel->getRowCount();
     801           0 :         if ( m_nTopRow >= m_nRowCount )
     802           0 :             m_nTopRow = ( m_nRowCount > 0 ) ? m_nRowCount - 1 : 0;
     803             : 
     804           0 :         impl_ni_updateCachedTableMetrics();
     805           0 :     }
     806             : 
     807             :     //------------------------------------------------------------------------------------------------------------------
     808             :     namespace
     809             :     {
     810             :         //..............................................................................................................
     811             :         /// determines whether a scrollbar is needed for the given values
     812           0 :         bool lcl_determineScrollbarNeed( long const i_position, ScrollbarVisibility const i_visibility,
     813             :             long const i_availableSpace, long const i_neededSpace )
     814             :         {
     815           0 :             if ( i_visibility == ScrollbarShowNever )
     816           0 :                 return false;
     817           0 :             if ( i_visibility == ScrollbarShowAlways )
     818           0 :                 return true;
     819           0 :             if ( i_position > 0 )
     820           0 :                 return true;
     821           0 :             if ( i_availableSpace >= i_neededSpace )
     822           0 :                 return false;
     823           0 :             return true;
     824             :         }
     825             : 
     826             :         //..............................................................................................................
     827           0 :         void lcl_setButtonRepeat( Window& _rWindow, sal_uLong _nDelay )
     828             :         {
     829           0 :             AllSettings aSettings = _rWindow.GetSettings();
     830           0 :             MouseSettings aMouseSettings = aSettings.GetMouseSettings();
     831             : 
     832           0 :             aMouseSettings.SetButtonRepeat( _nDelay );
     833           0 :             aSettings.SetMouseSettings( aMouseSettings );
     834             : 
     835           0 :             _rWindow.SetSettings( aSettings, sal_True );
     836           0 :         }
     837             : 
     838             :         //..............................................................................................................
     839           0 :         bool lcl_updateScrollbar( Window& _rParent, ScrollBar*& _rpBar,
     840             :             bool const i_needBar, long _nVisibleUnits,
     841             :             long _nPosition, long _nLineSize, long _nRange,
     842             :             bool _bHorizontal, const Link& _rScrollHandler )
     843             :         {
     844             :             // do we currently have the scrollbar?
     845           0 :             bool bHaveBar = _rpBar != NULL;
     846             : 
     847             :             // do we need to correct the scrollbar visibility?
     848           0 :             if ( bHaveBar && !i_needBar )
     849             :             {
     850           0 :                 if ( _rpBar->IsTracking() )
     851           0 :                     _rpBar->EndTracking();
     852           0 :                 DELETEZ( _rpBar );
     853             :             }
     854           0 :             else if ( !bHaveBar && i_needBar )
     855             :             {
     856             :                 _rpBar = new ScrollBar(
     857             :                     &_rParent,
     858             :                     WB_DRAG | ( _bHorizontal ? WB_HSCROLL : WB_VSCROLL )
     859           0 :                 );
     860           0 :                 _rpBar->SetScrollHdl( _rScrollHandler );
     861             :                 // get some speed into the scrolling ....
     862           0 :                 lcl_setButtonRepeat( *_rpBar, 0 );
     863             :             }
     864             : 
     865           0 :             if ( _rpBar )
     866             :             {
     867           0 :                 _rpBar->SetRange( Range( 0, _nRange ) );
     868           0 :                 _rpBar->SetVisibleSize( _nVisibleUnits );
     869           0 :                 _rpBar->SetPageSize( _nVisibleUnits );
     870           0 :                 _rpBar->SetLineSize( _nLineSize );
     871           0 :                 _rpBar->SetThumbPos( _nPosition );
     872           0 :                 _rpBar->Show();
     873             :             }
     874             : 
     875           0 :             return ( bHaveBar != i_needBar );
     876             :         }
     877             : 
     878             :         //..............................................................................................................
     879             :         /** returns the number of rows fitting into the given range,
     880             :             for the given row height. Partially fitting rows are counted, too, if the
     881             :             respective parameter says so.
     882             :         */
     883           0 :         TableSize lcl_getRowsFittingInto( long _nOverallHeight, long _nRowHeightPixel, bool _bAcceptPartialRow = false )
     884             :         {
     885             :             return  _bAcceptPartialRow
     886             :                 ?   ( _nOverallHeight + ( _nRowHeightPixel - 1 ) ) / _nRowHeightPixel
     887           0 :                 :   _nOverallHeight / _nRowHeightPixel;
     888             :         }
     889             : 
     890             :         //..............................................................................................................
     891             :         /** returns the number of columns fitting into the given area,
     892             :             with the first visible column as given. Partially fitting columns are counted, too,
     893             :             if the respective parameter says so.
     894             :         */
     895           0 :         TableSize lcl_getColumnsVisibleWithin( const Rectangle& _rArea, ColPos _nFirstVisibleColumn,
     896             :             const TableControl_Impl& _rControl, bool _bAcceptPartialRow )
     897             :         {
     898           0 :             TableSize visibleColumns = 0;
     899           0 :             TableColumnGeometry aColumn( _rControl, _rArea, _nFirstVisibleColumn );
     900           0 :             while ( aColumn.isValid() )
     901             :             {
     902           0 :                 if ( !_bAcceptPartialRow )
     903           0 :                     if ( aColumn.getRect().Right() > _rArea.Right() )
     904             :                         // this column is only partially visible, and this is not allowed
     905           0 :                         break;
     906             : 
     907           0 :                 aColumn.moveRight();
     908           0 :                 ++visibleColumns;
     909             :             }
     910           0 :             return visibleColumns;
     911             :         }
     912             : 
     913             :     }
     914             : 
     915             :     //------------------------------------------------------------------------------------------------------------------
     916           0 :     long TableControl_Impl::impl_ni_calculateColumnWidths( ColPos const i_assumeInflexibleColumnsUpToIncluding,
     917             :         bool const i_assumeVerticalScrollbar, ::std::vector< long >& o_newColWidthsPixel ) const
     918             :     {
     919             :         // the available horizontal space
     920           0 :         long gridWidthPixel = m_rAntiImpl.GetOutputSizePixel().Width();
     921           0 :         ENSURE_OR_RETURN( !!m_pModel, "TableControl_Impl::impl_ni_calculateColumnWidths: not allowed without a model!", gridWidthPixel );
     922           0 :         if ( m_pModel->hasRowHeaders() && ( gridWidthPixel != 0 ) )
     923             :         {
     924           0 :             gridWidthPixel -= m_nRowHeaderWidthPixel;
     925             :         }
     926             : 
     927           0 :         if ( i_assumeVerticalScrollbar && ( m_pModel->getVerticalScrollbarVisibility() != ScrollbarShowNever ) )
     928             :         {
     929           0 :             long nScrollbarMetrics = m_rAntiImpl.GetSettings().GetStyleSettings().GetScrollBarSize();
     930           0 :             gridWidthPixel -= nScrollbarMetrics;
     931             :         }
     932             : 
     933             :         // no need to do anything without columns
     934           0 :         TableSize const colCount = m_pModel->getColumnCount();
     935           0 :         if ( colCount == 0 )
     936           0 :             return gridWidthPixel;
     937             : 
     938             :         // collect some meta data for our columns:
     939             :         // - their current (pixel) metrics
     940           0 :         long accumulatedCurrentWidth = 0;
     941           0 :         ::std::vector< long > currentColWidths;
     942           0 :         currentColWidths.reserve( colCount );
     943             :         typedef ::std::vector< ::std::pair< long, long > >   ColumnLimits;
     944           0 :         ColumnLimits effectiveColumnLimits;
     945           0 :         effectiveColumnLimits.reserve( colCount );
     946           0 :         long accumulatedMinWidth = 0;
     947           0 :         long accumulatedMaxWidth = 0;
     948             :         // - their relative flexibility
     949           0 :         ::std::vector< ::sal_Int32 > columnFlexibilities;
     950           0 :         columnFlexibilities.reserve( colCount );
     951           0 :         long flexibilityDenominator = 0;
     952           0 :         size_t flexibleColumnCount = 0;
     953           0 :         for ( ColPos col = 0; col < colCount; ++col )
     954             :         {
     955           0 :             PColumnModel const pColumn = m_pModel->getColumnModel( col );
     956           0 :             ENSURE_OR_THROW( !!pColumn, "invalid column returned by the model!" );
     957             : 
     958             :             // current width
     959           0 :             long const currentWidth = appFontWidthToPixel( pColumn->getWidth() );
     960           0 :             currentColWidths.push_back( currentWidth );
     961             : 
     962             :             // accumulated width
     963           0 :             accumulatedCurrentWidth += currentWidth;
     964             : 
     965             :             // flexibility
     966           0 :             ::sal_Int32 flexibility = pColumn->getFlexibility();
     967             :             OSL_ENSURE( flexibility >= 0, "TableControl_Impl::impl_ni_calculateColumnWidths: a column's flexibility should be non-negative." );
     968           0 :             if  (   ( flexibility < 0 )                                 // normalization
     969           0 :                 ||  ( !pColumn->isResizable() )                         // column not resizeable => no auto-resize
     970             :                 ||  ( col <= i_assumeInflexibleColumnsUpToIncluding )   // column shall be treated as inflexible => respec this
     971             :                 )
     972           0 :                 flexibility = 0;
     973             : 
     974             :             // min/max width
     975           0 :             long effectiveMin = currentWidth, effectiveMax = currentWidth;
     976             :             // if the column is not flexible, it will not be asked for min/max, but we assume the current width as limit then
     977           0 :             if ( flexibility > 0 )
     978             :             {
     979           0 :                 long const minWidth = appFontWidthToPixel( pColumn->getMinWidth() );
     980           0 :                 if ( minWidth > 0 )
     981           0 :                     effectiveMin = minWidth;
     982             :                 else
     983           0 :                     effectiveMin = MIN_COLUMN_WIDTH_PIXEL;
     984             : 
     985           0 :                 long const maxWidth = appFontWidthToPixel( pColumn->getMaxWidth() );
     986             :                 OSL_ENSURE( minWidth <= maxWidth, "TableControl_Impl::impl_ni_calculateColumnWidths: pretty undecided 'bout its width limits, this column!" );
     987           0 :                 if ( ( maxWidth > 0 ) && ( maxWidth >= minWidth ) )
     988           0 :                     effectiveMax = maxWidth;
     989             :                 else
     990           0 :                     effectiveMax = gridWidthPixel; // TODO: any better guess here?
     991             : 
     992           0 :                 if ( effectiveMin == effectiveMax )
     993             :                     // if the min and the max are identical, this implies no flexibility at all
     994           0 :                     flexibility = 0;
     995             :             }
     996             : 
     997           0 :             columnFlexibilities.push_back( flexibility );
     998           0 :             flexibilityDenominator += flexibility;
     999           0 :             if ( flexibility > 0 )
    1000           0 :                 ++flexibleColumnCount;
    1001             : 
    1002           0 :             effectiveColumnLimits.push_back( ::std::pair< long, long >( effectiveMin, effectiveMax ) );
    1003           0 :             accumulatedMinWidth += effectiveMin;
    1004           0 :             accumulatedMaxWidth += effectiveMax;
    1005           0 :         }
    1006             : 
    1007           0 :         o_newColWidthsPixel = currentColWidths;
    1008           0 :         if ( flexibilityDenominator == 0 )
    1009             :         {
    1010             :             // no column is flexible => don't adjust anything
    1011             :         }
    1012           0 :         else if ( gridWidthPixel > accumulatedCurrentWidth )
    1013             :         {   // we have space to give away ...
    1014           0 :             long distributePixel = gridWidthPixel - accumulatedCurrentWidth;
    1015           0 :             if ( gridWidthPixel > accumulatedMaxWidth )
    1016             :             {
    1017             :                 // ... but the column's maximal widths are still less than we have
    1018             :                 // => set them all to max
    1019           0 :                 for ( size_t i = 0; i < size_t( colCount ); ++i )
    1020             :                 {
    1021           0 :                     o_newColWidthsPixel[i] = effectiveColumnLimits[i].second;
    1022             :                 }
    1023             :             }
    1024             :             else
    1025             :             {
    1026           0 :                 bool startOver = false;
    1027           0 :                 do
    1028             :                 {
    1029           0 :                     startOver = false;
    1030             :                     // distribute the remaining space amongst all columns with a positive flexibility
    1031           0 :                     for ( size_t i=0; i<o_newColWidthsPixel.size() && !startOver; ++i )
    1032             :                     {
    1033           0 :                         long const columnFlexibility = columnFlexibilities[i];
    1034           0 :                         if ( columnFlexibility == 0 )
    1035           0 :                             continue;
    1036             : 
    1037           0 :                         long newColWidth = currentColWidths[i] + columnFlexibility * distributePixel / flexibilityDenominator;
    1038             : 
    1039           0 :                         if ( newColWidth > effectiveColumnLimits[i].second )
    1040             :                         {   // that was too much, we hit the col's maximum
    1041             :                             // set the new width to exactly this maximum
    1042           0 :                             newColWidth = effectiveColumnLimits[i].second;
    1043             :                             // adjust the flexibility denominator ...
    1044           0 :                             flexibilityDenominator -= columnFlexibility;
    1045           0 :                             columnFlexibilities[i] = 0;
    1046           0 :                             --flexibleColumnCount;
    1047             :                             // ... and the remaining width ...
    1048           0 :                             long const difference = newColWidth - currentColWidths[i];
    1049           0 :                             distributePixel -= difference;
    1050             :                             // ... this way, we ensure that the width not taken up by this column is consumed by the other
    1051             :                             // flexible ones (if there are some)
    1052             : 
    1053             :                             // and start over with the first column, since there might be earlier columns which need
    1054             :                             // to be recalculated now
    1055           0 :                             startOver = true;
    1056             :                         }
    1057             : 
    1058           0 :                         o_newColWidthsPixel[i] = newColWidth;
    1059             :                     }
    1060             :                 }
    1061             :                 while ( startOver );
    1062             : 
    1063             :                 // are there pixels left (might be caused by rounding errors)?
    1064           0 :                 distributePixel = gridWidthPixel - ::std::accumulate( o_newColWidthsPixel.begin(), o_newColWidthsPixel.end(), 0 );
    1065           0 :                 while ( ( distributePixel > 0 ) && ( flexibleColumnCount > 0 ) )
    1066             :                 {
    1067             :                     // yes => ignore relative flexibilities, and subsequently distribute single pixels to all flexible
    1068             :                     // columns which did not yet reach their maximum.
    1069           0 :                     for ( size_t i=0; ( i < o_newColWidthsPixel.size() ) && ( distributePixel > 0 ); ++i )
    1070             :                     {
    1071           0 :                         if ( columnFlexibilities[i] == 0 )
    1072           0 :                             continue;
    1073             : 
    1074             :                         OSL_ENSURE( o_newColWidthsPixel[i] <= effectiveColumnLimits[i].second,
    1075             :                             "TableControl_Impl::impl_ni_calculateColumnWidths: inconsitency!" );
    1076           0 :                         if ( o_newColWidthsPixel[i] >= effectiveColumnLimits[i].first )
    1077             :                         {
    1078           0 :                             columnFlexibilities[i] = 0;
    1079           0 :                             --flexibleColumnCount;
    1080           0 :                             continue;
    1081             :                         }
    1082             : 
    1083           0 :                         ++o_newColWidthsPixel[i];
    1084           0 :                         --distributePixel;
    1085             :                     }
    1086             :                 }
    1087             :             }
    1088             :         }
    1089           0 :         else if ( gridWidthPixel < accumulatedCurrentWidth )
    1090             :         {   // we need to take away some space from the columns which allow it ...
    1091           0 :             long takeAwayPixel = accumulatedCurrentWidth - gridWidthPixel;
    1092           0 :             if ( gridWidthPixel < accumulatedMinWidth )
    1093             :             {
    1094             :                 // ... but the column's minimal widths are still more than we have
    1095             :                 // => set them all to min
    1096           0 :                 for ( size_t i = 0; i < size_t( colCount ); ++i )
    1097             :                 {
    1098           0 :                     o_newColWidthsPixel[i] = effectiveColumnLimits[i].first;
    1099             :                 }
    1100             :             }
    1101             :             else
    1102             :             {
    1103           0 :                 bool startOver = false;
    1104           0 :                 do
    1105             :                 {
    1106           0 :                     startOver = false;
    1107             :                     // take away the space we need from the columns with a positive flexibility
    1108           0 :                     for ( size_t i=0; i<o_newColWidthsPixel.size() && !startOver; ++i )
    1109             :                     {
    1110           0 :                         long const columnFlexibility = columnFlexibilities[i];
    1111           0 :                         if ( columnFlexibility == 0 )
    1112           0 :                             continue;
    1113             : 
    1114           0 :                         long newColWidth = currentColWidths[i] - columnFlexibility * takeAwayPixel / flexibilityDenominator;
    1115             : 
    1116           0 :                         if ( newColWidth < effectiveColumnLimits[i].first )
    1117             :                         {   // that was too much, we hit the col's minimum
    1118             :                             // set the new width to exactly this minimum
    1119           0 :                             newColWidth = effectiveColumnLimits[i].first;
    1120             :                             // adjust the flexibility denominator ...
    1121           0 :                             flexibilityDenominator -= columnFlexibility;
    1122           0 :                             columnFlexibilities[i] = 0;
    1123           0 :                             --flexibleColumnCount;
    1124             :                             // ... and the remaining width ...
    1125           0 :                             long const difference = currentColWidths[i] - newColWidth;
    1126           0 :                             takeAwayPixel -= difference;
    1127             : 
    1128             :                             // and start over with the first column, since there might be earlier columns which need
    1129             :                             // to be recalculated now
    1130           0 :                             startOver = true;
    1131             :                         }
    1132             : 
    1133           0 :                         o_newColWidthsPixel[i] = newColWidth;
    1134             :                     }
    1135             :                 }
    1136             :                 while ( startOver );
    1137             : 
    1138             :                 // are there pixels left (might be caused by rounding errors)?
    1139           0 :                 takeAwayPixel = ::std::accumulate( o_newColWidthsPixel.begin(), o_newColWidthsPixel.end(), 0 ) - gridWidthPixel;
    1140           0 :                 while ( ( takeAwayPixel > 0 ) && ( flexibleColumnCount > 0 ) )
    1141             :                 {
    1142             :                     // yes => ignore relative flexibilities, and subsequently take away pixels from all flexible
    1143             :                     // columns which did not yet reach their minimum.
    1144           0 :                     for ( size_t i=0; ( i < o_newColWidthsPixel.size() ) && ( takeAwayPixel > 0 ); ++i )
    1145             :                     {
    1146           0 :                         if ( columnFlexibilities[i] == 0 )
    1147           0 :                             continue;
    1148             : 
    1149             :                         OSL_ENSURE( o_newColWidthsPixel[i] >= effectiveColumnLimits[i].first,
    1150             :                             "TableControl_Impl::impl_ni_calculateColumnWidths: inconsitency!" );
    1151           0 :                         if ( o_newColWidthsPixel[i] <= effectiveColumnLimits[i].first )
    1152             :                         {
    1153           0 :                             columnFlexibilities[i] = 0;
    1154           0 :                             --flexibleColumnCount;
    1155           0 :                             continue;
    1156             :                         }
    1157             : 
    1158           0 :                         --o_newColWidthsPixel[i];
    1159           0 :                         --takeAwayPixel;
    1160             :                     }
    1161             :                 }
    1162             :             }
    1163             :         }
    1164             : 
    1165           0 :         return gridWidthPixel;
    1166             :     }
    1167             : 
    1168             :     //------------------------------------------------------------------------------------------------------------------
    1169           0 :     void TableControl_Impl::impl_ni_relayout( ColPos const i_assumeInflexibleColumnsUpToIncluding )
    1170             :     {
    1171           0 :         ENSURE_OR_RETURN_VOID( !m_bUpdatingColWidths, "TableControl_Impl::impl_ni_relayout: recursive call detected!" );
    1172             : 
    1173           0 :         m_aColumnWidths.resize( 0 );
    1174           0 :         if ( !m_pModel )
    1175             :             return;
    1176             : 
    1177           0 :         ::comphelper::FlagRestorationGuard const aWidthUpdateFlag( m_bUpdatingColWidths, true );
    1178           0 :         SuppressCursor aHideCursor( *this );
    1179             : 
    1180             :         // layouting steps:
    1181             :         //
    1182             :         // 1. adjust column widths, leaving space for a vertical scrollbar
    1183             :         // 2. determine need for a vertical scrollbar
    1184             :         //    - V-YES: all fine, result from 1. is still valid
    1185             :         //    - V-NO: result from 1. is still under consideration
    1186             :         //
    1187             :         // 3. determine need for a horizontal scrollbar
    1188             :         //   - H-NO: all fine, result from 2. is still valid
    1189             :         //   - H-YES: reconsider need for a vertical scrollbar, if result of 2. was V-NO
    1190             :         //     - V-YES: all fine, result from 1. is still valid
    1191             :         //     - V-NO: redistribute the remaining space (if any) amongst all columns which allow it
    1192             : 
    1193           0 :         ::std::vector< long > newWidthsPixel;
    1194           0 :         long gridWidthPixel = impl_ni_calculateColumnWidths( i_assumeInflexibleColumnsUpToIncluding, true, newWidthsPixel );
    1195             : 
    1196             :         // the width/height of a scrollbar, needed several times below
    1197           0 :         long const nScrollbarMetrics = m_rAntiImpl.GetSettings().GetStyleSettings().GetScrollBarSize();
    1198             : 
    1199             :         // determine the playground for the data cells (excluding headers)
    1200             :         // TODO: what if the control is smaller than needed for the headers/scrollbars?
    1201           0 :         Rectangle aDataCellPlayground( Point( 0, 0 ), m_rAntiImpl.GetOutputSizePixel() );
    1202           0 :         aDataCellPlayground.Left() = m_nRowHeaderWidthPixel;
    1203           0 :         aDataCellPlayground.Top() = m_nColHeaderHeightPixel;
    1204             : 
    1205             :         OSL_ENSURE( ( m_nRowCount == m_pModel->getRowCount() ) && ( m_nColumnCount == m_pModel->getColumnCount() ),
    1206             :             "TableControl_Impl::impl_ni_relayout: how is this expected to work with invalid data?" );
    1207           0 :         long const nAllColumnsWidth = ::std::accumulate( newWidthsPixel.begin(), newWidthsPixel.end(), 0 );
    1208             : 
    1209           0 :         ScrollbarVisibility const eVertScrollbar = m_pModel->getVerticalScrollbarVisibility();
    1210           0 :         ScrollbarVisibility const eHorzScrollbar = m_pModel->getHorizontalScrollbarVisibility();
    1211             : 
    1212             :         // do we need a vertical scrollbar?
    1213             :         bool bNeedVerticalScrollbar = lcl_determineScrollbarNeed(
    1214           0 :             m_nTopRow, eVertScrollbar, aDataCellPlayground.GetHeight(), m_nRowHeightPixel * m_nRowCount );
    1215           0 :         bool bFirstRoundVScrollNeed = false;
    1216           0 :         if ( bNeedVerticalScrollbar )
    1217             :         {
    1218           0 :             aDataCellPlayground.Right() -= nScrollbarMetrics;
    1219           0 :             bFirstRoundVScrollNeed = true;
    1220             :         }
    1221             : 
    1222             :         // do we need a horizontal scrollbar?
    1223             :         bool const bNeedHorizontalScrollbar = lcl_determineScrollbarNeed(
    1224           0 :             m_nLeftColumn, eHorzScrollbar, aDataCellPlayground.GetWidth(), nAllColumnsWidth );
    1225           0 :         if ( bNeedHorizontalScrollbar )
    1226             :         {
    1227           0 :             aDataCellPlayground.Bottom() -= nScrollbarMetrics;
    1228             : 
    1229             :             // now that we just found that we need a horizontal scrollbar,
    1230             :             // the need for a vertical one may have changed, since the horizontal
    1231             :             // SB might just occupy enough space so that not all rows do fit
    1232             :             // anymore
    1233           0 :             if  ( !bFirstRoundVScrollNeed )
    1234             :             {
    1235             :                 bNeedVerticalScrollbar = lcl_determineScrollbarNeed(
    1236           0 :                     m_nTopRow, eVertScrollbar, aDataCellPlayground.GetHeight(), m_nRowHeightPixel * m_nRowCount );
    1237           0 :                 if ( bNeedVerticalScrollbar )
    1238             :                 {
    1239           0 :                     aDataCellPlayground.Right() -= nScrollbarMetrics;
    1240             :                 }
    1241             :             }
    1242             :         }
    1243             : 
    1244             :         // the initial call to impl_ni_calculateColumnWidths assumed that we need a vertical scrollbar. If, by now,
    1245             :         // we know that this is not the case, re-calculate the column widths.
    1246           0 :         if ( !bNeedVerticalScrollbar )
    1247           0 :             gridWidthPixel = impl_ni_calculateColumnWidths( i_assumeInflexibleColumnsUpToIncluding, false, newWidthsPixel );
    1248             : 
    1249             :         // update the column objects with the new widths we finally calculated
    1250           0 :         TableSize const colCount = m_pModel->getColumnCount();
    1251           0 :         m_aColumnWidths.reserve( colCount );
    1252           0 :         long accumulatedWidthPixel = m_nRowHeaderWidthPixel;
    1253           0 :         bool anyColumnWidthChanged = false;
    1254           0 :         for ( ColPos col = 0; col < colCount; ++col )
    1255             :         {
    1256           0 :             const long columnStart = accumulatedWidthPixel;
    1257           0 :             const long columnEnd = columnStart + newWidthsPixel[col];
    1258           0 :             m_aColumnWidths.push_back( MutableColumnMetrics( columnStart, columnEnd ) );
    1259           0 :             accumulatedWidthPixel = columnEnd;
    1260             : 
    1261             :             // and don't forget to forward this to the column models
    1262           0 :             PColumnModel const pColumn = m_pModel->getColumnModel( col );
    1263           0 :             ENSURE_OR_THROW( !!pColumn, "invalid column returned by the model!" );
    1264             : 
    1265           0 :             long const oldColumnWidthAppFont = pColumn->getWidth();
    1266           0 :             long const newColumnWidthAppFont = pixelWidthToAppFont( newWidthsPixel[col] );
    1267           0 :             pColumn->setWidth( newColumnWidthAppFont );
    1268             : 
    1269           0 :             anyColumnWidthChanged |= ( oldColumnWidthAppFont != newColumnWidthAppFont );
    1270           0 :         }
    1271             : 
    1272             :         // if the column widths changed, ensure everything is repainted
    1273           0 :         if ( anyColumnWidthChanged )
    1274           0 :             invalidate( TableAreaAll );
    1275             : 
    1276             :         // if the column resizing happened to leave some space at the right, but there are columns
    1277             :         // scrolled out to the left, scroll them in
    1278           0 :         while   (   ( m_nLeftColumn > 0 )
    1279           0 :                 &&  ( accumulatedWidthPixel - m_aColumnWidths[ m_nLeftColumn - 1 ].getStart() <= gridWidthPixel )
    1280             :                 )
    1281             :         {
    1282           0 :             --m_nLeftColumn;
    1283             :         }
    1284             : 
    1285             :         // now adjust the column metrics, since they currently ignore the horizontal scroll position
    1286           0 :         if ( m_nLeftColumn > 0 )
    1287             :         {
    1288           0 :             const long offsetPixel = m_aColumnWidths[ 0 ].getStart() - m_aColumnWidths[ m_nLeftColumn ].getStart();
    1289           0 :             for (   ColumnPositions::iterator colPos = m_aColumnWidths.begin();
    1290           0 :                     colPos != m_aColumnWidths.end();
    1291             :                     ++colPos
    1292             :                  )
    1293             :             {
    1294           0 :                 colPos->move( offsetPixel );
    1295             :             }
    1296             :         }
    1297             : 
    1298             :         // show or hide the scrollbars as needed, and position the data window
    1299           0 :         impl_ni_positionChildWindows( aDataCellPlayground, bNeedVerticalScrollbar, bNeedHorizontalScrollbar );
    1300             :     }
    1301             : 
    1302             :     //------------------------------------------------------------------------------------------------------------------
    1303           0 :     void TableControl_Impl::impl_ni_positionChildWindows( Rectangle const & i_dataCellPlayground,
    1304             :         bool const i_verticalScrollbar, bool const i_horizontalScrollbar )
    1305             :     {
    1306           0 :         long const nScrollbarMetrics = m_rAntiImpl.GetSettings().GetStyleSettings().GetScrollBarSize();
    1307             : 
    1308             :         // create or destroy the vertical scrollbar, as needed
    1309             :         lcl_updateScrollbar(
    1310             :             m_rAntiImpl,
    1311             :             m_pVScroll,
    1312             :             i_verticalScrollbar,
    1313             :             lcl_getRowsFittingInto( i_dataCellPlayground.GetHeight(), m_nRowHeightPixel ),
    1314             :                                                                     // visible units
    1315             :             m_nTopRow,                                              // current position
    1316             :             1,                                                      // line size
    1317             :             m_nRowCount,                                            // range
    1318             :             false,                                                  // vertical
    1319             :             LINK( this, TableControl_Impl, OnScroll )               // scroll handler
    1320           0 :         );
    1321             : 
    1322             :         // position it
    1323           0 :         if ( m_pVScroll )
    1324             :         {
    1325             :             Rectangle aScrollbarArea(
    1326           0 :                 Point( i_dataCellPlayground.Right() + 1, 0 ),
    1327           0 :                 Size( nScrollbarMetrics, i_dataCellPlayground.Bottom() + 1 )
    1328           0 :             );
    1329             :             m_pVScroll->SetPosSizePixel(
    1330           0 :                 aScrollbarArea.TopLeft(), aScrollbarArea.GetSize() );
    1331             :         }
    1332             : 
    1333             :         // create or destroy the horizontal scrollbar, as needed
    1334             :         lcl_updateScrollbar(
    1335             :             m_rAntiImpl,
    1336             :             m_pHScroll,
    1337             :             i_horizontalScrollbar,
    1338             :             lcl_getColumnsVisibleWithin( i_dataCellPlayground, m_nLeftColumn, *this, false ),
    1339             :                                                                     // visible units
    1340             :             m_nLeftColumn,                                          // current position
    1341             :             1,                                                      // line size
    1342             :             m_nColumnCount,                                         // range
    1343             :             true,                                                   // horizontal
    1344             :             LINK( this, TableControl_Impl, OnScroll )               // scroll handler
    1345           0 :         );
    1346             : 
    1347             :         // position it
    1348           0 :         if ( m_pHScroll )
    1349             :         {
    1350           0 :             TableSize const nVisibleUnits = lcl_getColumnsVisibleWithin( i_dataCellPlayground, m_nLeftColumn, *this, false );
    1351           0 :             TableMetrics const nRange = m_nColumnCount;
    1352           0 :             if( m_nLeftColumn + nVisibleUnits == nRange - 1 )
    1353             :             {
    1354           0 :                 if ( m_aColumnWidths[ nRange - 1 ].getStart() - m_aColumnWidths[ m_nLeftColumn ].getEnd() + m_aColumnWidths[ nRange-1 ].getWidth() > i_dataCellPlayground.GetWidth() )
    1355             :                 {
    1356           0 :                     m_pHScroll->SetVisibleSize( nVisibleUnits -1 );
    1357           0 :                     m_pHScroll->SetPageSize( nVisibleUnits - 1 );
    1358             :                 }
    1359             :             }
    1360             :             Rectangle aScrollbarArea(
    1361           0 :                 Point( 0, i_dataCellPlayground.Bottom() + 1 ),
    1362           0 :                 Size( i_dataCellPlayground.Right() + 1, nScrollbarMetrics )
    1363           0 :             );
    1364             :             m_pHScroll->SetPosSizePixel(
    1365           0 :                 aScrollbarArea.TopLeft(), aScrollbarArea.GetSize() );
    1366             :         }
    1367             : 
    1368             :         // the corner window connecting the two scrollbars in the lower right corner
    1369           0 :         bool bHaveScrollCorner = NULL != m_pScrollCorner;
    1370           0 :         bool bNeedScrollCorner = ( NULL != m_pHScroll ) && ( NULL != m_pVScroll );
    1371           0 :         if ( bHaveScrollCorner && !bNeedScrollCorner )
    1372             :         {
    1373           0 :             DELETEZ( m_pScrollCorner );
    1374             :         }
    1375           0 :         else if ( !bHaveScrollCorner && bNeedScrollCorner )
    1376             :         {
    1377           0 :             m_pScrollCorner = new ScrollBarBox( &m_rAntiImpl );
    1378           0 :             m_pScrollCorner->SetSizePixel( Size( nScrollbarMetrics, nScrollbarMetrics ) );
    1379           0 :             m_pScrollCorner->SetPosPixel( Point( i_dataCellPlayground.Right() + 1, i_dataCellPlayground.Bottom() + 1 ) );
    1380           0 :             m_pScrollCorner->Show();
    1381             :         }
    1382           0 :         else if(bHaveScrollCorner && bNeedScrollCorner)
    1383             :         {
    1384           0 :             m_pScrollCorner->SetPosPixel( Point( i_dataCellPlayground.Right() + 1, i_dataCellPlayground.Bottom() + 1 ) );
    1385           0 :             m_pScrollCorner->Show();
    1386             :         }
    1387             : 
    1388             :         // resize the data window
    1389           0 :         m_pDataWindow->SetSizePixel( Size(
    1390           0 :             i_dataCellPlayground.GetWidth() + m_nRowHeaderWidthPixel,
    1391           0 :             i_dataCellPlayground.GetHeight() + m_nColHeaderHeightPixel
    1392           0 :         ) );
    1393           0 :     }
    1394             : 
    1395             :     //------------------------------------------------------------------------------------------------------------------
    1396           0 :     void TableControl_Impl::onResize()
    1397             :     {
    1398             :         DBG_CHECK_ME();
    1399             : 
    1400           0 :         impl_ni_relayout();
    1401           0 :         checkCursorPosition();
    1402           0 :     }
    1403             : 
    1404             :     //------------------------------------------------------------------------------------------------------------------
    1405           0 :     void TableControl_Impl::doPaintContent( const Rectangle& _rUpdateRect )
    1406             :     {
    1407             :         DBG_CHECK_ME();
    1408             : 
    1409           0 :         if ( !getModel() )
    1410             :             return;
    1411           0 :         PTableRenderer pRenderer = getModel()->getRenderer();
    1412             :         DBG_ASSERT( !!pRenderer, "TableDataWindow::doPaintContent: invalid renderer!" );
    1413           0 :         if ( !pRenderer )
    1414             :             return;
    1415             : 
    1416             :         // our current style settings, to be passed to the renderer
    1417           0 :         const StyleSettings& rStyle = m_rAntiImpl.GetSettings().GetStyleSettings();
    1418           0 :         m_nRowCount = m_pModel->getRowCount();
    1419             :         // the area occupied by all (at least partially) visible cells, including
    1420             :         // headers
    1421           0 :         Rectangle const aAllCellsWithHeaders( impl_getAllVisibleCellsArea() );
    1422             : 
    1423             :         // ............................
    1424             :         // draw the header column area
    1425           0 :         if ( m_pModel->hasColumnHeaders() )
    1426             :         {
    1427             :             TableRowGeometry const aHeaderRow( *this, Rectangle( Point( 0, 0 ),
    1428           0 :                 aAllCellsWithHeaders.BottomRight() ), ROW_COL_HEADERS );
    1429           0 :             Rectangle const aColRect(aHeaderRow.getRect());
    1430           0 :             pRenderer->PaintHeaderArea(
    1431           0 :                 *m_pDataWindow, aColRect, true, false, rStyle
    1432           0 :             );
    1433             :             // Note that strictly, aHeaderRow.getRect() also contains the intersection between column
    1434             :             // and row header area. However, below we go to paint this intersection, again,
    1435             :             // so this hopefully doesn't hurt if we already paint it here.
    1436             : 
    1437           0 :             for ( TableCellGeometry aCell( aHeaderRow, m_nLeftColumn );
    1438             :                   aCell.isValid();
    1439             :                   aCell.moveRight()
    1440             :                 )
    1441             :             {
    1442           0 :                 if ( _rUpdateRect.GetIntersection( aCell.getRect() ).IsEmpty() )
    1443           0 :                     continue;
    1444             : 
    1445           0 :                 bool isActiveColumn = ( aCell.getColumn() == getCurrentColumn() );
    1446           0 :                 bool isSelectedColumn = false;
    1447           0 :                 pRenderer->PaintColumnHeader( aCell.getColumn(), isActiveColumn, isSelectedColumn,
    1448           0 :                     *m_pDataWindow, aCell.getRect(), rStyle );
    1449             :             }
    1450             :         }
    1451             :         // the area occupied by the row header, if any
    1452           0 :         Rectangle aRowHeaderArea;
    1453           0 :         if ( m_pModel->hasRowHeaders() )
    1454             :         {
    1455           0 :             aRowHeaderArea = aAllCellsWithHeaders;
    1456           0 :             aRowHeaderArea.Right() = m_nRowHeaderWidthPixel - 1;
    1457             : 
    1458           0 :             TableSize const nVisibleRows = impl_getVisibleRows( true );
    1459           0 :             TableSize nActualRows = nVisibleRows;
    1460           0 :             if ( m_nTopRow + nActualRows > m_nRowCount )
    1461           0 :                 nActualRows = m_nRowCount - m_nTopRow;
    1462           0 :             aRowHeaderArea.Bottom() = m_nColHeaderHeightPixel + m_nRowHeightPixel * nActualRows - 1;
    1463             : 
    1464           0 :             pRenderer->PaintHeaderArea( *m_pDataWindow, aRowHeaderArea, false, true, rStyle );
    1465             :             // Note that strictly, aRowHeaderArea also contains the intersection between column
    1466             :             // and row header area. However, below we go to paint this intersection, again,
    1467             :             // so this hopefully doesn't hurt if we already paint it here.
    1468             : 
    1469           0 :             if ( m_pModel->hasColumnHeaders() )
    1470             :             {
    1471             :                 TableCellGeometry const aIntersection( *this, Rectangle( Point( 0, 0 ),
    1472           0 :                     aAllCellsWithHeaders.BottomRight() ), COL_ROW_HEADERS, ROW_COL_HEADERS );
    1473           0 :                 Rectangle const aInters( aIntersection.getRect() );
    1474           0 :                 pRenderer->PaintHeaderArea(
    1475           0 :                     *m_pDataWindow, aInters, true, true, rStyle
    1476           0 :                 );
    1477             :             }
    1478             :         }
    1479             : 
    1480             :         // ............................
    1481             :         // draw the table content row by row
    1482             : 
    1483           0 :         TableSize colCount = getModel()->getColumnCount();
    1484             : 
    1485             :         // paint all rows
    1486           0 :         Rectangle const aAllDataCellsArea( impl_getAllVisibleDataCellArea() );
    1487           0 :         for ( TableRowGeometry aRowIterator( *this, aAllCellsWithHeaders, getTopRow() );
    1488             :               aRowIterator.isValid();
    1489             :               aRowIterator.moveDown() )
    1490             :         {
    1491           0 :             if ( _rUpdateRect.GetIntersection( aRowIterator.getRect() ).IsEmpty() )
    1492           0 :                 continue;
    1493             : 
    1494           0 :             bool const isControlFocused = m_rAntiImpl.HasControlFocus();
    1495           0 :             bool const isSelectedRow = isRowSelected( aRowIterator.getRow() );
    1496             : 
    1497           0 :             Rectangle const aRect = aRowIterator.getRect().GetIntersection( aAllDataCellsArea );
    1498             : 
    1499             :             // give the redenderer a chance to prepare the row
    1500           0 :             pRenderer->PrepareRow(
    1501             :                 aRowIterator.getRow(), isControlFocused, isSelectedRow,
    1502           0 :                 *m_pDataWindow, aRect, rStyle
    1503           0 :             );
    1504             : 
    1505             :             // paint the row header
    1506           0 :             if ( m_pModel->hasRowHeaders() )
    1507             :             {
    1508           0 :                 const Rectangle aCurrentRowHeader( aRowHeaderArea.GetIntersection( aRowIterator.getRect() ) );
    1509           0 :                 pRenderer->PaintRowHeader( isControlFocused, isSelectedRow, *m_pDataWindow, aCurrentRowHeader,
    1510           0 :                     rStyle );
    1511             :             }
    1512             : 
    1513           0 :             if ( !colCount )
    1514           0 :                 continue;
    1515             : 
    1516             :             // paint all cells in this row
    1517           0 :             for ( TableCellGeometry aCell( aRowIterator, m_nLeftColumn );
    1518             :                   aCell.isValid();
    1519             :                   aCell.moveRight()
    1520             :                 )
    1521             :             {
    1522           0 :                 bool isSelectedColumn = false;
    1523           0 :                 pRenderer->PaintCell( aCell.getColumn(), isSelectedRow || isSelectedColumn, isControlFocused,
    1524           0 :                                 *m_pDataWindow, aCell.getRect(), rStyle );
    1525             :             }
    1526           0 :         }
    1527             :     }
    1528             :     //------------------------------------------------------------------------------------------------------------------
    1529           0 :     void TableControl_Impl::hideCursor()
    1530             :     {
    1531             :         DBG_CHECK_ME();
    1532             : 
    1533           0 :         if ( ++m_nCursorHidden == 1 )
    1534           0 :             impl_ni_doSwitchCursor( false );
    1535           0 :     }
    1536             : 
    1537             :     //------------------------------------------------------------------------------------------------------------------
    1538           0 :     void TableControl_Impl::showCursor()
    1539             :     {
    1540             :         DBG_CHECK_ME();
    1541             : 
    1542             :         DBG_ASSERT( m_nCursorHidden > 0, "TableControl_Impl::showCursor: cursor not hidden!" );
    1543           0 :         if ( --m_nCursorHidden == 0 )
    1544           0 :             impl_ni_doSwitchCursor( true );
    1545           0 :     }
    1546             : 
    1547             :     //------------------------------------------------------------------------------------------------------------------
    1548           0 :     bool TableControl_Impl::dispatchAction( TableControlAction _eAction )
    1549             :     {
    1550             :         DBG_CHECK_ME();
    1551             : 
    1552           0 :         bool bSuccess = false;
    1553           0 :         bool selectionChanged = false;
    1554             : 
    1555           0 :         switch ( _eAction )
    1556             :         {
    1557             :         case cursorDown:
    1558           0 :         if ( m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION )
    1559             :         {
    1560             :             //if other rows already selected, deselect them
    1561           0 :             if(!m_aSelectedRows.empty())
    1562             :             {
    1563           0 :                 invalidateSelectedRows();
    1564           0 :                 m_aSelectedRows.clear();
    1565             :             }
    1566           0 :             if ( m_nCurRow < m_nRowCount-1 )
    1567             :             {
    1568           0 :                 ++m_nCurRow;
    1569           0 :                 m_aSelectedRows.push_back(m_nCurRow);
    1570             :             }
    1571             :             else
    1572           0 :                 m_aSelectedRows.push_back(m_nCurRow);
    1573           0 :             invalidateRow( m_nCurRow );
    1574           0 :             ensureVisible(m_nCurColumn,m_nCurRow,false);
    1575           0 :             selectionChanged = true;
    1576           0 :             bSuccess = true;
    1577             :         }
    1578             :         else
    1579             :         {
    1580           0 :             if ( m_nCurRow < m_nRowCount - 1 )
    1581           0 :                 bSuccess = goTo( m_nCurColumn, m_nCurRow + 1 );
    1582             :         }
    1583           0 :             break;
    1584             : 
    1585             :         case cursorUp:
    1586           0 :         if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
    1587             :         {
    1588           0 :             if(!m_aSelectedRows.empty())
    1589             :             {
    1590           0 :                 invalidateSelectedRows();
    1591           0 :                 m_aSelectedRows.clear();
    1592             :             }
    1593           0 :             if(m_nCurRow>0)
    1594             :             {
    1595           0 :                 --m_nCurRow;
    1596           0 :                 m_aSelectedRows.push_back(m_nCurRow);
    1597           0 :                 invalidateRow( m_nCurRow );
    1598             :             }
    1599             :             else
    1600             :             {
    1601           0 :                 m_aSelectedRows.push_back(m_nCurRow);
    1602           0 :                 invalidateRow( m_nCurRow );
    1603             :             }
    1604           0 :             ensureVisible(m_nCurColumn,m_nCurRow,false);
    1605           0 :             selectionChanged = true;
    1606           0 :             bSuccess = true;
    1607             :         }
    1608             :         else
    1609             :         {
    1610           0 :             if ( m_nCurRow > 0 )
    1611           0 :                 bSuccess = goTo( m_nCurColumn, m_nCurRow - 1 );
    1612             :         }
    1613           0 :         break;
    1614             :         case cursorLeft:
    1615           0 :             if ( m_nCurColumn > 0 )
    1616           0 :                 bSuccess = goTo( m_nCurColumn - 1, m_nCurRow );
    1617             :             else
    1618           0 :                 if ( ( m_nCurColumn == 0) && ( m_nCurRow > 0 ) )
    1619           0 :                     bSuccess = goTo( m_nColumnCount - 1, m_nCurRow - 1 );
    1620           0 :             break;
    1621             : 
    1622             :         case cursorRight:
    1623           0 :             if ( m_nCurColumn < m_nColumnCount - 1 )
    1624           0 :                 bSuccess = goTo( m_nCurColumn + 1, m_nCurRow );
    1625             :             else
    1626           0 :                 if ( ( m_nCurColumn == m_nColumnCount - 1 ) && ( m_nCurRow < m_nRowCount - 1 ) )
    1627           0 :                     bSuccess = goTo( 0, m_nCurRow + 1 );
    1628           0 :             break;
    1629             : 
    1630             :         case cursorToLineStart:
    1631           0 :             bSuccess = goTo( 0, m_nCurRow );
    1632           0 :             break;
    1633             : 
    1634             :         case cursorToLineEnd:
    1635           0 :             bSuccess = goTo( m_nColumnCount - 1, m_nCurRow );
    1636           0 :             break;
    1637             : 
    1638             :         case cursorToFirstLine:
    1639           0 :             bSuccess = goTo( m_nCurColumn, 0 );
    1640           0 :             break;
    1641             : 
    1642             :         case cursorToLastLine:
    1643           0 :             bSuccess = goTo( m_nCurColumn, m_nRowCount - 1 );
    1644           0 :             break;
    1645             : 
    1646             :         case cursorPageUp:
    1647             :         {
    1648           0 :             RowPos nNewRow = ::std::max( (RowPos)0, m_nCurRow - impl_getVisibleRows( false ) );
    1649           0 :             bSuccess = goTo( m_nCurColumn, nNewRow );
    1650             :         }
    1651           0 :         break;
    1652             : 
    1653             :         case cursorPageDown:
    1654             :         {
    1655           0 :             RowPos nNewRow = ::std::min( m_nRowCount - 1, m_nCurRow + impl_getVisibleRows( false ) );
    1656           0 :             bSuccess = goTo( m_nCurColumn, nNewRow );
    1657             :         }
    1658           0 :         break;
    1659             : 
    1660             :         case cursorTopLeft:
    1661           0 :             bSuccess = goTo( 0, 0 );
    1662           0 :             break;
    1663             : 
    1664             :         case cursorBottomRight:
    1665           0 :             bSuccess = goTo( m_nColumnCount - 1, m_nRowCount - 1 );
    1666           0 :             break;
    1667             : 
    1668             :         case cursorSelectRow:
    1669             :         {
    1670           0 :             if(m_pSelEngine->GetSelectionMode() == NO_SELECTION)
    1671           0 :                 return bSuccess = false;
    1672             :             //pos is the position of the current row in the vector of selected rows, if current row is selected
    1673           0 :             int pos = getRowSelectedNumber(m_aSelectedRows, m_nCurRow);
    1674             :             //if current row is selected, it should be deselected, when ALT+SPACE are pressed
    1675           0 :             if(pos>-1)
    1676             :             {
    1677           0 :                 m_aSelectedRows.erase(m_aSelectedRows.begin()+pos);
    1678           0 :                 if(m_aSelectedRows.empty() && m_nAnchor != -1)
    1679           0 :                     m_nAnchor = -1;
    1680             :             }
    1681             :             //else select the row->put it in the vector
    1682             :             else
    1683           0 :                 m_aSelectedRows.push_back(m_nCurRow);
    1684           0 :             invalidateRow( m_nCurRow );
    1685           0 :             selectionChanged = true;
    1686           0 :             bSuccess = true;
    1687             :         }
    1688           0 :             break;
    1689             :         case cursorSelectRowUp:
    1690             :         {
    1691           0 :             if(m_pSelEngine->GetSelectionMode() == NO_SELECTION)
    1692           0 :                 return bSuccess = false;
    1693           0 :             else if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
    1694             :             {
    1695             :                 //if there are other selected rows, deselect them
    1696           0 :                 return false;
    1697             :             }
    1698             :             else
    1699             :             {
    1700             :                 //there are other selected rows
    1701           0 :                 if(!m_aSelectedRows.empty())
    1702             :                 {
    1703             :                     //the anchor wasn't set -> a region is not selected, that's why clear all selection
    1704             :                     //and select the current row
    1705           0 :                     if(m_nAnchor==-1)
    1706             :                     {
    1707           0 :                         invalidateSelectedRows();
    1708           0 :                         m_aSelectedRows.clear();
    1709           0 :                         m_aSelectedRows.push_back(m_nCurRow);
    1710           0 :                         invalidateRow( m_nCurRow );
    1711             :                     }
    1712             :                     else
    1713             :                     {
    1714             :                         //a region is already selected, prevRow is last selected row and the row above - nextRow - should be selected
    1715           0 :                         int prevRow = getRowSelectedNumber(m_aSelectedRows, m_nCurRow);
    1716           0 :                         int nextRow = getRowSelectedNumber(m_aSelectedRows, m_nCurRow-1);
    1717           0 :                         if(prevRow>-1)
    1718             :                          {
    1719             :                              //if m_nCurRow isn't the upper one, can move up, otherwise not
    1720           0 :                             if(m_nCurRow>0)
    1721           0 :                                  m_nCurRow--;
    1722             :                              else
    1723           0 :                                  return bSuccess = true;
    1724             :                              //if nextRow already selected, deselect it, otherwise select it
    1725           0 :                              if(nextRow>-1 && m_aSelectedRows[nextRow] == m_nCurRow)
    1726             :                              {
    1727           0 :                                  m_aSelectedRows.erase(m_aSelectedRows.begin()+prevRow);
    1728           0 :                                  invalidateRow( m_nCurRow + 1 );
    1729             :                              }
    1730             :                              else
    1731             :                             {
    1732           0 :                                  m_aSelectedRows.push_back(m_nCurRow);
    1733           0 :                                  invalidateRow( m_nCurRow );
    1734             :                              }
    1735             :                          }
    1736             :                         else
    1737             :                         {
    1738           0 :                             if(m_nCurRow>0)
    1739             :                             {
    1740           0 :                                 m_aSelectedRows.push_back(m_nCurRow);
    1741           0 :                                 m_nCurRow--;
    1742           0 :                                 m_aSelectedRows.push_back(m_nCurRow);
    1743           0 :                                 invalidateSelectedRegion( m_nCurRow+1, m_nCurRow );
    1744             :                             }
    1745             :                         }
    1746             :                     }
    1747             :                 }
    1748             :                 else
    1749             :                 {
    1750             :                     //if nothing is selected and the current row isn't the upper one
    1751             :                     //select the current and one row above
    1752             :                     //otherwise select only the upper row
    1753           0 :                     if(m_nCurRow>0)
    1754             :                     {
    1755           0 :                         m_aSelectedRows.push_back(m_nCurRow);
    1756           0 :                         m_nCurRow--;
    1757           0 :                         m_aSelectedRows.push_back(m_nCurRow);
    1758           0 :                         invalidateSelectedRegion( m_nCurRow+1, m_nCurRow );
    1759             :                     }
    1760             :                     else
    1761             :                     {
    1762           0 :                         m_aSelectedRows.push_back(m_nCurRow);
    1763           0 :                         invalidateRow( m_nCurRow );
    1764             :                     }
    1765             :                 }
    1766           0 :                 m_pSelEngine->SetAnchor(sal_True);
    1767           0 :                 m_nAnchor = m_nCurRow;
    1768           0 :                 ensureVisible(m_nCurColumn, m_nCurRow, false);
    1769           0 :                 selectionChanged = true;
    1770           0 :                 bSuccess = true;
    1771             :             }
    1772             :         }
    1773           0 :         break;
    1774             :         case cursorSelectRowDown:
    1775             :         {
    1776           0 :             if(m_pSelEngine->GetSelectionMode() == NO_SELECTION)
    1777           0 :                 bSuccess = false;
    1778           0 :             else if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
    1779             :             {
    1780           0 :                 bSuccess = false;
    1781             :             }
    1782             :             else
    1783             :             {
    1784           0 :                 if(!m_aSelectedRows.empty())
    1785             :                 {
    1786             :                     //the anchor wasn't set -> a region is not selected, that's why clear all selection
    1787             :                     //and select the current row
    1788           0 :                     if(m_nAnchor==-1)
    1789             :                     {
    1790           0 :                         invalidateSelectedRows();
    1791           0 :                         m_aSelectedRows.clear();
    1792           0 :                         m_aSelectedRows.push_back(m_nCurRow);
    1793           0 :                         invalidateRow( m_nCurRow );
    1794             :                         }
    1795             :                     else
    1796             :                     {
    1797             :                         //a region is already selected, prevRow is last selected row and the row beneath - nextRow - should be selected
    1798           0 :                         int prevRow = getRowSelectedNumber(m_aSelectedRows, m_nCurRow);
    1799           0 :                         int nextRow = getRowSelectedNumber(m_aSelectedRows, m_nCurRow+1);
    1800           0 :                         if(prevRow>-1)
    1801             :                          {
    1802             :                              //if m_nCurRow isn't the last one, can move down, otherwise not
    1803           0 :                              if(m_nCurRow<m_nRowCount-1)
    1804           0 :                                  m_nCurRow++;
    1805             :                              else
    1806           0 :                                 return bSuccess = true;
    1807             :                              //if next row already selected, deselect it, otherwise select it
    1808           0 :                              if(nextRow>-1 && m_aSelectedRows[nextRow] == m_nCurRow)
    1809             :                              {
    1810           0 :                                  m_aSelectedRows.erase(m_aSelectedRows.begin()+prevRow);
    1811           0 :                                  invalidateRow( m_nCurRow - 1 );
    1812             :                              }
    1813             :                              else
    1814             :                              {
    1815           0 :                                  m_aSelectedRows.push_back(m_nCurRow);
    1816           0 :                                  invalidateRow( m_nCurRow );
    1817             :                              }
    1818             :                         }
    1819             :                         else
    1820             :                         {
    1821           0 :                             if(m_nCurRow<m_nRowCount-1)
    1822             :                             {
    1823           0 :                                 m_aSelectedRows.push_back(m_nCurRow);
    1824           0 :                                 m_nCurRow++;
    1825           0 :                                 m_aSelectedRows.push_back(m_nCurRow);
    1826           0 :                                 invalidateSelectedRegion( m_nCurRow-1, m_nCurRow );
    1827             :                             }
    1828             :                         }
    1829             :                     }
    1830             :                 }
    1831             :                 else
    1832             :                 {
    1833             :                     //there wasn't any selection, select current and row beneath, otherwise only row beneath
    1834           0 :                     if(m_nCurRow<m_nRowCount-1)
    1835             :                     {
    1836           0 :                         m_aSelectedRows.push_back(m_nCurRow);
    1837           0 :                         m_nCurRow++;
    1838           0 :                         m_aSelectedRows.push_back(m_nCurRow);
    1839           0 :                         invalidateSelectedRegion( m_nCurRow-1, m_nCurRow );
    1840             :                     }
    1841             :                     else
    1842             :                     {
    1843           0 :                         m_aSelectedRows.push_back(m_nCurRow);
    1844           0 :                         invalidateRow( m_nCurRow );
    1845             :                     }
    1846             :                 }
    1847           0 :                 m_pSelEngine->SetAnchor(sal_True);
    1848           0 :                 m_nAnchor = m_nCurRow;
    1849           0 :                 ensureVisible(m_nCurColumn, m_nCurRow, false);
    1850           0 :                 selectionChanged = true;
    1851           0 :                 bSuccess = true;
    1852             :             }
    1853             :         }
    1854           0 :         break;
    1855             : 
    1856             :         case cursorSelectRowAreaTop:
    1857             :         {
    1858           0 :             if(m_pSelEngine->GetSelectionMode() == NO_SELECTION)
    1859           0 :                 bSuccess = false;
    1860           0 :             else if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
    1861           0 :                 bSuccess = false;
    1862             :             else
    1863             :             {
    1864             :                 //select the region between the current and the upper row
    1865           0 :                 RowPos iter = m_nCurRow;
    1866           0 :                 invalidateSelectedRegion( m_nCurRow, 0 );
    1867             :                 //put the rows in vector
    1868           0 :                 while(iter>=0)
    1869             :                 {
    1870           0 :                     if ( !isRowSelected( iter ) )
    1871           0 :                         m_aSelectedRows.push_back(iter);
    1872           0 :                     --iter;
    1873             :                 }
    1874           0 :                 m_nCurRow = 0;
    1875           0 :                 m_nAnchor = m_nCurRow;
    1876           0 :                 m_pSelEngine->SetAnchor(sal_True);
    1877           0 :                 ensureVisible(m_nCurColumn, 0, false);
    1878           0 :                 selectionChanged = true;
    1879           0 :                 bSuccess = true;
    1880             :             }
    1881             :         }
    1882           0 :         break;
    1883             : 
    1884             :         case cursorSelectRowAreaBottom:
    1885             :         {
    1886           0 :             if(m_pSelEngine->GetSelectionMode() == NO_SELECTION)
    1887           0 :                 return bSuccess = false;
    1888           0 :             else if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
    1889           0 :                 return bSuccess = false;
    1890             :             //select the region between the current and the last row
    1891           0 :             RowPos iter = m_nCurRow;
    1892           0 :             invalidateSelectedRegion( m_nCurRow, m_nRowCount-1 );
    1893             :             //put the rows in the vector
    1894           0 :             while(iter<=m_nRowCount)
    1895             :             {
    1896           0 :                 if ( !isRowSelected( iter ) )
    1897           0 :                     m_aSelectedRows.push_back(iter);
    1898           0 :                 ++iter;
    1899             :             }
    1900           0 :             m_nCurRow = m_nRowCount-1;
    1901           0 :             m_nAnchor = m_nCurRow;
    1902           0 :             m_pSelEngine->SetAnchor(sal_True);
    1903           0 :             ensureVisible(m_nCurColumn, m_nRowCount-1, false);
    1904           0 :             selectionChanged = true;
    1905           0 :             bSuccess = true;
    1906             :         }
    1907           0 :         break;
    1908             :         default:
    1909             :             OSL_FAIL( "TableControl_Impl::dispatchAction: unsupported action!" );
    1910           0 :             break;
    1911             :         }
    1912             : 
    1913           0 :         if ( bSuccess && selectionChanged )
    1914             :         {
    1915           0 :             m_rAntiImpl.Select();
    1916             :         }
    1917             : 
    1918           0 :         return bSuccess;
    1919             :     }
    1920             : 
    1921             :     //------------------------------------------------------------------------------------------------------------------
    1922           0 :     void TableControl_Impl::impl_ni_doSwitchCursor( bool _bShow )
    1923             :     {
    1924           0 :         PTableRenderer pRenderer = !!m_pModel ? m_pModel->getRenderer() : PTableRenderer();
    1925           0 :         if ( !!pRenderer )
    1926             :         {
    1927           0 :             Rectangle aCellRect;
    1928           0 :             impl_getCellRect( m_nCurColumn, m_nCurRow, aCellRect );
    1929           0 :             if ( _bShow )
    1930           0 :                 pRenderer->ShowCellCursor( *m_pDataWindow, aCellRect );
    1931             :             else
    1932           0 :                 pRenderer->HideCellCursor( *m_pDataWindow, aCellRect );
    1933           0 :         }
    1934           0 :     }
    1935             : 
    1936             :     //------------------------------------------------------------------------------------------------------------------
    1937           0 :     void TableControl_Impl::impl_getCellRect( ColPos _nColumn, RowPos _nRow, Rectangle& _rCellRect ) const
    1938             :     {
    1939             :         DBG_CHECK_ME();
    1940             : 
    1941           0 :         if  (   !m_pModel
    1942             :             ||  ( COL_INVALID == _nColumn )
    1943             :             ||  ( ROW_INVALID == _nRow )
    1944             :             )
    1945             :         {
    1946           0 :             _rCellRect.SetEmpty();
    1947           0 :             return;
    1948             :         }
    1949             : 
    1950           0 :         TableCellGeometry aCell( *this, impl_getAllVisibleCellsArea(), _nColumn, _nRow );
    1951           0 :         _rCellRect = aCell.getRect();
    1952             :     }
    1953             : 
    1954             :     //------------------------------------------------------------------------------------------------------------------
    1955           0 :     RowPos TableControl_Impl::getRowAtPoint( const Point& rPoint ) const
    1956             :     {
    1957             :         DBG_CHECK_ME();
    1958           0 :         return impl_getRowForAbscissa( rPoint.Y() );
    1959             :     }
    1960             : 
    1961             :     //------------------------------------------------------------------------------------------------------------------
    1962           0 :     ColPos TableControl_Impl::getColAtPoint( const Point& rPoint ) const
    1963             :     {
    1964             :         DBG_CHECK_ME();
    1965           0 :         return impl_getColumnForOrdinate( rPoint.X() );
    1966             :     }
    1967             : 
    1968             :     //------------------------------------------------------------------------------------------------------------------
    1969           0 :     TableCell TableControl_Impl::hitTest( Point const & i_point ) const
    1970             :     {
    1971           0 :         TableCell aCell( getColAtPoint( i_point ), getRowAtPoint( i_point ) );
    1972           0 :         if ( aCell.nColumn > COL_ROW_HEADERS )
    1973             :         {
    1974           0 :             PColumnModel const pColumn = m_pModel->getColumnModel( aCell.nColumn );
    1975           0 :             MutableColumnMetrics const & rColInfo( m_aColumnWidths[ aCell.nColumn ] );
    1976           0 :             if  (   ( rColInfo.getEnd() - 3 <= i_point.X() )
    1977           0 :                 &&  ( rColInfo.getEnd() >= i_point.X() )
    1978           0 :                 &&  pColumn->isResizable()
    1979             :                 )
    1980             :             {
    1981           0 :                 aCell.eArea = ColumnDivider;
    1982           0 :             }
    1983             :         }
    1984           0 :         return aCell;
    1985             :     }
    1986             : 
    1987             :     //------------------------------------------------------------------------------------------------------------------
    1988           0 :     ColumnMetrics TableControl_Impl::getColumnMetrics( ColPos const i_column ) const
    1989             :     {
    1990             :         DBG_CHECK_ME();
    1991             : 
    1992           0 :         ENSURE_OR_RETURN( ( i_column >= 0 ) && ( i_column < m_pModel->getColumnCount() ),
    1993             :             "TableControl_Impl::getColumnMetrics: illegal column index!", ColumnMetrics() );
    1994           0 :         return (ColumnMetrics const &)m_aColumnWidths[ i_column ];
    1995             :     }
    1996             : 
    1997             :     //------------------------------------------------------------------------------------------------------------------
    1998           0 :     PTableModel TableControl_Impl::getModel() const
    1999             :     {
    2000           0 :         return m_pModel;
    2001             :     }
    2002             : 
    2003             :     //------------------------------------------------------------------------------------------------------------------
    2004           0 :     RowPos TableControl_Impl::getCurrentColumn() const
    2005             :     {
    2006           0 :         return m_nCurColumn;
    2007             :     }
    2008             : 
    2009             :     //------------------------------------------------------------------------------------------------------------------
    2010           0 :     RowPos TableControl_Impl::getCurrentRow() const
    2011             :     {
    2012           0 :         return m_nCurRow;
    2013             :     }
    2014             : 
    2015             :     //------------------------------------------------------------------------------------------------------------------
    2016           0 :     ::Size TableControl_Impl::getTableSizePixel() const
    2017             :     {
    2018           0 :         return m_pDataWindow->GetOutputSizePixel();
    2019             :     }
    2020             : 
    2021             :     //------------------------------------------------------------------------------------------------------------------
    2022           0 :     void TableControl_Impl::setPointer( Pointer const & i_pointer )
    2023             :     {
    2024             :         DBG_CHECK_ME();
    2025           0 :         m_pDataWindow->SetPointer( i_pointer );
    2026           0 :     }
    2027             : 
    2028             :     //------------------------------------------------------------------------------------------------------------------
    2029           0 :     void TableControl_Impl::captureMouse()
    2030             :     {
    2031           0 :         m_pDataWindow->CaptureMouse();
    2032           0 :     }
    2033             : 
    2034             :     //------------------------------------------------------------------------------------------------------------------
    2035           0 :     void TableControl_Impl::releaseMouse()
    2036             :     {
    2037           0 :         m_pDataWindow->ReleaseMouse();
    2038           0 :     }
    2039             : 
    2040             :     //------------------------------------------------------------------------------------------------------------------
    2041           0 :     void TableControl_Impl::invalidate( TableArea const i_what )
    2042             :     {
    2043           0 :         switch ( i_what )
    2044             :         {
    2045             :         case TableAreaColumnHeaders:
    2046           0 :             m_pDataWindow->Invalidate( calcHeaderRect( true ) );
    2047           0 :             break;
    2048             : 
    2049             :         case TableAreaRowHeaders:
    2050           0 :             m_pDataWindow->Invalidate( calcHeaderRect( false ) );
    2051           0 :             break;
    2052             : 
    2053             :         case TableAreaDataArea:
    2054           0 :             m_pDataWindow->Invalidate( impl_getAllVisibleDataCellArea() );
    2055           0 :             break;
    2056             : 
    2057             :         case TableAreaAll:
    2058           0 :             m_pDataWindow->Invalidate();
    2059           0 :             break;
    2060             :         }
    2061           0 :     }
    2062             : 
    2063             :     //------------------------------------------------------------------------------------------------------------------
    2064           0 :     long TableControl_Impl::pixelWidthToAppFont( long const i_pixels ) const
    2065             :     {
    2066           0 :         return m_pDataWindow->PixelToLogic( Size( i_pixels, 0 ), MAP_APPFONT ).Width();
    2067             :     }
    2068             : 
    2069             :     //------------------------------------------------------------------------------------------------------------------
    2070           0 :     long TableControl_Impl::appFontWidthToPixel( long const i_appFontUnits ) const
    2071             :     {
    2072           0 :         return m_pDataWindow->LogicToPixel( Size( i_appFontUnits, 0 ), MAP_APPFONT ).Width();
    2073             :     }
    2074             : 
    2075             :     //------------------------------------------------------------------------------------------------------------------
    2076           0 :     void TableControl_Impl::hideTracking()
    2077             :     {
    2078           0 :         m_pDataWindow->HideTracking();
    2079           0 :     }
    2080             : 
    2081             :     //------------------------------------------------------------------------------------------------------------------
    2082           0 :     void TableControl_Impl::showTracking( Rectangle const & i_location, sal_uInt16 const i_flags )
    2083             :     {
    2084           0 :         m_pDataWindow->ShowTracking( i_location, i_flags );
    2085           0 :     }
    2086             : 
    2087             :     //------------------------------------------------------------------------------------------------------------------
    2088           0 :     bool TableControl_Impl::activateCell( ColPos const i_col, RowPos const i_row )
    2089             :     {
    2090             :         DBG_CHECK_ME();
    2091           0 :         return goTo( i_col, i_row );
    2092             :     }
    2093             : 
    2094             :     //------------------------------------------------------------------------------------------------------------------
    2095           0 :     void TableControl_Impl::invalidateSelectedRegion( RowPos _nPrevRow, RowPos _nCurRow )
    2096             :     {
    2097             :         DBG_CHECK_ME();
    2098             :         // get the visible area of the table control and set the Left and right border of the region to be repainted
    2099           0 :         Rectangle const aAllCells( impl_getAllVisibleCellsArea() );
    2100             : 
    2101           0 :         Rectangle aInvalidateRect;
    2102           0 :         aInvalidateRect.Left() = aAllCells.Left();
    2103           0 :         aInvalidateRect.Right() = aAllCells.Right();
    2104             :         // if only one row is selected
    2105           0 :         if ( _nPrevRow == _nCurRow )
    2106             :         {
    2107           0 :             Rectangle aCellRect;
    2108           0 :             impl_getCellRect( m_nCurColumn, _nCurRow, aCellRect );
    2109           0 :             aInvalidateRect.Top() = aCellRect.Top();
    2110           0 :             aInvalidateRect.Bottom() = aCellRect.Bottom();
    2111             :         }
    2112             :         //if the region is above the current row
    2113           0 :         else if(_nPrevRow < _nCurRow )
    2114             :         {
    2115           0 :             Rectangle aCellRect;
    2116           0 :             impl_getCellRect( m_nCurColumn, _nPrevRow, aCellRect );
    2117           0 :             aInvalidateRect.Top() = aCellRect.Top();
    2118           0 :             impl_getCellRect( m_nCurColumn, _nCurRow, aCellRect );
    2119           0 :             aInvalidateRect.Bottom() = aCellRect.Bottom();
    2120             :         }
    2121             :         //if the region is beneath the current row
    2122             :         else
    2123             :         {
    2124           0 :             Rectangle aCellRect;
    2125           0 :             impl_getCellRect( m_nCurColumn, _nCurRow, aCellRect );
    2126           0 :             aInvalidateRect.Top() = aCellRect.Top();
    2127           0 :             impl_getCellRect( m_nCurColumn, _nPrevRow, aCellRect );
    2128           0 :             aInvalidateRect.Bottom() = aCellRect.Bottom();
    2129             :         }
    2130           0 :         m_pDataWindow->Invalidate( aInvalidateRect );
    2131           0 :     }
    2132             : 
    2133             :     //------------------------------------------------------------------------------------------------------------------
    2134           0 :     void TableControl_Impl::invalidateSelectedRows()
    2135             :     {
    2136           0 :         for (   ::std::vector< RowPos >::iterator selRow = m_aSelectedRows.begin();
    2137           0 :                 selRow != m_aSelectedRows.end();
    2138             :                 ++selRow
    2139             :             )
    2140             :         {
    2141           0 :             invalidateRow( *selRow );
    2142             :         }
    2143           0 :     }
    2144             : 
    2145             :     //------------------------------------------------------------------------------------------------------------------
    2146           0 :     void TableControl_Impl::invalidateRowRange( RowPos const i_firstRow, RowPos const i_lastRow )
    2147             :     {
    2148           0 :         RowPos const firstRow = i_firstRow < m_nTopRow ? m_nTopRow : i_firstRow;
    2149           0 :         RowPos const lastVisibleRow = m_nTopRow + impl_getVisibleRows( true ) - 1;
    2150           0 :         RowPos const lastRow = ( ( i_lastRow == ROW_INVALID ) || ( i_lastRow > lastVisibleRow ) ) ? lastVisibleRow : i_lastRow;
    2151             : 
    2152           0 :         Rectangle aInvalidateRect;
    2153             : 
    2154           0 :         Rectangle const aVisibleCellsArea( impl_getAllVisibleCellsArea() );
    2155           0 :         TableRowGeometry aRow( *this, aVisibleCellsArea, firstRow, true );
    2156           0 :         while ( aRow.isValid() && ( aRow.getRow() <= lastRow ) )
    2157             :         {
    2158           0 :             aInvalidateRect.Union( aRow.getRect() );
    2159           0 :             aRow.moveDown();
    2160             :         }
    2161             : 
    2162           0 :         if ( i_lastRow == ROW_INVALID )
    2163           0 :             aInvalidateRect.Bottom() = m_pDataWindow->GetOutputSizePixel().Height();
    2164             : 
    2165           0 :         m_pDataWindow->Invalidate( aInvalidateRect );
    2166           0 :     }
    2167             : 
    2168             :     //------------------------------------------------------------------------------
    2169           0 :     void TableControl_Impl::checkCursorPosition()
    2170             :     {
    2171             :         DBG_CHECK_ME();
    2172             : 
    2173           0 :         TableSize nVisibleRows = impl_getVisibleRows(true);
    2174           0 :         TableSize nVisibleCols = impl_getVisibleColumns(true);
    2175           0 :         if  (   ( m_nTopRow + nVisibleRows > m_nRowCount )
    2176             :             &&  ( m_nRowCount >= nVisibleRows )
    2177             :             )
    2178             :         {
    2179           0 :             --m_nTopRow;
    2180             :         }
    2181             :         else
    2182             :         {
    2183           0 :             m_nTopRow = 0;
    2184             :         }
    2185             : 
    2186           0 :         if  (   ( m_nLeftColumn + nVisibleCols > m_nColumnCount )
    2187             :             &&  ( m_nColumnCount >= nVisibleCols )
    2188             :             )
    2189             :         {
    2190           0 :             --m_nLeftColumn;
    2191             :         }
    2192             :         else
    2193             :         {
    2194           0 :             m_nLeftColumn = 0;
    2195             :         }
    2196             : 
    2197           0 :         m_pDataWindow->Invalidate();
    2198           0 :     }
    2199             : 
    2200             :     //--------------------------------------------------------------------
    2201           0 :     TableSize TableControl_Impl::impl_getVisibleRows( bool _bAcceptPartialRow ) const
    2202             :     {
    2203             :         DBG_CHECK_ME();
    2204             : 
    2205             :         DBG_ASSERT( m_pDataWindow, "TableControl_Impl::impl_getVisibleRows: no data window!" );
    2206             : 
    2207             :         return lcl_getRowsFittingInto(
    2208           0 :             m_pDataWindow->GetOutputSizePixel().Height() - m_nColHeaderHeightPixel,
    2209             :             m_nRowHeightPixel,
    2210             :             _bAcceptPartialRow
    2211           0 :         );
    2212             :     }
    2213             : 
    2214             :     //--------------------------------------------------------------------
    2215           0 :     TableSize TableControl_Impl::impl_getVisibleColumns( bool _bAcceptPartialCol ) const
    2216             :     {
    2217             :         DBG_CHECK_ME();
    2218             : 
    2219             :         DBG_ASSERT( m_pDataWindow, "TableControl_Impl::impl_getVisibleColumns: no data window!" );
    2220             : 
    2221             :         return lcl_getColumnsVisibleWithin(
    2222           0 :             Rectangle( Point( 0, 0 ), m_pDataWindow->GetOutputSizePixel() ),
    2223             :             m_nLeftColumn,
    2224             :             *this,
    2225             :             _bAcceptPartialCol
    2226           0 :         );
    2227             :     }
    2228             : 
    2229             :     //--------------------------------------------------------------------
    2230           0 :     bool TableControl_Impl::goTo( ColPos _nColumn, RowPos _nRow )
    2231             :     {
    2232             :         DBG_CHECK_ME();
    2233             : 
    2234             :         // TODO: give veto listeners a chance
    2235             : 
    2236           0 :         if  (  ( _nColumn < 0 ) || ( _nColumn >= m_nColumnCount )
    2237             :             || ( _nRow < 0 ) || ( _nRow >= m_nRowCount )
    2238             :             )
    2239             :         {
    2240             :             OSL_ENSURE( false, "TableControl_Impl::goTo: invalid row or column index!" );
    2241           0 :             return false;
    2242             :         }
    2243             : 
    2244           0 :         SuppressCursor aHideCursor( *this );
    2245           0 :         m_nCurColumn = _nColumn;
    2246           0 :         m_nCurRow = _nRow;
    2247             : 
    2248             :         // ensure that the new cell is visible
    2249           0 :         ensureVisible( m_nCurColumn, m_nCurRow, false );
    2250           0 :         return true;
    2251             :     }
    2252             : 
    2253             :     //--------------------------------------------------------------------
    2254           0 :     void TableControl_Impl::ensureVisible( ColPos _nColumn, RowPos _nRow, bool _bAcceptPartialVisibility )
    2255             :     {
    2256             :         DBG_CHECK_ME();
    2257             :         DBG_ASSERT( ( _nColumn >= 0 ) && ( _nColumn < m_nColumnCount )
    2258             :                  && ( _nRow >= 0 ) && ( _nRow < m_nRowCount ),
    2259             :                  "TableControl_Impl::ensureVisible: invalid coordinates!" );
    2260             : 
    2261           0 :         SuppressCursor aHideCursor( *this );
    2262             : 
    2263           0 :         if ( _nColumn < m_nLeftColumn )
    2264           0 :             impl_scrollColumns( _nColumn - m_nLeftColumn );
    2265             :         else
    2266             :         {
    2267           0 :             TableSize nVisibleColumns = impl_getVisibleColumns( _bAcceptPartialVisibility );
    2268           0 :             if ( _nColumn > m_nLeftColumn + nVisibleColumns - 1 )
    2269             :             {
    2270           0 :                 impl_scrollColumns( _nColumn - ( m_nLeftColumn + nVisibleColumns - 1 ) );
    2271             :                 // TODO: since not all columns have the same width, this might in theory result
    2272             :                 // in the column still not being visible.
    2273             :             }
    2274             :         }
    2275             : 
    2276           0 :         if ( _nRow < m_nTopRow )
    2277           0 :             impl_scrollRows( _nRow - m_nTopRow );
    2278             :         else
    2279             :         {
    2280           0 :             TableSize nVisibleRows = impl_getVisibleRows( _bAcceptPartialVisibility );
    2281           0 :             if ( _nRow > m_nTopRow + nVisibleRows - 1 )
    2282           0 :                 impl_scrollRows( _nRow - ( m_nTopRow + nVisibleRows - 1 ) );
    2283           0 :         }
    2284           0 :     }
    2285             : 
    2286             :     //--------------------------------------------------------------------
    2287           0 :     ::rtl::OUString TableControl_Impl::getCellContentAsString( RowPos const i_row, ColPos const i_col )
    2288             :     {
    2289           0 :         Any aCellValue;
    2290           0 :         m_pModel->getCellContent( i_col, i_row, aCellValue );
    2291             : 
    2292           0 :         ::rtl::OUString sCellStringContent;
    2293           0 :         m_pModel->getRenderer()->GetFormattedCellString( aCellValue, i_col, i_row, sCellStringContent );
    2294             : 
    2295           0 :         return sCellStringContent;
    2296             :     }
    2297             : 
    2298             :     //--------------------------------------------------------------------
    2299           0 :     TableSize TableControl_Impl::impl_ni_ScrollRows( TableSize _nRowDelta )
    2300             :     {
    2301             :         // compute new top row
    2302             :         RowPos nNewTopRow =
    2303             :             ::std::max(
    2304           0 :                 ::std::min( (RowPos)( m_nTopRow + _nRowDelta ), (RowPos)( m_nRowCount - 1 ) ),
    2305             :                 (RowPos)0
    2306           0 :             );
    2307             : 
    2308           0 :         RowPos nOldTopRow = m_nTopRow;
    2309           0 :         m_nTopRow = nNewTopRow;
    2310             : 
    2311             :         // if updates are enabled currently, scroll the viewport
    2312           0 :         if ( m_nTopRow != nOldTopRow )
    2313             :         {
    2314             :             DBG_SUSPEND_INV( INV_SCROLL_POSITION );
    2315           0 :             SuppressCursor aHideCursor( *this );
    2316             :             // TODO: call a onStartScroll at our listener (or better an own onStartScroll,
    2317             :             // which hides the cursor and then calls the listener)
    2318             :             // Same for onEndScroll
    2319             : 
    2320             :             // scroll the view port, if possible
    2321           0 :             long nPixelDelta = m_nRowHeightPixel * ( m_nTopRow - nOldTopRow );
    2322             : 
    2323           0 :             Rectangle aDataArea( Point( 0, m_nColHeaderHeightPixel ), m_pDataWindow->GetOutputSizePixel() );
    2324             : 
    2325           0 :             if  (   m_pDataWindow->GetBackground().IsScrollable()
    2326           0 :                 &&  abs( nPixelDelta ) < aDataArea.GetHeight()
    2327             :                 )
    2328             :             {
    2329           0 :                 m_pDataWindow->Scroll( 0, (long)-nPixelDelta, aDataArea, SCROLL_CLIP | SCROLL_UPDATE | SCROLL_CHILDREN);
    2330             :             }
    2331             :             else
    2332           0 :                 m_pDataWindow->Invalidate( INVALIDATE_UPDATE );
    2333             : 
    2334             :             // update the position at the vertical scrollbar
    2335           0 :             if ( m_pVScroll != NULL )
    2336           0 :                 m_pVScroll->SetThumbPos( m_nTopRow );
    2337             :         }
    2338             : 
    2339             :         // The scroll bar availaility might change when we scrolled.
    2340             :         // For instance, imagine a view with 10 rows, if which 5 fit into the window, numbered 1 to 10.
    2341             :         // Now let
    2342             :         // - the user scroll to row number 6, so the last 5 rows are visible
    2343             :         // - somebody remove the last 4 rows
    2344             :         // - the user scroll to row number 5 being the top row, so the last two rows are visible
    2345             :         // - somebody remove row number 6
    2346             :         // - the user scroll to row number 1
    2347             :         // => in this case, the need for the scrollbar vanishes immediately.
    2348           0 :         if ( m_nTopRow == 0 )
    2349           0 :             m_rAntiImpl.PostUserEvent( LINK( this, TableControl_Impl, OnUpdateScrollbars ) );
    2350             : 
    2351           0 :         return (TableSize)( m_nTopRow - nOldTopRow );
    2352             :     }
    2353             : 
    2354             :     //--------------------------------------------------------------------
    2355           0 :     TableSize TableControl_Impl::impl_scrollRows( TableSize const i_rowDelta )
    2356             :     {
    2357             :         DBG_CHECK_ME();
    2358           0 :         return impl_ni_ScrollRows( i_rowDelta );
    2359             :     }
    2360             : 
    2361             :     //--------------------------------------------------------------------
    2362           0 :     TableSize TableControl_Impl::impl_ni_ScrollColumns( TableSize _nColumnDelta )
    2363             :     {
    2364             :         // compute new left column
    2365             :         const ColPos nNewLeftColumn =
    2366             :             ::std::max(
    2367           0 :                 ::std::min( (ColPos)( m_nLeftColumn + _nColumnDelta ), (ColPos)( m_nColumnCount - 1 ) ),
    2368             :                 (ColPos)0
    2369           0 :             );
    2370             : 
    2371           0 :         const ColPos nOldLeftColumn = m_nLeftColumn;
    2372           0 :         m_nLeftColumn = nNewLeftColumn;
    2373             : 
    2374             :         // if updates are enabled currently, scroll the viewport
    2375           0 :         if ( m_nLeftColumn != nOldLeftColumn )
    2376             :         {
    2377             :             DBG_SUSPEND_INV( INV_SCROLL_POSITION );
    2378           0 :             SuppressCursor aHideCursor( *this );
    2379             :             // TODO: call a onStartScroll at our listener (or better an own onStartScroll,
    2380             :             // which hides the cursor and then calls the listener)
    2381             :             // Same for onEndScroll
    2382             : 
    2383             :             // scroll the view port, if possible
    2384           0 :             const Rectangle aDataArea( Point( m_nRowHeaderWidthPixel, 0 ), m_pDataWindow->GetOutputSizePixel() );
    2385             : 
    2386             :             long nPixelDelta =
    2387           0 :                     m_aColumnWidths[ nOldLeftColumn ].getStart()
    2388           0 :                 -   m_aColumnWidths[ m_nLeftColumn ].getStart();
    2389             : 
    2390             :             // update our column positions
    2391             :             // Do this *before* scrolling, as SCROLL_UPDATE will trigger a paint, which already needs the correct
    2392             :             // information in m_aColumnWidths
    2393           0 :             for (   ColumnPositions::iterator colPos = m_aColumnWidths.begin();
    2394           0 :                     colPos != m_aColumnWidths.end();
    2395             :                     ++colPos
    2396             :                  )
    2397             :             {
    2398           0 :                 colPos->move( nPixelDelta );
    2399             :             }
    2400             : 
    2401             :             // scroll the window content (if supported and possible), or invalidate the complete window
    2402           0 :             if  (   m_pDataWindow->GetBackground().IsScrollable()
    2403           0 :                 &&  abs( nPixelDelta ) < aDataArea.GetWidth()
    2404             :                 )
    2405             :             {
    2406           0 :                 m_pDataWindow->Scroll( nPixelDelta, 0, aDataArea, SCROLL_CLIP | SCROLL_UPDATE );
    2407             :             }
    2408             :             else
    2409           0 :                 m_pDataWindow->Invalidate( INVALIDATE_UPDATE );
    2410             : 
    2411             :             // update the position at the horizontal scrollbar
    2412           0 :             if ( m_pHScroll != NULL )
    2413           0 :                 m_pHScroll->SetThumbPos( m_nLeftColumn );
    2414             :         }
    2415             : 
    2416             :         // The scroll bar availaility might change when we scrolled. This is because we do not hide
    2417             :         // the scrollbar when it is, in theory, unnecessary, but currently at a position > 0. In this case, it will
    2418             :         // be auto-hidden when it's scrolled back to pos 0.
    2419           0 :         if ( m_nLeftColumn == 0 )
    2420           0 :             m_rAntiImpl.PostUserEvent( LINK( this, TableControl_Impl, OnUpdateScrollbars ) );
    2421             : 
    2422           0 :         return (TableSize)( m_nLeftColumn - nOldLeftColumn );
    2423             :     }
    2424             : 
    2425             :     //------------------------------------------------------------------------------------------------------------------
    2426           0 :     TableSize TableControl_Impl::impl_scrollColumns( TableSize const i_columnDelta )
    2427             :     {
    2428             :         DBG_CHECK_ME();
    2429           0 :         return impl_ni_ScrollColumns( i_columnDelta );
    2430             :     }
    2431             : 
    2432             :     //------------------------------------------------------------------------------------------------------------------
    2433           0 :     SelectionEngine* TableControl_Impl::getSelEngine()
    2434             :     {
    2435           0 :         return m_pSelEngine;
    2436             :     }
    2437             : 
    2438             :     //------------------------------------------------------------------------------------------------------------------
    2439           0 :     ScrollBar* TableControl_Impl::getHorzScrollbar()
    2440             :     {
    2441           0 :         return m_pHScroll;
    2442             :     }
    2443             : 
    2444             :     //------------------------------------------------------------------------------------------------------------------
    2445           0 :     ScrollBar* TableControl_Impl::getVertScrollbar()
    2446             :     {
    2447           0 :         return m_pVScroll;
    2448             :     }
    2449             : 
    2450             :     //------------------------------------------------------------------------------------------------------------------
    2451           0 :     bool TableControl_Impl::isRowSelected( RowPos i_row ) const
    2452             :     {
    2453           0 :         return ::std::find( m_aSelectedRows.begin(), m_aSelectedRows.end(), i_row ) != m_aSelectedRows.end();
    2454             :     }
    2455             : 
    2456             :     //------------------------------------------------------------------------------------------------------------------
    2457           0 :     RowPos TableControl_Impl::getSelectedRowIndex( size_t const i_selectionIndex ) const
    2458             :     {
    2459           0 :         if ( i_selectionIndex < m_aSelectedRows.size() )
    2460           0 :             return m_aSelectedRows[ i_selectionIndex ];
    2461           0 :         return ROW_INVALID;
    2462             :     }
    2463             : 
    2464             :     //------------------------------------------------------------------------------------------------------------------
    2465           0 :     int TableControl_Impl::getRowSelectedNumber(const ::std::vector<RowPos>& selectedRows, RowPos current)
    2466             :     {
    2467           0 :         std::vector<RowPos>::const_iterator it = ::std::find(selectedRows.begin(),selectedRows.end(),current);
    2468           0 :         if ( it != selectedRows.end() )
    2469             :         {
    2470           0 :             return it - selectedRows.begin();
    2471             :         }
    2472           0 :         return -1;
    2473             :     }
    2474             : 
    2475             :     //--------------------------------------------------------------------
    2476           0 :     ColPos TableControl_Impl::impl_getColumnForOrdinate( long const i_ordinate ) const
    2477             :     {
    2478             :         DBG_CHECK_ME();
    2479             : 
    2480           0 :         if ( ( m_aColumnWidths.empty() ) || ( i_ordinate < 0 ) )
    2481           0 :             return COL_INVALID;
    2482             : 
    2483           0 :         if ( i_ordinate < m_nRowHeaderWidthPixel )
    2484           0 :             return COL_ROW_HEADERS;
    2485             : 
    2486             :         ColumnPositions::const_iterator lowerBound = ::std::lower_bound(
    2487             :             m_aColumnWidths.begin(),
    2488             :             m_aColumnWidths.end(),
    2489             :             MutableColumnMetrics(i_ordinate+1, i_ordinate+1),
    2490             :             ColumnInfoPositionLess()
    2491           0 :         );
    2492           0 :         if ( lowerBound == m_aColumnWidths.end() )
    2493             :         {
    2494             :             // point is *behind* the start of the last column ...
    2495           0 :             if ( i_ordinate < m_aColumnWidths.rbegin()->getEnd() )
    2496             :                 // ... but still before its end
    2497           0 :                 return m_nColumnCount - 1;
    2498           0 :             return COL_INVALID;
    2499             :         }
    2500           0 :         return lowerBound - m_aColumnWidths.begin();
    2501             :     }
    2502             : 
    2503             :     //--------------------------------------------------------------------
    2504           0 :     RowPos TableControl_Impl::impl_getRowForAbscissa( long const i_abscissa ) const
    2505             :     {
    2506             :         DBG_CHECK_ME();
    2507             : 
    2508           0 :         if ( i_abscissa < 0 )
    2509           0 :             return ROW_INVALID;
    2510             : 
    2511           0 :         if ( i_abscissa < m_nColHeaderHeightPixel )
    2512           0 :             return ROW_COL_HEADERS;
    2513             : 
    2514           0 :         long const abscissa = i_abscissa - m_nColHeaderHeightPixel;
    2515           0 :         long const row = m_nTopRow + abscissa / m_nRowHeightPixel;
    2516           0 :         return row < m_pModel->getRowCount() ? row : ROW_INVALID;
    2517             :     }
    2518             : 
    2519             :     //--------------------------------------------------------------------
    2520           0 :     bool TableControl_Impl::markRowAsDeselected( RowPos const i_rowIndex )
    2521             :     {
    2522             :         DBG_CHECK_ME();
    2523             : 
    2524           0 :         ::std::vector< RowPos >::iterator selPos = ::std::find( m_aSelectedRows.begin(), m_aSelectedRows.end(), i_rowIndex );
    2525           0 :         if ( selPos == m_aSelectedRows.end() )
    2526           0 :             return false;
    2527             : 
    2528           0 :         m_aSelectedRows.erase( selPos );
    2529           0 :         return true;
    2530             :     }
    2531             : 
    2532             :     //--------------------------------------------------------------------
    2533           0 :     bool TableControl_Impl::markRowAsSelected( RowPos const i_rowIndex )
    2534             :     {
    2535             :         DBG_CHECK_ME();
    2536             : 
    2537           0 :         if ( isRowSelected( i_rowIndex ) )
    2538           0 :             return false;
    2539             : 
    2540           0 :         SelectionMode const eSelMode = getSelEngine()->GetSelectionMode();
    2541           0 :         switch ( eSelMode )
    2542             :         {
    2543             :         case SINGLE_SELECTION:
    2544           0 :             if ( !m_aSelectedRows.empty() )
    2545             :             {
    2546             :                 OSL_ENSURE( m_aSelectedRows.size() == 1, "TableControl::markRowAsSelected: SingleSelection with more than one selected element?" );
    2547           0 :                 m_aSelectedRows[0] = i_rowIndex;
    2548           0 :                 break;
    2549             :             }
    2550             :             // fall through
    2551             : 
    2552             :         case MULTIPLE_SELECTION:
    2553           0 :             m_aSelectedRows.push_back( i_rowIndex );
    2554           0 :             break;
    2555             : 
    2556             :         default:
    2557             :             OSL_ENSURE( false, "TableControl_Impl::markRowAsSelected: unsupported selection mode!" );
    2558           0 :             return false;
    2559             :         }
    2560             : 
    2561           0 :         return true;
    2562             :     }
    2563             : 
    2564             :     //--------------------------------------------------------------------
    2565           0 :     bool TableControl_Impl::markAllRowsAsDeselected()
    2566             :     {
    2567           0 :         if ( m_aSelectedRows.empty() )
    2568           0 :             return false;
    2569             : 
    2570           0 :         m_aSelectedRows.clear();
    2571           0 :         return true;
    2572             :     }
    2573             : 
    2574             :     //--------------------------------------------------------------------
    2575           0 :     bool TableControl_Impl::markAllRowsAsSelected()
    2576             :     {
    2577             :         DBG_CHECK_ME();
    2578             : 
    2579           0 :         SelectionMode const eSelMode = getSelEngine()->GetSelectionMode();
    2580           0 :         ENSURE_OR_RETURN_FALSE( eSelMode == MULTIPLE_SELECTION, "TableControl_Impl::markAllRowsAsSelected: unsupported selection mode!" );
    2581             : 
    2582           0 :         if ( m_aSelectedRows.size() == size_t( m_pModel->getRowCount() ) )
    2583             :         {
    2584             :         #if OSL_DEBUG_LEVEL > 0
    2585             :             for ( TableSize row = 0; row < m_pModel->getRowCount(); ++row )
    2586             :             {
    2587             :                 OSL_ENSURE( isRowSelected( row ), "TableControl_Impl::markAllRowsAsSelected: inconsistency in the selected rows!" );
    2588             :             }
    2589             :         #endif
    2590             :             // already all rows marked as selected
    2591           0 :             return false;
    2592             :         }
    2593             : 
    2594           0 :         m_aSelectedRows.clear();
    2595           0 :         for ( RowPos i=0; i < m_pModel->getRowCount(); ++i )
    2596           0 :             m_aSelectedRows.push_back(i);
    2597             : 
    2598           0 :         return true;
    2599             :     }
    2600             : 
    2601             :     //--------------------------------------------------------------------
    2602           0 :     void TableControl_Impl::commitAccessibleEvent( sal_Int16 const i_eventID, const Any& i_newValue, const Any& i_oldValue )
    2603             :     {
    2604           0 :         impl_commitAccessibleEvent( i_eventID, i_newValue, i_oldValue );
    2605           0 :     }
    2606             : 
    2607             :     //--------------------------------------------------------------------
    2608           0 :     void TableControl_Impl::commitCellEvent( sal_Int16 const i_eventID, const Any& i_newValue, const Any& i_oldValue )
    2609             :     {
    2610             :         DBG_CHECK_ME();
    2611           0 :         if ( impl_isAccessibleAlive() )
    2612           0 :              m_pAccessibleTable->commitCellEvent( i_eventID, i_newValue, i_oldValue );
    2613           0 :     }
    2614             : 
    2615             :     //--------------------------------------------------------------------
    2616           0 :     void TableControl_Impl::commitTableEvent( sal_Int16 const i_eventID, const Any& i_newValue, const Any& i_oldValue )
    2617             :     {
    2618             :         DBG_CHECK_ME();
    2619           0 :         if ( impl_isAccessibleAlive() )
    2620           0 :              m_pAccessibleTable->commitTableEvent( i_eventID, i_newValue, i_oldValue );
    2621           0 :     }
    2622             : 
    2623             :     //--------------------------------------------------------------------
    2624           0 :     Rectangle TableControl_Impl::calcHeaderRect(bool bColHeader)
    2625             :     {
    2626           0 :         Rectangle const aRectTableWithHeaders( impl_getAllVisibleCellsArea() );
    2627           0 :         Size const aSizeTableWithHeaders( aRectTableWithHeaders.GetSize() );
    2628           0 :         if ( bColHeader )
    2629           0 :             return Rectangle( aRectTableWithHeaders.TopLeft(), Size( aSizeTableWithHeaders.Width(), m_nColHeaderHeightPixel ) );
    2630             :         else
    2631           0 :             return Rectangle( aRectTableWithHeaders.TopLeft(), Size( m_nRowHeaderWidthPixel, aSizeTableWithHeaders.Height() ) );
    2632             :     }
    2633             : 
    2634             :     //--------------------------------------------------------------------
    2635           0 :     Rectangle TableControl_Impl::calcHeaderCellRect( bool bColHeader, sal_Int32 nPos )
    2636             :     {
    2637           0 :         Rectangle const aHeaderRect = calcHeaderRect( bColHeader );
    2638             :         TableCellGeometry const aGeometry(
    2639             :             *this, aHeaderRect,
    2640             :             bColHeader ? nPos : COL_ROW_HEADERS,
    2641             :             bColHeader ? ROW_COL_HEADERS : nPos
    2642           0 :         );
    2643           0 :         return aGeometry.getRect();
    2644             :     }
    2645             : 
    2646             :     //--------------------------------------------------------------------
    2647           0 :     Rectangle TableControl_Impl::calcTableRect()
    2648             :     {
    2649           0 :         return impl_getAllVisibleDataCellArea();
    2650             :     }
    2651             : 
    2652             :     //--------------------------------------------------------------------
    2653           0 :     Rectangle TableControl_Impl::calcCellRect( sal_Int32 nRow, sal_Int32 nCol )
    2654             :     {
    2655           0 :         Rectangle aCellRect;
    2656           0 :         impl_getCellRect( nRow, nCol, aCellRect );
    2657           0 :         return aCellRect;
    2658             :     }
    2659             : 
    2660             :     //--------------------------------------------------------------------
    2661           0 :     IMPL_LINK( TableControl_Impl, OnUpdateScrollbars, void*, /**/ )
    2662             :     {
    2663             :         DBG_CHECK_ME();
    2664             :         // TODO: can't we simply use lcl_updateScrollbar here, so the scrollbars ranges are updated, instead of
    2665             :         // doing a complete re-layout?
    2666           0 :         impl_ni_relayout();
    2667           0 :         return 1L;
    2668             :     }
    2669             : 
    2670             :     //--------------------------------------------------------------------
    2671           0 :     IMPL_LINK( TableControl_Impl, OnScroll, ScrollBar*, _pScrollbar )
    2672             :     {
    2673             :         DBG_ASSERT( ( _pScrollbar == m_pVScroll ) || ( _pScrollbar == m_pHScroll ),
    2674             :             "TableControl_Impl::OnScroll: where did this come from?" );
    2675             : 
    2676           0 :         if ( _pScrollbar == m_pVScroll )
    2677           0 :             impl_ni_ScrollRows( _pScrollbar->GetDelta() );
    2678             :         else
    2679           0 :             impl_ni_ScrollColumns( _pScrollbar->GetDelta() );
    2680             : 
    2681           0 :         return 0L;
    2682             :     }
    2683             : 
    2684             :     //------------------------------------------------------------------------------------------------------------------
    2685           0 :     Reference< XAccessible > TableControl_Impl::getAccessible( Window& i_parentWindow )
    2686             :     {
    2687             :         DBG_TESTSOLARMUTEX();
    2688           0 :         if ( m_pAccessibleTable == NULL )
    2689             :         {
    2690           0 :             Reference< XAccessible > const xAccParent = i_parentWindow.GetAccessible();
    2691           0 :             if ( xAccParent.is() )
    2692             :             {
    2693           0 :                 m_pAccessibleTable = m_aFactoryAccess.getFactory().createAccessibleTableControl(
    2694             :                     xAccParent, m_rAntiImpl
    2695           0 :                 );
    2696           0 :             }
    2697             :         }
    2698             : 
    2699           0 :         Reference< XAccessible > xAccessible;
    2700           0 :         if ( m_pAccessibleTable )
    2701           0 :             xAccessible = m_pAccessibleTable->getMyself();
    2702           0 :         return xAccessible;
    2703             :     }
    2704             : 
    2705             :     //------------------------------------------------------------------------------------------------------------------
    2706           0 :     void TableControl_Impl::disposeAccessible()
    2707             :     {
    2708           0 :         if ( m_pAccessibleTable )
    2709           0 :             m_pAccessibleTable->dispose();
    2710           0 :         m_pAccessibleTable = NULL;
    2711           0 :     }
    2712             : 
    2713             :     //------------------------------------------------------------------------------------------------------------------
    2714           0 :     bool TableControl_Impl::impl_isAccessibleAlive() const
    2715             :     {
    2716             :         DBG_CHECK_ME();
    2717           0 :         return ( NULL != m_pAccessibleTable ) && m_pAccessibleTable->isAlive();
    2718             :     }
    2719             : 
    2720             :     //------------------------------------------------------------------------------------------------------------------
    2721           0 :     void TableControl_Impl::impl_commitAccessibleEvent( sal_Int16 const i_eventID, Any const & i_newValue, Any const & i_oldValue )
    2722             :     {
    2723             :         DBG_CHECK_ME();
    2724           0 :         if ( impl_isAccessibleAlive() )
    2725           0 :              m_pAccessibleTable->commitEvent( i_eventID, i_newValue, i_oldValue );
    2726           0 :     }
    2727             : 
    2728             :     //==================================================================================================================
    2729             :     //= TableFunctionSet
    2730             :     //==================================================================================================================
    2731             :     //------------------------------------------------------------------------------------------------------------------
    2732           0 :     TableFunctionSet::TableFunctionSet(TableControl_Impl* _pTableControl)
    2733             :         :m_pTableControl( _pTableControl)
    2734           0 :         ,m_nCurrentRow( ROW_INVALID )
    2735             :     {
    2736           0 :     }
    2737             :     //------------------------------------------------------------------------------------------------------------------
    2738           0 :     TableFunctionSet::~TableFunctionSet()
    2739             :     {
    2740           0 :     }
    2741             :     //------------------------------------------------------------------------------------------------------------------
    2742           0 :     void TableFunctionSet::BeginDrag()
    2743             :     {
    2744           0 :     }
    2745             :     //------------------------------------------------------------------------------------------------------------------
    2746           0 :     void TableFunctionSet::CreateAnchor()
    2747             :     {
    2748           0 :         m_pTableControl->setAnchor( m_pTableControl->getCurRow() );
    2749           0 :     }
    2750             : 
    2751             :     //------------------------------------------------------------------------------------------------------------------
    2752           0 :     void TableFunctionSet::DestroyAnchor()
    2753             :     {
    2754           0 :         m_pTableControl->setAnchor( ROW_INVALID );
    2755           0 :     }
    2756             : 
    2757             :     //------------------------------------------------------------------------------------------------------------------
    2758           0 :     sal_Bool TableFunctionSet::SetCursorAtPoint(const Point& rPoint, sal_Bool bDontSelectAtCursor)
    2759             :     {
    2760           0 :         sal_Bool bHandled = sal_False;
    2761             :         // newRow is the row which includes the point, getCurRow() is the last selected row, before the mouse click
    2762           0 :         RowPos newRow = m_pTableControl->getRowAtPoint( rPoint );
    2763           0 :         if ( newRow == ROW_COL_HEADERS )
    2764           0 :             newRow = m_pTableControl->getTopRow();
    2765             : 
    2766           0 :         ColPos newCol = m_pTableControl->getColAtPoint( rPoint );
    2767           0 :         if ( newCol == COL_ROW_HEADERS )
    2768           0 :             newCol = m_pTableControl->getLeftColumn();
    2769             : 
    2770           0 :         if ( ( newRow == ROW_INVALID ) || ( newCol == COL_INVALID ) )
    2771           0 :             return sal_False;
    2772             : 
    2773           0 :         if ( bDontSelectAtCursor )
    2774             :         {
    2775           0 :             if ( m_pTableControl->getSelectedRowCount() > 1 )
    2776           0 :                 m_pTableControl->getSelEngine()->AddAlways(sal_True);
    2777           0 :             bHandled = sal_True;
    2778             :         }
    2779           0 :         else if ( m_pTableControl->getAnchor() == m_pTableControl->getCurRow() )
    2780             :         {
    2781             :             //selecting region,
    2782           0 :             int diff = m_pTableControl->getCurRow() - newRow;
    2783             :             //selected region lies above the last selection
    2784           0 :             if( diff >= 0)
    2785             :             {
    2786             :                 //put selected rows in vector
    2787           0 :                 while ( m_pTableControl->getAnchor() >= newRow )
    2788             :                 {
    2789           0 :                     m_pTableControl->markRowAsSelected( m_pTableControl->getAnchor() );
    2790           0 :                     m_pTableControl->setAnchor( m_pTableControl->getAnchor() - 1 );
    2791           0 :                     diff--;
    2792             :                 }
    2793           0 :                 m_pTableControl->setAnchor( m_pTableControl->getAnchor() + 1 );
    2794             :             }
    2795             :             //selected region lies beneath the last selected row
    2796             :             else
    2797             :             {
    2798           0 :                 while ( m_pTableControl->getAnchor() <= newRow )
    2799             :                 {
    2800           0 :                     m_pTableControl->markRowAsSelected( m_pTableControl->getAnchor() );
    2801           0 :                     m_pTableControl->setAnchor( m_pTableControl->getAnchor() + 1 );
    2802           0 :                     diff++;
    2803             :                 }
    2804           0 :                 m_pTableControl->setAnchor( m_pTableControl->getAnchor() - 1 );
    2805             :             }
    2806           0 :             m_pTableControl->invalidateSelectedRegion( m_pTableControl->getCurRow(), newRow );
    2807           0 :             bHandled = sal_True;
    2808             :         }
    2809             :         //no region selected
    2810             :         else
    2811             :         {
    2812           0 :             if ( !m_pTableControl->hasRowSelection() )
    2813           0 :                 m_pTableControl->markRowAsSelected( newRow );
    2814             :             else
    2815             :             {
    2816           0 :                 if ( m_pTableControl->getSelEngine()->GetSelectionMode() == SINGLE_SELECTION )
    2817             :                 {
    2818           0 :                     DeselectAll();
    2819           0 :                     m_pTableControl->markRowAsSelected( newRow );
    2820             :                 }
    2821             :                 else
    2822             :                 {
    2823           0 :                     m_pTableControl->markRowAsSelected( newRow );
    2824             :                 }
    2825             :             }
    2826           0 :             if ( m_pTableControl->getSelectedRowCount() > 1 && m_pTableControl->getSelEngine()->GetSelectionMode() != SINGLE_SELECTION )
    2827           0 :                 m_pTableControl->getSelEngine()->AddAlways(sal_True);
    2828             : 
    2829           0 :             m_pTableControl->invalidateRow( newRow );
    2830           0 :             bHandled = sal_True;
    2831             :         }
    2832           0 :         m_pTableControl->goTo( newCol, newRow );
    2833           0 :         return bHandled;
    2834             :     }
    2835             :     //------------------------------------------------------------------------------------------------------------------
    2836           0 :     sal_Bool TableFunctionSet::IsSelectionAtPoint( const Point& rPoint )
    2837             :     {
    2838           0 :         m_pTableControl->getSelEngine()->AddAlways(sal_False);
    2839           0 :         if ( !m_pTableControl->hasRowSelection() )
    2840           0 :             return sal_False;
    2841             :         else
    2842             :         {
    2843           0 :             RowPos curRow = m_pTableControl->getRowAtPoint( rPoint );
    2844           0 :             m_pTableControl->setAnchor( ROW_INVALID );
    2845           0 :             bool selected = m_pTableControl->isRowSelected( curRow );
    2846           0 :             m_nCurrentRow = curRow;
    2847           0 :             return selected;
    2848             :         }
    2849             :     }
    2850             :     //------------------------------------------------------------------------------------------------------------------
    2851           0 :     void TableFunctionSet::DeselectAtPoint( const Point& rPoint )
    2852             :     {
    2853             :         (void)rPoint;
    2854           0 :         m_pTableControl->invalidateRow( m_nCurrentRow );
    2855           0 :         m_pTableControl->markRowAsDeselected( m_nCurrentRow );
    2856           0 :     }
    2857             : 
    2858             :     //------------------------------------------------------------------------------------------------------------------
    2859           0 :     void TableFunctionSet::DeselectAll()
    2860             :     {
    2861           0 :         if ( m_pTableControl->hasRowSelection() )
    2862             :         {
    2863           0 :             for ( size_t i=0; i<m_pTableControl->getSelectedRowCount(); ++i )
    2864             :             {
    2865           0 :                 RowPos const rowIndex = m_pTableControl->getSelectedRowIndex(i);
    2866           0 :                 m_pTableControl->invalidateRow( rowIndex );
    2867             :             }
    2868             : 
    2869           0 :             m_pTableControl->markAllRowsAsDeselected();
    2870             :         }
    2871           0 :     }
    2872             : 
    2873             : //......................................................................................................................
    2874         108 : } } // namespace svt::table
    2875             : //......................................................................................................................
    2876             : 
    2877             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10