+// ----------------------------------------------------------------------------
+// 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
+ {
+ // free the old attribute
+ m_attrs[(size_t)n].attr->DecRef();
+
+ 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,
+ wxGridCellAttr::wxAttrKind kind ) const
+{
+ wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
+ if ( m_data )
+ {
+ switch(kind)
+ {
+ case (wxGridCellAttr::Any):
+ //Get cached merge attributes.
+ // Currenlty not used as no cache implemented as not mutiable
+ // attr = m_data->m_mergeAttr.GetAttr(row, col);
+ if(!attr)
+ {
+ //Basicaly implement old version.
+ //Also check merge cache, so we don't have to re-merge every time..
+ wxGridCellAttr *attrcell = (wxGridCellAttr *)NULL,
+ *attrrow = (wxGridCellAttr *)NULL,
+ *attrcol = (wxGridCellAttr *)NULL;
+
+ attrcell = m_data->m_cellAttrs.GetAttr(row, col);
+ attrcol = m_data->m_colAttrs.GetAttr(col);
+ attrrow = m_data->m_rowAttrs.GetAttr(row);
+
+ if((attrcell != attrrow) && (attrrow !=attrcol) && (attrcell != attrcol)){
+ // Two or move are non NULL
+ attr = new wxGridCellAttr;
+ attr->SetKind(wxGridCellAttr::Merged);
+
+ //Order important..
+ if(attrcell){
+ attr->MergeWith(attrcell);
+ attrcell->DecRef();
+ }
+ if(attrcol){
+ attr->MergeWith(attrcol);
+ attrcol->DecRef();
+ }
+ if(attrrow){
+ attr->MergeWith(attrrow);
+ attrrow->DecRef();
+ }
+ //store merge attr if cache implemented
+ //attr->IncRef();
+ //m_data->m_mergeAttr.SetAttr(attr, row, col);
+ }
+ else
+ {
+ // one or none is non null return it or null.
+ if(attrrow) attr = attrrow;
+ if(attrcol) attr = attrcol;
+ if(attrcell) attr = attrcell;
+ }
+ }
+ break;
+ case (wxGridCellAttr::Cell):
+ attr = m_data->m_cellAttrs.GetAttr(row, col);
+ break;
+ case (wxGridCellAttr::Col):
+ attr = m_data->m_colAttrs.GetAttr(col);
+ break;
+ case (wxGridCellAttr::Row):
+ attr = m_data->m_rowAttrs.GetAttr(row);
+ break;
+ default:
+ // unused as yet...
+ // (wxGridCellAttr::Default):
+ // (wxGridCellAttr::Merged):
+ break;
+ }
+ }
+ 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 wxUSE_TEXTCTRL
+ if ( typeName == wxGRID_VALUE_STRING )
+ {
+ RegisterDataType(wxGRID_VALUE_STRING,
+ new wxGridCellStringRenderer,
+ new wxGridCellTextEditor);
+ } else
+#endif // wxUSE_TEXTCTRL
+#if wxUSE_CHECKBOX
+ if ( typeName == wxGRID_VALUE_BOOL )
+ {
+ RegisterDataType(wxGRID_VALUE_BOOL,
+ new wxGridCellBoolRenderer,
+ new wxGridCellBoolEditor);
+ } else
+#endif // wxUSE_CHECKBOX
+#if wxUSE_TEXTCTRL
+ 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
+#endif // wxUSE_TEXTCTRL
+#if wxUSE_COMBOBOX
+ if ( typeName == wxGRID_VALUE_CHOICE )
+ {
+ RegisterDataType(wxGRID_VALUE_CHOICE,
+ new wxGridCellStringRenderer,
+ new wxGridCellChoiceEditor);
+ } else
+#endif // wxUSE_COMBOBOX
+ {
+ 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;
+}
+
+wxGridCellRenderer* wxGridTypeRegistry::GetRenderer(int index)
+{
+ wxGridCellRenderer* renderer = m_typeinfo[index]->m_renderer;
+ if (renderer)
+ renderer->IncRef();
+ return renderer;
+}
+
+wxGridCellEditor* wxGridTypeRegistry::GetEditor(int index)
+{
+ wxGridCellEditor* editor = m_typeinfo[index]->m_editor;
+ if (editor)
+ editor->IncRef();
+ return editor;
+}
+
+// ----------------------------------------------------------------------------
+// wxGridTableBase
+// ----------------------------------------------------------------------------
+
+IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject )
+
+
+wxGridTableBase::wxGridTableBase()
+{
+ m_view = (wxGrid *) NULL;
+ m_attrProvider = (wxGridCellAttrProvider *) NULL;
+}
+
+wxGridTableBase::~wxGridTableBase()
+{
+ delete m_attrProvider;
+}
+
+void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider *attrProvider)
+{
+ delete m_attrProvider;
+ 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, wxGridCellAttr::wxAttrKind kind)
+{
+ if ( m_attrProvider )
+ return m_attrProvider->GetAttr(row, col, kind);
+ else
+ return (wxGridCellAttr *)NULL;
+}
+
+void wxGridTableBase::SetAttr(wxGridCellAttr* attr, int row, int col)
+{
+ if ( m_attrProvider )
+ {
+ attr->SetKind(wxGridCellAttr::Cell);
+ m_attrProvider->SetAttr(attr, row, col);
+ }
+ else
+ {
+ // as we take ownership of the pointer and don't store it, we must
+ // free it now
+ wxSafeDecRef(attr);
+ }
+}
+
+void wxGridTableBase::SetRowAttr(wxGridCellAttr *attr, int row)
+{
+ if ( m_attrProvider )
+ {
+ attr->SetKind(wxGridCellAttr::Row);
+ m_attrProvider->SetRowAttr(attr, row);
+ }
+ else
+ {
+ // as we take ownership of the pointer and don't store it, we must
+ // free it now
+ wxSafeDecRef(attr);
+ }
+}
+
+void wxGridTableBase::SetColAttr(wxGridCellAttr *attr, int col)
+{
+ if ( m_attrProvider )
+ {
+ attr->SetKind(wxGridCellAttr::Col);
+ m_attrProvider->SetColAttr(attr, col);
+ }
+ else
+ {
+ // as we take ownership of the pointer and don't store it, we must
+ // free it now
+ wxSafeDecRef(attr);
+ }
+}
+
+bool wxGridTableBase::InsertRows( size_t WXUNUSED(pos),
+ size_t WXUNUSED(numRows) )
+{
+ wxFAIL_MSG( wxT("Called grid table class function InsertRows\nbut your derived table class does not override this function") );
+
+ return FALSE;
+}
+
+bool wxGridTableBase::AppendRows( size_t WXUNUSED(numRows) )
+{
+ wxFAIL_MSG( wxT("Called grid table class function AppendRows\nbut your derived table class does not override this function"));
+
+ return FALSE;
+}
+
+bool wxGridTableBase::DeleteRows( size_t WXUNUSED(pos),
+ size_t WXUNUSED(numRows) )
+{
+ wxFAIL_MSG( wxT("Called grid table class function DeleteRows\nbut your derived table class does not override this function"));
+
+ return FALSE;
+}
+
+bool wxGridTableBase::InsertCols( size_t WXUNUSED(pos),
+ size_t WXUNUSED(numCols) )
+{
+ wxFAIL_MSG( wxT("Called grid table class function InsertCols\nbut your derived table class does not override this function"));
+
+ return FALSE;
+}
+
+bool wxGridTableBase::AppendCols( size_t WXUNUSED(numCols) )
+{
+ wxFAIL_MSG(wxT("Called grid table class function AppendCols\nbut your derived table class does not override this function"));
+
+ return FALSE;
+}
+
+bool wxGridTableBase::DeleteCols( size_t WXUNUSED(pos),
+ size_t WXUNUSED(numCols) )
+{
+ wxFAIL_MSG( wxT("Called grid table class function DeleteCols\nbut your derived table class does not override this function"));
+
+ return FALSE;
+}
+
+
+wxString wxGridTableBase::GetRowLabelValue( int row )
+{
+ wxString s;
+ 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::GetColLabelValue( int col )
+{
+ // default col labels are:
+ // cols 0 to 25 : A-Z
+ // cols 26 to 675 : AA-ZZ
+ // etc.
+
+ wxString s;
+ unsigned int i, n;
+ for ( n = 1; ; n++ )
+ {
+ s += (_T('A') + (wxChar)( col%26 ));
+ col = col/26 - 1;
+ if ( col < 0 ) break;
+ }
+
+ // reverse the string...
+ wxString s2;
+ for ( i = 0; i < n; i++ )
+ {
+ s2 += s[n-i-1];
+ }
+
+ return s2;
+}
+
+
+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) )
+{
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// Message class for the grid table to send requests and notifications
+// to the grid view
+//
+
+wxGridTableMessage::wxGridTableMessage()
+{
+ m_table = (wxGridTableBase *) NULL;
+ m_id = -1;
+ m_comInt1 = -1;
+ m_comInt2 = -1;
+}
+
+wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id,
+ int commandInt1, int commandInt2 )
+{
+ m_table = table;
+ m_id = id;
+ m_comInt1 = commandInt1;
+ m_comInt2 = commandInt2;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// A basic grid table for string data. An object of this class will
+// created by wxGrid if you don't specify an alternative table class.
+//
+
+WX_DEFINE_OBJARRAY(wxGridStringArray)
+
+IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase )
+
+wxGridStringTable::wxGridStringTable()
+ : wxGridTableBase()
+{
+}
+
+wxGridStringTable::wxGridStringTable( int numRows, int numCols )
+ : wxGridTableBase()
+{
+ m_data.Alloc( numRows );
+
+ wxArrayString sa;
+ sa.Alloc( numCols );
+ sa.Add( wxEmptyString, numCols );
+
+ m_data.Add( sa, numRows );
+}
+
+wxGridStringTable::~wxGridStringTable()
+{
+}
+
+int wxGridStringTable::GetNumberRows()
+{
+ return m_data.GetCount();
+}
+
+int wxGridStringTable::GetNumberCols()
+{
+ if ( m_data.GetCount() > 0 )
+ return m_data[0].GetCount();
+ else
+ return 0;
+}
+
+wxString wxGridStringTable::GetValue( int row, int col )
+{
+ wxCHECK_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
+ wxEmptyString,
+ _T("invalid row or column index in wxGridStringTable") );
+
+ return m_data[row][col];
+}
+
+void wxGridStringTable::SetValue( int row, int col, const wxString& value )
+{
+ wxCHECK_RET( (row < GetNumberRows()) && (col < GetNumberCols()),
+ _T("invalid row or column index in wxGridStringTable") );
+
+ m_data[row][col] = value;
+}
+
+bool wxGridStringTable::IsEmptyCell( int row, int col )
+{
+ wxCHECK_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
+ true,
+ _T("invalid row or column index in wxGridStringTable") );
+
+ return (m_data[row][col] == wxEmptyString);
+}
+
+void wxGridStringTable::Clear()
+{
+ int row, col;
+ int numRows, numCols;
+
+ numRows = m_data.GetCount();
+ if ( numRows > 0 )
+ {
+ numCols = m_data[0].GetCount();
+
+ for ( row = 0; row < numRows; row++ )
+ {
+ for ( col = 0; col < numCols; col++ )
+ {
+ m_data[row][col] = wxEmptyString;
+ }
+ }
+ }
+}
+
+
+bool wxGridStringTable::InsertRows( size_t pos, size_t numRows )
+{
+ size_t curNumRows = m_data.GetCount();
+ size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
+ ( GetView() ? GetView()->GetNumberCols() : 0 ) );
+
+ if ( pos >= curNumRows )
+ {
+ return AppendRows( numRows );
+ }
+
+ wxArrayString sa;
+ sa.Alloc( curNumCols );
+ sa.Add( wxEmptyString, curNumCols );
+ m_data.Insert( sa, pos, numRows );
+ if ( GetView() )
+ {
+ wxGridTableMessage msg( this,
+ wxGRIDTABLE_NOTIFY_ROWS_INSERTED,
+ pos,
+ numRows );
+
+ GetView()->ProcessTableMessage( msg );
+ }
+
+ return TRUE;
+}
+
+bool wxGridStringTable::AppendRows( size_t numRows )
+{
+ size_t curNumRows = m_data.GetCount();
+ size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
+ ( GetView() ? GetView()->GetNumberCols() : 0 ) );
+
+ wxArrayString sa;
+ if ( curNumCols > 0 )
+ {
+ sa.Alloc( curNumCols );
+ sa.Add( wxEmptyString, curNumCols );
+ }
+
+ m_data.Add( sa, numRows );
+
+ if ( GetView() )
+ {
+ wxGridTableMessage msg( this,
+ wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
+ numRows );
+
+ GetView()->ProcessTableMessage( msg );
+ }
+
+ return TRUE;
+}
+
+bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows )
+{
+ size_t curNumRows = m_data.GetCount();
+
+ if ( pos >= curNumRows )
+ {
+ wxFAIL_MSG( wxString::Format
+ (
+ wxT("Called wxGridStringTable::DeleteRows(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu rows"),
+ (unsigned long)pos,
+ (unsigned long)numRows,
+ (unsigned long)curNumRows
+ ) );
+
+ return FALSE;
+ }
+
+ if ( numRows > curNumRows - pos )
+ {
+ numRows = curNumRows - pos;
+ }
+
+ if ( numRows >= curNumRows )
+ {
+ m_data.Clear();
+ }
+ else
+ {
+ m_data.RemoveAt( pos, numRows );
+ }
+ if ( GetView() )
+ {
+ wxGridTableMessage msg( this,
+ wxGRIDTABLE_NOTIFY_ROWS_DELETED,
+ pos,
+ numRows );
+
+ GetView()->ProcessTableMessage( msg );
+ }
+
+ return TRUE;
+}
+
+bool wxGridStringTable::InsertCols( size_t pos, size_t numCols )
+{
+ size_t row, col;
+
+ size_t curNumRows = m_data.GetCount();
+ size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
+ ( GetView() ? GetView()->GetNumberCols() : 0 ) );
+
+ if ( pos >= curNumCols )
+ {
+ return AppendCols( numCols );
+ }
+
+ for ( row = 0; row < curNumRows; row++ )
+ {
+ for ( col = pos; col < pos + numCols; col++ )
+ {
+ m_data[row].Insert( wxEmptyString, col );
+ }
+ }
+ if ( GetView() )
+ {
+ wxGridTableMessage msg( this,
+ wxGRIDTABLE_NOTIFY_COLS_INSERTED,
+ pos,
+ numCols );
+
+ GetView()->ProcessTableMessage( msg );
+ }
+
+ return TRUE;
+}
+
+bool wxGridStringTable::AppendCols( size_t numCols )
+{
+ size_t row;
+
+ size_t curNumRows = m_data.GetCount();
+#if 0
+ if ( !curNumRows )
+ {
+ // TODO: something better than this ?
+ //
+ wxFAIL_MSG( wxT("Unable to append cols to a grid table with no rows.\nCall AppendRows() first") );
+ return FALSE;
+ }
+#endif
+
+ for ( row = 0; row < curNumRows; row++ )
+ {
+ m_data[row].Add( wxEmptyString, numCols );
+ }
+
+ if ( GetView() )
+ {
+ wxGridTableMessage msg( this,
+ wxGRIDTABLE_NOTIFY_COLS_APPENDED,
+ numCols );
+
+ GetView()->ProcessTableMessage( msg );
+ }
+
+ return TRUE;
+}
+
+bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols )
+{
+ size_t row;
+
+ size_t curNumRows = m_data.GetCount();
+ size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
+ ( GetView() ? GetView()->GetNumberCols() : 0 ) );
+
+ if ( pos >= curNumCols )
+ {
+ wxFAIL_MSG( wxString::Format
+ (
+ wxT("Called wxGridStringTable::DeleteCols(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu cols"),
+ (unsigned long)pos,
+ (unsigned long)numCols,
+ (unsigned long)curNumCols
+ ) );
+ return FALSE;
+ }
+
+ if ( numCols > curNumCols - pos )
+ {
+ numCols = curNumCols - pos;
+ }
+
+ for ( row = 0; row < curNumRows; row++ )
+ {
+ if ( numCols >= curNumCols )
+ {
+ m_data[row].Clear();
+ }
+ else
+ {
+ m_data[row].RemoveAt( pos, numCols );
+ }
+ }
+ if ( GetView() )
+ {
+ wxGridTableMessage msg( this,
+ wxGRIDTABLE_NOTIFY_COLS_DELETED,
+ pos,
+ numCols );
+
+ GetView()->ProcessTableMessage( msg );
+ }
+
+ return TRUE;
+}
+
+wxString wxGridStringTable::GetRowLabelValue( int row )
+{
+ if ( row > (int)(m_rowLabels.GetCount()) - 1 )
+ {
+ // using default label
+ //
+ return wxGridTableBase::GetRowLabelValue( row );
+ }
+ else
+ {
+ return m_rowLabels[ row ];
+ }
+}
+
+wxString wxGridStringTable::GetColLabelValue( int col )
+{
+ if ( col > (int)(m_colLabels.GetCount()) - 1 )
+ {
+ // using default label
+ //
+ return wxGridTableBase::GetColLabelValue( col );
+ }
+ else
+ {
+ return m_colLabels[ col ];
+ }
+}
+
+void wxGridStringTable::SetRowLabelValue( int row, const wxString& value )
+{
+ if ( row > (int)(m_rowLabels.GetCount()) - 1 )
+ {
+ int n = m_rowLabels.GetCount();
+ int i;
+ for ( i = n; i <= row; i++ )
+ {
+ m_rowLabels.Add( wxGridTableBase::GetRowLabelValue(i) );
+ }
+ }
+
+ m_rowLabels[row] = value;
+}
+
+void wxGridStringTable::SetColLabelValue( int col, const wxString& value )
+{
+ if ( col > (int)(m_colLabels.GetCount()) - 1 )
+ {
+ int n = m_colLabels.GetCount();
+ int i;
+ for ( i = n; i <= col; i++ )
+ {
+ m_colLabels.Add( wxGridTableBase::GetColLabelValue(i) );
+ }
+ }
+
+ m_colLabels[col] = value;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////