]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/grid.cpp
ignore clicks on a toolbar but outside any button
[wxWidgets.git] / src / generic / grid.cpp
index e2b9e3580721124017104ac5a4c6e8e0901d0ad4..b6afb0c214aab8b69b1c46d0e6910a1694913d85 100644 (file)
@@ -2,7 +2,7 @@
 // Name:        generic/grid.cpp
 // Purpose:     wxGrid and related classes
 // Author:      Michael Bedward (based on code by Julian Smart, Robin Dunn)
-// Modified by:
+// Modified by: Robin Dunn, Vadim Zeitlin
 // Created:     1/08/1999
 // RCS-ID:      $Id$
 // Copyright:   (c) Michael Bedward (mbedward@ozemail.com.au)
@@ -185,7 +185,7 @@ private:
     DECLARE_EVENT_TABLE()
 };
 
-class WXDLLEXPORT wxGridWindow : public wxPanel
+class WXDLLEXPORT wxGridWindow : public wxWindow
 {
 public:
     wxGridWindow()
@@ -388,13 +388,31 @@ wxRect           wxGridNoCellRect( -1, -1, -1, -1 );
 //       The scroll bars may be a little flakey once in a while, but that is
 //       surely much less horrible than having scroll lines of only 1!!!
 //       -- Robin
-static const size_t GRID_SCROLL_LINE = 15;  // 1;
-
+//
+//       Well, it's still seriously broken so it might be better but needs
+//       fixing anyhow
+//       -- Vadim
+static const size_t GRID_SCROLL_LINE_X = 15;  // 1;
+static const size_t GRID_SCROLL_LINE_Y = GRID_SCROLL_LINE_X;
 
 // the size of hash tables used a bit everywhere (the max number of elements
 // in these hash tables is the number of rows/columns)
 static const int GRID_HASH_SIZE = 100;
 
+// ----------------------------------------------------------------------------
+// private functions
+// ----------------------------------------------------------------------------
+
+static inline int GetScrollX(int x)
+{
+    return (x + GRID_SCROLL_LINE_X - 1) / GRID_SCROLL_LINE_X;
+}
+
+static inline int GetScrollY(int y)
+{
+    return (y + GRID_SCROLL_LINE_Y - 1) / GRID_SCROLL_LINE_Y;
+}
+
 // ============================================================================
 // implementation
 // ============================================================================
@@ -1880,9 +1898,24 @@ void wxGridCellBoolRenderer::Draw(wxGrid& grid,
 // wxGridCellAttr
 // ----------------------------------------------------------------------------
 
+void wxGridCellAttr::Init(wxGridCellAttr *attrDefault)
+{
+    m_nRef = 1;
+
+    m_isReadOnly = Unset;
+
+    m_renderer = NULL;
+    m_editor = NULL;
+
+    m_attrkind = wxGridCellAttr::Cell;
+
+    SetDefAttr(attrDefault);
+}
+
 wxGridCellAttr *wxGridCellAttr::Clone() const
 {
-    wxGridCellAttr *attr = new wxGridCellAttr;
+    wxGridCellAttr *attr = new wxGridCellAttr(m_defGridAttr);
+
     if ( HasTextColour() )
         attr->SetTextColour(GetTextColour());
     if ( HasBackgroundColour() )
@@ -1908,8 +1941,6 @@ wxGridCellAttr *wxGridCellAttr::Clone() const
 
     attr->SetKind( m_attrkind );
 
-    attr->SetDefAttr(m_defGridAttr);
-
     return attr;
 }
 
@@ -1953,7 +1984,7 @@ const wxColour& wxGridCellAttr::GetTextColour() const
     {
         return m_colText;
     }
-    else if (m_defGridAttr != this)
+    else if (m_defGridAttr && m_defGridAttr != this)
     {
         return m_defGridAttr->GetTextColour();
     }
@@ -1969,7 +2000,7 @@ const wxColour& wxGridCellAttr::GetBackgroundColour() const
 {
     if (HasBackgroundColour())
         return m_colBack;
-    else if (m_defGridAttr != this)
+    else if (m_defGridAttr && m_defGridAttr != this)
         return m_defGridAttr->GetBackgroundColour();
     else
     {
@@ -1983,7 +2014,7 @@ const wxFont& wxGridCellAttr::GetFont() const
 {
     if (HasFont())
         return m_font;
-    else if (m_defGridAttr != this)
+    else if (m_defGridAttr && m_defGridAttr != this)
         return m_defGridAttr->GetFont();
     else
     {
@@ -2000,7 +2031,7 @@ void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const
         if ( hAlign ) *hAlign = m_hAlign;
         if ( vAlign ) *vAlign = m_vAlign;
     }
-    else if (m_defGridAttr != this)
+    else if (m_defGridAttr && m_defGridAttr != this)
         m_defGridAttr->GetAlignment(hAlign, vAlign);
     else
     {
@@ -2018,59 +2049,96 @@ void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const
 
 wxGridCellRenderer* wxGridCellAttr::GetRenderer(wxGrid* grid, int row, int col) const
 {
-    wxGridCellRenderer* renderer = NULL;
+    wxGridCellRenderer *renderer;
 
-    if ( m_defGridAttr == this || grid == NULL )
+    if ( m_renderer && this != m_defGridAttr )
     {
-        renderer = m_renderer;      // use local attribute
-        if ( renderer )
-            renderer->IncRef();
+        // use the cells renderer if it has one
+        renderer = m_renderer;
+        renderer->IncRef();
     }
-
-    if ( !renderer && grid )        // get renderer for the data type
+    else // no non default cell renderer
     {
-        // GetDefaultRendererForCell() will do IncRef() for us
-        renderer = grid->GetDefaultRendererForCell(row, col);
-    }
+        // get default renderer for the data type
+        if ( grid )
+        {
+            // GetDefaultRendererForCell() will do IncRef() for us
+            renderer = grid->GetDefaultRendererForCell(row, col);
+        }
+        else
+        {
+            renderer = NULL;
+        }
 
-    if ( !renderer )
-    {
-        // if we still don't have one then use the grid default
-        // (no need for IncRef() here neither)
-        renderer = m_defGridAttr->GetRenderer(NULL,0,0);
+        if ( !renderer )
+        {
+            if (m_defGridAttr &&  this != m_defGridAttr )
+            {
+                // if we still don't have one then use the grid default
+                // (no need for IncRef() here neither)
+                renderer = m_defGridAttr->GetRenderer(NULL, 0, 0);
+            }
+            else // default grid attr
+            {
+                // use m_renderer which we had decided not to use initially
+                renderer = m_renderer;
+                if ( renderer )
+                    renderer->IncRef();
+            }
+        }
     }
 
-    if ( !renderer)
-    {
-        wxFAIL_MSG(wxT("Missing default cell attribute"));
-    }
+    // we're supposed to always find something
+    wxASSERT_MSG(renderer, wxT("Missing default cell renderer"));
 
     return renderer;
 }
 
+// same as above, except for s/renderer/editor/g
 wxGridCellEditor* wxGridCellAttr::GetEditor(wxGrid* grid, int row, int col) const
 {
-    wxGridCellEditor* editor = NULL;
+    wxGridCellEditor *editor;
 
-    if ( m_defGridAttr != this || grid == NULL )
+    if ( m_editor && this != m_defGridAttr )
     {
-        editor = m_editor;      // use local attribute
-        if ( editor )
-            editor->IncRef();
+        // use the cells editor if it has one
+        editor = m_editor;
+        editor->IncRef();
     }
-
-    if ( !editor && grid )                   // get renderer for the data type
-        editor = grid->GetDefaultEditorForCell(row, col);
-
-    if ( !editor )
-        // if we still don't have one then use the grid default
-        editor = m_defGridAttr->GetEditor(NULL,0,0);
-
-    if ( !editor )
+    else // no non default cell editor
     {
-        wxFAIL_MSG(wxT("Missing default cell attribute"));
+        // get default editor for the data type
+        if ( grid )
+        {
+            // GetDefaultEditorForCell() will do IncRef() for us
+            editor = grid->GetDefaultEditorForCell(row, col);
+        }
+        else
+        {
+            editor = NULL;
+        }
+
+        if ( !editor )
+        {
+            if ( m_defGridAttr && this != m_defGridAttr )
+            {
+                // if we still don't have one then use the grid default
+                // (no need for IncRef() here neither)
+                editor = m_defGridAttr->GetEditor(NULL, 0, 0);
+            }
+            else // default grid attr
+            {
+                // use m_editor which we had decided not to use initially
+                editor = m_editor;
+                if ( editor )
+                    editor->IncRef();
+            }
+        }
     }
 
+    // we're supposed to always find something
+    wxASSERT_MSG(editor, wxT("Missing default cell editor"));
+
     return editor;
 }
 
@@ -3418,9 +3486,9 @@ void wxGridCornerLabelWindow::OnKeyUp( wxKeyEvent& event )
 
 //////////////////////////////////////////////////////////////////////
 
-IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxPanel )
+IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxWindow )
 
-BEGIN_EVENT_TABLE( wxGridWindow, wxPanel )
+BEGIN_EVENT_TABLE( wxGridWindow, wxWindow )
     EVT_PAINT( wxGridWindow::OnPaint )
     EVT_MOUSEWHEEL( wxGridWindow::OnMouseWheel)
     EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent )
@@ -3433,7 +3501,7 @@ wxGridWindow::wxGridWindow( wxGrid *parent,
                             wxGridRowLabelWindow *rowLblWin,
                             wxGridColLabelWindow *colLblWin,
                             wxWindowID id, const wxPoint &pos, const wxSize &size )
-        : wxPanel( parent, id, pos, size, wxWANTS_CHARS, "grid window" )
+        : wxWindow( parent, id, pos, size, wxWANTS_CHARS, "grid window" )
 {
     m_owner = parent;
     m_rowLabelWin = rowLblWin;
@@ -3464,7 +3532,7 @@ void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
 
 void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
 {
-    wxPanel::ScrollWindow( dx, dy, rect );
+    wxWindow::ScrollWindow( dx, dy, rect );
     m_rowLabelWin->ScrollWindow( 0, dy, rect );
     m_colLabelWin->ScrollWindow( dx, 0, rect );
 }
@@ -3561,17 +3629,17 @@ void wxGrid::Create()
 
     m_cellEditCtrlEnabled = FALSE;
 
-    m_defaultCellAttr = new wxGridCellAttr;
-    m_defaultCellAttr->SetDefAttr(m_defaultCellAttr);
+    m_defaultCellAttr = new wxGridCellAttr();
 
     // Set default cell attributes
+    m_defaultCellAttr->SetDefAttr(m_defaultCellAttr);
     m_defaultCellAttr->SetKind(wxGridCellAttr::Default);
     m_defaultCellAttr->SetFont(GetFont());
     m_defaultCellAttr->SetAlignment(wxALIGN_LEFT, wxALIGN_TOP);
     m_defaultCellAttr->SetTextColour(
-        wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT));
+        wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
     m_defaultCellAttr->SetBackgroundColour(
-        wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
+        wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
     m_defaultCellAttr->SetRenderer(new wxGridCellStringRenderer);
     m_defaultCellAttr->SetEditor(new wxGridCellTextEditor);
 
@@ -3743,8 +3811,8 @@ void wxGrid::Init()
 
     m_selectingTopLeft = wxGridNoCellCoords;
     m_selectingBottomRight = wxGridNoCellCoords;
-    m_selectionBackground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT);
-    m_selectionForeground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+    m_selectionBackground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
+    m_selectionForeground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
 
     m_editable = TRUE;  // default for whole grid
 
@@ -3752,7 +3820,7 @@ void wxGrid::Init()
     m_batchCount = 0;
 
     m_extraWidth =
-    m_extraHeight = 50;
+    m_extraHeight = 0;
 }
 
 // ----------------------------------------------------------------------------
@@ -3837,9 +3905,9 @@ void wxGrid::CalcDimensions()
     int cw, ch;
     GetClientSize( &cw, &ch );
 
-    if ( m_colLabelWin->IsShown() )
-        cw -= m_rowLabelWidth;
     if ( m_rowLabelWin->IsShown() )
+        cw -= m_rowLabelWidth;
+    if ( m_colLabelWin->IsShown() )
         ch -= m_colLabelHeight;
 
     // grid total size
@@ -3849,32 +3917,34 @@ void wxGrid::CalcDimensions()
     // preserve (more or less) the previous position
     int x, y;
     GetViewStart( &x, &y );
-    // maybe we don't need scrollbars at all? and if we do, transform w and h
-    // from pixels into logical units
+
+    // maybe we don't need scrollbars at all?
+    //
+    // also adjust the position to be valid for the new scroll rangs
     if ( w <= cw )
     {
-        w = 0; x= 0;
+        w = = 0;
     }
     else
     {
-        w = (w + GRID_SCROLL_LINE - 1)/GRID_SCROLL_LINE;
         if ( x >= w )
             x = w - 1;
     }
+
     if ( h <= ch )
     {
-        h = 0; y = 0;
+        h = y = 0;
     }
     else
     {
-        h = (h + GRID_SCROLL_LINE - 1)/GRID_SCROLL_LINE;
         if ( y >= h )
             y = h - 1;
     }
 
     // do set scrollbar parameters
-    SetScrollbars( GRID_SCROLL_LINE, GRID_SCROLL_LINE,
-                   w, h, x, y, (GetBatchCount() != 0));
+    SetScrollbars( GRID_SCROLL_LINE_X, GRID_SCROLL_LINE_Y,
+                   GetScrollX(w), GetScrollY(h), x, y,
+                   GetBatchCount() != 0);
 }
 
 
@@ -5460,66 +5530,62 @@ int wxGrid::SendEvent( const wxEventType type,
 {
    bool claimed;
    bool vetoed= FALSE;
-       
-   if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
-    {
-        int rowOrCol = (row == -1 ? col : row);
 
-        wxGridSizeEvent gridEvt( GetId(),
-                                 type,
-                                 this,
-                                 rowOrCol,
-                                 mouseEv.GetX() + GetRowLabelSize(),
-                                 mouseEv.GetY() + GetColLabelSize(),
-                                 mouseEv.ControlDown(),
-                                 mouseEv.ShiftDown(),
-                                 mouseEv.AltDown(),
-                                 mouseEv.MetaDown() );
-
-        claimed = GetEventHandler()->ProcessEvent(gridEvt);
-       vetoed = !gridEvt.IsAllowed();
-
-    }
+   if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
+   {
+       int rowOrCol = (row == -1 ? col : row);
+
+       wxGridSizeEvent gridEvt( GetId(),
+               type,
+               this,
+               rowOrCol,
+               mouseEv.GetX() + GetRowLabelSize(),
+               mouseEv.GetY() + GetColLabelSize(),
+               mouseEv.ControlDown(),
+               mouseEv.ShiftDown(),
+               mouseEv.AltDown(),
+               mouseEv.MetaDown() );
+
+       claimed = GetEventHandler()->ProcessEvent(gridEvt);
+       vetoed = !gridEvt.IsAllowed();
+   }
    else if ( type == wxEVT_GRID_RANGE_SELECT )
-    {
-        // Right now, it should _never_ end up here!
-        wxGridRangeSelectEvent gridEvt( GetId(),
-                                        type,
-                                        this,
-                                        m_selectingTopLeft,
-                                        m_selectingBottomRight,
-                                        TRUE,
-                                        mouseEv.ControlDown(),
-                                        mouseEv.ShiftDown(),
-                                        mouseEv.AltDown(),
-                                        mouseEv.MetaDown() );
-
-        claimed = GetEventHandler()->ProcessEvent(gridEvt);
-       vetoed = !gridEvt.IsAllowed();
-       
-    }
+   {
+       // Right now, it should _never_ end up here!
+       wxGridRangeSelectEvent gridEvt( GetId(),
+               type,
+               this,
+               m_selectingTopLeft,
+               m_selectingBottomRight,
+               TRUE,
+               mouseEv.ControlDown(),
+               mouseEv.ShiftDown(),
+               mouseEv.AltDown(),
+               mouseEv.MetaDown() );
+
+       claimed = GetEventHandler()->ProcessEvent(gridEvt);
+       vetoed = !gridEvt.IsAllowed();
+   }
    else
-    {
-        wxGridEvent gridEvt( GetId(),
-                             type,
-                             this,
-                             row, col,
-                             mouseEv.GetX() + GetRowLabelSize(),
-                             mouseEv.GetY() + GetColLabelSize(),
-                             FALSE,
-                             mouseEv.ControlDown(),
-                             mouseEv.ShiftDown(),
-                             mouseEv.AltDown(),
-                             mouseEv.MetaDown() );
-         claimed = GetEventHandler()->ProcessEvent(gridEvt);
-        vetoed = !gridEvt.IsAllowed();
-    }
-
-  // A Veto'd event may not be `claimed' so test this first
-  if (vetoed) return -1;
-  return claimed ? 1 : 0;
-
-
+   {
+       wxGridEvent gridEvt( GetId(),
+               type,
+               this,
+               row, col,
+               mouseEv.GetX() + GetRowLabelSize(),
+               mouseEv.GetY() + GetColLabelSize(),
+               FALSE,
+               mouseEv.ControlDown(),
+               mouseEv.ShiftDown(),
+               mouseEv.AltDown(),
+               mouseEv.MetaDown() );
+       claimed = GetEventHandler()->ProcessEvent(gridEvt);
+       vetoed = !gridEvt.IsAllowed();
+   }
+
+   // A Veto'd event may not be `claimed' so test this first
+   if (vetoed) return -1;
+   return claimed ? 1 : 0;
 }
 
 
@@ -5555,10 +5621,9 @@ int wxGrid::SendEvent( const wxEventType type,
         vetoed  = !gridEvt.IsAllowed();
      }
 
-       // A Veto'd event may not be `claimed' so test this first
-       if (vetoed) return -1;
-       return claimed ? 1 : 0;
-
+    // A Veto'd event may not be `claimed' so test this first
+    if (vetoed) return -1;
+    return claimed ? 1 : 0;
 }
 
 
@@ -5568,14 +5633,14 @@ void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) )
 }
 
 
