]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/grid.cpp
WinCE compilation fix: don't use FNERR_INVALIDFILENAME
[wxWidgets.git] / src / generic / grid.cpp
index 65907544568016da9a08ec3f3c4ff3b40de423a4..de06f058ed5fe38e01b4ddfe9e6dfaba5fc3c761 100644 (file)
@@ -96,7 +96,7 @@ struct wxGridCellWithAttr
     {
         if (attr != new_attr)
         {
-           // "Delete" (i.e. DecRef) the old attribute.
+            // "Delete" (i.e. DecRef) the old attribute.
             attr->DecRef();
             attr = new_attr;
             // Take ownership of the new attribute, i.e. no IncRef.
@@ -953,7 +953,6 @@ void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid)
 bool wxGridCellNumberEditor::EndEdit(int row, int col,
                                      wxGrid* grid)
 {
-    bool changed;
     long value = 0;
     wxString text;
 
@@ -961,26 +960,40 @@ bool wxGridCellNumberEditor::EndEdit(int row, int col,
     if ( HasRange() )
     {
         value = Spin()->GetValue();
-        changed = value != m_valueOld;
-        if (changed)
-            text = wxString::Format(wxT("%ld"), value);
+        if ( value == m_valueOld )
+            return false;
+
+        text.Printf(wxT("%ld"), value);
     }
-    else
-#endif
+    else // using unconstrained input
+#endif // wxUSE_SPINCTRL
     {
+        const wxString textOld(grid->GetCellValue(row, col));
         text = Text()->GetValue();
-        changed = (text.empty() || text.ToLong(&value)) && (value != m_valueOld);
-    }
+        if ( text.empty() )
+        {
+            if ( textOld.empty() )
+                return false;
+        }
+        else // non-empty text now (maybe 0)
+        {
+            if ( !text.ToLong(&value) )
+                return false;
 
-    if ( changed )
-    {
-        if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER))
-            grid->GetTable()->SetValueAsLong(row, col, value);
-        else
-            grid->GetTable()->SetValue(row, col, text);
+            // if value == m_valueOld == 0 but old text was "" and new one is
+            // "0" something still did change
+            if ( value == m_valueOld && (value || !textOld.empty()) )
+                return false;
+        }
     }
 
-    return changed;
+    wxGridTableBase * const table = grid->GetTable();
+    if ( table->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER) )
+        table->SetValueAsLong(row, col, value);
+    else
+        table->SetValue(row, col, text);
+
+    return true;
 }
 
 void wxGridCellNumberEditor::Reset()
@@ -2799,7 +2812,7 @@ void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol)
         size_t n = (size_t)i;
         if ( m_attrs[n] == attr )
             // nothing to do
