#include "wx/log.h"
#include "wx/textctrl.h"
#include "wx/checkbox.h"
+ #include "wx/combobox.h"
+ #include "wx/valtext.h"
#endif
-// this include needs to be outside precomp for BCC
#include "wx/textfile.h"
+#include "wx/spinctrl.h"
#include "wx/grid.h"
m_colAttrs;
};
+
+// ----------------------------------------------------------------------------
+// data structures used for the data type registry
+// ----------------------------------------------------------------------------
+
+struct wxGridDataTypeInfo {
+ wxGridDataTypeInfo(const wxString& typeName,
+ wxGridCellRenderer* renderer,
+ wxGridCellEditor* editor)
+ : m_typeName(typeName), m_renderer(renderer), m_editor(editor)
+ { }
+
+ ~wxGridDataTypeInfo() { delete m_renderer; delete m_editor; }
+
+ wxString m_typeName;
+ wxGridCellRenderer* m_renderer;
+ wxGridCellEditor* m_editor;
+};
+
+
+WX_DEFINE_ARRAY(wxGridDataTypeInfo*, wxGridDataTypeInfoArray);
+
+
+class WXDLLEXPORT wxGridTypeRegistry {
+public:
+ ~wxGridTypeRegistry();
+ void RegisterDataType(const wxString& typeName,
+ wxGridCellRenderer* renderer,
+ wxGridCellEditor* editor);
+ int FindDataType(const wxString& typeName);
+ wxGridCellRenderer* GetRenderer(int index);
+ wxGridCellEditor* GetEditor(int index);
+
+private:
+ wxGridDataTypeInfoArray m_typeinfo;
+};
+
+
+
+
// ----------------------------------------------------------------------------
// conditional compilation
// ----------------------------------------------------------------------------
// set the colours/fonts if we have any
if ( attr )
{
- if ( attr->HasTextColour() )
- {
- m_colFgOld = m_control->GetForegroundColour();
- m_control->SetForegroundColour(attr->GetTextColour());
- }
+ m_colFgOld = m_control->GetForegroundColour();
+ m_control->SetForegroundColour(attr->GetTextColour());
- if ( attr->HasBackgroundColour() )
- {
- m_colBgOld = m_control->GetBackgroundColour();
- m_control->SetBackgroundColour(attr->GetBackgroundColour());
- }
+ m_colBgOld = m_control->GetBackgroundColour();
+ m_control->SetBackgroundColour(attr->GetBackgroundColour());
- if ( attr->HasFont() )
- {
- m_fontOld = m_control->GetFont();
- m_control->SetFont(attr->GetFont());
- }
+ m_fontOld = m_control->GetFont();
+ m_control->SetFont(attr->GetFont());
// can't do anything more in the base class version, the other
// attributes may only be used by the derived classes
// flicker
}
+void wxGridCellTextEditor::SetSize(const wxRect& rectOrig)
+{
+ wxRect rect(rectOrig);
+
+ // Make the edit control large enough to allow for internal
+ // margins
+ //
+ // TODO: remove this if the text ctrl sizing is improved esp. for
+ // unix
+ //
+#if defined(__WXGTK__)
+ rect.Inflate(rect.x ? 1 : 0, rect.y ? 1 : 0);
+#else // !GTK
+ int extra = row && col ? 2 : 1;
+#if defined(__WXMOTIF__)
+ extra *= 2;
+#endif
+ rect.SetLeft( wxMax(0, rect.x - extra) );
+ rect.SetTop( wxMax(0, rect.y - extra) );
+ rect.SetRight( rect.GetRight() + 2*extra );
+ rect.SetBottom( rect.GetBottom() + 2*extra );
+#endif // GTK/!GTK
+
+ wxGridCellEditor::SetSize(rect);
+}
+
void wxGridCellTextEditor::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);
- Text()->SetValue(m_startValue);
+
+ DoBeginEdit(m_startValue);
+}
+
+void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue)
+{
+ Text()->SetValue(startValue);
Text()->SetInsertionPointEnd();
Text()->SetFocus();
}
-
bool wxGridCellTextEditor::EndEdit(int row, int col, bool saveValue,
wxGrid* grid)
{
wxASSERT_MSG(m_control,
wxT("The wxGridCellEditor must be Created first!"));
- Text()->SetValue(m_startValue);
+ DoReset(m_startValue);
+}
+
+void wxGridCellTextEditor::DoReset(const wxString& startValue)
+{
+ Text()->SetValue(startValue);
Text()->SetInsertionPointEnd();
}
#endif
}
+// ----------------------------------------------------------------------------
+// wxGridCellNumberEditor
+// ----------------------------------------------------------------------------
+
+wxGridCellNumberEditor::wxGridCellNumberEditor(int min, int max)
+{
+ m_min = min;
+ m_max = max;
+}
+
+void wxGridCellNumberEditor::Create(wxWindow* parent,
+ wxWindowID id,
+ wxEvtHandler* evtHandler)
+{
+ if ( HasRange() )
+ {
+ // create a spin ctrl
+ m_control = new wxSpinCtrl(parent, -1, wxEmptyString,
+ wxDefaultPosition, wxDefaultSize,
+ wxSP_ARROW_KEYS,
+ m_min, m_max);
+
+ wxGridCellEditor::Create(parent, id, evtHandler);
+ }
+ else
+ {
+ // just a text control
+ wxGridCellTextEditor::Create(parent, id, evtHandler);
+
+#if wxUSE_VALIDATORS
+ Text()->SetValidator(new wxTextValidator(wxFILTER_NUMERIC));
+#endif // wxUSE_VALIDATORS
+ }
+}
+
+void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid)
+{
+ // first get the value
+ wxGridTableBase *table = grid->GetTable();
+ if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
+ {
+ m_valueOld = table->GetValueAsLong(row, col);
+ }
+ else
+ {
+ wxFAIL_MSG( _T("this cell doesn't have numeric value") );
+
+ return;
+ }
+
+ if ( HasRange() )
+ {
+ Spin()->SetValue(m_valueOld);
+ }
+ else
+ {
+ DoBeginEdit(GetString());
+ }
+}
+
+bool wxGridCellNumberEditor::EndEdit(int row, int col, bool saveValue,
+ 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 )
+ {
+ grid->GetTable()->SetValueAsLong(row, col, value);
+ }
+
+ return changed;
+}
+
+void wxGridCellNumberEditor::Reset()
+{
+ if ( HasRange() )
+ {
+ Spin()->SetValue(m_valueOld);
+ }
+ else
+ {
+ DoReset(GetString());
+ }
+}
+
+void wxGridCellNumberEditor::StartingKey(wxKeyEvent& event)
+{
+ if ( !HasRange() )
+ {
+ long keycode = event.KeyCode();
+ if ( isdigit(keycode) || keycode == '+' || keycode == '-' )
+ {
+ wxGridCellTextEditor::StartingKey(event);
+
+ // skip Skip() below
+ return;
+ }
+ }
+
+ event.Skip();
+}
+// ----------------------------------------------------------------------------
+// wxGridCellFloatEditor
+// ----------------------------------------------------------------------------
+
+void wxGridCellFloatEditor::Create(wxWindow* parent,
+ wxWindowID id,
+ wxEvtHandler* evtHandler)
+{
+ wxGridCellTextEditor::Create(parent, id, evtHandler);
+
+#if wxUSE_VALIDATORS
+ Text()->SetValidator(new 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
+ {
+ wxFAIL_MSG( _T("this cell doesn't have float value") );
+
+ return;
+ }
+
+ DoBeginEdit(GetString());
+}
+
+bool wxGridCellFloatEditor::EndEdit(int row, int col, bool saveValue,
+ wxGrid* grid)
+{
+ double value;
+ if ( Text()->GetValue().ToDouble(&value) && (value != m_valueOld) )
+ {
+ grid->GetTable()->SetValueAsDouble(row, col, value);
+
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+void wxGridCellFloatEditor::Reset()
+{
+ DoReset(GetString());
+}
+
+void wxGridCellFloatEditor::StartingKey(wxKeyEvent& event)
+{
+ long keycode = event.KeyCode();
+ if ( isdigit(keycode) ||
+ keycode == '+' || keycode == '-' || keycode == '.' )
+ {
+ wxGridCellTextEditor::StartingKey(event);
+
+ // skip Skip() below
+ return;
+ }
+
+ event.Skip();
+}
+
// ----------------------------------------------------------------------------
// wxGridCellBoolEditor
// ----------------------------------------------------------------------------
void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr)
{
- wxGridCellEditor::Show(show, attr);
+ m_control->Show(show);
+
if ( show )
{
- // VZ: normally base class already does it, but it doesn't work (FIXME)
wxColour colBg = attr ? attr->GetBackgroundColour() : *wxLIGHT_GREY;
CBox()->SetBackgroundColour(colBg);
}
wxASSERT_MSG(m_control,
wxT("The wxGridCellEditor must be Created first!"));
- m_startValue = !!grid->GetTable()->GetValue(row, col); // FIXME-DATA
+ if (grid->GetTable()->CanGetValueAs(row, col, wxT("bool")))
+ m_startValue = grid->GetTable()->GetValueAsBool(row, col);
+ else
+ m_startValue = !!grid->GetTable()->GetValue(row, col);
CBox()->SetValue(m_startValue);
CBox()->SetFocus();
}
if ( changed )
{
- // FIXME-DATA
- grid->GetTable()->SetValue(row, col, value ? _T("1") : wxEmptyString);
+ if (grid->GetTable()->CanGetValueAs(row, col, wxT("bool")))
+ grid->GetTable()->SetValueAsBool(row, col, value);
+ else
+ grid->GetTable()->SetValue(row, col, value ? _T("1") : wxEmptyString);
}
return changed;
CBox()->SetValue(!CBox()->GetValue());
}
+// ----------------------------------------------------------------------------
+// wxGridCellChoiceEditor
+// ----------------------------------------------------------------------------
+
+wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count,
+ const wxChar* choices[],
+ bool allowOthers)
+ : m_allowOthers(allowOthers)
+{
+ m_choices.Alloc(count);
+ for ( size_t n = 0; n < count; n++ )
+ {
+ m_choices.Add(choices[n]);
+ }
+}
+
+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& WXUNUSED(rectCell),
+ wxGridCellAttr * WXUNUSED(attr))
+{
+ // as we fill the entire client area, don't do anything here to minimize
+ // flicker
+}
+
+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);
+ Combo()->SetInsertionPointEnd();
+ Combo()->SetFocus();
+}
+
+bool wxGridCellChoiceEditor::EndEdit(int row, int col,
+ bool saveValue,
+ 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();
+}
+
// ----------------------------------------------------------------------------
// wxGridCellEditorEvtHandler
// ----------------------------------------------------------------------------
dc.DrawRectangle(rect);
}
+wxGridCellRenderer::~wxGridCellRenderer()
+{
+}
+
// ----------------------------------------------------------------------------
// 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,
wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
// now we only have to draw the text
- dc.SetBackgroundMode( wxTRANSPARENT );
+ SetTextColoursAndFont(grid, attr, dc, isSelected);
- // TODO some special colours for attr.IsReadOnly() case?
+ 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: leave the string empty or put 0 into it?
+
+ 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);
+}
- if ( isSelected )
- {
- dc.SetTextBackground( grid.GetSelectionBackground() );
- dc.SetTextForeground( grid.GetSelectionForeground() );
- }
- else
+wxString wxGridCellFloatRenderer::GetString(wxGrid& grid, int row, int col)
+{
+ wxGridTableBase *table = grid.GetTable();
+ wxString text;
+ if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
{
- dc.SetTextBackground( attr.GetBackgroundColour() );
- dc.SetTextForeground( attr.GetTextColour() );
+ if ( !m_format )
+ {
+ m_format.Printf(_T("%%%d.%d%%f"), m_width, m_precision);
+ }
+
+ text.Printf(m_format, table->GetValueAsDouble(row, col));
}
- dc.SetFont( attr.GetFont() );
+ //else: leave the string empty or put 0 into it?
+
+ 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.x++;
- rect.y++;
- rect.width -= 2;
- rect.height -= 2;
+ rect.Inflate(-1);
- grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
- rect, hAlign, vAlign);
+ 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));
}
// ----------------------------------------------------------------------------
// wxGridCellBoolRenderer
// ----------------------------------------------------------------------------
-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);
+wxSize wxGridCellBoolRenderer::ms_sizeCheckMark;
- // between checkmark and box
- static const wxCoord margin = 4;
+// between checkmark and box
+static const wxCoord wxGRID_CHECKMARK_MARGIN = 4;
- // get checkbox size
- static wxCoord s_checkSize = 0;
- if ( s_checkSize == 0 )
+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 )
{
- // compute it only once (no locks for MT safeness in GUI thread...)
+ // get checkbox size
+ wxCoord checkSize = 0;
wxCheckBox *checkbox = new wxCheckBox(&grid, -1, wxEmptyString);
wxSize size = checkbox->GetBestSize();
- s_checkSize = size.y + margin;
+ checkSize = size.y + wxGRID_CHECKMARK_MARGIN;
- // FIXME wxGTK::wxCheckBox::GetBestSize() is really weird...
+ // FIXME wxGTK::wxCheckBox::GetBestSize() gives "wrong" result
#ifdef __WXGTK__
- s_checkSize -= size.y / 2;
+ 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);
wxRect rectMark;
- rectMark.x = rect.x + rect.width/2 - s_checkSize/2;
- rectMark.y = rect.y + rect.height/2 - s_checkSize/2;
- rectMark.width = rectMark.height = s_checkSize;
+ rectMark.x = rect.x + rect.width/2 - size.x/2;
+ rectMark.y = rect.y + rect.height/2 - size.y/2;
+ rectMark.width = size.x;
+ rectMark.height = size.y;
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.SetPen(wxPen(attr.GetTextColour(), 1, wxSOLID));
dc.DrawRectangle(rectMark);
- rectMark.Inflate(-margin);
+ rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN);
+
+ bool value;
+ if (grid.GetTable()->CanGetValueAs(row, col, wxT("bool")))
+ value = grid.GetTable()->GetValueAsBool(row, col);
+ else
+ value = !!grid.GetTable()->GetValue(row, col);
- if ( !!grid.GetTable()->GetValue(row, col) ) // FIXME-DATA
+ if ( value )
{
dc.SetTextForeground(attr.GetTextColour());
dc.DrawCheckMark(rectMark);
}
-wxGridCellRenderer* wxGridCellAttr::GetRenderer() const
+// GetRenderer and GetEditor use a slightly different decision path about
+// which to use. If a non-default attr object has one then it is used,
+// otherwise the default editor or renderer passed in is 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(wxGridCellRenderer* def) const
{
- if (HasRenderer())
+ if ((m_defGridAttr != this || def == NULL) && HasRenderer())
return m_renderer;
+ else if (def)
+ return def;
else if (m_defGridAttr != this)
- return m_defGridAttr->GetRenderer();
+ return m_defGridAttr->GetRenderer(NULL);
else
{
wxFAIL_MSG(wxT("Missing default cell attribute"));
}
}
-wxGridCellEditor* wxGridCellAttr::GetEditor() const
+wxGridCellEditor* wxGridCellAttr::GetEditor(wxGridCellEditor* def) const
{
- if (HasEditor())
+ if ((m_defGridAttr != this || def == NULL) && HasEditor())
return m_editor;
+ else if (def)
+ return def;
else if (m_defGridAttr != this)
- return m_defGridAttr->GetEditor();
+ return m_defGridAttr->GetEditor(NULL);
else
{
wxFAIL_MSG(wxT("Missing default cell attribute"));
}
}
+// ----------------------------------------------------------------------------
+// wxGridTypeRegistry
+// ----------------------------------------------------------------------------
+
+wxGridTypeRegistry::~wxGridTypeRegistry()
+{
+ for (size_t i=0; i<m_typeinfo.Count(); i++)
+ delete m_typeinfo[i];
+}
+
+
+void wxGridTypeRegistry::RegisterDataType(const wxString& typeName,
+ wxGridCellRenderer* renderer,
+ wxGridCellEditor* editor)
+{
+ int loc;
+ wxGridDataTypeInfo* info = new wxGridDataTypeInfo(typeName, renderer, editor);
+
+ // is it already registered?
+ if ((loc = FindDataType(typeName)) != -1) {
+ delete m_typeinfo[loc];
+ m_typeinfo[loc] = info;
+ }
+ else {
+ m_typeinfo.Add(info);
+ }
+}
+
+int wxGridTypeRegistry::FindDataType(const wxString& typeName)
+{
+ int found = -1;
+
+ for (size_t i=0; i<m_typeinfo.Count(); i++) {
+ if (typeName == m_typeinfo[i]->m_typeName) {
+ found = i;
+ break;
+ }
+ }
+
+ return found;
+}
+
+wxGridCellRenderer* wxGridTypeRegistry::GetRenderer(int index)
+{
+ wxGridCellRenderer* renderer = m_typeinfo[index]->m_renderer;
+ return renderer;
+}
+
+wxGridCellEditor* wxGridTypeRegistry::GetEditor(int index)
+{
+ wxGridCellEditor* editor = m_typeinfo[index]->m_editor;
+ return editor;
+}
+
// ----------------------------------------------------------------------------
// wxGridTableBase
// ----------------------------------------------------------------------------
-//////////////////////////////////////////////////////////////////////
-//
-// Abstract base class for grid data (the model)
-//
IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject )
m_attrProvider = attrProvider;
}
+bool wxGridTableBase::CanHaveAttributes()
+{
+ if ( ! GetAttrProvider() )
+ {
+ // use the default attr provider by default
+ SetAttrProvider(new wxGridCellAttrProvider);
+ }
+ return TRUE;
+}
+
wxGridCellAttr *wxGridTableBase::GetAttr(int row, int col)
{
if ( m_attrProvider )
wxString wxGridTableBase::GetRowLabelValue( int row )
{
wxString s;
- s << row;
+ s << row + 1; // RD: Starting the rows at zero confuses users, no matter
+ // how much it makes sense to us geeks.
return s;
}
}
+wxString wxGridTableBase::GetTypeName( int WXUNUSED(row), int WXUNUSED(col) )
+{
+ return wxGRID_VALUE_STRING;
+}
+
+bool wxGridTableBase::CanGetValueAs( int WXUNUSED(row), int WXUNUSED(col),
+ const wxString& typeName )
+{
+ return typeName == wxGRID_VALUE_STRING;
+}
+
+bool wxGridTableBase::CanSetValueAs( int row, int col, const wxString& typeName )
+{
+ return CanGetValueAs(row, col, typeName);
+}
+
+long wxGridTableBase::GetValueAsLong( int WXUNUSED(row), int WXUNUSED(col) )
+{
+ return 0;
+}
+
+double wxGridTableBase::GetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col) )
+{
+ return 0.0;
+}
+
+bool wxGridTableBase::GetValueAsBool( int WXUNUSED(row), int WXUNUSED(col) )
+{
+ return FALSE;
+}
+
+void wxGridTableBase::SetValueAsLong( int WXUNUSED(row), int WXUNUSED(col),
+ long WXUNUSED(value) )
+{
+}
+
+void wxGridTableBase::SetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col),
+ double WXUNUSED(value) )
+{
+}
+
+void wxGridTableBase::SetValueAsBool( int WXUNUSED(row), int WXUNUSED(col),
+ bool WXUNUSED(value) )
+{
+}
+
+
+void* wxGridTableBase::GetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
+ const wxString& WXUNUSED(typeName) )
+{
+ return NULL;
+}
+
+void wxGridTableBase::SetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
+ const wxString& WXUNUSED(typeName),
+ void* WXUNUSED(value) )
+{
+}
+
//////////////////////////////////////////////////////////////////////
//
return m_data[row][col];
}
-void wxGridStringTable::SetValue( int row, int col, const wxString& s )
+void wxGridStringTable::SetValue( int row, int col, const wxString& value )
{
// TODO: bounds checking
//
- m_data[row][col] = s;
+ m_data[row][col] = value;
}
bool wxGridStringTable::IsEmptyCell( int row, int col )
{
int cw, ch;
GetClientSize( &cw, &ch );
-
+
int right, bottom;
m_owner->CalcUnscrolledPosition( cw, ch, &right, &bottom );
-
+
wxRect rightRect;
rightRect = m_owner->CellToRect( 0, m_owner->GetNumberCols()-1 );
wxRect bottomRect;
bottomRect = m_owner->CellToRect( m_owner->GetNumberRows()-1, 0 );
-
+
if ( right > rightRect.GetRight() || bottom > bottomRect.GetBottom() )
{
int left, top;
m_owner->CalcUnscrolledPosition( 0, 0, &left, &top );
-
+
wxClientDC dc( this );
m_owner->PrepareDC( dc );
dc.SetBrush( wxBrush(m_owner->GetDefaultCellBackgroundColour(), wxSOLID) );
dc.SetPen( *wxTRANSPARENT_PEN );
-
+
if ( right > rightRect.GetRight() )
dc.DrawRectangle( rightRect.GetRight()+1, top, right - rightRect.GetRight(), ch );
-
+
if ( bottom > bottomRect.GetBottom() )
dc.DrawRectangle( left, bottomRect.GetBottom()+1, cw, bottom - bottomRect.GetBottom() );
}
if (m_ownTable)
delete m_table;
+
+ delete m_typeRegistry;
}
m_defaultCellAttr = new wxGridCellAttr;
m_defaultCellAttr->SetDefAttr(m_defaultCellAttr);
- // RD: Should we fill the default attrs now or is waiting until Init() okay?
+
+ // Set default cell attributes
+ m_defaultCellAttr->SetFont(GetFont());
+ m_defaultCellAttr->SetAlignment(wxLEFT, wxTOP);
+ m_defaultCellAttr->SetTextColour(
+ wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT));
+ m_defaultCellAttr->SetBackgroundColour(
+ wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
+ m_defaultCellAttr->SetRenderer(new wxGridCellStringRenderer);
+ m_defaultCellAttr->SetEditor(new wxGridCellTextEditor);
m_numRows = 0;
m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
+ // data type registration: register all standard data types
+ // TODO: may be allow the app to selectively disable some of them?
+ m_typeRegistry = new wxGridTypeRegistry;
+ RegisterDataType(wxGRID_VALUE_STRING,
+ new wxGridCellStringRenderer,
+ new wxGridCellTextEditor);
+ RegisterDataType(wxGRID_VALUE_BOOL,
+ new wxGridCellBoolRenderer,
+ new wxGridCellBoolEditor);
+ RegisterDataType(wxGRID_VALUE_NUMBER,
+ new wxGridCellNumberRenderer,
+ new wxGridCellNumberEditor);
+
+ // subwindow components that make up the wxGrid
m_cornerLabelWin = new wxGridCornerLabelWindow( this,
-1,
wxDefaultPosition,
m_defaultRowHeight += 4;
#endif
- // Set default cell attributes
- m_defaultCellAttr->SetFont(GetFont());
- m_defaultCellAttr->SetAlignment(wxLEFT, wxTOP);
- m_defaultCellAttr->SetRenderer(new wxGridCellStringRenderer);
- m_defaultCellAttr->SetEditor(new wxGridCellTextEditor);
- m_defaultCellAttr->SetTextColour(
- wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT));
- m_defaultCellAttr->SetBackgroundColour(
- wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
-
-
m_gridLineColour = wxColour( 128, 128, 255 );
m_gridLinesEnabled = TRUE;
m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
m_winCapture = (wxWindow *)NULL;
+ m_canDragRowSize = TRUE;
+ m_canDragColSize = TRUE;
m_dragLastPos = -1;
m_dragRowOrCol = -1;
m_isDragging = FALSE;
{
// starting to drag-resize a row
//
- ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin);
+ if ( CanDragRowSize() )
+ ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin);
}
}
if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
{
// don't capture the mouse yet
- ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, FALSE);
+ if ( CanDragRowSize() )
+ ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, FALSE);
}
}
else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
{
// starting to drag-resize a col
//
- ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin);
+ if ( CanDragColSize() )
+ ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin);
}
}
if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
{
// don't capture the cursor yet
- ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin, FALSE);
+ if ( CanDragColSize() )
+ ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin, FALSE);
}
}
else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
EnableCellEditControl();
wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
- attr->GetEditor()->StartingClick();
+ attr->GetEditor(GetDefaultEditorForCell(coords.GetRow(), coords.GetCol()))->StartingClick();
attr->DecRef();
m_waitForSlowClick = FALSE;
if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
{
- ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW);
+ if ( CanDragRowSize() )
+ ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW);
}
return;
if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
{
- ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL);
+ if ( CanDragColSize() )
+ ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL);
}
return;
if ( !IsCellEditControlEnabled() && CanEnableCellControl() )
{
EnableCellEditControl();
- wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
- attr->GetEditor()->StartingKey(event);
+ int row = m_currentCellCoords.GetRow();
+ int col = m_currentCellCoords.GetCol();
+ wxGridCellAttr* attr = GetCellAttr(row, col);
+ attr->GetEditor(GetDefaultEditorForCell(row, col))->StartingKey(event);
attr->DecRef();
}
else
// if the editor is shown, we should use it and not the renderer
if ( isCurrent && IsCellEditControlEnabled() )
{
- attr->GetEditor()->PaintBackground(rect, attr);
+ attr->GetEditor(GetDefaultEditorForCell(row, col))->
+ PaintBackground(rect, attr);
}
else
{
// but all the rest is drawn by the cell renderer and hence may be
// customized
- attr->GetRenderer()->Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords));
+ attr->GetRenderer(GetDefaultRendererForCell(row,col))->
+ Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords));
+
}
attr->DecRef();
#endif // 0
}
+
void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
{
int row = coords.GetRow();
void wxGrid::DrawHighlight(wxDC& dc)
{
+ if ( IsCellEditControlEnabled() )
+ {
+ // don't show highlight when the edit control is shown
+ return;
+ }
+
// if the active cell was repainted, repaint its highlight too because it
// might have been damaged by the grid lines
size_t count = m_cellsExposed.GetCount();
return m_cellEditCtrlEnabled ? !IsCurrentCellReadOnly() : FALSE;
}
-wxWindow *wxGrid::GetGridWindow() const
-{
- return m_gridWin;
-}
-
void wxGrid::ShowCellEditControl()
{
if ( IsCellEditControlEnabled() )
// convert to scrolled coords
//
- int left, top, right, bottom;
- CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
- CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
+ CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
- // cell is shifted by one pixel
- left--;
- top--;
- right--;
- bottom--;
-
- // Make the edit control large enough to allow for internal
- // margins
- //
- // TODO: remove this if the text ctrl sizing is improved esp. for
- // unix
- //
- int extra;
-#if defined(__WXMOTIF__)
- if ( row == 0 || col == 0 )
- {
- extra = 2;
- }
- else
- {
- extra = 4;
- }
-#else
- if ( row == 0 || col == 0 )
- {
- extra = 1;
- }
- else
- {
- extra = 2;
- }
-#endif
+ // done in PaintBackground()
+#if 0
+ // erase the highlight and the cell contents because the editor
+ // might not cover the entire cell
+ wxClientDC dc( m_gridWin );
+ PrepareDC( dc );
+ dc.SetBrush(*wxLIGHT_GREY_BRUSH); //wxBrush(attr->GetBackgroundColour(), wxSOLID));
+ dc.SetPen(*wxTRANSPARENT_PEN);
+ dc.DrawRectangle(rect);
+#endif // 0
-#if defined(__WXGTK__)
- int top_diff = 0;
- int left_diff = 0;
- if (left != 0) left_diff++;
- if (top != 0) top_diff++;
- rect.SetLeft( left + left_diff );
- rect.SetTop( top + top_diff );
- rect.SetRight( rect.GetRight() - left_diff );
- rect.SetBottom( rect.GetBottom() - top_diff );
-#else
- rect.SetLeft( wxMax(0, left - extra) );
- rect.SetTop( wxMax(0, top - extra) );
- rect.SetRight( rect.GetRight() + 2*extra );
- rect.SetBottom( rect.GetBottom() + 2*extra );
-#endif
+ // cell is shifted by one pixel
+ rect.x--;
+ rect.y--;
wxGridCellAttr* attr = GetCellAttr(row, col);
- wxGridCellEditor* editor = attr->GetEditor();
+ wxGridCellEditor* editor = attr->GetEditor(GetDefaultEditorForCell(row, col));
if ( !editor->IsCreated() )
{
editor->Create(m_gridWin, -1,
}
editor->SetSize( rect );
+
editor->Show( TRUE, attr );
editor->BeginEdit(row, col, this);
attr->DecRef();
int col = m_currentCellCoords.GetCol();
wxGridCellAttr* attr = GetCellAttr(row, col);
- attr->GetEditor()->Show( FALSE );
+ attr->GetEditor(GetDefaultEditorForCell(row, col))->Show( FALSE );
attr->DecRef();
m_gridWin->SetFocus();
}
int col = m_currentCellCoords.GetCol();
wxGridCellAttr* attr = GetCellAttr(row, col);
- bool changed = attr->GetEditor()->EndEdit(row, col, TRUE, this);
+ wxGridCellEditor* editor = attr->GetEditor(GetDefaultEditorForCell(row, col));
+ bool changed = editor->EndEdit(row, col, TRUE, this);
attr->DecRef();
return i;
}
- return m_numRows; //-1;
+ return -1;
}
return i;
}
- return m_numCols; //-1;
+ return -1;
}
wxGridCellRenderer *wxGrid::GetDefaultRenderer() const
{
- return m_defaultCellAttr->GetRenderer();
+ return m_defaultCellAttr->GetRenderer(NULL);
}
wxGridCellEditor *wxGrid::GetDefaultEditor() const
{
- return m_defaultCellAttr->GetEditor();
+ return m_defaultCellAttr->GetEditor(NULL);
}
// ----------------------------------------------------------------------------
wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col)
{
wxGridCellAttr* attr = GetCellAttr(row, col);
- wxGridCellRenderer* renderer = attr->GetRenderer();
+ wxGridCellRenderer* renderer = attr->GetRenderer(GetDefaultRendererForCell(row,col));
attr->DecRef();
return renderer;
}
wxGridCellEditor* wxGrid::GetCellEditor(int row, int col)
{
wxGridCellAttr* attr = GetCellAttr(row, col);
- wxGridCellEditor* editor = attr->GetEditor();
+ wxGridCellEditor* editor = attr->GetEditor(GetDefaultEditorForCell(row, col));
attr->DecRef();
return editor;
}
return FALSE;
}
- // RD: Maybe m_table->CanHaveAttributes() would be better in case the
- // table is providing the attributes itself??? In which case
- // I don't think the grid should create a Provider object for the
- // table but the table should be smart enough to do that on its own.
- if ( !m_table->GetAttrProvider() )
- {
- // use the default attr provider by default
- // (another choice would be to just return FALSE thus forcing the user
- // to it himself)
- m_table->SetAttrProvider(new wxGridCellAttrProvider);
- }
-
- return TRUE;
+ return m_table->CanHaveAttributes();
}
void wxGrid::ClearAttrCache()
}
}
+// ----------------------------------------------------------------------------
+// Data type registration
+// ----------------------------------------------------------------------------
+
+void wxGrid::RegisterDataType(const wxString& typeName,
+ wxGridCellRenderer* renderer,
+ wxGridCellEditor* editor)
+{
+ m_typeRegistry->RegisterDataType(typeName, renderer, editor);
+}
+
+
+wxGridCellEditor* wxGrid::GetDefaultEditorForCell(int row, int col) const
+{
+ wxString typeName = m_table->GetTypeName(row, col);
+ return GetDefaultEditorForType(typeName);
+}
+
+wxGridCellRenderer* wxGrid::GetDefaultRendererForCell(int row, int col) const
+{
+ wxString typeName = m_table->GetTypeName(row, col);
+ return GetDefaultRendererForType(typeName);
+}
+
+wxGridCellEditor*
+wxGrid::GetDefaultEditorForType(const wxString& typeName) const
+{
+ int index = m_typeRegistry->FindDataType(typeName);
+ if (index == -1) {
+ // Should we force the failure here or let it fallback to string handling???
+ // wxFAIL_MSG(wxT("Unknown data type name"));
+ return NULL;
+ }
+ return m_typeRegistry->GetEditor(index);
+}
+
+wxGridCellRenderer*
+wxGrid::GetDefaultRendererForType(const wxString& typeName) const
+{
+ int index = m_typeRegistry->FindDataType(typeName);
+ if (index == -1) {
+ // Should we force the failure here or let it fallback to string handling???
+ // wxFAIL_MSG(wxT("Unknown data type name"));
+ return NULL;
+ }
+ return m_typeRegistry->GetRenderer(index);
+}
+
+
// ----------------------------------------------------------------------------
// row/col size
// ----------------------------------------------------------------------------
+void wxGrid::EnableDragRowSize( bool enable )
+{
+ m_canDragRowSize = enable;
+}
+
+
+void wxGrid::EnableDragColSize( bool enable )
+{
+ m_canDragColSize = enable;
+}
+
+
void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
{
m_defaultRowHeight = wxMax( height, WXGRID_MIN_ROW_HEIGHT );
return obj ? (int)obj : WXGRID_MIN_COL_WIDTH;
}
+void wxGrid::AutoSizeColumn( int col, bool setAsMin )
+{
+ wxClientDC dc(m_gridWin);
+
+ wxCoord width, widthMax = 0;
+ for ( int row = 0; row < m_numRows; row++ )
+ {
+ wxGridCellAttr* attr = GetCellAttr(row, col);
+ wxGridCellRenderer* renderer = attr->GetRenderer(GetDefaultRendererForCell(row,col));
+ if ( renderer )
+ {
+ width = renderer->GetBestSize(*this, *attr, dc, row, col).x;
+ if ( width > widthMax )
+ {
+ widthMax = width;
+ }
+ }
+
+ attr->DecRef();
+ }
+
+ // now also compare with the column label width
+ dc.SetFont( GetLabelFont() );
+ dc.GetTextExtent( GetColLabelValue(col), &width, NULL );
+ if ( width > widthMax )
+ {
+ widthMax = width;
+ }
+
+ if ( !widthMax )
+ {
+ // empty column - give default width (notice that if widthMax is less
+ // than default width but != 0, it's ok)
+ widthMax = m_defaultColWidth;
+ }
+ else
+ {
+ // leave some space around text
+ widthMax += 10;
+ }
+
+ SetColSize(col, widthMax);
+ if ( setAsMin )
+ {
+ SetColMinimalWidth(col, widthMax);
+ }
+}
+
+void wxGrid::AutoSizeColumns( bool setAsMin )
+{
+ for ( int col = 0; col < m_numCols; col++ )
+ {
+ AutoSizeColumn(col, setAsMin);
+ }
+}
+
//
// ------ cell value accessor functions
//