-// This is just here to make sure that CalcDimensions gets called when
-// the grid view is resized... then the size event is skipped to allow
-// the box sizers to handle everything
-//
-void wxGrid::OnSize( wxSizeEvent& WXUNUSED(event) )
+void wxGrid::OnSize( wxSizeEvent& event )
 {
+    // position the child windows
     CalcWindowSizes();
-    CalcDimensions();
+
+    // don't call CalcDimensions() from here, the base class handles the size
+    // changes itself
+    event.Skip();
 }
 
 
@@ -5767,7 +5832,14 @@ void wxGrid::OnKeyDown( wxKeyEvent& event )
                          || editor->IsAcceptedKey(event) )
                     {
                         EnableCellEditControl();
-                        editor->StartingKey(event);
+
+                        // the editor could be not shown for a variety of
+                        // reasons (i.e. blocked by the app or whatever), so
+                        // check if it really was created
+                        if ( m_cellEditCtrlEnabled )
+                        {
+                            editor->StartingKey(event);
+                        }
                     }
                     else
                     {
@@ -6610,10 +6682,10 @@ void wxGrid::EnableCellEditControl( bool enable )
     {
         if ( enable )
         {
-           if (SendEvent( wxEVT_GRID_EDITOR_SHOWN) <0)
-               return;
+            if (SendEvent( wxEVT_GRID_EDITOR_SHOWN) <0)
+                return;
 
-           // this should be checked by the caller!
+            // this should be checked by the caller!
             wxASSERT_MSG( CanEnableCellControl(),
                           _T("can't enable editing for this cell!") );
 
@@ -6624,10 +6696,10 @@ void wxGrid::EnableCellEditControl( bool enable )
         }
         else
         {
-           //FIXME:add veto support
-           SendEvent( wxEVT_GRID_EDITOR_HIDDEN);
+            //FIXME:add veto support
+            SendEvent( wxEVT_GRID_EDITOR_HIDDEN);
 
-           HideCellEditControl();
+            HideCellEditControl();
             SaveEditControlValue();
 
             // do it after HideCellEditControl()
@@ -6788,9 +6860,9 @@ void wxGrid::SaveEditControlValue()
                        m_currentCellCoords.GetRow(),
                        m_currentCellCoords.GetCol() ) < 0 ) {
 
-                             //Event has been veto set the data back.
-                              SetCellValue(row,col,oldval);
-              }
+                // Event has been vetoed, set the data back.
+                SetCellValue(row,col,oldval);
+            }
         }
     }
 }