-            return; 
+            return;
         if ( attr )
         {
             // change the attribute, handling reference count manually,
@@ -4209,6 +4222,7 @@ bool wxGrid::Create(wxWindow *parent, wxWindowID id,
 
     Create();
     SetInitialSize(size);
+    SetScrollRate(m_scrollLineX, m_scrollLineY);
     CalcDimensions();
 
     return true;
@@ -4675,17 +4689,25 @@ void wxGrid::CalcDimensions()
     if ( y >= h )
         y = wxMax( h - 1, 0 );
 
-    // do set scrollbar parameters
-    SetScrollbars( m_scrollLineX, m_scrollLineY,
-                   GetScrollX(w), GetScrollY(h),
-                   x, y,
-                   GetBatchCount() != 0);
+    // update the virtual size and refresh the scrollbars to reflect it
+    m_gridWin->SetVirtualSize(w, h);
+    Scroll(x, y);
+    AdjustScrollbars();
 
     // if our OnSize() hadn't been called (it would if we have scrollbars), we
     // still must reposition the children
     CalcWindowSizes();
 }
 
+wxSize wxGrid::GetSizeAvailableForScrollTarget(const wxSize& size)
+{
+    wxSize sizeGridWin(size);
+    sizeGridWin.x -= m_rowLabelWidth;
+    sizeGridWin.y -= m_colLabelHeight;
+
+    return sizeGridWin;
+}
+
 void wxGrid::CalcWindowSizes()
 {
     // escape if the window is has not been fully created yet
@@ -4696,33 +4718,6 @@ void wxGrid::CalcWindowSizes()
     int cw, ch;
     GetClientSize( &cw, &ch );
 
-    // this block of code tries to work around the following problem: the grid
-    // could have been just resized to have enough space to show the full grid
-    // window contents without the scrollbars, but its client size could be
-    // not big enough because the grid has the scrollbars right now and so the
-    // scrollbars would remain even though we don't need them any more
-    //
-    // to prevent this from happening, check if we have enough space for
-    // everything without the scrollbars and explicitly disable them then
-    wxSize size = GetSize() - GetWindowBorderSize();
-    if ( size != wxSize(cw, ch) )
-    {
-        // check if we have enough space for grid window after accounting for
-        // the fixed size elements
-        size.x -= m_rowLabelWidth;
-        size.y -= m_colLabelHeight;
-
-        const wxSize vsize = m_gridWin->GetVirtualSize();
-
-        if ( size.x >= vsize.x && size.y >= vsize.y )
-        {
-            // yes, we do, so remove the scrollbars and use the new client size
-            // (which should be the same as full window size - borders now)
-            SetScrollbars(0, 0, 0, 0);
-            GetClientSize(&cw, &ch);
-        }
-    }
-
     // the grid may be too small to have enough space for the labels yet, don't
     // size the windows to negative sizes in this case
     int gw = cw - m_rowLabelWidth;
@@ -5579,12 +5574,21 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
 
                     if ( m_moveToCol < 0 )
                         markerX = GetColRight( GetColAt( m_numCols - 1 ) );
+                    else if ( x >= (GetColLeft( m_moveToCol ) + (GetColWidth(m_moveToCol) / 2)) )
+                    {
+                        m_moveToCol = GetColAt( GetColPos( m_moveToCol ) + 1 );
+                        if ( m_moveToCol < 0 )
+                            markerX = GetColRight( GetColAt( m_numCols - 1 ) );
+                        else
+                            markerX = GetColLeft( m_moveToCol );
+                    }
                     else
                         markerX = GetColLeft( m_moveToCol );
 
                     if ( markerX != m_dragLastPos )
                     {
                         wxClientDC dc( m_colLabelWin );
+                        DoPrepareDC(dc);
 
                         int cw, ch;
                         m_colLabelWin->GetClientSize( &cw, &ch );
@@ -5603,17 +5607,17 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
                                 DrawColLabel( dc, XToCol( m_dragLastPos ) );
                         }
 
+                        const wxColour *color;
                         //Moving to the same place? Don't draw a marker
                         if ( (m_moveToCol == m_dragRowOrCol)
                           || (GetColPos( m_moveToCol ) == GetColPos( m_dragRowOrCol ) + 1)
                           || (m_moveToCol < 0 && m_dragRowOrCol == GetColAt( m_numCols - 1 )))
-                        {
-                            m_dragLastPos = -1;
-                            return;
-                        }
+                            color = wxLIGHT_GREY;
+                        else
+                            color = wxBLUE;
 
                         //Draw the marker
-                        wxPen pen( *wxBLUE, 2 );
+                        wxPen pen( *color, 2 );
                         dc.SetPen(pen);
 
                         dc.DrawLine( markerX, 0, markerX, ch );
@@ -6139,16 +6143,9 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event )
                 }
                 else
                 {
-                    m_waitForSlowClick = m_currentCellCoords == coords && coords != wxGridNoCellCoords;
+                    m_waitForSlowClick = m_currentCellCoords == coords &&
+                                                coords != wxGridNoCellCoords;
                     SetCurrentCell( coords );
-                    if ( m_selection )
-                    {
-                        if ( m_selection->GetSelectionMode() !=
-                                wxGrid::wxGridSelectCells )
-                        {
-                            HighlightBlock( coords, coords );
-                        }
-                    }
                 }
             }
         }
