summaryrefslogtreecommitdiff
path: root/svtools
diff options
context:
space:
mode:
authorFrank Schoenheit [fs] <frank.schoenheit@oracle.com>2010-12-23 15:48:53 +0100
committerFrank Schoenheit [fs] <frank.schoenheit@oracle.com>2010-12-23 15:48:53 +0100
commit6f7105ef88fcb3e8979617cbbac3a8503e4766ea (patch)
treece1c0a1da3d82168f582ae18bbb2824fda01b88d /svtools
parent7eaf01c7332179229dab928fec6aff5369c6b9d7 (diff)
gridsort: re-factoring the column-resizing thingie, step 1
In the current implementation, this is rather complex, and hardly maintainable. Also, it all happens in TableControl_Impl and TableDataWindow, while in the original design, the InputHandler was intended to care for this kind of tasks (one class - one responsibility).
Diffstat (limited to 'svtools')
-rw-r--r--svtools/inc/svtools/table/abstracttablecontrol.hxx23
-rw-r--r--svtools/inc/svtools/table/tablecontrol.hxx3
-rwxr-xr-xsvtools/inc/svtools/table/tablemodel.hxx2
-rw-r--r--svtools/source/table/defaultinputhandler.cxx70
-rw-r--r--svtools/source/table/tablecontrol.cxx28
-rwxr-xr-xsvtools/source/table/tablecontrol_impl.cxx795
-rwxr-xr-xsvtools/source/table/tablecontrol_impl.hxx120
-rw-r--r--svtools/source/table/tabledatawindow.cxx15
-rw-r--r--svtools/source/table/tablegeometry.cxx85
-rw-r--r--svtools/source/table/tablegeometry.hxx6
-rw-r--r--svtools/source/uno/svtxgridcontrol.cxx3
-rw-r--r--svtools/source/uno/unocontroltablemodel.cxx6
12 files changed, 690 insertions, 466 deletions
diff --git a/svtools/inc/svtools/table/abstracttablecontrol.hxx b/svtools/inc/svtools/table/abstracttablecontrol.hxx
index 9206f20ecbcb..ac91006e42f5 100644
--- a/svtools/inc/svtools/table/abstracttablecontrol.hxx
+++ b/svtools/inc/svtools/table/abstracttablecontrol.hxx
@@ -73,7 +73,6 @@ namespace svt { namespace table
/// selects the row, from the actual cursor till bottom
cursorSelectRowAreaBottom,
-
/// invalid and final enumeration value, not to be actually used
invalidTableControlAction
};
@@ -113,16 +112,18 @@ namespace svt { namespace table
@see TableControlAction
*/
virtual bool dispatchAction( TableControlAction _eAction ) = 0;
- /** returns selection engine*/
- virtual SelectionEngine* getSelEngine() = 0;
- virtual void setCursorAtCurrentCell(const Point& rPoint) = 0;
- virtual bool isTooltipActive() = 0;
- virtual rtl::OUString& setTooltip(const Point& rPoint ) = 0;
- virtual RowPos getCurrentRow(const Point& rPoint ) = 0;
- virtual void resizeColumn(const Point& rPoint ) = 0;
- virtual bool startResizeColumn(const Point& rPoint) = 0;
- virtual bool endResizeColumn(const Point& rPoint) = 0;
- virtual bool isRowSelected(RowPos _nRow) = 0;
+
+ /** returns selection engine*/
+ virtual SelectionEngine* getSelEngine() = 0;
+ virtual void activateCellAt( const Point& rPoint ) = 0;
+ virtual bool isTooltipActive() = 0;
+ virtual rtl::OUString& setTooltip(const Point& rPoint ) = 0;
+ virtual RowPos getRowAtPoint( const Point& rPoint ) = 0;
+ virtual ColPos getColAtPoint( const Point& rPoint ) = 0;
+ virtual void resizeColumn(const Point& rPoint ) = 0;
+ virtual bool checkResizeColumn(const Point& rPoint) = 0;
+ virtual bool endResizeColumn(const Point& rPoint) = 0;
+ virtual bool isRowSelected(RowPos _nRow) = 0;
virtual ~IAbstractTableControl() {};
};
diff --git a/svtools/inc/svtools/table/tablecontrol.hxx b/svtools/inc/svtools/table/tablecontrol.hxx
index 07384540261b..b75ebe0dcc88 100644
--- a/svtools/inc/svtools/table/tablecontrol.hxx
+++ b/svtools/inc/svtools/table/tablecontrol.hxx
@@ -111,8 +111,7 @@ namespace svt { namespace table
sal_Int32 GetCurrentRow() const;
/** returns the row, which contains the input point*/
-
- ColPos GetCurrentRow (const Point& rPoint);
+ ColPos GetRowAtPoint( const Point& rPoint );
/** retrieves the current column
diff --git a/svtools/inc/svtools/table/tablemodel.hxx b/svtools/inc/svtools/table/tablemodel.hxx
index a9d6c7325e65..99cd0e2792d6 100755
--- a/svtools/inc/svtools/table/tablemodel.hxx
+++ b/svtools/inc/svtools/table/tablemodel.hxx
@@ -232,7 +232,7 @@ namespace svt { namespace table
If there is more than one column with width COLWIDTH_FIT_TO_VIEW in a model,
they're all layouted equal-width.
- If the columns with a read width (i.e. other than COLWIDTH_FIT_TO_VIEW) are,
+ If the columns with a real width (i.e. other than COLWIDTH_FIT_TO_VIEW) are,
in sum, wider than the view, then the view is free to choose a real width for any
columns which return COLWIDTH_FIT_TO_VIEW here.
diff --git a/svtools/source/table/defaultinputhandler.cxx b/svtools/source/table/defaultinputhandler.cxx
index f6a58ad17efe..9f170c929eba 100644
--- a/svtools/source/table/defaultinputhandler.cxx
+++ b/svtools/source/table/defaultinputhandler.cxx
@@ -64,9 +64,9 @@ namespace svt { namespace table
bool DefaultInputHandler::MouseMove( IAbstractTableControl& _rControl, const MouseEvent& _rMEvt )
{
Point aPoint = _rMEvt.GetPosPixel();
- if(m_bResize)
+ if ( m_bResize )
{
- _rControl.resizeColumn(aPoint);
+ _rControl.resizeColumn( aPoint );
return true;
}
return false;
@@ -77,25 +77,35 @@ namespace svt { namespace table
{
bool bHandled = false;
Point aPoint = _rMEvt.GetPosPixel();
- RowPos nRow = _rControl.getCurrentRow(aPoint);
- if(nRow == -1)
+ RowPos nRow = _rControl.getRowAtPoint( aPoint );
+ if ( nRow == ROW_COL_HEADERS )
{
- m_bResize = _rControl.startResizeColumn(aPoint);
+ m_bResize = _rControl.checkResizeColumn(aPoint);
bHandled = true;
}
else if(nRow >= 0)
{
- if(_rControl.getSelEngine()->GetSelectionMode() == NO_SELECTION)
+ bool bSetCursor = false;
+ if ( _rControl.getSelEngine()->GetSelectionMode() == NO_SELECTION )
{
- _rControl.setCursorAtCurrentCell(aPoint);
- bHandled = true;
+ bSetCursor = true;
}
else
{
- if(!_rControl.isRowSelected(nRow))
- bHandled = _rControl.getSelEngine()->SelMouseButtonDown(_rMEvt);
+ if ( !_rControl.isRowSelected( nRow ) )
+ {
+ bHandled = _rControl.getSelEngine()->SelMouseButtonDown( _rMEvt );
+ }
else
- bHandled = true;
+ {
+ bSetCursor = true;
+ }
+ }
+
+ if ( bSetCursor )
+ {
+ _rControl.activateCellAt( aPoint );
+ bHandled = true;
}
}
return bHandled;
@@ -104,29 +114,22 @@ namespace svt { namespace table
bool DefaultInputHandler::MouseButtonUp( IAbstractTableControl& _rControl, const MouseEvent& _rMEvt )
{
bool bHandled = false;
- Point aPoint = _rMEvt.GetPosPixel();
- if(_rControl.getCurrentRow(aPoint) >= 0)
+ const Point aPoint = _rMEvt.GetPosPixel();
+
+ if ( m_bResize )
{
- if(m_bResize)
- {
- m_bResize = _rControl.endResizeColumn(aPoint);
- bHandled = true;
- }
- else if(_rControl.getSelEngine()->GetSelectionMode() == NO_SELECTION)
+ m_bResize = _rControl.endResizeColumn( aPoint );
+ bHandled = true;
+ }
+ else if ( _rControl.getRowAtPoint( aPoint ) >= 0 )
+ {
+ if ( _rControl.getSelEngine()->GetSelectionMode() == NO_SELECTION )
{
bHandled = true;
}
else
{
- bHandled = _rControl.getSelEngine()->SelMouseButtonUp(_rMEvt);
- }
- }
- else
- {
- if(m_bResize)
- {
- m_bResize = _rControl.endResizeColumn(aPoint);
- bHandled = true;
+ bHandled = _rControl.getSelEngine()->SelMouseButtonUp( _rMEvt );
}
}
return bHandled;
@@ -158,11 +161,11 @@ namespace svt { namespace table
{ KEY_PAGEDOWN, KEY_MOD1, cursorToLastLine },
{ KEY_HOME, KEY_MOD1, cursorTopLeft },
{ KEY_END, KEY_MOD1, cursorBottomRight },
- { KEY_SPACE, KEY_MOD1, cursorSelectRow },
- { KEY_UP, KEY_SHIFT, cursorSelectRowUp },
- { KEY_DOWN, KEY_SHIFT, cursorSelectRowDown },
- { KEY_END, KEY_SHIFT, cursorSelectRowAreaBottom },
- { KEY_HOME, KEY_SHIFT, cursorSelectRowAreaTop },
+ { KEY_SPACE, KEY_MOD1, cursorSelectRow },
+ { KEY_UP, KEY_SHIFT, cursorSelectRowUp },
+ { KEY_DOWN, KEY_SHIFT, cursorSelectRowDown },
+ { KEY_END, KEY_SHIFT, cursorSelectRowAreaBottom },
+ { KEY_HOME, KEY_SHIFT, cursorSelectRowAreaTop },
{ 0, 0, invalidTableControlAction }
};
@@ -173,7 +176,6 @@ namespace svt { namespace table
if ( ( pActions->nKeyCode == nKeyCode ) && ( pActions->nKeyModifier == rKeyCode.GetAllModifier() ) )
{
bHandled = _rControl.dispatchAction( pActions->eAction );
- bHandled = true; // always handled issue #i114340
break;
}
}
diff --git a/svtools/source/table/tablecontrol.cxx b/svtools/source/table/tablecontrol.cxx
index cde198a92a6e..24486d024091 100644
--- a/svtools/source/table/tablecontrol.cxx
+++ b/svtools/source/table/tablecontrol.cxx
@@ -100,10 +100,7 @@ namespace svt { namespace table
void TableControl::GetFocus()
{
if ( !m_pImpl->getInputHandler()->GetFocus( *m_pImpl ) )
- {
Control::GetFocus();
- Control::GrabFocus();
- }
}
//--------------------------------------------------------------------
@@ -246,23 +243,26 @@ namespace svt { namespace table
{
m_pImpl->removeSelectedRow(_nRowPos);
}
- //--------------------------------------------------------------------
- RowPos TableControl::GetCurrentRow(const Point& rPoint)
+ //--------------------------------------------------------------------
+ RowPos TableControl::GetRowAtPoint( const Point& rPoint )
{
- return m_pImpl->getCurrentRow( rPoint );
+ return m_pImpl->getRowAtPoint( rPoint );
}
+ //--------------------------------------------------------------------
SelectionEngine* TableControl::getSelEngine()
{
return m_pImpl->getSelEngine();
}
+ //--------------------------------------------------------------------
TableDataWindow* TableControl::getDataWindow()
{
return m_pImpl->getDataWindow();
}
+ //--------------------------------------------------------------------
Reference< XAccessible > TableControl::CreateAccessible()
{
Window* pParent = GetAccessibleParentWindow();
@@ -494,10 +494,10 @@ sal_Int32 TableControl::GetAccessibleControlCount() const
}
sal_Bool TableControl::ConvertPointToControlIndex( sal_Int32& _rnIndex, const Point& _rPoint )
{
- sal_Int32 nRow = m_pImpl->getCurrentRow(_rPoint);
- sal_Int32 nCol = GetCurrentColumn();
+ sal_Int32 nRow = m_pImpl->getRowAtPoint( _rPoint );
+ sal_Int32 nCol = m_pImpl->getColAtPoint( _rPoint );
_rnIndex = nRow * GetColumnCount() + nCol;
- return nRow>=0 ? sal_True : sal_False;
+ return nRow >= 0 ? sal_True : sal_False;
}
long TableControl::GetRowCount() const
@@ -523,9 +523,9 @@ bool TableControl::IsRowSelected( long _nRow ) const
}
sal_Bool TableControl::ConvertPointToCellAddress( sal_Int32& _rnRow, sal_Int32& _rnColPos, const Point& _rPoint )
{
- _rnRow = m_pImpl->getCurrentRow(_rPoint);
- _rnColPos = GetCurrentColumn();
- return _rnRow>=0 ? sal_True : sal_False;
+ _rnRow = m_pImpl->getRowAtPoint( _rPoint );
+ _rnColPos = m_pImpl->getColAtPoint( _rPoint );
+ return _rnRow >= 0 ? sal_True : sal_False;
}
void TableControl::FillAccessibleStateSetForCell( ::utl::AccessibleStateSetHelper& _rStateSet, sal_Int32 _nRow, sal_uInt16 _nColumnPos ) const
{
@@ -612,12 +612,12 @@ IMPL_LINK( TableControl, ImplSelectHdl, void*, EMPTYARG )
IMPL_LINK( TableControl, ImplMouseButtonDownHdl, MouseEvent*, pData )
{
CallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONDOWN, pData );
- return 1;
+ return 1;
}
IMPL_LINK( TableControl, ImplMouseButtonUpHdl, MouseEvent*, pData )
{
CallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONUP, pData );
- return 1;
+ return 1;
}
// -----------------------------------------------------------------------
void TableControl::Select()
diff --git a/svtools/source/table/tablecontrol_impl.cxx b/svtools/source/table/tablecontrol_impl.cxx
index 46ebda453b10..09ac0412c615 100755
--- a/svtools/source/table/tablecontrol_impl.cxx
+++ b/svtools/source/table/tablecontrol_impl.cxx
@@ -280,12 +280,9 @@ namespace svt { namespace table
if ( m_pModel->getRowCount() != m_nRowCount )
return "row counts are inconsistent!";
- if ( ( m_nCurColumn != COL_INVALID ) && !m_aColumnWidthsPixel.empty() && ( m_nCurColumn < 0 ) || ( m_nCurColumn >= (ColPos)m_aColumnWidthsPixel.size() ) )
+ if ( ( m_nCurColumn != COL_INVALID ) && !m_aColumnWidths.empty() && ( m_nCurColumn < 0 ) || ( m_nCurColumn >= (ColPos)m_aColumnWidths.size() ) )
return "current column is invalid!";
- if ( m_aColumnWidthsPixel.size() != m_aAccColumnWidthsPixel.size() )
- return "columnd width caches are inconsistent!";
-
if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nTopRow, (RowPos)-1, m_nRowCount, getModel(), (RowPos)0 ) )
return "invalid top row value!";
@@ -326,7 +323,11 @@ namespace svt { namespace table
return "row header widths are inconsistent!";
}
- // TODO: check m_aColumnWidthsPixel and m_aAccColumnWidthsPixel
+ // TODO: check m_aColumnWidths
+ // - for each element, getStart <= getEnd()
+ // - for each i: col[ i ].getEnd() == col[ i+1 ].getStart()
+ // - col[ m_nLeftColumn ].getStart == m_nRowHeaderWidthPixel
+
if ( m_nCursorHidden < 0 )
return "invalid hidden count for the cursor!";
@@ -335,6 +336,8 @@ namespace svt { namespace table
DBG_SUSPEND_INV( INV_SCROLL_POSITION );
// prevent infinite recursion
+ if ( m_nLeftColumn < 0 )
+ return "invalid left-most column index";
if ( m_pVScroll->GetThumbPos() != m_nTopRow )
return "vertical scroll bar |position| is incorrect!";
if ( m_pVScroll->GetRange().Max() != m_nRowCount )
@@ -386,7 +389,7 @@ namespace svt { namespace table
,m_nRowSelected ( )
,m_pTableFunctionSet ( new TableFunctionSet( this ) )
,m_nAnchor (-1 )
- ,m_bResizing ( false )
+ ,m_bResizingColumn ( false )
,m_nResizingColumn ( 0 )
,m_bResizingGrid ( false )
#if DBG_UTIL
@@ -519,19 +522,20 @@ namespace svt { namespace table
// determine the right-most border of the last column which is
// at least partially visible
_rCellArea.Right() = m_nRowHeaderWidthPixel;
- if ( !m_aAccColumnWidthsPixel.empty() )
+ if ( !m_aColumnWidths.empty() )
{
- // the number of pixels which are scroll out of the left hand
+ // the number of pixels which are scrolled out of the left hand
// side of the window
- long nScrolledOutLeft = m_nLeftColumn == 0 ? 0 : m_aAccColumnWidthsPixel[ m_nLeftColumn - 1 ];
+ const long nScrolledOutLeft = m_nLeftColumn == 0 ? 0 : m_aColumnWidths[ m_nLeftColumn - 1 ].getEnd();
- ArrayOfLong::const_reverse_iterator loop = m_aAccColumnWidthsPixel.rbegin();
+ ColumnPositions::const_reverse_iterator loop = m_aColumnWidths.rbegin();
do
{
- _rCellArea.Right() = *loop++ - nScrolledOutLeft + m_nRowHeaderWidthPixel;
+ _rCellArea.Right() = loop->getEnd() - nScrolledOutLeft + m_nRowHeaderWidthPixel;
+ ++loop;
}
- while ( ( loop != m_aAccColumnWidthsPixel.rend() )
- && ( *loop - nScrolledOutLeft >= _rCellArea.Right() )
+ while ( ( loop != m_aColumnWidths.rend() )
+ && ( loop->getEnd() - nScrolledOutLeft >= _rCellArea.Right() )
);
}
// so far, _rCellArea.Right() denotes the first pixel *after* the cell area
@@ -582,54 +586,54 @@ namespace svt { namespace table
//--------------------------------------------------------------------
void TableControl_Impl::impl_ni_updateColumnWidths()
{
- m_aColumnWidthsPixel.resize( 0 );
- m_aAccColumnWidthsPixel.resize( 0 );
+ m_aColumnWidths.resize( 0 );
if ( !m_pModel )
return;
- TableSize colCount = m_pModel->getColumnCount();
+ const TableSize colCount = m_pModel->getColumnCount();
if ( colCount == 0 )
return;
- m_aColumnWidthsPixel.reserve( colCount );
- m_aAccColumnWidthsPixel.reserve( colCount );
+ m_aColumnWidths.reserve( colCount );
std::vector<sal_Int32> aPrePixelWidths(0);
long accumulatedPixelWidth = 0;
- int lastResizableCol = -1;
+ int lastResizableCol = COL_INVALID;
double gridWidth = m_rAntiImpl.GetOutputSizePixel().Width();
- if(m_pModel->hasRowHeaders())
+ if ( m_pModel->hasRowHeaders() && ( gridWidth != 0 ) )
{
- TableMetrics rowHeaderWidth = m_pModel->getRowHeaderWidth();
- gridWidth-= m_rAntiImpl.LogicToPixel( Size( rowHeaderWidth, 0 ), MAP_APPFONT ).Width();
+#if OSL_DEBUG_LEVEL > 0
+ const TableMetrics rowHeaderWidth = m_pModel->getRowHeaderWidth();
+ const long rowHeaderWidthPixel = m_rAntiImpl.LogicToPixel( Size( rowHeaderWidth, 0 ), MAP_APPFONT ).Width();
+ OSL_ENSURE( rowHeaderWidthPixel == m_nRowHeaderWidthPixel,
+ "TableControl_Impl::impl_ni_updateColumnWidths: cached row header width is not correct anymore!" );
+#endif
+ accumulatedPixelWidth += m_nRowHeaderWidthPixel;
+ gridWidth -= m_nRowHeaderWidthPixel;
}
- if(m_pModel->hasVerticalScrollbar())
+
+ if ( m_pModel->hasVerticalScrollbar() && ( gridWidth != 0 ) )
{
sal_Int32 scrollbarWidth = m_rAntiImpl.GetSettings().GetStyleSettings().GetScrollBarSize();
gridWidth-=scrollbarWidth;
}
+
double colWidthsSum = 0.0;
double colWithoutFixedWidthsSum = 0.0;
double minColWithoutFixedSum = 0.0;
+
for ( ColPos col = 0; col < colCount; ++col )
{
- PColumnModel pColumn = m_pModel->getColumnModel( col );
- DBG_ASSERT( !!pColumn, "TableControl_Impl::impl_ni_updateColumnWidths: invalid column returned by the model!" );
- if ( !pColumn )
- continue;
+ const PColumnModel pColumn = m_pModel->getColumnModel( col );
+ ENSURE_OR_CONTINUE( !!pColumn, "TableControl_Impl::impl_ni_updateColumnWidths: invalid column returned by the model!" );
+
TableMetrics colWidth = 0;
- TableMetrics colPrefWidth = pColumn->getPreferredWidth();
- bool bResizable = pColumn->isResizable();
- if(pColumn->getMinWidth() == 0 && bResizable)
- {
- pColumn->setMinWidth(1);
- minColWithoutFixedSum+=m_rAntiImpl.PixelToLogic( Size( 1, 0 ), MAP_APPFONT ).Width();
- }
- if(pColumn->getMaxWidth() == 0 && bResizable)
- pColumn->setMaxWidth(m_rAntiImpl.PixelToLogic( Size( (int)gridWidth, 0 ), MAP_APPFONT ).Width());
- if( colPrefWidth != 0)
+ const TableMetrics colPrefWidth = pColumn->getPreferredWidth();
+ const bool bResizable = pColumn->isResizable();
+
+ if ( colPrefWidth != 0)
{
- if(m_bResizingGrid)
+ if ( m_bResizingGrid )
{
colWidth = pColumn->getWidth();
pColumn->setPreferredWidth(0);
@@ -637,66 +641,88 @@ namespace svt { namespace table
else
{
colWidth = colPrefWidth;
- pColumn->setWidth(colPrefWidth);
+ pColumn->setWidth( colPrefWidth );
}
}
else
colWidth = pColumn->getWidth();
- long pixelWidth = m_rAntiImpl.LogicToPixel( Size( colWidth, 0 ), MAP_APPFONT ).Width();
- if(bResizable && colPrefWidth == 0)
+
+ const long pixelWidth = m_rAntiImpl.LogicToPixel( Size( colWidth, 0 ), MAP_APPFONT ).Width();
+ if ( bResizable && colPrefWidth == 0 )
{
- colWithoutFixedWidthsSum+=pixelWidth;
+ colWithoutFixedWidthsSum += pixelWidth;
lastResizableCol = col;
}
- colWidthsSum+=pixelWidth;
- aPrePixelWidths.push_back(pixelWidth);
+ colWidthsSum += pixelWidth;
+ aPrePixelWidths.push_back( pixelWidth );
}
+
double gridWidthWithoutFixed = gridWidth - colWidthsSum + colWithoutFixedWidthsSum;
double scalingFactor = 1.0;
- if(m_bResizingGrid)
+ if ( m_bResizingGrid )
{
- if(gridWidthWithoutFixed > (minColWithoutFixedSum+colWidthsSum - colWithoutFixedWidthsSum))
- scalingFactor = gridWidthWithoutFixed/colWithoutFixedWidthsSum;
+ if ( gridWidthWithoutFixed > ( minColWithoutFixedSum + colWidthsSum - colWithoutFixedWidthsSum ) )
+ scalingFactor = gridWidthWithoutFixed / colWithoutFixedWidthsSum;
}
else
{
- if(colWidthsSum < gridWidthWithoutFixed)
+ if ( colWidthsSum < gridWidthWithoutFixed )
{
- if(colWithoutFixedWidthsSum>0)
- scalingFactor = gridWidthWithoutFixed/colWithoutFixedWidthsSum;
+ if ( colWithoutFixedWidthsSum > 0 )
+ scalingFactor = gridWidthWithoutFixed / colWithoutFixedWidthsSum;
}
}
for ( ColPos i = 0; i < colCount; ++i )
{
- PColumnModel pColumn = m_pModel->getColumnModel( i );
- DBG_ASSERT( !!pColumn, "TableControl_Impl::impl_ni_updateColumnWidths: invalid column returned by the model!" );
- if ( !pColumn )
- continue;
- if(pColumn->isResizable() && pColumn->getPreferredWidth() == 0)
+ const PColumnModel pColumn = m_pModel->getColumnModel( i );
+ ENSURE_OR_CONTINUE( !!pColumn, "TableControl_Impl::impl_ni_updateColumnWidths: invalid column returned by the model!" );
+
+ if ( pColumn->isResizable() && ( pColumn->getPreferredWidth() == 0 ) )
{
- aPrePixelWidths[i]*=scalingFactor;
- TableMetrics logicColWidth = m_rAntiImpl.PixelToLogic( Size( aPrePixelWidths[i], 0 ), MAP_APPFONT ).Width();
- pColumn->setWidth(logicColWidth);
+ aPrePixelWidths[i] *= scalingFactor;
+ const TableMetrics logicColWidth = m_rAntiImpl.PixelToLogic( Size( aPrePixelWidths[i], 0 ), MAP_APPFONT ).Width();
+ pColumn->setWidth( logicColWidth );
}
- m_aColumnWidthsPixel.push_back( aPrePixelWidths[i] );
- m_aAccColumnWidthsPixel.push_back( accumulatedPixelWidth += aPrePixelWidths[i] );
+
+ const long columnStart = accumulatedPixelWidth;
+ const long columnEnd = columnStart + aPrePixelWidths[i];
+ m_aColumnWidths.push_back( ColumnWidthInfo( columnStart, columnEnd ) );
+ accumulatedPixelWidth = columnEnd;
}
- if(gridWidth > m_aAccColumnWidthsPixel[colCount-1])
+
+ // care for the horizontal scroll position (as indicated by m_nLeftColumn)
+ if ( m_nLeftColumn > 0 )
{
- if(lastResizableCol >= 0)
+ const long offsetPixel = m_aColumnWidths[ 0 ].getStart() - m_aColumnWidths[ m_nLeftColumn ].getStart();
+ for ( ColumnPositions::iterator colPos = m_aColumnWidths.begin();
+ colPos != m_aColumnWidths.end();
+ ++colPos
+ )
{
- PColumnModel pColumn = m_pModel->getColumnModel(lastResizableCol);
- m_aColumnWidthsPixel[lastResizableCol]+=gridWidth-m_aAccColumnWidthsPixel[colCount-1];
- TableMetrics logicColWidth1 = m_rAntiImpl.PixelToLogic( Size( m_aColumnWidthsPixel[lastResizableCol], 0 ), MAP_APPFONT ).Width();
- pColumn->setWidth(logicColWidth1);
- while(lastResizableCol < colCount)
- {
- if(lastResizableCol == 0)
- m_aAccColumnWidthsPixel[0] = m_aColumnWidthsPixel[lastResizableCol];
- else
- m_aAccColumnWidthsPixel[lastResizableCol]=m_aAccColumnWidthsPixel[lastResizableCol-1]+m_aColumnWidthsPixel[lastResizableCol];
- ++lastResizableCol;
- }
+ colPos->move( offsetPixel );
+ }
+ }
+
+ const long freeSpaceRight = gridWidth - m_aColumnWidths[ colCount-1 ].getEnd();
+ if ( ( freeSpaceRight > 0 )
+ && ( lastResizableCol != COL_INVALID )
+ && ( lastResizableCol >= m_nLeftColumn )
+ )
+ {
+ // make the last resizable column wider
+ ColumnWidthInfo& rResizeColInfo( m_aColumnWidths[ lastResizableCol ] );
+ rResizeColInfo.setEnd( rResizeColInfo.getEnd() + freeSpaceRight );
+
+ // update the column model
+ const TableMetrics logicColWidth = m_rAntiImpl.PixelToLogic( Size( rResizeColInfo.getWidth(), 0 ), MAP_APPFONT ).Width();
+ const PColumnModel pColumn = m_pModel->getColumnModel( lastResizableCol );
+ pColumn->setWidth( logicColWidth );
+
+ // update all other columns after the resized one
+ ColPos adjustColumn = lastResizableCol;
+ while ( ++adjustColumn < colCount )
+ {
+ m_aColumnWidths[ adjustColumn ].move( freeSpaceRight );
}
}
}
@@ -707,8 +733,10 @@ namespace svt { namespace table
//................................................................
/// determines whether a scrollbar is needed for the given values
bool lcl_determineScrollbarNeed( ScrollbarVisibility _eVisibility,
- long _nVisibleUnits, long _nRange )
+ long _nVisibleUnits, long _nRange, long const i_nPosition )
{
+ if ( i_nPosition > 0 )
+ return true;
if ( _eVisibility == ScrollbarShowNever )
return false;
if ( _eVisibility == ScrollbarShowAlways )
@@ -735,7 +763,7 @@ namespace svt { namespace table
bool _bHorizontal, const Link& _rScrollHandler )
{
// do we need the scrollbar?
- bool bNeedBar = lcl_determineScrollbarNeed( _eVisibility, _nVisibleUnits, _nRange );
+ bool bNeedBar = lcl_determineScrollbarNeed( _eVisibility, _nVisibleUnits, _nRange, _nPosition );
// do we currently have the scrollbar?
bool bHaveBar = _rpBar != NULL;
@@ -743,6 +771,8 @@ namespace svt { namespace table
// do we need to correct the scrollbar visibility?
if ( bHaveBar && !bNeedBar )
{
+ if ( _rpBar->IsTracking() )
+ _rpBar->EndTracking();
DELETEZ( _rpBar );
}
else if ( !bHaveBar && bNeedBar )
@@ -822,26 +852,30 @@ namespace svt { namespace table
m_nRowCount = m_pModel->getRowCount();
m_nColumnCount = m_pModel->getColumnCount();
- if ( m_aAccColumnWidthsPixel.empty() )
+ if ( m_aColumnWidths.empty() )
impl_ni_updateColumnWidths();
- OSL_ENSURE( m_aAccColumnWidthsPixel.size() == m_nColumnCount, "TableControl_Impl::impl_ni_updateScrollbars: inconsistency!" );
- const long nAllColumnsWidth = m_aAccColumnWidthsPixel.empty() ? 0 : m_aAccColumnWidthsPixel[ m_nColumnCount - 1 ];
+ OSL_ENSURE( m_aColumnWidths.size() == m_nColumnCount, "TableControl_Impl::impl_ni_updateScrollbars: inconsistency!" );
+ const long nAllColumnsWidth = m_aColumnWidths.empty()
+ ? 0
+ : m_aColumnWidths[ m_nColumnCount - 1 ].getEnd() - m_aColumnWidths[ 0 ].getStart();
// do we need a vertical scrollbar?
bool bFirstRoundVScrollNeed = false;
if ( lcl_determineScrollbarNeed(
m_pModel->getVerticalScrollbarVisibility(aDataCellPlayground.GetHeight(), m_nRowHeightPixel*m_nRowCount),
lcl_getRowsFittingInto( aDataCellPlayground.GetHeight(), m_nRowHeightPixel ),
- m_nRowCount ) )
+ m_nRowCount,
+ m_nTopRow ) )
{
aDataCellPlayground.Right() -= nScrollbarMetrics;
bFirstRoundVScrollNeed = true;
}
// do we need a horizontal scrollbar?
if ( lcl_determineScrollbarNeed(
- m_pModel->getHorizontalScrollbarVisibility(aDataCellPlayground.GetWidth(), nAllColumnsWidth),
+ m_pModel->getHorizontalScrollbarVisibility( aDataCellPlayground.GetWidth(), nAllColumnsWidth ),
lcl_getColumnsVisibleWithin( aDataCellPlayground, m_nLeftColumn, *this, false ),
- m_nColumnCount ) )
+ m_nColumnCount,
+ m_nLeftColumn ) )
{
aDataCellPlayground.Bottom() -= nScrollbarMetrics;
@@ -852,7 +886,8 @@ namespace svt { namespace table
if ( !bFirstRoundVScrollNeed && lcl_determineScrollbarNeed(
m_pModel->getVerticalScrollbarVisibility(aDataCellPlayground.GetHeight(),m_nRowHeightPixel*m_nRowCount),
lcl_getRowsFittingInto( aDataCellPlayground.GetHeight(), m_nRowHeightPixel ),
- m_nRowCount ) )
+ m_nRowCount,
+ m_nTopRow ) )
{
aDataCellPlayground.Right() -= nScrollbarMetrics;
}
@@ -901,7 +936,7 @@ namespace svt { namespace table
int nRange = m_nColumnCount;
if( m_nLeftColumn + nVisibleUnits == nRange-1)
{
- if(m_aAccColumnWidthsPixel[nRange-2] - m_aAccColumnWidthsPixel[m_nLeftColumn] + m_aColumnWidthsPixel[nRange-1]>aDataCellPlayground.GetWidth())
+ if ( m_aColumnWidths[ nRange-2 ].getEnd() - m_aColumnWidths[ m_nLeftColumn ].getEnd() + m_aColumnWidths[ nRange-1 ].getWidth() > aDataCellPlayground.GetWidth() )
{
m_pHScroll->SetVisibleSize( nVisibleUnits -1 );
m_pHScroll->SetPageSize(nVisibleUnits -1);
@@ -946,11 +981,11 @@ namespace svt { namespace table
void TableControl_Impl::onResize()
{
DBG_CHECK_ME();
- if(m_nRowCount != 0)
+ if ( m_nRowCount != 0 )
{
- if(m_nColumnCount != 0)
+ if ( m_nColumnCount != 0 )
{
- if(m_bResizingGrid)
+ if ( m_bResizingGrid )
impl_ni_updateColumnWidths();
invalidateRows();
m_bResizingGrid = true;
@@ -960,13 +995,13 @@ namespace svt { namespace table
{
//In the case that column headers are defined but data hasn't yet been set,
//only column headers will be shown
- if(m_pModel->hasColumnHeaders())
+ if ( m_pModel->hasColumnHeaders() )
{
- if(m_nColHeaderHeightPixel>1)
+ if ( m_nColHeaderHeightPixel > 1 )
{
- m_pDataWindow->SetSizePixel( m_rAntiImpl.GetOutputSizePixel());
- if(m_bResizingGrid)
- //update column widths to fit in grid
+ m_pDataWindow->SetSizePixel( m_rAntiImpl.GetOutputSizePixel() );
+ if ( m_bResizingGrid )
+ //update column widths to fit in grid
impl_ni_updateColumnWidths();
m_bResizingGrid = true;
}
@@ -1006,8 +1041,8 @@ namespace svt { namespace table
TableRowGeometry aHeaderRow( *this, Rectangle( Point( 0, 0 ),
aAllCellsWithHeaders.BottomRight() ), ROW_COL_HEADERS );
Rectangle aColRect(aHeaderRow.getRect());
- //to avoid double lines when scrolling horizontally
- if(m_nLeftColumn != 0)
+ // to avoid double lines when scrolling horizontally
+ if ( m_nLeftColumn != 0 )
--aColRect.Left();
pRenderer->PaintHeaderArea(
*m_pDataWindow, aColRect, true, false, rStyle
@@ -1094,19 +1129,21 @@ namespace svt { namespace table
}
}
Rectangle aRect = aRowIterator.getRect().GetIntersection( aAllDataCellsArea );
- //to avoid double lines
- if( aRowIterator.getRow() != 0 )
+ // to avoid double lines
+ if ( aRowIterator.getRow() != 0 )
--aRect.Top();
- if(m_nLeftColumn != 0)
+ if ( m_nLeftColumn != 0 )
--aRect.Left();
else
{
- if(m_pModel->hasRowHeaders())
+ if ( m_pModel->hasRowHeaders( ))
--aRect.Left();
}
// give the redenderer a chance to prepare the row
- pRenderer->PrepareRow( aRowIterator.getRow(), isActiveRow, isSelectedRow,
- *m_pDataWindow, aRect, rStyle );
+ pRenderer->PrepareRow(
+ aRowIterator.getRow(), isActiveRow, isSelectedRow,
+ *m_pDataWindow, aRect, rStyle
+ );
// paint the row header
if ( m_pModel->hasRowHeaders() )
@@ -1580,55 +1617,64 @@ namespace svt { namespace table
_rCellRect.Top()--;_rCellRect.Left()--;
}
//-------------------------------------------------------------------------------
- RowPos TableControl_Impl::getCurrentRow(const Point& rPoint)
+ RowPos TableControl_Impl::getRowAtPoint( const Point& rPoint )
{
DBG_CHECK_ME();
- Rectangle rCellRect;
- RowPos newRowPos = -2;//-1 is HeaderRow
- ColPos newColPos = 0;
- for(int i=-1;i<m_nRowCount;i++)
+
+ if ( ( rPoint.Y() >= 0 ) && ( rPoint.Y() < m_nColHeaderHeightPixel ) )
+ return ROW_COL_HEADERS;
+
+ Rectangle aAllCellsArea;
+ impl_getAllVisibleCellsArea( aAllCellsArea );
+
+ TableRowGeometry aHitTest( *this, aAllCellsArea, ROW_COL_HEADERS );
+ while ( aHitTest.isValid() )
{
- for(int j=-1;j<m_nColumnCount;j++)
- {
- impl_getCellRect(j,i,rCellRect);
- if((rPoint.X() >= rCellRect.Left() && rPoint.X() <= rCellRect.Right()) && rPoint.Y() >= rCellRect.Top() && rPoint.Y() <= rCellRect.Bottom())
- {
- newRowPos = i;
- newColPos = j;
- if(newColPos != -1)
- m_nCurColumn = newColPos;
- return newRowPos;
- }
- }
+ if ( aHitTest.getRect().IsInside( rPoint ) )
+ return aHitTest.getRow();
+ aHitTest.moveDown();
}
- return newRowPos;
+ return ROW_INVALID;
}
+
//-------------------------------------------------------------------------------
- void TableControl_Impl::setCursorAtCurrentCell(const Point& rPoint)
+ ColPos TableControl_Impl::getColAtPoint( const Point& rPoint )
{
DBG_CHECK_ME();
- hideCursor();
- Rectangle rCellRect;
- RowPos newRowPos = -2;//-1 is HeaderRow
- ColPos newColPos = 0;
- for(int i=0;i<m_nRowCount;i++)
+
+ if ( ( rPoint.X() >= 0 ) && ( rPoint.X() < m_nRowHeaderWidthPixel ) )
+ return COL_ROW_HEADERS;
+
+ Rectangle aAllCellsArea;
+ impl_getAllVisibleCellsArea( aAllCellsArea );
+
+ TableColumnGeometry aHitTest( *this, aAllCellsArea, COL_ROW_HEADERS );
+ while ( aHitTest.isValid() )
{
- for(int j=-1;j<m_nColumnCount;j++)
- {
- impl_getCellRect(j,i,rCellRect);
- if((rPoint.X() >= rCellRect.Left() && rPoint.X() <= rCellRect.Right()) && rPoint.Y() >= rCellRect.Top() && rPoint.Y() <= rCellRect.Bottom())
- {
- newRowPos = i;
- m_nCurRow = newRowPos;
- newColPos = j;
- if(newColPos == -1)
- m_nCurColumn = 0;
- else
- m_nCurColumn = newColPos;
- }
- }
+ if ( aHitTest.getRect().IsInside( rPoint ) )
+ return aHitTest.getCol();
+ aHitTest.moveRight();
+ }
+
+ return COL_INVALID;
+ }
+
+ //-------------------------------------------------------------------------------
+ void TableControl_Impl::activateCellAt(const Point& rPoint)
+ {
+ DBG_CHECK_ME();
+
+ TempHideCursor aHideCursor( *this );
+
+ const RowPos newRowPos = getRowAtPoint( rPoint );
+ const ColPos newColPos = getColAtPoint( rPoint );
+
+ if ( ( newRowPos != ROW_INVALID ) && ( newColPos != COL_INVALID ) )
+ {
+ m_nCurColumn = newColPos;
+ m_nCurRow = newRowPos;
+ ensureVisible( m_nCurColumn, m_nCurRow, true );
}
- showCursor();
}
//-------------------------------------------------------------------------------
void TableControl_Impl::invalidateSelectedRegion(RowPos _nPrevRow, RowPos _nCurRow, Rectangle& _rCellRect)
@@ -1639,29 +1685,31 @@ namespace svt { namespace table
impl_getAllVisibleCellsArea( aAllCells );
_rCellRect.Left() = aAllCells.Left();
_rCellRect.Right() = aAllCells.Right();
- Rectangle rCells;
//if only one row is selected
if(_nPrevRow == _nCurRow)
{
- impl_getCellRect(m_nCurColumn,_nCurRow,rCells);
- _rCellRect.Top()=--rCells.Top();
- _rCellRect.Bottom()=rCells.Bottom();
+ Rectangle aCellRect;
+ impl_getCellRect( m_nCurColumn, _nCurRow, aCellRect );
+ _rCellRect.Top() = --aCellRect.Top();
+ _rCellRect.Bottom() = aCellRect.Bottom();
}
//if the region is above the current row
else if(_nPrevRow < _nCurRow )
{
- impl_getCellRect(m_nCurColumn,_nPrevRow,rCells);
- _rCellRect.Top()= --rCells.Top();
- impl_getCellRect(m_nCurColumn,_nCurRow,rCells);
- _rCellRect.Bottom()=rCells.Bottom();
+ Rectangle aCellRect;
+ impl_getCellRect( m_nCurColumn, _nPrevRow, aCellRect );
+ _rCellRect.Top() = --aCellRect.Top();
+ impl_getCellRect( m_nCurColumn, _nCurRow, aCellRect );
+ _rCellRect.Bottom() = aCellRect.Bottom();
}
//if the region is beneath the current row
else
{
- impl_getCellRect(m_nCurColumn,_nCurRow,rCells);
- _rCellRect.Top()= --rCells.Top();
- impl_getCellRect(m_nCurColumn,_nPrevRow,rCells);
- _rCellRect.Bottom()=rCells.Bottom();
+ Rectangle aCellRect;
+ impl_getCellRect( m_nCurColumn, _nCurRow, aCellRect );
+ _rCellRect.Top() = --aCellRect.Top();
+ impl_getCellRect( m_nCurColumn, _nPrevRow, aCellRect );
+ _rCellRect.Bottom() = aCellRect.Bottom();
}
m_pDataWindow->Invalidate(_rCellRect);
}
@@ -1722,14 +1770,28 @@ namespace svt { namespace table
impl_ni_updateScrollbars();
TableSize nVisibleRows = impl_getVisibleRows(true);
TableSize nVisibleCols = impl_getVisibleColumns(true);
- if(m_nTopRow+nVisibleRows>m_nRowCount && m_nRowCount>=nVisibleRows)
- m_nTopRow--;
+ if ( ( m_nTopRow + nVisibleRows > m_nRowCount )
+ && ( m_nRowCount >= nVisibleRows )
+ )
+ {
+ --m_nTopRow;
+ }
else
+ {
m_nTopRow = 0;
- if(m_nLeftColumn+nVisibleCols>m_nColumnCount && m_nColumnCount>=nVisibleCols)
- m_nLeftColumn--;
+ }
+
+ if ( ( m_nLeftColumn + nVisibleCols > m_nColumnCount )
+ && ( m_nColumnCount >= nVisibleCols )
+ )
+ {
+ --m_nLeftColumn;
+ }
else
+ {
m_nLeftColumn = 0;
+ }
+
m_pDataWindow->Invalidate();
}
@@ -1794,25 +1856,25 @@ namespace svt { namespace table
TempHideCursor aHideCursor( *this );
if ( _nColumn < m_nLeftColumn )
- impl_ni_ScrollColumns( _nColumn - m_nLeftColumn );
+ impl_scrollColumns( _nColumn - m_nLeftColumn );
else
{
TableSize nVisibleColumns = impl_getVisibleColumns( _bAcceptPartialVisibility );
if ( _nColumn > m_nLeftColumn + nVisibleColumns - 1 )
{
- impl_ni_ScrollColumns( _nColumn - ( m_nLeftColumn + nVisibleColumns - 1 ) );
+ impl_scrollColumns( _nColumn - ( m_nLeftColumn + nVisibleColumns - 1 ) );
// TODO: since not all columns have the same width, this might in theory result
// in the column still not being visible.
}
}
if ( _nRow < m_nTopRow )
- impl_ni_ScrollRows( _nRow - m_nTopRow );
+ impl_scrollRows( _nRow - m_nTopRow );
else
{
TableSize nVisibleRows = impl_getVisibleRows( _bAcceptPartialVisibility );
if ( _nRow > m_nTopRow + nVisibleRows - 1 )
- impl_ni_ScrollRows( _nRow - ( m_nTopRow + nVisibleRows - 1 ) );
+ impl_scrollRows( _nRow - ( m_nTopRow + nVisibleRows - 1 ) );
}
}
@@ -1830,7 +1892,7 @@ namespace svt { namespace table
m_nTopRow = nNewTopRow;
// if updates are enabled currently, scroll the viewport
- if ( m_rAntiImpl.IsUpdateMode() && ( m_nTopRow != nOldTopRow ) )
+ if ( m_nTopRow != nOldTopRow )
{
DBG_SUSPEND_INV( INV_SCROLL_POSITION );
TempHideCursor aHideCursor( *this );
@@ -1856,24 +1918,37 @@ namespace svt { namespace table
m_pVScroll->SetThumbPos( m_nTopRow );
}
+ // The scroll bar availaility might change when we scrolled. This is because we do not hide
+ // the scrollbar when it is, in theory, unnecessary, but currently at a position > 0. In this case, it will
+ // be auto-hidden when it's scrolled back to pos 0.
+ if ( m_nTopRow == 0 )
+ m_rAntiImpl.PostUserEvent( LINK( this, TableControl_Impl, OnUpdateScrollbars ) );
+
return (TableSize)( m_nTopRow - nOldTopRow );
}
//--------------------------------------------------------------------
+ TableSize TableControl_Impl::impl_scrollRows( TableSize const i_rowDelta )
+ {
+ DBG_CHECK_ME();
+ return impl_ni_ScrollRows( i_rowDelta );
+ }
+
+ //--------------------------------------------------------------------
TableSize TableControl_Impl::impl_ni_ScrollColumns( TableSize _nColumnDelta )
{
// compute new left column
- ColPos nNewLeftColumn =
+ const ColPos nNewLeftColumn =
::std::max(
::std::min( (ColPos)( m_nLeftColumn + _nColumnDelta ), (ColPos)( m_nColumnCount - 1 ) ),
(ColPos)0
);
- ColPos nOldLeftColumn = m_nLeftColumn;
+ const ColPos nOldLeftColumn = m_nLeftColumn;
m_nLeftColumn = nNewLeftColumn;
// if updates are enabled currently, scroll the viewport
- if ( m_rAntiImpl.IsUpdateMode() && ( m_nLeftColumn != nOldLeftColumn ) )
+ if ( m_nLeftColumn != nOldLeftColumn )
{
DBG_SUSPEND_INV( INV_SCROLL_POSITION );
TempHideCursor aHideCursor( *this );
@@ -1882,17 +1957,29 @@ namespace svt { namespace table
// Same for onEndScroll
// scroll the view port, if possible
- Rectangle aDataArea( Point( m_nRowHeaderWidthPixel, 0 ), m_pDataWindow->GetOutputSizePixel() );
+ const Rectangle aDataArea( Point( m_nRowHeaderWidthPixel, 0 ), m_pDataWindow->GetOutputSizePixel() );
long nPixelDelta =
- ( m_nLeftColumn > 0 ? m_aAccColumnWidthsPixel[ m_nLeftColumn - 1 ] : 0 )
- - ( nOldLeftColumn > 0 ? m_aAccColumnWidthsPixel[ nOldLeftColumn - 1 ] : 0 );
+ m_aColumnWidths[ nOldLeftColumn ].getStart()
+ - m_aColumnWidths[ m_nLeftColumn ].getStart();
+
+ // update our column positions
+ // Do this *before* scrolling, as SCROLL_UPDATE will trigger a paint, which already needs the correct
+ // information in m_aColumnWidths
+ for ( ColumnPositions::iterator colPos = m_aColumnWidths.begin();
+ colPos != m_aColumnWidths.end();
+ ++colPos
+ )
+ {
+ colPos->move( nPixelDelta );
+ }
+ // scroll the window content (if supported and possible), or invalidate the complete window
if ( m_pDataWindow->GetBackground().IsScrollable()
&& abs( nPixelDelta ) < aDataArea.GetWidth()
)
{
- m_pDataWindow->Scroll( (long)-nPixelDelta, 0, aDataArea, SCROLL_CLIP | SCROLL_UPDATE );
+ m_pDataWindow->Scroll( nPixelDelta, 0, aDataArea, SCROLL_CLIP | SCROLL_UPDATE );
}
else
m_pDataWindow->Invalidate( INVALIDATE_UPDATE );
@@ -1901,8 +1988,22 @@ namespace svt { namespace table
m_pHScroll->SetThumbPos( m_nLeftColumn );
}
+ // The scroll bar availaility might change when we scrolled. This is because we do not hide
+ // the scrollbar when it is, in theory, unnecessary, but currently at a position > 0. In this case, it will
+ // be auto-hidden when it's scrolled back to pos 0.
+ if ( m_nLeftColumn == 0 )
+ m_rAntiImpl.PostUserEvent( LINK( this, TableControl_Impl, OnUpdateScrollbars ) );
+
return (TableSize)( m_nLeftColumn - nOldLeftColumn );
}
+
+ //-------------------------------------------------------------------------------
+ TableSize TableControl_Impl::impl_scrollColumns( TableSize const i_columnDelta )
+ {
+ DBG_CHECK_ME();
+ return impl_ni_ScrollColumns( i_columnDelta );
+ }
+
//-------------------------------------------------------------------------------
SelectionEngine* TableControl_Impl::getSelEngine()
{
@@ -1952,12 +2053,13 @@ namespace svt { namespace table
::rtl::OUString& TableControl_Impl::setTooltip(const Point& rPoint )
{
::rtl::OUString aTooltipText;
- RowPos current = getCurrentRow(rPoint);
+ const RowPos hitRow = getRowAtPoint( rPoint );
+ const ColPos hitCol = getColAtPoint( rPoint );
com::sun::star::uno::Sequence< sal_Int32 > cols = m_rAntiImpl.getColumnsForTooltip();
com::sun::star::uno::Sequence< ::rtl::OUString > text = m_rAntiImpl.getTextForTooltip();
if(text.getLength()==0 && cols.getLength()==0)
{
- ::com::sun::star::uno::Any content = m_pModel->getCellContent()[current][m_nCurColumn];
+ ::com::sun::star::uno::Any content = m_pModel->getCellContent()[hitRow][hitCol];
aTooltipText = convertToString(content);
}
else if(text.getLength() == 0)
@@ -1966,13 +2068,13 @@ namespace svt { namespace table
{
if(i==0)
{
- ::com::sun::star::uno::Any content = m_pModel->getCellContent()[current][cols[i]];
+ ::com::sun::star::uno::Any content = m_pModel->getCellContent()[hitRow][cols[i]];
aTooltipText = convertToString(content);
}
else
{
aTooltipText+= ::rtl::OUString::createFromAscii("\n");
- ::com::sun::star::uno::Any content = m_pModel->getCellContent()[current][cols[i]];
+ ::com::sun::star::uno::Any content = m_pModel->getCellContent()[hitRow][cols[i]];
aTooltipText += convertToString(content);
}
}
@@ -2002,7 +2104,7 @@ namespace svt { namespace table
{
if(i==0)
{
- ::com::sun::star::uno::Any content = m_pModel->getCellContent()[current][cols[i]];
+ ::com::sun::star::uno::Any content = m_pModel->getCellContent()[hitRow][cols[i]];
aTooltipText = text[i] + convertToString(content);
}
else
@@ -2011,7 +2113,7 @@ namespace svt { namespace table
aTooltipText+= text[i];
if(nCols > i)
{
- ::com::sun::star::uno::Any content = m_pModel->getCellContent()[current][cols[i]];
+ ::com::sun::star::uno::Any content = m_pModel->getCellContent()[hitRow][cols[i]];
::com::sun::star::uno::Reference< ::com::sun::star::graphic::XGraphic >xGraphic;
aTooltipText += convertToString(content);
}
@@ -2020,168 +2122,196 @@ namespace svt { namespace table
}
return m_aTooltipText = aTooltipText;
}
+
+ //--------------------------------------------------------------------
+ ColPos TableControl_Impl::impl_getColumnForOrdinate( long const i_ordinate ) const
+ {
+ DBG_CHECK_ME();
+
+ if ( m_aColumnWidths.empty() )
+ return COL_INVALID;
+
+ ColumnPositions::const_iterator lowerBound = ::std::lower_bound(
+ m_aColumnWidths.begin(),
+ m_aColumnWidths.end(),
+ i_ordinate + 1,
+ ColumnInfoPositionLess()
+ );
+ if ( lowerBound == m_aColumnWidths.end() )
+ {
+ // point is *behind* the start of the last column ...
+ if ( i_ordinate < m_aColumnWidths.rbegin()->getEnd() )
+ // ... but still before its end
+ return m_nColumnCount - 1;
+ return COL_INVALID;
+ }
+ return lowerBound - m_aColumnWidths.begin();
+ }
+
//--------------------------------------------------------------------
- void TableControl_Impl::resizeColumn(const Point& rPoint)
- {
- Pointer aNewPointer(POINTER_ARROW);
- int headerRowWidth = 0;
- if(m_pModel->hasRowHeaders())
- headerRowWidth = m_rAntiImpl.LogicToPixel( Size(m_pModel->getRowHeaderWidth(), 0 ), MAP_APPFONT ).Width();
- int resizingColumn=m_nCurColumn-m_nLeftColumn;
- PColumnModel pColumn = m_pModel->getColumnModel(m_nCurColumn);
- impl_ni_getAccVisibleColWidths();
- int newColWidth = m_aColumnWidthsPixel[m_nCurColumn];
- //make resize area for the separator wider
- int nLeft = m_aVisibleColumnWidthsPixel[resizingColumn]-4;
- //subtract 1 from m_aAccColumnWidthPixel because right border should be part of the current cell
- int nRight = m_aVisibleColumnWidthsPixel[resizingColumn]-1;
- if( rPoint.X()> nLeft && rPoint.X()<nRight && pColumn->isResizable())
- aNewPointer = Pointer( POINTER_HSPLIT );
- //MouseButton was pressed but not yet released, mouse is moving
- if(m_bResizing)
- {
- if(rPoint.X() > m_pDataWindow->GetOutputSizePixel().Width() || rPoint.X() < m_aVisibleColumnWidthsPixel[resizingColumn]-newColWidth)
- aNewPointer = Pointer( POINTER_NOTALLOWED);
+ void TableControl_Impl::resizeColumn( const Point& rPoint )
+ {
+ Pointer aNewPointer( POINTER_ARROW );
+ const ColPos hitColumn = impl_getColumnForOrdinate( rPoint.X() );
+ if ( m_bResizingColumn )
+ {
+ const ColumnWidthInfo& rColInfo( m_aColumnWidths[ m_nResizingColumn ] );
+ if ( ( rPoint.X() > m_pDataWindow->GetOutputSizePixel().Width() )
+ || ( rPoint.X() < rColInfo.getStart() )
+ )
+ {
+ aNewPointer = Pointer( POINTER_NOTALLOWED );
+ }
else
+ {
aNewPointer = Pointer( POINTER_HSPLIT );
+ }
m_pDataWindow->HideTracking();
- int lineHeight = 0;
- if(m_pModel->hasColumnHeaders())
- lineHeight+= m_nColHeaderHeightPixel;
- lineHeight+=m_nRowHeightPixel*m_nRowCount;
- int gridHeight = m_pDataWindow->GetOutputSizePixel().Height();
- if(lineHeight >= gridHeight)
+
+ int lineHeight = m_nColHeaderHeightPixel;
+ lineHeight += m_nRowHeightPixel * m_nRowCount;
+ const int gridHeight = m_pDataWindow->GetOutputSizePixel().Height();
+ if ( lineHeight >= gridHeight )
lineHeight = gridHeight;
- m_pDataWindow->ShowTracking(Rectangle(Point(rPoint.X(),0), Size(1, lineHeight )),
- SHOWTRACK_SPLIT | SHOWTRACK_WINDOW);
+
+ m_pDataWindow->ShowTracking(
+ Rectangle(
+ Point( rPoint.X(), 0 ),
+ Size( 1, lineHeight )
+ ),
+ SHOWTRACK_SPLIT | SHOWTRACK_WINDOW
+ );
}
- m_pDataWindow->SetPointer(aNewPointer);
+ else if ( hitColumn != COL_INVALID )
+ {
+ // hit test for the column separator
+ const PColumnModel pColumn = m_pModel->getColumnModel( hitColumn );
+ const ColumnWidthInfo& rColInfo( m_aColumnWidths[ hitColumn ] );
+ if ( ( rColInfo.getEnd() - 2 <= rPoint.X() )
+ && ( rColInfo.getEnd() + 2 > rPoint.X() )
+ && pColumn->isResizable()
+ )
+ aNewPointer = Pointer( POINTER_HSPLIT );
+ }
+
+ m_pDataWindow->SetPointer( aNewPointer );
}
+
//--------------------------------------------------------------------
- bool TableControl_Impl::startResizeColumn(const Point& rPoint)
+ bool TableControl_Impl::checkResizeColumn( const Point& rPoint )
{
m_bResizingGrid = false;
- m_nResizingColumn = m_nCurColumn;
- PColumnModel pColumn = m_pModel->getColumnModel(m_nResizingColumn);
- //make resize area for the separator wider
- int nLeft = m_aVisibleColumnWidthsPixel[m_nResizingColumn-m_nLeftColumn]-4;
- int nRight = m_aVisibleColumnWidthsPixel[m_nResizingColumn-m_nLeftColumn]-1;
- if(rPoint.X()> nLeft && rPoint.X()<nRight && pColumn->isResizable())
+
+ if ( m_bResizingColumn )
+ return true;
+
+ const ColPos hitColumn = impl_getColumnForOrdinate( rPoint.X() );
+ if ( hitColumn == COL_INVALID )
+ return false;
+
+ const PColumnModel pColumn = m_pModel->getColumnModel( hitColumn );
+ const ColumnWidthInfo& rColInfo( m_aColumnWidths[ hitColumn ] );
+
+ // hit test for the column separator
+ if ( ( rColInfo.getEnd() - 2 <= rPoint.X() )
+ && ( rColInfo.getEnd() + 2 > rPoint.X() )
+ && pColumn->isResizable()
+ )
{
+ m_nResizingColumn = hitColumn;
m_pDataWindow->CaptureMouse();
- m_bResizing = true;
+ m_bResizingColumn = true;
}
- return m_bResizing;
+ return m_bResizingColumn;
}
//--------------------------------------------------------------------
- bool TableControl_Impl::endResizeColumn(const Point& rPoint)
+ bool TableControl_Impl::endResizeColumn( const Point& rPoint )
{
- if(m_bResizing)
+ DBG_CHECK_ME();
+ ENSURE_OR_RETURN_FALSE( m_bResizingColumn, "TableControl_Impl::endResizeColumn: not resizing currently!" );
+
+ m_pDataWindow->HideTracking();
+ const PColumnModel pColumn = m_pModel->getColumnModel( m_nResizingColumn );
+ const long maxWidthLogical = pColumn->getMaxWidth();
+ const long minWidthLogical = pColumn->getMinWidth();
+
+ // new position of mouse
+ const long requestedEnd = rPoint.X();
+
+ // old position of right border
+ const long oldEnd = m_aColumnWidths[ m_nResizingColumn ].getEnd();
+
+ // position of left border if cursor in the to-be-resized column
+ const long columnStart = m_aColumnWidths[ m_nResizingColumn ].getStart();
+ const long requestedWidth = requestedEnd - columnStart;
+ // TODO: this is not correct, strictly: It assumes that the mouse was pressed exactly on the "end" pos,
+ // but for a while now, we have relaxed this, and allow clicking a few pixels aside, too
+
+ if ( requestedEnd >= columnStart )
{
- m_pDataWindow->HideTracking();
- PColumnModel pColumn = m_pModel->getColumnModel(m_nResizingColumn);
- int maxWidth = m_rAntiImpl.LogicToPixel( Size( pColumn->getMaxWidth(), 0 ), MAP_APPFONT ).Width();
- int minWidth = m_rAntiImpl.LogicToPixel( Size( pColumn->getMinWidth(), 0 ), MAP_APPFONT ).Width();
- int resizeCol = m_nResizingColumn-m_nLeftColumn;
- //new position of mouse
- int actX = rPoint.X();
- //old position of right border
- int oldX = m_aVisibleColumnWidthsPixel[resizeCol];
- //position of left border if cursor in the first cell
- int leftX = 0;
- if(m_nResizingColumn > m_nLeftColumn)
- leftX = m_aVisibleColumnWidthsPixel[resizeCol-1];
- else if(m_nResizingColumn == m_nLeftColumn && m_pModel->hasRowHeaders())
- leftX = m_rAntiImpl.LogicToPixel( Size( m_pModel->getRowHeaderWidth(), 0 ), MAP_APPFONT ).Width();
- int actWidth = actX - leftX;
- int newActWidth = 0;
- //minimize the column width
- if(oldX > actX && actX >= leftX)
+ long requestedWidthLogical = m_rAntiImpl.PixelToLogic( Size( requestedWidth, 0 ), MAP_APPFONT ).Width();
+ // respect column width limits
+ if ( oldEnd > requestedEnd )
{
- if(minWidth < actWidth)
- {
- newActWidth = m_rAntiImpl.PixelToLogic( Size( actWidth, 0 ), MAP_APPFONT ).Width();
- pColumn->setPreferredWidth(newActWidth);
- }
- else
- pColumn->setPreferredWidth(pColumn->getMinWidth());
- if(m_nLeftColumn != 0)
- impl_updateLeftColumn();
- }
- else if(oldX < actX)
- {
- if(actWidth < maxWidth)
+ // column has become smaller, check against minimum width
+ if ( ( minWidthLogical != 0 ) && ( requestedWidthLogical < minWidthLogical ) )
+ requestedWidthLogical = minWidthLogical;
+
+ // impl_updateLeftColumn();
+ // does this make sense here? We didn't call impl_ni_updateColumnWidths, yet, so m_aColumnWidths
+ // still contains the old values
+ }
+ else if ( oldEnd < requestedEnd )
{
- newActWidth = m_rAntiImpl.PixelToLogic( Size( actWidth, 0 ), MAP_APPFONT ).Width();
- pColumn->setPreferredWidth(newActWidth);
+ // column has become larger, check against max width
+ if ( ( maxWidthLogical != 0 ) && ( requestedWidthLogical >= maxWidthLogical ) )
+ requestedWidthLogical = maxWidthLogical;
}
- else
- pColumn->setPreferredWidth(pColumn->getMaxWidth());
+ pColumn->setPreferredWidth( requestedWidthLogical );
}
- m_nCurColumn = m_nResizingColumn;
+
impl_ni_updateColumnWidths();
impl_ni_updateScrollbars();
- m_pDataWindow->Invalidate(INVALIDATE_UPDATE);
- m_pDataWindow->SetPointer(Pointer());
- m_bResizing = false;
+ m_pDataWindow->Invalidate( INVALIDATE_UPDATE );
+ m_pDataWindow->SetPointer( Pointer() );
+ m_bResizingColumn = false;
m_bResizingGrid = true;
+
+ m_pDataWindow->ReleaseMouse();
+ return m_bResizingColumn;
}
- m_pDataWindow->ReleaseMouse();
- return m_bResizing;
- }
+
//-------------------------------------------------------------------------------
- void TableControl_Impl::impl_ni_getAccVisibleColWidths()
+ void TableControl_Impl::impl_updateLeftColumn()
{
- TableSize nVisCols = impl_getVisibleColumns(true);
- int widthsPixel = 0;
- m_aVisibleColumnWidthsPixel.resize(0);
- m_aVisibleColumnWidthsPixel.reserve(nVisCols);
- int headerRowWidth = 0;
- if(m_pModel->hasRowHeaders())
- {
- headerRowWidth = m_rAntiImpl.LogicToPixel( Size(m_pModel->getRowHeaderWidth(), 0 ), MAP_APPFONT ).Width();
- widthsPixel+=headerRowWidth;
- }
- int col = m_nLeftColumn;
- while(nVisCols)
+ DBG_CHECK_ME();
+ if ( m_nLeftColumn == 0 )
+ return;
+
+ // the right end of the last column
+ const long lastColumnEnd = m_aColumnWidths[ m_nColumnCount - 1 ].getEnd();
+
+ // free space at the right of the last column
+ const long freeSpace = m_pDataWindow->GetOutputSizePixel().Width() - lastColumnEnd;
+
+ // if the columnd left of the currently-left-most column would fit into the free
+ // space, then implicitly scroll
+ const long leftNeighbourWidth = m_aColumnWidths[ m_nLeftColumn - 1 ].getWidth();
+ if ( leftNeighbourWidth < freeSpace )
{
- m_aVisibleColumnWidthsPixel.push_back(widthsPixel+=m_aColumnWidthsPixel[col]);
- col++;
- nVisCols--;
+ for ( ColumnPositions::iterator colPos = m_aColumnWidths.begin();
+ colPos != m_aColumnWidths.end();
+ ++colPos
+ )
+ {
+ colPos->move( leftNeighbourWidth );
+ }
+
+ --m_nLeftColumn;
+ // TODO: wouldn't this require updating the scrollbar?
}
- }
- //-------------------------------------------------------------------------------
- void TableControl_Impl::impl_updateLeftColumn()
- {
- int nVisCols = m_aVisibleColumnWidthsPixel.size();
- int headerRowWidth = 0;
- //sum of currently visible columns
- int widthsPixel = 0;
- //header pixel should be added, because header doesn't vanish when scrolling
- if(m_pModel->hasRowHeaders())
- {
- headerRowWidth = m_rAntiImpl.LogicToPixel( Size(m_pModel->getRowHeaderWidth(), 0 ), MAP_APPFONT ).Width();
- widthsPixel+=headerRowWidth;
- }
- int col = m_nLeftColumn;
- //add column width of the neighbour of the left column
- widthsPixel+=m_aColumnWidthsPixel[col-1];
- //compute the sum of the new column widths
- while(nVisCols)
- {
- PColumnModel pColumn = m_pModel->getColumnModel(col);
- int colWidth = pColumn->getWidth();
- int colPrefWidth = pColumn->getPreferredWidth();
- if(colPrefWidth!=0)
- colWidth = colPrefWidth;
- widthsPixel += m_rAntiImpl.LogicToPixel( Size( colWidth, 0 ), MAP_APPFONT ).Width();
- col++;
- nVisCols--;
- }
- //when the sum of all visible columns and the next to the left column is smaller than
- //window width, then update m_nLeftColumn
- if(widthsPixel<m_pDataWindow->GetOutputSizePixel().Width())
- m_nLeftColumn--;
+
+ // TODO: isnt' it that this might be done repeatedly?
}
//--------------------------------------------------------------------
rtl::OUString TableControl_Impl::convertToString(const ::com::sun::star::uno::Any& value)
@@ -2221,6 +2351,14 @@ namespace svt { namespace table
}
//--------------------------------------------------------------------
+ IMPL_LINK( TableControl_Impl, OnUpdateScrollbars, void*, /**/ )
+ {
+ DBG_CHECK_ME();
+ impl_ni_updateScrollbars();
+ return 1L;
+ }
+
+ //--------------------------------------------------------------------
IMPL_LINK( TableControl_Impl, OnScroll, ScrollBar*, _pScrollbar )
{
DBG_ASSERT( ( _pScrollbar == m_pVScroll ) || ( _pScrollbar == m_pHScroll ),
@@ -2261,26 +2399,27 @@ namespace svt { namespace table
BOOL TableFunctionSet::SetCursorAtPoint(const Point& rPoint, BOOL bDontSelectAtCursor)
{
BOOL bHandled = FALSE;
- Rectangle rCells;
- //curRow is the row where the mouse click happened, m_nCurRow is the last selected row, before the mouse click
- RowPos curRow = m_pTableControl->getCurrentRow(rPoint);
- if(curRow == -2)
+ // newRow is the row which includes the point, m_nCurRow is the last selected row, before the mouse click
+ const RowPos newRow = m_pTableControl->getRowAtPoint( rPoint );
+ const ColPos newCol = m_pTableControl->getColAtPoint( rPoint );
+ if ( ( newRow == ROW_INVALID ) || ( newCol == COL_INVALID ) )
return FALSE;
- if( bDontSelectAtCursor )
+
+ if ( bDontSelectAtCursor )
{
- if(m_pTableControl->m_nRowSelected.size()>1)
+ if ( m_pTableControl->m_nRowSelected.size()>1 )
m_pTableControl->m_pSelEngine->AddAlways(TRUE);
bHandled = TRUE;
}
- else if(m_pTableControl->m_nAnchor == m_pTableControl->m_nCurRow)
+ else if ( m_pTableControl->m_nAnchor == m_pTableControl->m_nCurRow )
{
//selecting region,
- int diff = m_pTableControl->m_nCurRow - curRow;
+ int diff = m_pTableControl->m_nCurRow - newRow;
//selected region lies above the last selection
if( diff >= 0)
{
//put selected rows in vector
- while(m_pTableControl->m_nAnchor>=curRow)
+ while ( m_pTableControl->m_nAnchor >= newRow )
{
bool isAlreadySelected = m_pTableControl->isRowSelected(m_pTableControl->m_nRowSelected, m_pTableControl->m_nAnchor);
//if row isn't selected, put it in vector, otherwise don't put it there, because it will be twice there
@@ -2294,7 +2433,7 @@ namespace svt { namespace table
//selected region lies beneath the last selected row
else
{
- while(m_pTableControl->m_nAnchor<=curRow)
+ while ( m_pTableControl->m_nAnchor <= newRow )
{
bool isAlreadySelected = m_pTableControl->isRowSelected(m_pTableControl->m_nRowSelected, m_pTableControl->m_nAnchor);
if(!isAlreadySelected)
@@ -2304,35 +2443,39 @@ namespace svt { namespace table
}
m_pTableControl->m_nAnchor--;
}
- m_pTableControl->invalidateSelectedRegion(m_pTableControl->m_nCurRow, curRow, rCells);
+ Rectangle aCellRect;
+ m_pTableControl->invalidateSelectedRegion( m_pTableControl->m_nCurRow, newRow, aCellRect );
bHandled = TRUE;
}
//no region selected
else
{
if(m_pTableControl->m_nRowSelected.empty())
- m_pTableControl->m_nRowSelected.push_back(curRow);
+ m_pTableControl->m_nRowSelected.push_back( newRow );
else
{
if(m_pTableControl->m_pSelEngine->GetSelectionMode()==SINGLE_SELECTION)
{
DeselectAll();
- m_pTableControl->m_nRowSelected.push_back(curRow);
+ m_pTableControl->m_nRowSelected.push_back( newRow );
}
else
{
- bool isAlreadySelected = m_pTableControl->isRowSelected(m_pTableControl->m_nRowSelected, curRow);
- if(!isAlreadySelected)
- m_pTableControl->m_nRowSelected.push_back(curRow);
+ bool isAlreadySelected = m_pTableControl->isRowSelected( m_pTableControl->m_nRowSelected, newRow );
+ if ( !isAlreadySelected )
+ m_pTableControl->m_nRowSelected.push_back( newRow );
}
}
if(m_pTableControl->m_nRowSelected.size()>1 && m_pTableControl->m_pSelEngine->GetSelectionMode()!=SINGLE_SELECTION)
m_pTableControl->m_pSelEngine->AddAlways(TRUE);
- m_pTableControl->invalidateSelectedRegion(curRow, curRow, rCells);
+
+ Rectangle aCellRect;
+ m_pTableControl->invalidateSelectedRegion( newRow, newRow, aCellRect );
bHandled = TRUE;
}
- m_pTableControl->m_nCurRow = curRow;
- m_pTableControl->ensureVisible(m_pTableControl->m_nCurColumn,m_pTableControl->m_nCurRow,false);
+ m_pTableControl->m_nCurRow = newRow;
+ m_pTableControl->m_nCurColumn = newCol;
+ m_pTableControl->ensureVisible( newCol, newRow, true );
return bHandled;
}
//-------------------------------------------------------------------------------
@@ -2343,7 +2486,7 @@ namespace svt { namespace table
return FALSE;
else
{
- RowPos curRow = m_pTableControl->getCurrentRow(rPoint);
+ RowPos curRow = m_pTableControl->getRowAtPoint( rPoint );
m_pTableControl->m_nAnchor = -1;
bool selected = m_pTableControl->isRowSelected(m_pTableControl->m_nRowSelected, curRow);
m_nCurrentRow = curRow;
diff --git a/svtools/source/table/tablecontrol_impl.hxx b/svtools/source/table/tablecontrol_impl.hxx
index b456cf248bed..91a57752fca2 100755
--- a/svtools/source/table/tablecontrol_impl.hxx
+++ b/svtools/source/table/tablecontrol_impl.hxx
@@ -43,7 +43,53 @@ namespace svt { namespace table
{
//........................................................................
- typedef ::std::vector< long > ArrayOfLong;
+ struct ColumnWidthInfo
+ {
+ ColumnWidthInfo()
+ :nStartPixel( 0 )
+ ,nEndPixel( 0 )
+ {
+ }
+
+ ColumnWidthInfo( long const i_startPixel, long const i_endPixel )
+ :nStartPixel( i_startPixel )
+ ,nEndPixel( i_endPixel )
+ {
+ }
+
+ long getStart() const { return nStartPixel; }
+ long getEnd() const { return nEndPixel; }
+
+ void setEnd( long const i_end ) { nEndPixel = i_end; }
+ void move( long const i_offset ) { nStartPixel += i_offset; nEndPixel += i_offset; }
+
+ long getWidth() const { return nEndPixel - nStartPixel; }
+
+ private:
+ /** the start of the column, in pixels. Might be negative, in case the column is scrolled out of the visible
+ area.
+ */
+ long nStartPixel;
+
+ /** the end of the column, in pixels, plus 1. Effectively, this is the accumulated width of a all columns
+ up to the current one.
+ */
+ long nEndPixel;
+ };
+
+ struct ColumnInfoPositionLess
+ {
+ bool operator()( ColumnWidthInfo const& i_colInfo, long const i_position )
+ {
+ return i_colInfo.getEnd() < i_position;
+ }
+ bool operator()( long const i_position, ColumnWidthInfo const& i_colInfo )
+ {
+ return i_position < i_colInfo.getStart();
+ }
+ };
+
+ typedef ::std::vector< ColumnWidthInfo > ColumnPositions;
class TableControl;
class TableDataWindow;
@@ -59,7 +105,8 @@ namespace svt { namespace table
friend class TableRowGeometry;
friend class TableColumnGeometry;
friend class SuspendInvariants;
- friend class TableFunctionSet;
+ friend class TableFunctionSet;
+
private:
/// the control whose impl-instance we implemnt
TableControl& m_rAntiImpl;
@@ -67,14 +114,9 @@ namespace svt { namespace table
PTableModel m_pModel;
/// the input handler to use, usually the input handler as provided by ->m_pModel
PTableInputHandler m_pInputHandler;
- /// the widths of the single columns, measured in pixel
- ArrayOfLong m_aColumnWidthsPixel;
- /** the accumulated widths of the single columns, i.e. their exclusive right borders,
- <strong<not</strong> counting the space for a possible row header column
- */
- ArrayOfLong m_aAccColumnWidthsPixel;
+ /// info about the widths of our columns
+ ColumnPositions m_aColumnWidths;
- ArrayOfLong m_aVisibleColumnWidthsPixel;
/// the height of a single row in the table, measured in pixels
long m_nRowHeightPixel;
/// the height of the column header row in the table, measured in pixels
@@ -103,7 +145,7 @@ namespace svt { namespace table
/// the vertical scrollbar, if any
ScrollBar* m_pVScroll;
/// the horizontal scrollbar, if any
- ScrollBar* m_pHScroll;
+ ScrollBar* m_pHScroll;
ScrollBarBox* m_pScrollCorner;
//selection engine - for determining selection range, e.g. single, multiple
SelectionEngine* m_pSelEngine;
@@ -112,11 +154,11 @@ namespace svt { namespace table
//part of selection engine
TableFunctionSet* m_pTableFunctionSet;
//part of selection engine
- RowPos m_nAnchor;
- bool m_bResizing;
- ColPos m_nResizingColumn;
- bool m_bResizingGrid;
- rtl::OUString m_aTooltipText;
+ RowPos m_nAnchor;
+ bool m_bResizingColumn;
+ ColPos m_nResizingColumn;
+ bool m_bResizingGrid;
+ rtl::OUString m_aTooltipText;
#if DBG_UTIL
#define INV_SCROLL_POSITION 1
@@ -143,8 +185,6 @@ namespace svt { namespace table
inline long getRowCount() const { return m_nRowCount; }
inline long getColumnCount() const { return m_nColumnCount; }
- inline long getColHeaderHightPixel() const { return m_nColHeaderHeightPixel; }
-
inline const TableControl& getAntiImpl() const { return m_rAntiImpl; }
inline TableControl& getAntiImpl() { return m_rAntiImpl; }
@@ -181,10 +221,7 @@ namespace svt { namespace table
<TRUE/> if it's okay that the given cooordinate is only partially visible
*/
void ensureVisible( ColPos _nColumn, RowPos _nRow, bool _bAcceptPartialVisibility );
- /** returns the row, which contains the input point*/
- virtual RowPos getCurrentRow (const Point& rPoint);
- void setCursorAtCurrentCell(const Point& rPoint);
/** checks whether the vector with the selected rows contains the current row*/
BOOL isRowSelected(const ::std::vector<RowPos>& selectedRows, RowPos current);
@@ -201,16 +238,19 @@ namespace svt { namespace table
void removeSelectedRow(RowPos _nRowPos);
void invalidateRows();
void clearSelection();
- // IAbstractTableControl
- virtual void hideCursor();
- virtual void showCursor();
- virtual bool dispatchAction( TableControlAction _eAction );
- virtual SelectionEngine* getSelEngine();
- virtual bool isTooltipActive();
- virtual rtl::OUString& setTooltip(const Point& rPoint );
- virtual void resizeColumn(const Point& rPoint);
- virtual bool startResizeColumn(const Point& rPoint);
- virtual bool endResizeColumn(const Point& rPoint);
+ // IAbstractTableControl
+ virtual void hideCursor();
+ virtual void showCursor();
+ virtual bool dispatchAction( TableControlAction _eAction );
+ virtual SelectionEngine* getSelEngine();
+ virtual void activateCellAt( const Point& rPoint );
+ virtual bool isTooltipActive();
+ virtual rtl::OUString& setTooltip(const Point& rPoint );
+ virtual RowPos getRowAtPoint( const Point& rPoint );
+ virtual ColPos getColAtPoint( const Point& rPoint );
+ virtual void resizeColumn(const Point& rPoint);
+ virtual bool checkResizeColumn(const Point& rPoint);
+ virtual bool endResizeColumn(const Point& rPoint);
TableDataWindow* getDataWindow();
ScrollBar* getHorzScrollbar();
@@ -301,6 +341,10 @@ namespace svt { namespace table
*/
TableSize impl_ni_ScrollRows( TableSize _nRowDelta );
+ /** equivalent to impl_ni_ScrollRows, but checks the instances invariants beforehand (in a non-product build only)
+ */
+ TableSize impl_scrollRows( TableSize const i_rowDelta );
+
/** scrolls the view by the given number of columns
The method is not bound to the classes public invariants, as it's used in
@@ -311,8 +355,13 @@ namespace svt { namespace table
from the given numbers to scroll in case the begin or the end of the
column range were reached.
*/
- TableSize impl_ni_ScrollColumns( TableSize _nRowDelta );
- /** retrieves the area occupied by the totality of (at least partially) visible cells
+ TableSize impl_ni_ScrollColumns( TableSize _nColumnDelta );
+
+ /** equivalent to impl_ni_ScrollColumns, but checks the instances invariants beforehand (in a non-product build only)
+ */
+ TableSize impl_scrollColumns( TableSize const i_columnDelta );
+
+ /** retrieves the area occupied by the totality of (at least partially) visible cells
The returned area includes row and column headers. Also, it takes into
account the the fact that there might be less columns than would normally
@@ -330,11 +379,16 @@ namespace svt { namespace table
*/
void impl_getAllVisibleDataCellArea( Rectangle& _rCellArea ) const;
- void impl_ni_getAccVisibleColWidths();
+ /** retrieves the column which covers the given ordinate
+ */
+ ColPos impl_getColumnForOrdinate( long const i_ordinate ) const;
+
void impl_updateLeftColumn();
DECL_LINK( OnScroll, ScrollBar* );
+ DECL_LINK( OnUpdateScrollbars, void* );
};
+
//see seleng.hxx, seleng.cxx, FunctionSet overridables, part of selection engine
class TableFunctionSet : public FunctionSet
{
diff --git a/svtools/source/table/tabledatawindow.cxx b/svtools/source/table/tabledatawindow.cxx
index bbd7f6829369..41bd851e6b82 100644
--- a/svtools/source/table/tabledatawindow.cxx
+++ b/svtools/source/table/tabledatawindow.cxx
@@ -83,14 +83,14 @@ namespace svt { namespace table
Point aPoint = rMEvt.GetPosPixel();
if ( !m_rTableControl.getInputHandler()->MouseMove( m_rTableControl, rMEvt ) )
{
- if(m_rTableControl.getCurrentRow(aPoint)>=0 && m_rTableControl.isTooltipActive() )
+ if ( m_rTableControl.isTooltipActive() && m_rTableControl.getRowAtPoint( aPoint ) >= 0 )
{
SetPointer(POINTER_ARROW);
- rtl::OUString& rHelpText = m_rTableControl.setTooltip(aPoint);
+ const ::rtl::OUString& rHelpText = m_rTableControl.setTooltip(aPoint);
Help::EnableBalloonHelp();
- Window::SetHelpText( rHelpText.getStr());
+ Window::SetHelpText( rHelpText );
}
- else if(m_rTableControl.getCurrentRow(aPoint) == -1)
+ else if ( m_rTableControl.getRowAtPoint( aPoint ) == ROW_COL_HEADERS )
{
if(Help::IsBalloonHelpEnabled())
Help::DisableBalloonHelp();
@@ -107,8 +107,8 @@ namespace svt { namespace table
//--------------------------------------------------------------------
void TableDataWindow::MouseButtonDown( const MouseEvent& rMEvt )
{
- Point aPoint = rMEvt.GetPosPixel();
- RowPos nCurRow = m_rTableControl.getCurrentRow(aPoint);
+ const Point aPoint = rMEvt.GetPosPixel();
+ const RowPos nCurRow = m_rTableControl.getRowAtPoint( aPoint );
std::vector<RowPos> selectedRows(m_rTableControl.getSelectedRows());
if ( !m_rTableControl.getInputHandler()->MouseButtonDown( m_rTableControl, rMEvt ) )
Window::MouseButtonDown( rMEvt );
@@ -125,7 +125,6 @@ namespace svt { namespace table
}
}
m_aMouseButtonDownHdl.Call((MouseEvent*) &rMEvt);
- m_rTableControl.getAntiImpl().LoseFocus();
}
//--------------------------------------------------------------------
void TableDataWindow::MouseButtonUp( const MouseEvent& rMEvt )
@@ -133,7 +132,7 @@ namespace svt { namespace table
if ( !m_rTableControl.getInputHandler()->MouseButtonUp( m_rTableControl, rMEvt ) )
Window::MouseButtonUp( rMEvt );
m_aMouseButtonUpHdl.Call((MouseEvent*) &rMEvt);
- m_rTableControl.getAntiImpl().GetFocus();
+ m_rTableControl.getAntiImpl().GrabFocus();
}
//--------------------------------------------------------------------
void TableDataWindow::SetPointer( const Pointer& rPointer )
diff --git a/svtools/source/table/tablegeometry.cxx b/svtools/source/table/tablegeometry.cxx
index d60de9e6438f..01425f3bb292 100644
--- a/svtools/source/table/tablegeometry.cxx
+++ b/svtools/source/table/tablegeometry.cxx
@@ -49,30 +49,42 @@ namespace svt { namespace table
{
if ( m_nRowPos == ROW_COL_HEADERS )
{
- //DBG_ASSERT( m_rControl.m_pModel->hasColumnHeaders(),
- // "TableRowGeometry::TableRowGeometry: why asking for the geoemtry of the non-existent column header row?" );
m_aRect.Top() = 0;
m_aRect.Bottom() = m_rControl.m_nColHeaderHeightPixel - 1;
}
else
{
- if ( ( m_nRowPos >= m_rControl.m_nTopRow ) && ( m_nRowPos < m_rControl.m_pModel->getRowCount() ) )
- {
- m_aRect.Top() = m_rControl.m_nColHeaderHeightPixel + ( m_nRowPos - m_rControl.m_nTopRow ) * m_rControl.m_nRowHeightPixel;
- m_aRect.Bottom() = m_aRect.Top() + m_rControl.m_nRowHeightPixel - 1;
- }
- else
- m_aRect.SetEmpty();
+ impl_initRect();
}
}
//--------------------------------------------------------------------
- bool TableRowGeometry::moveDown()
+ void TableRowGeometry::impl_initRect()
{
- if ( ++m_nRowPos < m_rControl.m_pModel->getRowCount() )
- m_aRect.Move( 0, m_rControl.m_nRowHeightPixel );
+ if ( ( m_nRowPos >= m_rControl.m_nTopRow ) && ( m_nRowPos < m_rControl.m_pModel->getRowCount() ) )
+ {
+ m_aRect.Top() = m_rControl.m_nColHeaderHeightPixel + ( m_nRowPos - m_rControl.m_nTopRow ) * m_rControl.m_nRowHeightPixel;
+ m_aRect.Bottom() = m_aRect.Top() + m_rControl.m_nRowHeightPixel - 1;
+ }
else
m_aRect.SetEmpty();
+ }
+
+ //--------------------------------------------------------------------
+ bool TableRowGeometry::moveDown()
+ {
+ if ( m_nRowPos == ROW_COL_HEADERS )
+ {
+ m_nRowPos = m_rControl.m_nTopRow;
+ impl_initRect();
+ }
+ else
+ {
+ if ( ++m_nRowPos < m_rControl.m_pModel->getRowCount() )
+ m_aRect.Move( 0, m_rControl.m_nRowHeightPixel );
+ else
+ m_aRect.SetEmpty();
+ }
return isValid();
}
@@ -87,41 +99,50 @@ namespace svt { namespace table
{
if ( m_nColPos == COL_ROW_HEADERS )
{
-/* DBG_ASSERT( m_rControl.m_pModel->hasRowHeaders(),
- "TableColumnGeometry::TableColumnGeometry: why asking for the geoemtry of the non-existent row header column?" )*/;
m_aRect.Left() = 0;
m_aRect.Right() = m_rControl.m_nRowHeaderWidthPixel - 1;
}
else
{
- ColPos nLeftColumn = m_rControl.m_nLeftColumn;
- if ( ( m_nColPos >= nLeftColumn ) && ( m_nColPos < (ColPos)m_rControl.m_aColumnWidthsPixel.size() ) )
- {
- m_aRect.Left() = m_rControl.m_nRowHeaderWidthPixel;
- // TODO: take into account any possibly frozen columns
+ impl_initRect();
+ }
+ }
- for ( ColPos col = nLeftColumn; col < m_nColPos; ++col )
- m_aRect.Left() += m_rControl.m_aColumnWidthsPixel[ col ];
- m_aRect.Right() = m_aRect.Left() + m_rControl.m_aColumnWidthsPixel[ m_nColPos ] - 1;
- }
- else
- m_aRect.SetEmpty();
+ //--------------------------------------------------------------------
+ void TableColumnGeometry::impl_initRect()
+ {
+ ColPos nLeftColumn = m_rControl.m_nLeftColumn;
+ if ( ( m_nColPos >= nLeftColumn ) && ( m_nColPos < (ColPos)m_rControl.m_aColumnWidths.size() ) )
+ {
+ m_aRect.Left() = m_rControl.m_nRowHeaderWidthPixel;
+ // TODO: take into account any possibly frozen columns
+
+ for ( ColPos col = nLeftColumn; col < m_nColPos; ++col )
+ m_aRect.Left() += m_rControl.m_aColumnWidths[ col ].getWidth();
+ m_aRect.Right() = m_aRect.Left() + m_rControl.m_aColumnWidths[ m_nColPos ].getWidth() - 1;
}
+ else
+ m_aRect.SetEmpty();
}
//--------------------------------------------------------------------
bool TableColumnGeometry::moveRight()
{
- DBG_ASSERT( m_nColPos != COL_ROW_HEADERS, "TableColumnGeometry::moveRight: cannot move the row header column!" );
- // what would be COL_ROW_HEADERS + 1?
-
- if ( ++m_nColPos < (ColPos)m_rControl.m_aColumnWidthsPixel.size() )
+ if ( m_nColPos == COL_ROW_HEADERS )
{
- m_aRect.Left() = m_aRect.Right() + 1;
- m_aRect.Right() += m_rControl.m_aColumnWidthsPixel[ m_nColPos ];
+ m_nColPos = m_rControl.m_nLeftColumn;
+ impl_initRect();
}
else
- m_aRect.SetEmpty();
+ {
+ if ( ++m_nColPos < (ColPos)m_rControl.m_aColumnWidths.size() )
+ {
+ m_aRect.Left() = m_aRect.Right() + 1;
+ m_aRect.Right() += m_rControl.m_aColumnWidths[ m_nColPos ].getWidth();
+ }
+ else
+ m_aRect.SetEmpty();
+ }
return isValid();
}
diff --git a/svtools/source/table/tablegeometry.hxx b/svtools/source/table/tablegeometry.hxx
index 3ddde0c98c64..7bfc2527d5fc 100644
--- a/svtools/source/table/tablegeometry.hxx
+++ b/svtools/source/table/tablegeometry.hxx
@@ -91,6 +91,9 @@ namespace svt { namespace table
RowPos getRow() const { return m_nRowPos; }
// operations
bool moveDown();
+
+ private:
+ void impl_initRect();
};
//====================================================================
@@ -112,6 +115,9 @@ namespace svt { namespace table
ColPos getCol() const { return m_nColPos; }
// operations
bool moveRight();
+
+ private:
+ void impl_initRect();
};
//====================================================================
diff --git a/svtools/source/uno/svtxgridcontrol.cxx b/svtools/source/uno/svtxgridcontrol.cxx
index 1a6ce6ff88e5..8d4a20be3c43 100644
--- a/svtools/source/uno/svtxgridcontrol.cxx
+++ b/svtools/source/uno/svtxgridcontrol.cxx
@@ -99,7 +99,7 @@ sal_Int32 SAL_CALL SVTXGridControl::getItemIndexAtPoint(::sal_Int32 x, ::sal_Int
TableControl* pTable = dynamic_cast< TableControl* >( GetWindow() );
ENSURE_OR_RETURN( pTable != NULL, "SVTXGridControl::getItemIndexAtPoint: no control (anymore)!", -1 );
- return pTable->GetCurrentRow( Point(x,y) );
+ return pTable->GetRowAtPoint( Point( x, y ) );
}
// ---------------------------------------------------------------------------------------------------------------------
@@ -398,7 +398,6 @@ void SAL_CALL SVTXGridControl::rowAdded(const ::com::sun::star::awt::grid::GridD
{
m_xColumnModel->setDefaultColumns(rawRowData.getLength());
// this will trigger notifications, which in turn will let us update our m_pTableModel
-
}
else if((unsigned int)rawRowData.getLength()!=(unsigned)colCount)
throw GridInvalidDataException( ::rtl::OUString::createFromAscii("The column count doesn't match with the length of row data"), *this );
diff --git a/svtools/source/uno/unocontroltablemodel.cxx b/svtools/source/uno/unocontroltablemodel.cxx
index 4ed310aa8b28..a4c4b4f0a29c 100644
--- a/svtools/source/uno/unocontroltablemodel.cxx
+++ b/svtools/source/uno/unocontroltablemodel.cxx
@@ -229,7 +229,7 @@ using namespace ::com::sun::star::awt::grid;
:aColumns ( )
,nRowCount ( 0 )
,bHasColumnHeaders ( true )
- ,bHasRowHeaders ( true )
+ ,bHasRowHeaders ( false )
,bVScroll ( false )
,bHScroll ( false )
,pRenderer ( )
@@ -257,7 +257,7 @@ using namespace ::com::sun::star::awt::grid;
:m_pImpl( new UnoControlTableModel_Impl )
{
m_pImpl->bHasColumnHeaders = true;
- m_pImpl->bHasRowHeaders = true;
+ m_pImpl->bHasRowHeaders = false;
m_pImpl->pRenderer.reset( new GridTableRenderer( *this ) );
m_pImpl->pInputHandler.reset( new DefaultInputHandler );
}
@@ -340,7 +340,7 @@ using namespace ::com::sun::star::awt::grid;
ENSURE_OR_RETURN_VOID( ( i_position >= 0 ) && ( i_position <= m_pImpl->aColumns.size() ), "illegal position!" );
ENSURE_OR_RETURN_VOID( !!i_column, "illegal column" );
- m_pImpl->aColumns.insert( m_pImpl->aColumns.begin(), i_column );
+ m_pImpl->aColumns.insert( m_pImpl->aColumns.begin() + i_position, i_column );
// notify listeners
ModellListeners aListeners( m_pImpl->m_aListeners );