@@ -6994,7 +7066,7 @@ void wxGrid::MakeCellVisible( int row, int col )
             //
             // Sometimes GRID_SCROLL_LINE/2 is not enough, so just add a full
             // scroll unit...
-            ypos += GRID_SCROLL_LINE;
+            ypos += GRID_SCROLL_LINE_Y;
         }
 
         if ( left < 0 )
@@ -7016,13 +7088,15 @@ void wxGrid::MakeCellVisible( int row, int col )
             }
 
             // see comment for ypos above
-            xpos += GRID_SCROLL_LINE;
+            xpos += GRID_SCROLL_LINE_X;
         }
 
         if ( xpos != -1  ||  ypos != -1 )
         {
-            if ( xpos != -1 ) xpos /= GRID_SCROLL_LINE;
-            if ( ypos != -1 ) ypos /= GRID_SCROLL_LINE;
+            if ( xpos != -1 )
+                xpos /= GRID_SCROLL_LINE_X;
+            if ( ypos != -1 )
+                ypos /= GRID_SCROLL_LINE_Y;
             Scroll( xpos, ypos );
             AdjustScrollbars();
         }
@@ -8047,19 +8121,20 @@ wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const
 wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const
 {
     wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
-        wxASSERT_MSG( m_table,
-                      _T("we may only be called if CanHaveAttributes() returned TRUE and then m_table should be !NULL") );
 
-    attr = m_table->GetAttr(row, col, wxGridCellAttr::Cell );
-        if ( !attr )
-        {
-            attr = new wxGridCellAttr;
+    wxCHECK_MSG( m_table, attr,
+                  _T("we may only be called if CanHaveAttributes() returned TRUE and then m_table should be !NULL") );
+
+    attr = m_table->GetAttr(row, col, wxGridCellAttr::Cell);
+    if ( !attr )
+    {
+        attr = new wxGridCellAttr(m_defaultCellAttr);
+
+        // artificially inc the ref count to match DecRef() in caller
+        attr->IncRef();
+        m_table->SetAttr(attr, row, col);
+    }
 
-            // artificially inc the ref count to match DecRef() in caller
-            attr->IncRef();
-            m_table->SetAttr(attr, row, col);
-        }
-    attr->SetDefAttr(m_defaultCellAttr);
     return attr;
 }
 