@@ -6967,8 +6964,8 @@ void wxGrid::OnSize(wxSizeEvent& WXUNUSED(event))
 {
     if (m_targetWindow != this) // check whether initialisation has been done
     {
-        // update our children window positions and scrollbars
-        CalcDimensions();
+        // reposition our children windows
+        CalcWindowSizes();
     }
 }
 
@@ -7113,25 +7110,34 @@ void wxGrid::OnKeyDown( wxKeyEvent& event )
                 break;
 
             case WXK_SPACE:
-                if ( event.ControlDown() )
+                // Ctrl-Space selects the current column, Shift-Space -- the
+                // current row and Ctrl-Shift-Space -- everything
+                switch ( m_selection ? event.GetModifiers() : wxMOD_NONE )
                 {
-                    if ( m_selection )
-                    {
-                        m_selection->ToggleCellSelection(
-                            m_currentCellCoords.GetRow(),
-                            m_currentCellCoords.GetCol(),
-                            event.ControlDown(),
-                            event.ShiftDown(),
-                            event.AltDown(),
-                            event.MetaDown() );
-                    }
-                    break;
-                }
+                    case wxMOD_CONTROL:
+                        m_selection->SelectCol(m_currentCellCoords.GetCol());
+                        break;
 
-                if ( !IsEditable() )
-                    MoveCursorRight( false );
-                else
-                    event.Skip();
+                    case wxMOD_SHIFT:
+                        m_selection->SelectRow(m_currentCellCoords.GetRow());
+                        break;
+
+                    case wxMOD_CONTROL | wxMOD_SHIFT:
+                        m_selection->SelectBlock(0, 0,
+                                                 m_numRows - 1, m_numCols - 1);
+                        break;
+
+                    case wxMOD_NONE:
+                        if ( !IsEditable() )
+                        {
+                            MoveCursorRight(false);
+                            break;
+                        }
+                        //else: fall through
+
+                    default:
+                        event.Skip();
+                }
                 break;
 
             default:
