+bool wxGridCellNumberEditor::EndEdit(int row, int col,
+                                     wxGrid* grid)
+{
+    bool changed;
+    long value;
+
+    if ( HasRange() )
+    {
+        value = Spin()->GetValue();
+        changed = value != m_valueOld;
+    }
+    else
+    {
+        changed = Text()->GetValue().ToLong(&value) && (value != m_valueOld);
+    }
+
+    if ( changed )
+    {
+        if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER))
+            grid->GetTable()->SetValueAsLong(row, col, value);
+        else
+            grid->GetTable()->SetValue(row, col, wxString::Format("%ld", value));
+    }
+
+    return changed;
+}
+
+void wxGridCellNumberEditor::Reset()
+{
+    if ( HasRange() )
+    {
+        Spin()->SetValue((int)m_valueOld);
+    }
+    else
+    {
+        DoReset(GetString());
+    }
+}
+
+void wxGridCellNumberEditor::StartingKey(wxKeyEvent& event)
+{
+    if ( !HasRange() )
+    {
+        int keycode = (int) event.KeyCode();
+        if ( isdigit(keycode) || keycode == '+' || keycode == '-' )
+        {
+            wxGridCellTextEditor::StartingKey(event);
+
+            // skip Skip() below
+            return;
+        }
+    }
+
+    event.Skip();
+}
+
+void wxGridCellNumberEditor::SetParameters(const wxString& params)
+{
+    if ( !params )
+    {
+        // reset to default
+        m_min =
+        m_max = -1;
+    }
+    else
+    {
+        long tmp;
+        if ( params.BeforeFirst(_T(',')).ToLong(&tmp) )
+        {
+            m_min = (int)tmp;
+
+            if ( params.AfterFirst(_T(',')).ToLong(&tmp) )
+            {
+                m_max = (int)tmp;
+
+                // skip the error message below
+                return;
+            }
+        }
+
+        wxLogDebug(_T("Invalid wxGridCellNumberEditor parameter string "
+                      "'%s' ignored"), params.c_str());
+    }
+}
+
+// ----------------------------------------------------------------------------
+// wxGridCellFloatEditor
+// ----------------------------------------------------------------------------
+
+void wxGridCellFloatEditor::Create(wxWindow* parent,
+                                   wxWindowID id,
+                                   wxEvtHandler* evtHandler)
+{
+    wxGridCellTextEditor::Create(parent, id, evtHandler);
+
+#if wxUSE_VALIDATORS
+    Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
+#endif // wxUSE_VALIDATORS
+}
+
+void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid)
+{
+    // first get the value
+    wxGridTableBase *table = grid->GetTable();
+    if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
+    {
+        m_valueOld = table->GetValueAsDouble(row, col);
+    }
+    else
+    {
+        wxString sValue = table->GetValue(row, col);
+        if (! sValue.ToDouble(&m_valueOld))
+        {
+            wxFAIL_MSG( _T("this cell doesn't have float value") );
+            return;
+        }
+    }
+
+    DoBeginEdit(GetString());
+}
+
+bool wxGridCellFloatEditor::EndEdit(int row, int col,
+                                     wxGrid* grid)
+{
+    double value;
+    if ( Text()->GetValue().ToDouble(&value) && (value != m_valueOld) )
+    {
+        if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_FLOAT))
+            grid->GetTable()->SetValueAsDouble(row, col, value);
+        else
+            grid->GetTable()->SetValue(row, col, wxString::Format("%f", value));
+
+        return TRUE;
+    }
+    else
+    {
+        return FALSE;
+    }
+}
+
+void wxGridCellFloatEditor::Reset()
+{
+    DoReset(GetString());
+}
+
+void wxGridCellFloatEditor::StartingKey(wxKeyEvent& event)
+{
+    int keycode = (int)event.KeyCode();
+    if ( isdigit(keycode) ||
+         keycode == '+' || keycode == '-' || keycode == '.' )
+    {
+        wxGridCellTextEditor::StartingKey(event);
+
+        // skip Skip() below
+        return;
+    }
+
+    event.Skip();
+}
+
+// ----------------------------------------------------------------------------
+// wxGridCellBoolEditor
+// ----------------------------------------------------------------------------
+
+void wxGridCellBoolEditor::Create(wxWindow* parent,
+                                  wxWindowID id,
+                                  wxEvtHandler* evtHandler)
+{
+    m_control = new wxCheckBox(parent, id, wxEmptyString,
+                               wxDefaultPosition, wxDefaultSize,
+                               wxNO_BORDER);
+
+    wxGridCellEditor::Create(parent, id, evtHandler);
+}
+
+void wxGridCellBoolEditor::SetSize(const wxRect& r)
+{
+    bool resize = FALSE;
+    wxSize size = m_control->GetSize();
+    wxCoord minSize = wxMin(r.width, r.height);
+
+    // check if the checkbox is not too big/small for this cell
+    wxSize sizeBest = m_control->GetBestSize();
+    if ( !(size == sizeBest) )
+    {
+        // reset to default size if it had been made smaller
+        size = sizeBest;
+
+        resize = TRUE;
+    }
+
+    if ( size.x >= minSize || size.y >= minSize )
+    {
+        // leave 1 pixel margin
+        size.x = size.y = minSize - 2;
+
+        resize = TRUE;
+    }
+
+    if ( resize )
+    {
+        m_control->SetSize(size);
+    }
+
+    // position it in the centre of the rectangle (TODO: support alignment?)
+
+#if defined(__WXGTK__) || defined (__WXMOTIF__)
+    // the checkbox without label still has some space to the right in wxGTK,
+    // so shift it to the right
+    size.x -= 8;
+#elif defined(__WXMSW__)
+    // here too, but in other way
+    size.x += 1;
+    size.y -= 2;
+#endif
+
+    m_control->Move(r.x + r.width/2 - size.x/2, r.y + r.height/2 - size.y/2);
+}
+
+void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr)
+{
+    m_control->Show(show);
+
+    if ( show )
+    {
+        wxColour colBg = attr ? attr->GetBackgroundColour() : *wxLIGHT_GREY;
+        CBox()->SetBackgroundColour(colBg);
+    }
+}
+
+void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid)
+{
+    wxASSERT_MSG(m_control,
+                 wxT("The wxGridCellEditor must be Created first!"));
+
+    if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
+        m_startValue = grid->GetTable()->GetValueAsBool(row, col);
+    else
+        m_startValue = !!grid->GetTable()->GetValue(row, col);
+    CBox()->SetValue(m_startValue);
+    CBox()->SetFocus();
+}
+
+bool wxGridCellBoolEditor::EndEdit(int row, int col,
+                                   wxGrid* grid)
+{
+    wxASSERT_MSG(m_control,
+                 wxT("The wxGridCellEditor must be Created first!"));
+
+    bool changed = FALSE;
+    bool value = CBox()->GetValue();
+    if ( value != m_startValue )
+        changed = TRUE;
+
+    if ( changed )
+    {
+        if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
+            grid->GetTable()->SetValueAsBool(row, col, value);
+        else
+            grid->GetTable()->SetValue(row, col, value ? _T("1") : wxEmptyString);
+    }
+
+    return changed;
+}
+
+void wxGridCellBoolEditor::Reset()
+{
+    wxASSERT_MSG(m_control,
+                 wxT("The wxGridCellEditor must be Created first!"));
+
+    CBox()->SetValue(m_startValue);
+}
+
+void wxGridCellBoolEditor::StartingClick()
+{
+    CBox()->SetValue(!CBox()->GetValue());
+}
+
+// ----------------------------------------------------------------------------
+// wxGridCellChoiceEditor
+// ----------------------------------------------------------------------------
+
+wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count,
+                                               const wxChar* choices[],
+                                               bool allowOthers)
+                      : m_allowOthers(allowOthers)
+{
+    if ( count )
+    {
+        m_choices.Alloc(count);
+        for ( size_t n = 0; n < count; n++ )
+        {
+            m_choices.Add(choices[n]);
+        }
+    }
+}
+
+wxGridCellEditor *wxGridCellChoiceEditor::Clone() const
+{
+    wxGridCellChoiceEditor *editor = new wxGridCellChoiceEditor;
+    editor->m_allowOthers = m_allowOthers;
+    editor->m_choices = m_choices;
+
+    return editor;
+}
+
+void wxGridCellChoiceEditor::Create(wxWindow* parent,
+                                    wxWindowID id,
+                                    wxEvtHandler* evtHandler)
+{
+    size_t count = m_choices.GetCount();
+    wxString *choices = new wxString[count];
+    for ( size_t n = 0; n < count; n++ )
+    {
+        choices[n] = m_choices[n];
+    }
+
+    m_control = new wxComboBox(parent, id, wxEmptyString,
+                               wxDefaultPosition, wxDefaultSize,
+                               count, choices,
+                               m_allowOthers ? 0 : wxCB_READONLY);
+
+    delete [] choices;
+
+    wxGridCellEditor::Create(parent, id, evtHandler);
+}
+
+void wxGridCellChoiceEditor::PaintBackground(const wxRect& rectCell,
+                                             wxGridCellAttr * attr)
+{
+    // as we fill the entire client area, don't do anything here to minimize
+    // flicker
+
+    // TODO: It doesn't actually fill the client area since the height of a
+    // combo always defaults to the standard...  Until someone has time to
+    // figure out the right rectangle to paint, just do it the normal way...
+    wxGridCellEditor::PaintBackground(rectCell, attr);
+}
+
+void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid)
+{
+    wxASSERT_MSG(m_control,
+                 wxT("The wxGridCellEditor must be Created first!"));
+
+    m_startValue = grid->GetTable()->GetValue(row, col);
+
+    Combo()->SetValue(m_startValue);
+    size_t count = m_choices.GetCount();
+    for (size_t i=0; i<count; i++)
+    {
+        if (m_startValue == m_choices[i])
+        {
+            Combo()->SetSelection(i);
+            break;
+        }
+    }
+    Combo()->SetInsertionPointEnd();
+    Combo()->SetFocus();
+}
+
+bool wxGridCellChoiceEditor::EndEdit(int row, int col,
+                                     wxGrid* grid)
+{
+    wxString value = Combo()->GetValue();
+    bool changed = value != m_startValue;
+
+    if ( changed )
+        grid->GetTable()->SetValue(row, col, value);
+
+    m_startValue = wxEmptyString;
+    Combo()->SetValue(m_startValue);
+
+    return changed;
+}
+
+void wxGridCellChoiceEditor::Reset()
+{
+    Combo()->SetValue(m_startValue);
+    Combo()->SetInsertionPointEnd();
+}
+
+void wxGridCellChoiceEditor::SetParameters(const wxString& params)
+{
+    if ( !params )
+    {
+        // what can we do?
+        return;
+    }
+
+    m_choices.Empty();
+
+    wxStringTokenizer tk(params, _T(','));
+    while ( tk.HasMoreTokens() )
+    {
+        m_choices.Add(tk.GetNextToken());
+    }
+}
+
+// ----------------------------------------------------------------------------
+// wxGridCellEditorEvtHandler
+// ----------------------------------------------------------------------------
+
+void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent& event)
+{
+    switch ( event.KeyCode() )
+    {
+        case WXK_ESCAPE:
+            m_editor->Reset();
+            m_grid->DisableCellEditControl();
+            break;
+
+        case WXK_TAB:
+            event.Skip( m_grid->ProcessEvent( event ) );
+            break;
+
+        case WXK_RETURN:
+            if (!m_grid->ProcessEvent(event))
+                m_editor->HandleReturn(event);
+            break;
+
+
+        default:
+            event.Skip();
+    }
+}
+
+void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent& event)
+{
+    switch ( event.KeyCode() )
+    {
+        case WXK_ESCAPE:
+        case WXK_TAB:
+        case WXK_RETURN:
+            break;
+
+        default:
+            event.Skip();
+    }
+}
+
+// ----------------------------------------------------------------------------
+// wxGridCellWorker is an (almost) empty common base class for
+// wxGridCellRenderer and wxGridCellEditor managing ref counting
+// ----------------------------------------------------------------------------
+
+void wxGridCellWorker::SetParameters(const wxString& WXUNUSED(params))
+{
+    // nothing to do
+}
+
+wxGridCellWorker::~wxGridCellWorker()
+{
+}
+
+// ============================================================================
+// renderer classes
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// wxGridCellRenderer
+// ----------------------------------------------------------------------------
+
+void wxGridCellRenderer::Draw(wxGrid& grid,
+                              wxGridCellAttr& attr,
+                              wxDC& dc,
+                              const wxRect& rect,
+                              int WXUNUSED(row), int WXUNUSED(col),
+                              bool isSelected)
+{
+    dc.SetBackgroundMode( wxSOLID );
+
+    if ( isSelected )
+    {
+        dc.SetBrush( wxBrush(grid.GetSelectionBackground(), wxSOLID) );
+    }
+    else
+    {
+        dc.SetBrush( wxBrush(attr.GetBackgroundColour(), wxSOLID) );
+    }
+
+    dc.SetPen( *wxTRANSPARENT_PEN );
+    dc.DrawRectangle(rect);
+}
+
+// ----------------------------------------------------------------------------
+// wxGridCellStringRenderer
+// ----------------------------------------------------------------------------
+
+void wxGridCellStringRenderer::SetTextColoursAndFont(wxGrid& grid,
+                                                     wxGridCellAttr& attr,
+                                                     wxDC& dc,
+                                                     bool isSelected)
+{
+    dc.SetBackgroundMode( wxTRANSPARENT );
+
+    // TODO some special colours for attr.IsReadOnly() case?
+
+    if ( isSelected )
+    {
+        dc.SetTextBackground( grid.GetSelectionBackground() );
+        dc.SetTextForeground( grid.GetSelectionForeground() );
+    }
+    else
+    {
+        dc.SetTextBackground( attr.GetBackgroundColour() );
+        dc.SetTextForeground( attr.GetTextColour() );
+    }
+
+    dc.SetFont( attr.GetFont() );
+}
+
+wxSize wxGridCellStringRenderer::DoGetBestSize(wxGridCellAttr& attr,
+                                               wxDC& dc,
+                                               const wxString& text)
+{
+    wxCoord x, y;
+    dc.SetFont(attr.GetFont());
+    dc.GetTextExtent(text, &x, &y);
+
+    return wxSize(x, y);
+}
+
+wxSize wxGridCellStringRenderer::GetBestSize(wxGrid& grid,
+                                             wxGridCellAttr& attr,
+                                             wxDC& dc,
+                                             int row, int col)
+{
+    return DoGetBestSize(attr, dc, grid.GetCellValue(row, col));
+}
+
+void wxGridCellStringRenderer::Draw(wxGrid& grid,
+                                    wxGridCellAttr& attr,
+                                    wxDC& dc,
+                                    const wxRect& rectCell,
+                                    int row, int col,
+                                    bool isSelected)
+{
+    wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
+
+    // now we only have to draw the text
+    SetTextColoursAndFont(grid, attr, dc, isSelected);
+
+    int hAlign, vAlign;
+    attr.GetAlignment(&hAlign, &vAlign);
+
+    wxRect rect = rectCell;
+    rect.Inflate(-1);
+
+    grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
+                           rect, hAlign, vAlign);
+}
+
+// ----------------------------------------------------------------------------
+// wxGridCellNumberRenderer
+// ----------------------------------------------------------------------------
+
+wxString wxGridCellNumberRenderer::GetString(wxGrid& grid, int row, int col)
+{
+    wxGridTableBase *table = grid.GetTable();
+    wxString text;
+    if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
+    {
+        text.Printf(_T("%ld"), table->GetValueAsLong(row, col));
+    }
+    else
+    {
+        text = table->GetValue(row, col);
+    }
+
+    return text;
+}
+
+void wxGridCellNumberRenderer::Draw(wxGrid& grid,
+                                    wxGridCellAttr& attr,
+                                    wxDC& dc,
+                                    const wxRect& rectCell,
+                                    int row, int col,
+                                    bool isSelected)
+{
+    wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
+
+    SetTextColoursAndFont(grid, attr, dc, isSelected);
+
+    // draw the text right aligned by default
+    int hAlign, vAlign;
+    attr.GetAlignment(&hAlign, &vAlign);
+    hAlign = wxRIGHT;
+
+    wxRect rect = rectCell;
+    rect.Inflate(-1);
+
+    grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
+}
+
+wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid,
+                                             wxGridCellAttr& attr,
+                                             wxDC& dc,
+                                             int row, int col)
+{
+    return DoGetBestSize(attr, dc, GetString(grid, row, col));
+}
+
+// ----------------------------------------------------------------------------
+// wxGridCellFloatRenderer
+// ----------------------------------------------------------------------------
+
+wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width, int precision)
+{
+    SetWidth(width);
+    SetPrecision(precision);
+}
+
+wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const
+{
+    wxGridCellFloatRenderer *renderer = new wxGridCellFloatRenderer;
+    renderer->m_width = m_width;
+    renderer->m_precision = m_precision;
+    renderer->m_format = m_format;
+
+    return renderer;
+}
+
+wxString wxGridCellFloatRenderer::GetString(wxGrid& grid, int row, int col)
+{
+    wxGridTableBase *table = grid.GetTable();
+
+    bool hasDouble;
+    double val;
+    wxString text;
+    if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
+    {
+        val = table->GetValueAsDouble(row, col);
+        hasDouble = TRUE;
+    }
+    else
+    {
+        text = table->GetValue(row, col);
+        hasDouble = text.ToDouble(&val);
+    }
+
+    if ( hasDouble )
+    {
+        if ( !m_format )
+        {
+            if ( m_width == -1 )
+            {
+                // default width/precision
+                m_format = _T("%f");
+            }
+            else if ( m_precision == -1 )
+            {
+                // default precision
+                m_format.Printf(_T("%%%d.f"), m_width);
+            }
+            else
+            {
+                m_format.Printf(_T("%%%d.%df"), m_width, m_precision);
+            }
+        }
+
+        text.Printf(m_format, val);
+    }
+    //else: text already contains the string
+
+    return text;
+}
+
+void wxGridCellFloatRenderer::Draw(wxGrid& grid,
+                                   wxGridCellAttr& attr,
+                                   wxDC& dc,
+                                   const wxRect& rectCell,
+                                   int row, int col,
+                                   bool isSelected)
+{
+    wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
+
+    SetTextColoursAndFont(grid, attr, dc, isSelected);
+
+    // draw the text right aligned by default
+    int hAlign, vAlign;
+    attr.GetAlignment(&hAlign, &vAlign);
+    hAlign = wxRIGHT;
+
+    wxRect rect = rectCell;
+    rect.Inflate(-1);
+
+    grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
+}
+
+wxSize wxGridCellFloatRenderer::GetBestSize(wxGrid& grid,
+                                            wxGridCellAttr& attr,
+                                            wxDC& dc,
+                                            int row, int col)
+{
+    return DoGetBestSize(attr, dc, GetString(grid, row, col));
+}
+
+void wxGridCellFloatRenderer::SetParameters(const wxString& params)
+{
+    bool ok = TRUE;
+
+    if ( !params )
+    {
+        // reset to defaults
+        SetWidth(-1);
+        SetPrecision(-1);
+    }
+    else
+    {
+        wxString tmp = params.BeforeFirst(_T(','));
+        if ( !!tmp )
+        {
+            long width;
+            if ( !tmp.ToLong(&width) )
+            {
+                ok = FALSE;
+            }
+            else
+            {
+                SetWidth((int)width);
+
+                tmp = params.AfterFirst(_T(','));
+                if ( !!tmp )
+                {
+                    long precision;
+                    if ( !tmp.ToLong(&precision) )
+                    {
+                        ok = FALSE;
+                    }
+                    else
+                    {
+                        SetPrecision((int)precision);
+                    }
+                }
+            }
+        }
+
+        if ( !ok )
+        {
+            wxLogDebug(_T("Invalid wxGridCellFloatRenderer parameter string "
+                          "'%s ignored"), params.c_str());
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+// wxGridCellBoolRenderer
+// ----------------------------------------------------------------------------
+
+wxSize wxGridCellBoolRenderer::ms_sizeCheckMark;
+
+// FIXME these checkbox size calculations are really ugly...
+
+// between checkmark and box
+static const wxCoord wxGRID_CHECKMARK_MARGIN = 2;
+
+wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
+                                           wxGridCellAttr& WXUNUSED(attr),
+                                           wxDC& WXUNUSED(dc),
+                                           int WXUNUSED(row),
+                                           int WXUNUSED(col))
+{
+    // compute it only once (no locks for MT safeness in GUI thread...)
+    if ( !ms_sizeCheckMark.x )
+    {
+        // get checkbox size
+        wxCoord checkSize = 0;
+        wxCheckBox *checkbox = new wxCheckBox(&grid, -1, wxEmptyString);
+        wxSize size = checkbox->GetBestSize();
+        checkSize = size.y + 2*wxGRID_CHECKMARK_MARGIN;
+
+        // FIXME wxGTK::wxCheckBox::GetBestSize() gives "wrong" result
+#if defined(__WXGTK__) || defined(__WXMOTIF__)
+        checkSize -= size.y / 2;
+#endif
+
+        delete checkbox;
+
+        ms_sizeCheckMark.x = ms_sizeCheckMark.y = checkSize;
+    }
+
+    return ms_sizeCheckMark;
+}
+
+void wxGridCellBoolRenderer::Draw(wxGrid& grid,
+                                  wxGridCellAttr& attr,
+                                  wxDC& dc,
+                                  const wxRect& rect,
+                                  int row, int col,
+                                  bool isSelected)
+{
+    wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
+
+    // draw a check mark in the centre (ignoring alignment - TODO)
+    wxSize size = GetBestSize(grid, attr, dc, row, col);
+
+    // don't draw outside the cell
+    wxCoord minSize = wxMin(rect.width, rect.height);
+    if ( size.x >= minSize || size.y >= minSize )
+    {
+        // and even leave (at least) 1 pixel margin
+        size.x = size.y = minSize - 2;
+    }
+
+    // draw a border around checkmark
+    wxRect rectBorder;
+    rectBorder.x = rect.x + rect.width/2 - size.x/2;
+    rectBorder.y = rect.y + rect.height/2 - size.y/2;
+    rectBorder.width = size.x;
+    rectBorder.height = size.y;
+
+    bool value;
+    if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) )
+        value = grid.GetTable()->GetValueAsBool(row, col);
+    else
+        value = !!grid.GetTable()->GetValue(row, col);
+
+    if ( value )
+    {
+        wxRect rectMark = rectBorder;
+#ifdef __WXMSW__
+        // MSW DrawCheckMark() is weird (and should probably be changed...)
+        rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN/2);
+        rectMark.x++;
+        rectMark.y++;
+#else // !MSW
+        rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN);
+#endif // MSW/!MSW
+
+        dc.SetTextForeground(attr.GetTextColour());
+        dc.DrawCheckMark(rectMark);
+    }
+
+    dc.SetBrush(*wxTRANSPARENT_BRUSH);
+    dc.SetPen(wxPen(attr.GetTextColour(), 1, wxSOLID));
+    dc.DrawRectangle(rectBorder);
+}
+
+// ----------------------------------------------------------------------------
+// wxGridCellAttr
+// ----------------------------------------------------------------------------
+
+wxGridCellAttr *wxGridCellAttr::Clone() const
+{
+    wxGridCellAttr *attr = new wxGridCellAttr;
+    if ( HasTextColour() )
+        attr->SetTextColour(GetTextColour());
+    if ( HasBackgroundColour() )
+        attr->SetBackgroundColour(GetBackgroundColour());
+    if ( HasFont() )
+        attr->SetFont(GetFont());
+    if ( HasAlignment() )
+        attr->SetAlignment(m_hAlign, m_vAlign);
+
+    if ( m_renderer )
+    {
+        attr->SetRenderer(m_renderer);
+        m_renderer->IncRef();
+    }
+    if ( m_editor )
+    {
+        attr->SetEditor(m_editor);
+        m_editor->IncRef();
+    }
+
+    if ( IsReadOnly() )
+        attr->SetReadOnly();
+
+    attr->SetDefAttr(m_defGridAttr);
+
+    return attr;
+}
+
+const wxColour& wxGridCellAttr::GetTextColour() const
+{
+    if (HasTextColour())
+    {
+        return m_colText;
+    }
+    else if (m_defGridAttr != this)
+    {
+        return m_defGridAttr->GetTextColour();
+    }
+    else
+    {
+        wxFAIL_MSG(wxT("Missing default cell attribute"));
+        return wxNullColour;
+    }
+}
+
+
+const wxColour& wxGridCellAttr::GetBackgroundColour() const
+{
+    if (HasBackgroundColour())
+        return m_colBack;
+    else if (m_defGridAttr != this)
+        return m_defGridAttr->GetBackgroundColour();
+    else
+    {
+        wxFAIL_MSG(wxT("Missing default cell attribute"));
+        return wxNullColour;
+    }
+}
+
+
+const wxFont& wxGridCellAttr::GetFont() const
+{
+    if (HasFont())
+        return m_font;
+    else if (m_defGridAttr != this)
+        return m_defGridAttr->GetFont();
+    else
+    {
+        wxFAIL_MSG(wxT("Missing default cell attribute"));
+        return wxNullFont;
+    }
+}
+
+
+void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const
+{
+    if (HasAlignment())
+    {
+        if ( hAlign ) *hAlign = m_hAlign;
+        if ( vAlign ) *vAlign = m_vAlign;
+    }
+    else if (m_defGridAttr != this)
+        m_defGridAttr->GetAlignment(hAlign, vAlign);
+    else
+    {
+        wxFAIL_MSG(wxT("Missing default cell attribute"));
+    }
+}
+
+
+// GetRenderer and GetEditor use a slightly different decision path about
+// which attribute to use.  If a non-default attr object has one then it is
+// used, otherwise the default editor or renderer is fetched from the grid and
+// used.  It should be the default for the data type of the cell.  If it is
+// NULL (because the table has a type that the grid does not have in its
+// registry,) then the grid's default editor or renderer is used.
+
+wxGridCellRenderer* wxGridCellAttr::GetRenderer(wxGrid* grid, int row, int col) const
+{
+    wxGridCellRenderer* renderer = NULL;
+
+    if ( m_defGridAttr != this || grid == NULL )
+    {
+        renderer = m_renderer;      // use local attribute
+        if ( renderer )
+            renderer->IncRef();
+    }
+
+    if ( !renderer && grid )        // get renderer for the data type
+    {
+        // GetDefaultRendererForCell() will do IncRef() for us
+        renderer = grid->GetDefaultRendererForCell(row, col);
+    }
+
+    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)
+    {
+        wxFAIL_MSG(wxT("Missing default cell attribute"));
+    }
+
+    return renderer;
+}
+
+wxGridCellEditor* wxGridCellAttr::GetEditor(wxGrid* grid, int row, int col) const
+{
+    wxGridCellEditor* editor = NULL;
+
+    if ( m_defGridAttr != this || grid == NULL )
+    {
+        editor = m_editor;      // use local attribute
+        if ( 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 )
+    {
+        wxFAIL_MSG(wxT("Missing default cell attribute"));
+    }
+
+    return editor;
+}
+
+// ----------------------------------------------------------------------------
+// wxGridCellAttrData
+// ----------------------------------------------------------------------------
+
+void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col)
+{
+    int n = FindIndex(row, col);
+    if ( n == wxNOT_FOUND )
+    {
+        // add the attribute
+        m_attrs.Add(new wxGridCellWithAttr(row, col, attr));
+    }
+    else
+    {
+        if ( attr )
+        {
+            // change the attribute
+            m_attrs[(size_t)n].attr = attr;
+        }
+        else
+        {
+            // remove this attribute
+            m_attrs.RemoveAt((size_t)n);
+        }
+    }
+}
+
+wxGridCellAttr *wxGridCellAttrData::GetAttr(int row, int col) const
+{
+    wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
+
+    int n = FindIndex(row, col);
+    if ( n != wxNOT_FOUND )
+    {
+        attr = m_attrs[(size_t)n].attr;
+        attr->IncRef();
+    }
+
+    return attr;
+}
+
+void wxGridCellAttrData::UpdateAttrRows( size_t pos, int numRows )
+{
+    size_t count = m_attrs.GetCount();
+    for ( size_t n = 0; n < count; n++ )
+    {
+        wxGridCellCoords& coords = m_attrs[n].coords;
+        wxCoord row = coords.GetRow();
+        if ((size_t)row >= pos)
+        {
+            if (numRows > 0)
+            {
+                // If rows inserted, include row counter where necessary
+                coords.SetRow(row + numRows);
+            }
+            else if (numRows < 0)
+            {
+                // If rows deleted ...
+                if ((size_t)row >= pos - numRows)
+                {
+                    // ...either decrement row counter (if row still exists)...
+                    coords.SetRow(row + numRows);
+                }
+                else
+                {
+                    // ...or remove the attribute
+                    m_attrs.RemoveAt((size_t)n);
+                    n--; count--;
+                }
+            }
+        }
+    }
+}
+
+void wxGridCellAttrData::UpdateAttrCols( size_t pos, int numCols )
+{
+    size_t count = m_attrs.GetCount();
+    for ( size_t n = 0; n < count; n++ )
+    {
+        wxGridCellCoords& coords = m_attrs[n].coords;
+        wxCoord col = coords.GetCol();
+        if ( (size_t)col >= pos )
+        {
+            if ( numCols > 0 )
+            {
+                // If rows inserted, include row counter where necessary
+                coords.SetCol(col + numCols);
+            }
+            else if (numCols < 0)
+            {
+                // If rows deleted ...
+                if ((size_t)col >= pos - numCols)
+                {
+                    // ...either decrement row counter (if row still exists)...
+                    coords.SetCol(col + numCols);
+                }
+                else
+                {
+                    // ...or remove the attribute
+                    m_attrs.RemoveAt((size_t)n);
+                    n--; count--;
+                }
+            }
+        }
+    }
+}
+
+int wxGridCellAttrData::FindIndex(int row, int col) const
+{
+    size_t count = m_attrs.GetCount();
+    for ( size_t n = 0; n < count; n++ )
+    {
+        const wxGridCellCoords& coords = m_attrs[n].coords;
+        if ( (coords.GetRow() == row) && (coords.GetCol() == col) )
+        {
+            return n;
+        }
+    }
+
+    return wxNOT_FOUND;
+}
+
+// ----------------------------------------------------------------------------
+// wxGridRowOrColAttrData
+// ----------------------------------------------------------------------------
+
+wxGridRowOrColAttrData::~wxGridRowOrColAttrData()
+{
+    size_t count = m_attrs.Count();
+    for ( size_t n = 0; n < count; n++ )
+    {
+        m_attrs[n]->DecRef();
+    }
+}
+
+wxGridCellAttr *wxGridRowOrColAttrData::GetAttr(int rowOrCol) const
+{
+    wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
+
+    int n = m_rowsOrCols.Index(rowOrCol);
+    if ( n != wxNOT_FOUND )
+    {
+        attr = m_attrs[(size_t)n];
+        attr->IncRef();
+    }
+
+    return attr;
+}
+
+void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol)
+{
+    int i = m_rowsOrCols.Index(rowOrCol);
+    if ( i == wxNOT_FOUND )
+    {
+        // add the attribute
+        m_rowsOrCols.Add(rowOrCol);
+        m_attrs.Add(attr);
+    }
+    else
+    {
+        size_t n = (size_t)i;
+        if ( attr )
+        {
+            // change the attribute
+            m_attrs[n]->DecRef();
+            m_attrs[n] = attr;
+        }
+        else
+        {
+            // remove this attribute
+            m_attrs[n]->DecRef();
+            m_rowsOrCols.RemoveAt(n);
+            m_attrs.RemoveAt(n);
+        }
+    }
+}
+
+void wxGridRowOrColAttrData::UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols )
+{
+    size_t count = m_attrs.GetCount();
+    for ( size_t n = 0; n < count; n++ )
+    {
+        int & rowOrCol = m_rowsOrCols[n];
+        if ( (size_t)rowOrCol >= pos )
+        {
+            if ( numRowsOrCols > 0 )
+            {
+                // If rows inserted, include row counter where necessary
+                rowOrCol += numRowsOrCols;
+            }
+            else if ( numRowsOrCols < 0)
+            {
+                // If rows deleted, either decrement row counter (if row still exists)
+                if ((size_t)rowOrCol >= pos - numRowsOrCols)
+                    rowOrCol += numRowsOrCols;
+                else
+                {
+                    m_rowsOrCols.RemoveAt((size_t)n);
+                    m_attrs.RemoveAt((size_t)n);
+                    n--; count--;
+                }
+            }
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+// wxGridCellAttrProvider
+// ----------------------------------------------------------------------------
+
+wxGridCellAttrProvider::wxGridCellAttrProvider()
+{
+    m_data = (wxGridCellAttrProviderData *)NULL;
+}
+
+wxGridCellAttrProvider::~wxGridCellAttrProvider()
+{
+    delete m_data;
+}
+
+void wxGridCellAttrProvider::InitData()
+{
+    m_data = new wxGridCellAttrProviderData;
+}
+
+wxGridCellAttr *wxGridCellAttrProvider::GetAttr(int row, int col) const
+{
+    wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
+    if ( m_data )
+    {
+        // first look for the attribute of this specific cell
+        attr = m_data->m_cellAttrs.GetAttr(row, col);
+
+        if ( !attr )
+        {
+            // then look for the col attr (col attributes are more common than
+            // the row ones, hence they have priority)
+            attr = m_data->m_colAttrs.GetAttr(col);
+        }
+
+        if ( !attr )
+        {
+            // finally try the row attributes
+            attr = m_data->m_rowAttrs.GetAttr(row);
+        }
+    }
+
+    return attr;
+}
+
+void wxGridCellAttrProvider::SetAttr(wxGridCellAttr *attr,
+                                     int row, int col)
+{
+    if ( !m_data )
+        InitData();
+
+    m_data->m_cellAttrs.SetAttr(attr, row, col);
+}
+
+void wxGridCellAttrProvider::SetRowAttr(wxGridCellAttr *attr, int row)
+{
+    if ( !m_data )
+        InitData();
+
+    m_data->m_rowAttrs.SetAttr(attr, row);
+}
+
+void wxGridCellAttrProvider::SetColAttr(wxGridCellAttr *attr, int col)
+{
+    if ( !m_data )
+        InitData();
+
+    m_data->m_colAttrs.SetAttr(attr, col);
+}
+
+void wxGridCellAttrProvider::UpdateAttrRows( size_t pos, int numRows )
+{
+    if ( m_data )
+    {
+        m_data->m_cellAttrs.UpdateAttrRows( pos, numRows );
+
+        m_data->m_rowAttrs.UpdateAttrRowsOrCols( pos, numRows );
+    }
+}
+
+void wxGridCellAttrProvider::UpdateAttrCols( size_t pos, int numCols )
+{
+    if ( m_data )
+    {
+        m_data->m_cellAttrs.UpdateAttrCols( pos, numCols );
+
+        m_data->m_colAttrs.UpdateAttrRowsOrCols( pos, numCols );
+    }
+}
+
+// ----------------------------------------------------------------------------
+// wxGridTypeRegistry
+// ----------------------------------------------------------------------------
+
+wxGridTypeRegistry::~wxGridTypeRegistry()
+{
+    size_t count = m_typeinfo.Count();
+    for ( size_t i = 0; i < count; i++ )
+        delete m_typeinfo[i];
+}
+
+
+void wxGridTypeRegistry::RegisterDataType(const wxString& typeName,
+                                          wxGridCellRenderer* renderer,
+                                          wxGridCellEditor* editor)
+{
+    wxGridDataTypeInfo* info = new wxGridDataTypeInfo(typeName, renderer, editor);
+
+    // is it already registered?
+    int loc = FindRegisteredDataType(typeName);
+    if ( loc != wxNOT_FOUND )
+    {
+        delete m_typeinfo[loc];
+        m_typeinfo[loc] = info;
+    }
+    else
+    {
+        m_typeinfo.Add(info);
+    }
+}
+
+int wxGridTypeRegistry::FindRegisteredDataType(const wxString& typeName)
+{
+    size_t count = m_typeinfo.GetCount();
+    for ( size_t i = 0; i < count; i++ )
+    {
+        if ( typeName == m_typeinfo[i]->m_typeName )
+        {
+            return i;
+        }
+    }
+
+    return wxNOT_FOUND;
+}
+
+int wxGridTypeRegistry::FindDataType(const wxString& typeName)
+{
+    int index = FindRegisteredDataType(typeName);
+    if ( index == wxNOT_FOUND )
+    {
+        // check whether this is one of the standard ones, in which case
+        // register it "on the fly"
+        if ( typeName == wxGRID_VALUE_STRING )
+        {
+            RegisterDataType(wxGRID_VALUE_STRING,
+                             new wxGridCellStringRenderer,
+                             new wxGridCellTextEditor);
+        }
+        else if ( typeName == wxGRID_VALUE_BOOL )
+        {
+            RegisterDataType(wxGRID_VALUE_BOOL,
+                             new wxGridCellBoolRenderer,
+                             new wxGridCellBoolEditor);
+        }
+        else if ( typeName == wxGRID_VALUE_NUMBER )
+        {
+            RegisterDataType(wxGRID_VALUE_NUMBER,
+                             new wxGridCellNumberRenderer,
+                             new wxGridCellNumberEditor);
+        }
+        else if ( typeName == wxGRID_VALUE_FLOAT )
+        {
+            RegisterDataType(wxGRID_VALUE_FLOAT,
+                             new wxGridCellFloatRenderer,
+                             new wxGridCellFloatEditor);
+        }
+        else if ( typeName == wxGRID_VALUE_CHOICE )
+        {
+            RegisterDataType(wxGRID_VALUE_CHOICE,
+                             new wxGridCellStringRenderer,
+                             new wxGridCellChoiceEditor);
+        }
+        else
+        {
+            return wxNOT_FOUND;
+        }
+
+        // we get here only if just added the entry for this type, so return
+        // the last index
+        index = m_typeinfo.GetCount() - 1;
+    }
+
+    return index;
+}
+
+int wxGridTypeRegistry::FindOrCloneDataType(const wxString& typeName)
+{
+    int index = FindDataType(typeName);
+    if ( index == wxNOT_FOUND )
+    {
+        // the first part of the typename is the "real" type, anything after ':'
+        // are the parameters for the renderer
+        index = FindDataType(typeName.BeforeFirst(_T(':')));
+        if ( index == wxNOT_FOUND )
+        {
+            return wxNOT_FOUND;
+        }
+
+        wxGridCellRenderer *renderer = GetRenderer(index);
+        wxGridCellRenderer *rendererOld = renderer;
+        renderer = renderer->Clone();
+        rendererOld->DecRef();
+
+        wxGridCellEditor *editor = GetEditor(index);
+        wxGridCellEditor *editorOld = editor;
+        editor = editor->Clone();
+        editorOld->DecRef();
+
+        // do it even if there are no parameters to reset them to defaults
+        wxString params = typeName.AfterFirst(_T(':'));
+        renderer->SetParameters(params);
+        editor->SetParameters(params);
+
+        // register the new typename
+        RegisterDataType(typeName, renderer, editor);
+
+        // we just registered it, it's the last one
+        index = m_typeinfo.GetCount() - 1;
+    }
+
+    return index;