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