@@ -7778,7 +7784,27 @@ void wxGrid::DrawHighlight(wxDC& dc, const wxGridCellCoordsArray& cells)
     size_t count = cells.GetCount();
     for ( size_t n = 0; n < count; n++ )
     {
-        if ( cells[n] == m_currentCellCoords )
+        wxGridCellCoords cell = cells[n];
+
+        // If we are using attributes, then we may have just exposed another
+        // cell in a partially-visible merged cluster of cells. If the "anchor"
+        // (upper left) cell of this merged cluster is the cell indicated by
+        // m_currentCellCoords, then we need to refresh the cell highlight even
+        // though the "anchor" itself is not part of our update segment.
+        if ( CanHaveAttributes() )
+        {
+            int rows = 0,
+                cols = 0;
+            GetCellSize(cell.GetRow(), cell.GetCol(), &rows, &cols);
+
+            if ( rows < 0 )
+                cell.SetRow(cell.GetRow() + rows);
+
+            if ( cols < 0 )
+                cell.SetCol(cell.GetCol() + cols);
+        }
+
+        if ( cell == m_currentCellCoords )
         {
             wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
             DrawCellHighlight(dc, attr);
@@ -8492,11 +8518,18 @@ void wxGrid::HideCellEditControl()
 
         wxGridCellAttr *attr = GetCellAttr(row, col);
         wxGridCellEditor *editor = attr->GetEditor(this, row, col);
+        const bool editorHadFocus = editor->GetControl()->HasFocus();
         editor->Show( false );
         editor->DecRef();
         attr->DecRef();
 
-        m_gridWin->SetFocus();
+        // return the focus to the grid itself if the editor had it
+        //
+        // note that we must not do this unconditionally to avoid stealing
+        // focus from the window which just received it if we are hiding the
+        // editor precisely because we lost focus
+        if ( editorHadFocus )
+            m_gridWin->SetFocus();
 
         // refresh whole row to the right
         wxRect rect( CellToRect(row, col) );
@@ -9931,9 +9964,14 @@ void wxGrid::ClearAttrCache()
 {
     if ( m_attrCache.row != -1 )
     {
-        wxSafeDecRef(m_attrCache.attr);
+        wxGridCellAttr *oldAttr = m_attrCache.attr;
         m_attrCache.attr = NULL;
         m_attrCache.row = -1;
+        // wxSafeDecRec(...) might cause event processing that accesses
+        // the cached attribute, if one exists (e.g. by deleting the
+        // editor stored within the attribute). Therefore it is important
+        // to invalidate the cache  before calling wxSafeDecRef!
+        wxSafeDecRef(oldAttr);
     }
 }
 
@@ -10055,8 +10093,8 @@ void wxGrid::SetColFormatCustom(int col, const wxString& typeName)
         attr = new wxGridCellAttr;
     wxGridCellRenderer *renderer = GetDefaultRendererForType(typeName);
     attr->SetRenderer(renderer);
-    wxGridCellEditor *editor = GetDefaultEditorForType(typeName); 
-    attr->SetEditor(editor); 
+    wxGridCellEditor *editor = GetDefaultEditorForType(typeName);
+    attr->SetEditor(editor);
 
     SetColAttr(col, attr);
 
@@ -10176,7 +10214,7 @@ void wxGrid::SetCellSize( int row, int col, int num_rows, int num_cols )
                       wxT("wxGrid::SetCellSize setting cell size to < 1"));
 
         // if this was already a multicell then "turn off" the other cells first
-        if ((cell_rows > 1) || (cell_rows > 1))
+        if ((cell_rows > 1) || (cell_cols > 1))
         {
             int i, j;
             for (j=row; j < row + cell_rows; j++)
@@ -10339,6 +10377,19 @@ void wxGrid::SetRowSize( int row, int height )
 {
     wxCHECK_RET( row >= 0 && row < m_numRows, _T("invalid row index") );
 
+    // if < 0 then calculate new height from label
+    if ( height < 0 )
+    {
+        long w, h;
+        wxArrayString lines;
+        wxClientDC dc(m_rowLabelWin);
+        dc.SetFont(GetLabelFont());
+        StringToLines(GetRowLabelValue( row ), lines);
+        GetTextBoxSize( dc, lines, &w, &h );
+        //check that it is not less than the minimal height
+        height = wxMax(h, GetRowMinimalAcceptableHeight());
+    }
+
     // See comment in SetColSize
     if ( height < GetRowMinimalAcceptableHeight())
         return;
@@ -10384,6 +10435,23 @@ void wxGrid::SetColSize( int col, int width )
 {
     wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") );
 
+    // if < 0 then calculate new width from label
+    if ( width < 0 )
+    {
+        long w, h;
+        wxArrayString lines;
+        wxClientDC dc(m_colLabelWin);
+        dc.SetFont(GetLabelFont());
+        StringToLines(GetColLabelValue(col), lines);
+        if ( GetColLabelTextOrientation() == wxHORIZONTAL )
+            GetTextBoxSize( dc, lines, &w, &h );
+        else
+            GetTextBoxSize( dc, lines, &h, &w );
+        width = w + 6;
+        //check that it is not less than the minimal width
+        width = wxMax(width, GetColMinimalAcceptableWidth());
+    }
+
     // should we check that it's bigger than GetColMinimalWidth(col) here?
     //                                                                 (VZ)
     // No, because it is reasonable to assume the library user know's
@@ -10401,18 +10469,6 @@ void wxGrid::SetColSize( int col, int width )
         InitColWidths();
     }
 
-    // if < 0 then calculate new width from label
-    if ( width < 0 )
-    {
-        long w, h;
-        wxArrayString lines;
-        wxClientDC dc(m_colLabelWin);
-        dc.SetFont(GetLabelFont());
-        StringToLines(GetColLabelValue(col), lines);
-        GetTextBoxSize(dc, lines, &w, &h);
-        width = w + 6;
-    }
-
     int w = wxMax( 0, width );
     int diff = w - m_colWidths[col];
     m_colWidths[col] = w;
@@ -10712,77 +10768,22 @@ void wxGrid::AutoSize()
 {
     wxGridUpdateLocker locker(this);
 
-    // we need to round up the size of the scrollable area to a multiple of
-    // scroll step to ensure that we don't get the scrollbars when we're sized
-    // exactly to fit our contents
     wxSize size(SetOrCalcColumnSizes(false) - m_rowLabelWidth + m_extraWidth,
                 SetOrCalcRowSizes(false) - m_colLabelHeight + m_extraHeight);
-    wxSize sizeFit(GetScrollX(size.x) * GetScrollLineX(),
-                   GetScrollY(size.y) * GetScrollLineY());
-
-    // distribute the extra space between the columns/rows to avoid having
-    // extra white space
-    wxCoord diff = sizeFit.x - size.x;
-    if ( diff && m_numCols )
-    {
-        // 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 && m_numRows )
-    {
-        // 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);
-            }
-        }
-    }
 
     // we know that we're not going to have scrollbars so disable them now to
     // avoid trouble in SetClientSize() which can otherwise set the correct
     // client size but also leave space for (not needed any more) scrollbars
     SetScrollbars(0, 0, 0, 0, 0, 0, true);
-    SetClientSize(sizeFit.x + m_rowLabelWidth, sizeFit.y + m_colLabelHeight);
+
+    // restore the scroll rate parameters overwritten by SetScrollbars()
+    SetScrollRate(m_scrollLineX, m_scrollLineY);
+
+    SetClientSize(size.x + m_rowLabelWidth, size.y + m_colLabelHeight);
 }
 
 void wxGrid::AutoSizeRowLabelSize( int row )
 {
-    wxArrayString lines;
-    long w, h;
-
     // Hide the edit control, so it
     // won't interfere with drag-shrinking.
     if ( IsCellEditControlShown() )
@@ -10792,20 +10793,12 @@ void wxGrid::AutoSizeRowLabelSize( int row )
     }
 
     // autosize row height depending on label text
-    StringToLines( GetRowLabelValue( row ), lines );
-    wxClientDC dc( m_rowLabelWin );
-    GetTextBoxSize( dc, lines, &w, &h );
-    if ( h < m_defaultRowHeight )
-        h = m_defaultRowHeight;
-    SetRowSize(row, h);
+    SetRowSize(row, -1);
     ForceRefresh();
 }
 
 void wxGrid::AutoSizeColLabelSize( int col )
 {
-    wxArrayString lines;
-    long w, h;
-
     // Hide the edit control, so it
     // won't interfere with drag-shrinking.
     if ( IsCellEditControlShown() )
@@ -10815,15 +10808,7 @@ void wxGrid::AutoSizeColLabelSize( int col )
     }
 
     // autosize column width depending on label text
-    StringToLines( GetColLabelValue( col ), lines );
-    wxClientDC dc( m_colLabelWin );
-    if ( GetColLabelTextOrientation() == wxHORIZONTAL )
-        GetTextBoxSize( dc, lines, &w, &h );
-    else
-        GetTextBoxSize( dc, lines, &h, &w );
-    if ( w < m_defaultColWidth )
-        w = m_defaultColWidth;
-    SetColSize(col, w);
+    SetColSize(col, -1);
     ForceRefresh();
 }
 
@@ -10835,15 +10820,13 @@ wxSize wxGrid::DoGetBestSize() const
     // change the column/row sizes, only calculate them
     wxSize size(self->SetOrCalcColumnSizes(true) - m_rowLabelWidth + m_extraWidth,
                 self->SetOrCalcRowSizes(true) - m_colLabelHeight + m_extraHeight);
-    wxSize sizeFit(GetScrollX(size.x) * GetScrollLineX(),
-                   GetScrollY(size.y) * GetScrollLineY());
 
     // NOTE: This size should be cached, but first we need to add calls to
     // InvalidateBestSize everywhere that could change the results of this
     // calculation.
     // CacheBestSize(size);
 
-    return wxSize(sizeFit.x + m_rowLabelWidth, sizeFit.y + m_colLabelHeight)
+    return wxSize(size.x + m_rowLabelWidth, size.y + m_colLabelHeight)
             + GetWindowBorderSize();
 }