@@ -8492,6 +8567,7 @@ int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin)
 
     if ( !calcOnly )
         BeginBatch();
+
     for ( int col = 0; col < m_numCols; col++ )
     {
         if ( !calcOnly )
@@ -8501,8 +8577,10 @@ int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin)
 
         width += GetColWidth(col);
     }
+
     if ( !calcOnly )
         EndBatch();
+
     return width;
 }
 
@@ -8512,6 +8590,7 @@ int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin)
 
     if ( !calcOnly )
         BeginBatch();
+
     for ( int row = 0; row < m_numRows; row++ )
     {
         if ( !calcOnly )
@@ -8521,15 +8600,78 @@ int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin)
 
         height += GetRowHeight(row);
     }
+
     if ( !calcOnly )
         EndBatch();
+
     return height;
 }
 
 void wxGrid::AutoSize()
 {
-    // set the size too
-    SetClientSize(SetOrCalcColumnSizes(FALSE), SetOrCalcRowSizes(FALSE));
+    BeginBatch();
+
+    wxSize size(SetOrCalcColumnSizes(FALSE), SetOrCalcRowSizes(FALSE));
+
+    // round up the size to a multiple of scroll step - this ensures that we
+    // won't get the scrollbars if we're sized exactly to this width
+    wxSize sizeFit(GetScrollX(size.x) * GRID_SCROLL_LINE_X,
+                   GetScrollY(size.y) * GRID_SCROLL_LINE_Y);
+
+    // distribute the extra space between teh columns/rows to avoid having
+    // extra white space
+    wxCoord diff = sizeFit.x - size.x;
+    if ( diff )
+    {
+        // try to resize the columns uniformly
+        wxCoord diffPerCol = diff / m_numCols;
+        if ( diffPerCol )
+        {
+            for ( int col = 0; col < m_numCols; col++ )
+            {
+                SetColSize(col, GetColWidth(col) + diffPerCol);
+            }
+        }
+
+        // add remaining amount to the last columns
+        diff -= diffPerCol * m_numCols;
+        if ( diff )
+        {
+            for ( int col = m_numCols - 1; col >= m_numCols - diff; col-- )
+            {
+                SetColSize(col, GetColWidth(col) + 1);
+            }
+        }
+    }
+
+    // same for rows
+    diff = sizeFit.y - size.y;
+    if ( diff )
+    {
+        // try to resize the columns uniformly
+        wxCoord diffPerRow = diff / m_numRows;
+        if ( diffPerRow )
+        {
+            for ( int row = 0; row < m_numRows; row++ )
+            {
+                SetRowSize(row, GetRowHeight(row) + diffPerRow);
+            }
+        }
+
+        // add remaining amount to the last rows
+        diff -= diffPerRow * m_numRows;
+        if ( diff )
+        {
+            for ( int row = m_numRows - 1; row >= m_numRows - diff; row-- )
+            {
+                SetRowSize(row, GetRowHeight(row) + 1);
+            }
+        }
+    }
+
+    EndBatch();
+
+    SetClientSize(sizeFit);
 }
 
 wxSize wxGrid::DoGetBestSize() const