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