]> git.saurik.com Git - wxWidgets.git/commitdiff
wxDbGrid additions contributed by Paul and Roger Gammans with additions/corrections...
authorGeorge Tasker <gtasker@allenbrook.com>
Sun, 10 Jun 2001 17:08:42 +0000 (17:08 +0000)
committerGeorge Tasker <gtasker@allenbrook.com>
Sun, 10 Jun 2001 17:08:42 +0000 (17:08 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@10503 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/dbgrid.h [new file with mode: 0644]
include/wx/dbkeyg.h [new file with mode: 0644]
src/common/dbgrid.cpp [new file with mode: 0644]

diff --git a/include/wx/dbgrid.h b/include/wx/dbgrid.h
new file mode 100644 (file)
index 0000000..60f9ca0
--- /dev/null
@@ -0,0 +1,169 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name:        dbgrid.h
+// Purpose:     Displays a wxDbTable in a wxGrid.
+// Author:      Roger Gammans, Paul Gammans
+// Modified by:
+// Created:     
+// RCS-ID:      $Id$
+// Copyright:   (c) 1999 The Computer Surgery (roger@computer-surgery.co.uk)
+// Licence:     wxWindows licence
+///////////////////////////////////////////////////////////////////////////////
+// Branched From : dbgrid.h,v 1.19 2001/03/28 11:16:01
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_GENERIC_DBGRID_H_
+#define _WX_GENERIC_DBGRID_H_
+
+#ifdef __GNUG__
+    #pragma interface "dbgrid.h"
+#endif
+
+#if wxUSE_ODBC
+#if wxUSE_NEW_GRID
+
+#include "wx/log.h"
+#include "wx/dbtable.h"
+#include "wx/dynarray.h"
+#include "wx/grid.h"
+#include "wx/dbkeyg.h"
+
+#define wxGRID_VALUE_DBAUTO     _T("dbauto")
+
+WX_DECLARE_OBJARRAY(GenericKey,keyarray);
+
+static const int wxUSE_QUERY = -1;
+
+class wxDbGridColInfoBase
+{
+public:
+    //Default ctor
+    wxDbGridColInfoBase() { }
+    wxDbGridColInfoBase(int colNo,
+                        wxString type, wxString title) :
+                        DbCol(colNo),
+                        wxtypename(type),
+                        Title(title)
+                        { }
+    //Copy Ctor
+    wxDbGridColInfoBase(const wxDbGridColInfoBase& ref)
+    {
+        DbCol       = ref.DbCol;
+        wxtypename  = ref.wxtypename;
+        Title       = ref.Title;    
+    }
+    //Empty destructor for member obj's
+    ~wxDbGridColInfoBase() {}
+    
+    int        DbCol;
+    wxString   wxtypename;
+    wxString   Title;
+};
+
+
+class wxDbGridColInfo
+{
+public:
+    wxDbGridColInfo(int colNo,
+                    wxString type,
+                    wxString title,
+                    wxDbGridColInfo *next) :
+        m_data(colNo,type,title)
+    {
+        m_next=next;
+    }
+
+    //Empty List
+    ~wxDbGridColInfo() { delete m_next; }
+
+    //Recurse to find length.
+    int Length() { return (m_next ? m_next->Length() +1 :  1); }
+
+    protected:
+    wxDbGridColInfoBase  m_data;
+    wxDbGridColInfo     *m_next;
+
+    friend class wxDbGridTableBase;
+};
+
+
+class wxDbGridCellAttrProvider : public wxGridCellAttrProvider
+{
+public:
+    wxDbGridCellAttrProvider();
+    wxDbGridCellAttrProvider(wxDbTable *tab, wxDbGridColInfoBase* ColInfo);
+    virtual ~wxDbGridCellAttrProvider();
+
+    virtual wxGridCellAttr *GetAttr(int row, int col,
+                                    wxGridCellAttr::wxAttrKind kind) const;
+    virtual void AssignDbTable(wxDbTable *tab);
+private:
+    wxDbTable           *m_data;
+    wxDbGridColInfoBase *m_ColInfo;
+};
+
+
+class wxDbGridTableBase : public wxGridTableBase
+{
+public:
+    wxDbGridTableBase(wxDbTable *tab, wxDbGridColInfo *ColInfo,
+              int count = wxUSE_QUERY, bool takeOwnership = true);
+    ~wxDbGridTableBase();
+
+    virtual int GetNumberRows()
+    {
+        wxLogDebug(" GetNumberRows() = %i",m_rowtotal);
+        return m_rowtotal; 
+    }
+    virtual int GetNumberCols()
+    { 
+        wxLogDebug(" GetNumberCols() = %i",m_nocols);
+        return m_nocols; 
+    }
+    virtual bool     IsEmptyCell(int row, int col) ;
+    virtual wxString GetValue(int row, int col) ;
+    virtual void     SetValue(int row, int col, const wxString& value);
+    virtual bool     CanHaveAttributes();
+    virtual wxString GetTypeName(int row, int col);
+    virtual bool     CanGetValueAs(int row, int col, const wxString& typeName);
+    virtual bool     CanSetValueAs(int row, int col, const wxString& typeName);
+    virtual long     GetValueAsLong(int row, int col);
+    virtual double   GetValueAsDouble(int row, int col);
+    virtual bool     GetValueAsBool(int row, int col);
+    virtual void     SetValueAsLong(int row, int col, long value);
+    virtual void     SetValueAsDouble(int row, int col, double value);
+    virtual void     SetValueAsBool(int row, int col, bool value);
+    virtual void    *GetValueAsCustom(int row, int col, const wxString& typeName);
+    virtual void     SetValueAsCustom(int row, int col, const wxString& typeName, void* value);
+
+
+    virtual wxString wxDbGridTableBase::GetColLabelValue(int col);
+
+    virtual bool     AssignDbTable(wxDbTable *tab, int count = wxUSE_QUERY, bool takeOwnership=true);
+    virtual void     ValidateRow(int row);
+    virtual bool     UpdateRow(int row) const
+    {
+        if (m_row != row)
+            return true;
+        else 
+            return Writeback();
+    }
+    
+private:
+    //Operates on the current row
+    bool Writeback() const;
+
+    typedef wxGridTableBase inherited;
+    keyarray     m_keys;
+    wxDbTable   *m_data;
+    bool         m_dbowner;
+    int          m_rowtotal;
+    int          m_nocols;
+    int          m_row;
+    wxDbGridColInfoBase *m_ColInfo;
+    bool         m_rowmodified;
+};
+
+#endif  // #if wxUSE_NEW_GRID
+#endif  // #if wxUSE_ODBC
+
+#endif _WX_GENERIC_DBGRID_H_
diff --git a/include/wx/dbkeyg.h b/include/wx/dbkeyg.h
new file mode 100644 (file)
index 0000000..d618768
--- /dev/null
@@ -0,0 +1,41 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name:        dbkeyg.h
+// Purpose:     Generic key support for wxDbTable
+// Author:      Roger Gammans
+// Modified by:
+// Created:     
+// RCS-ID:      $Id$
+// Copyright:   (c) 1999 The Computer Surgery (roger@computer-surgery.co.uk)
+// Licence:     wxWindows licence
+//
+// NOTE : There is no CPP file to go along with this
+//
+///////////////////////////////////////////////////////////////////////////////
+// Branched From : gkey.h,v 1.3 2001/06/01 10:31:41
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_DBGKEY_H_
+#define _WX_DBGKEY_H_
+
+class GenericKey
+{
+public:
+    GenericKey(void *blk, size_t sz)    { clone(blk,sz); }
+    GenericKey(const GenericKey &ref)   { clone(ref.m_data,ref.m_sz); }
+    ~GenericKey()                       { free(m_data); }
+
+    void *GetBlk(void) const { return m_data; }
+
+private:
+    void clone(void *blk, size_t sz)
+    {
+        m_data = malloc(sz);
+        memcpy(m_data,blk,sz);
+        m_sz = sz;
+    }
+
+    void   *m_data;
+    size_t  m_sz;
+};
+
+#endif // _WX_DBGKEY_H_
diff --git a/src/common/dbgrid.cpp b/src/common/dbgrid.cpp
new file mode 100644 (file)
index 0000000..545d307
--- /dev/null
@@ -0,0 +1,745 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name:        dbgrid.cpp
+// Purpose:     Displays a wxDbTable in a wxGrid.
+// Author:      Roger Gammans, Paul Gammans
+// Modified by: 
+// Created:     
+// RCS-ID:      $Id$
+// Copyright:   (c) 1999 The Computer Surgery (roger@computer-surgery.co.uk)
+// Licence:     wxWindows licence
+///////////////////////////////////////////////////////////////////////////////
+// Branched From : dbgrid.cpp,v 1.18 2000/12/19 13:00:58
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+    #pragma implementation "dbgrid.h"
+#endif
+
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+
+#if wxUSE_ODBC
+#if wxUSE_NEW_GRID
+
+#ifndef WX_PRECOMP
+    #include "wx/textctrl.h"
+    #include "wx/dc.h"
+#endif // WX_PRECOMP
+
+#include "wx/generic/gridctrl.h"
+#include "wx/dbgrid.h"
+
+
+wxDbGridCellAttrProvider::wxDbGridCellAttrProvider()
+{
+    m_data=NULL;
+    m_ColInfo=NULL;
+}
+
+wxDbGridCellAttrProvider::wxDbGridCellAttrProvider(wxDbTable *tab, wxDbGridColInfoBase* ColInfo)
+{
+    m_data=tab;
+    m_ColInfo=ColInfo;
+}
+
+wxDbGridCellAttrProvider::~wxDbGridCellAttrProvider()
+{
+}
+
+wxGridCellAttr *wxDbGridCellAttrProvider::GetAttr(int row, int col,
+                                      wxGridCellAttr::wxAttrKind  kind) const
+{
+    wxGridCellAttr *attr = wxGridCellAttrProvider::GetAttr(row,col,kind);
+
+    if (m_data && m_ColInfo && (m_data->GetNumberOfColumns() > m_ColInfo[col].DbCol))
+    {
+        //FIXME: this test could.
+        //  ??::InsertPending == m_data->get_ModifiedStatus()
+        //  and if InsertPending use colDef[].InsertAllowed
+        if (!(m_data->GetColDefs()[(m_ColInfo[col].DbCol)].Updateable))
+        {
+            switch(kind)
+            {
+                case (wxGridCellAttr::Any):
+                    if (!attr)
+                    {
+                        attr = new wxGridCellAttr;
+                        // Store so we don't keep creating / deleting this...
+                        wxDbGridCellAttrProvider * self = wxConstCast(this, wxDbGridCellAttrProvider) ;
+                        attr->IncRef();
+                        self->SetColAttr(attr, col);
+                        attr->SetReadOnly();
+                    }
+                    else
+                    {
+                        //We now must check what we were returned. and do the right thing (tm)
+                        wxGridCellAttr::wxAttrKind attrkind = attr->GetKind();
+                        if ((attrkind == (wxGridCellAttr::Default)) || (attrkind == (wxGridCellAttr::Cell)) ||
+                            (attrkind == (wxGridCellAttr::Col)))
+                        {
+                                wxGridCellAttr *attrtomerge = attr;
+                                attr = new wxGridCellAttr;
+                                attr->SetKind(wxGridCellAttr::Merged);
+                                attr->MergeWith(attrtomerge);
+                                attr->SetReadOnly();
+                                attrtomerge->DecRef();
+                        }
+                        attr->SetReadOnly();
+                    }
+                break;
+                case (wxGridCellAttr::Col):
+                    //As we must have a Coll, and were setting Coll attributes
+                    // we can based on wxdbTable's so just set RO if attr valid
+                    if (!attr)
+                    {
+                        attr = new wxGridCellAttr;
+                        wxDbGridCellAttrProvider * self = wxConstCast(this, wxDbGridCellAttrProvider) ;
+                        attr->IncRef();
+                        self->SetColAttr(attr, col);
+                    }
+                    attr->SetReadOnly();
+                break;
+                default:
+                    //Dont add RO for...
+                    //  wxGridCellAttr::Cell - Not required, will inherit on merge from row.
+                    //  wxGridCellAttr::Row - If wxDbtable ever supports row locking could add
+                    //                        support to make RO on a row basis also.
+                    //  wxGridCellAttr::Default - Don't edit this ! or all cell with a attr will become readonly
+                    //  wxGridCellAttr::Merged - This should never be asked for.
+                break;
+            }
+        }
+        
+    }
+    return attr;
+}
+
+void wxDbGridCellAttrProvider::AssignDbTable(wxDbTable *tab)
+{
+    m_data = tab;
+}
+
+wxDbGridTableBase::wxDbGridTableBase(wxDbTable *tab, wxDbGridColInfo*  ColInfo,
+                     int count, bool takeOwnership)  :
+    m_keys(), 
+    m_data(tab),
+    m_dbowner(takeOwnership),
+    m_rowmodified(false)
+{
+
+    if (count == wxUSE_QUERY)
+    {
+        m_rowtotal = m_data ? m_data->Count() : 0;
+    }
+    else
+    {
+        m_rowtotal = count;
+    }
+//    m_keys.Size(m_rowtotal);
+    m_row = -1;
+    if (ColInfo)
+    {
+        m_nocols = ColInfo->Length();
+        m_ColInfo = new wxDbGridColInfoBase[m_nocols];
+        //Do Copy.
+        wxDbGridColInfo *ptr = ColInfo;
+        int i =0;
+        while (ptr && i < m_nocols)
+        {
+            m_ColInfo[i] = ptr->m_data;
+            ptr = ptr->m_next;
+            i++;
+        }
+#ifdef __WXDEBUG__
+        if (ptr)
+        {
+            wxLogDebug(wxT("NoCols over length after traversing %i items"),i);
+        }
+        if (i < m_nocols)
+        {
+            wxLogDebug(wxT("NoCols under length after traversing %i items"),i);
+        } 
+#endif
+    }
+}
+
+wxDbGridTableBase::~wxDbGridTableBase()
+{
+    wxDbGridCellAttrProvider *provider;
+
+    //Can't check for update here as 
+
+    //FIXME: should i remove m_ColInfo and m_data from m_attrProvider if a wxDbGridAttrProvider
+//    if ((provider = dynamic_cast<wxDbGridCellAttrProvider *>(GetAttrProvider())))
+     // Using C casting for now until we can support dynamic_cast with wxWindows
+    if ((provider = (wxDbGridCellAttrProvider *)(GetAttrProvider())))
+    {
+        provider->AssignDbTable(NULL);
+    }
+    delete [] m_ColInfo;
+    
+    Writeback();
+    if (m_dbowner)
+    {
+        delete m_data;
+    }
+}
+
+bool wxDbGridTableBase::CanHaveAttributes()
+{
+    if (!GetAttrProvider())
+    {
+        // use the default attr provider by default
+        SetAttrProvider(new wxDbGridCellAttrProvider(m_data, m_ColInfo));
+    }
+    return true;
+}
+
+
+bool wxDbGridTableBase::AssignDbTable(wxDbTable *tab, int count, bool takeOwnership)
+{
+    wxDbGridCellAttrProvider *provider;
+
+    //Remove Information from grid about old data
+    if (GetView())
+    {
+        wxGrid *grid = GetView();
+        grid->BeginBatch();
+        grid->ClearSelection();
+        if (grid->IsCellEditControlEnabled())
+        {
+            grid->DisableCellEditControl();
+        }
+        wxGridTableMessage msg(this, wxGRIDTABLE_NOTIFY_ROWS_DELETED,0,m_rowtotal);
+        grid->ProcessTableMessage(msg);
+    }
+
+    //reset our internals...
+    Writeback();
+    if (m_dbowner)
+    {
+        delete m_data;
+    }
+    m_keys.Empty();
+    m_data = tab;
+    //FIXME: Remove dynamic_cast before sumision to wxwin 
+//    if ((provider = dynamic_cast<wxDbGridCellAttrProvider *> (GetAttrProvider())))
+     // Using C casting for now until we can support dynamic_cast with wxWindows
+    if ((provider = (wxDbGridCellAttrProvider *)(GetAttrProvider())))
+    {
+        provider->AssignDbTable(m_data);
+    }
+    
+    if (count == wxUSE_QUERY)
+    {
+        m_rowtotal = m_data ? m_data->Count() : 0;
+    }
+    else
+    {
+         m_rowtotal = count;
+    }
+    m_row = -1;
+
+    //Add Information to grid about new data
+    if (GetView())
+    {
+        wxGrid * grid = GetView();
+        wxGridTableMessage msg(this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_rowtotal);
+        grid->ProcessTableMessage(msg);
+        grid->EndBatch();
+    }
+    m_dbowner = takeOwnership;
+    m_rowmodified = false;
+    return true;
+}
+
+wxString wxDbGridTableBase::GetTypeName(int row, int col)
+{
+    if (col == 8)
+        int breakpoint = 1;
+
+    if (GetNumberCols() > col)
+    {
+        if (m_ColInfo[col].wxtypename == wxGRID_VALUE_DBAUTO)
+        {
+            if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
+            {
+                wxFAIL_MSG (_T("You can not use wxGRID_VALUE_DBAUTO for virtual columns"));
+            }
+            switch(m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype)
+            {
+                case SQL_C_CHAR:
+                    return wxGRID_VALUE_STRING;
+                    break;
+                case SQL_C_SSHORT:
+                    return wxGRID_VALUE_NUMBER;
+                    break;
+                case SQL_C_USHORT:
+                    return wxGRID_VALUE_NUMBER;
+                    break;
+                case SQL_C_SLONG:
+                    return wxGRID_VALUE_NUMBER;
+                    break;
+                case SQL_C_ULONG:
+                    return wxGRID_VALUE_NUMBER;
+                    break;
+                case SQL_C_FLOAT:
+                    return wxGRID_VALUE_FLOAT;
+                    break;
+                case SQL_C_DOUBLE:
+                    return wxGRID_VALUE_FLOAT;
+                    break;
+                case SQL_C_DATE:
+                    return wxGRID_VALUE_DATETIME;
+                    break;
+                case SQL_C_TIME:
+                    return wxGRID_VALUE_DATETIME;
+                    break;
+                case SQL_C_TIMESTAMP:
+                    return wxGRID_VALUE_DATETIME;
+                    break;
+                default:
+                    return wxGRID_VALUE_STRING;
+                    break;
+            }
+        }
+        else
+        {
+            return m_ColInfo[col].wxtypename;
+        }
+    }
+    wxFAIL_MSG (_T("unknown column"));
+    return wxString();
+}
+
+bool wxDbGridTableBase::CanGetValueAs(int row, int col, const wxString& typeName)
+{
+    wxLogDebug(wxT("CanGetValueAs() on %i,%i"),row,col);
+    //Is this needed? As it will be validated on GetValueAsXXXX
+    ValidateRow(row);
+
+    if (typeName == wxGRID_VALUE_STRING)
+    {
+        //FIXME ummm What about blob field etc.
+        return true;
+    }
+
+    if (m_data->IsColNull(m_ColInfo[col].DbCol))
+    {
+        return false;
+    }
+
+    if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
+    {
+        //If a virtual column then we can't find it's type. we have to 
+        // return false to get using wxVariant.
+        return false;
+    }
+    int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype;
+    
+    if (typeName == wxGRID_VALUE_DATETIME)
+    {
+        if ((sqltype == SQL_C_DATE) ||
+            (sqltype == SQL_C_TIME) || 
+            (sqltype == SQL_C_TIMESTAMP))
+        {
+            return true;
+        }
+        return false;
+    }
+    if (typeName == wxGRID_VALUE_NUMBER)
+    {
+        if ((sqltype == SQL_C_SSHORT) ||
+            (sqltype == SQL_C_USHORT) || 
+            (sqltype == SQL_C_SLONG)  ||
+            (sqltype == SQL_C_ULONG))
+        {
+            return true;
+        }
+        return false;
+    }
+    if (typeName == wxGRID_VALUE_FLOAT)
+    {
+        if ((sqltype == SQL_C_SSHORT) ||
+            (sqltype == SQL_C_USHORT) || 
+            (sqltype == SQL_C_SLONG)  ||
+            (sqltype == SQL_C_ULONG)  ||
+            (sqltype == SQL_C_FLOAT)  ||
+            (sqltype == SQL_C_DOUBLE))
+        {
+            return true;
+        }
+        return false;
+    }
+    return false;
+}
+
+bool wxDbGridTableBase::CanSetValueAs(int row, int col, const wxString& typeName)
+{
+    //Is this needed? As will be validated on SetValueAsXXXX
+    ValidateRow(row);
+
+    if (m_data->IsColNull(m_ColInfo[col].DbCol))
+    {
+        return false;
+    }
+
+    if (typeName == wxGRID_VALUE_STRING)
+    {
+        //FIXME ummm What about blob field etc.
+        return true;
+    }
+
+    if (!(m_data->GetColDefs()[(m_ColInfo[col].DbCol)].Updateable))
+    {
+        return false;
+    }
+
+    if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
+    {
+        //If a virtual column then we can't find it's type. we have to faulse to 
+        //get using wxVairent.
+        return false;
+    }
+
+    int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype;
+    if (typeName == wxGRID_VALUE_DATETIME)
+    {
+        if ((sqltype == SQL_C_DATE) ||
+            (sqltype == SQL_C_TIME) || 
+            (sqltype == SQL_C_TIMESTAMP))
+        {
+            return true;
+        }
+        return false;
+    }
+    if (typeName == wxGRID_VALUE_NUMBER)
+    {
+        if ((sqltype == SQL_C_SSHORT) ||
+            (sqltype == SQL_C_USHORT) || 
+            (sqltype == SQL_C_SLONG)  ||
+            (sqltype == SQL_C_ULONG))
+        {
+            return true;
+        }
+        return false;
+    }
+    if (typeName == wxGRID_VALUE_FLOAT)
+    {
+        if ((sqltype == SQL_C_SSHORT) ||
+            (sqltype == SQL_C_USHORT) || 
+            (sqltype == SQL_C_SLONG)  ||
+            (sqltype == SQL_C_ULONG)  ||
+            (sqltype == SQL_C_FLOAT)  ||
+            (sqltype == SQL_C_DOUBLE))
+        {
+            return true;
+        }
+        return false;
+    }
+    return false;
+}
+
+long wxDbGridTableBase::GetValueAsLong(int row, int col)
+{
+    ValidateRow(row);
+
+    if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
+    {
+        wxFAIL_MSG (_T("You can not use GetValueAsLong for virtual columns"));
+        return 0;
+    }
+    int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype;
+    if ((sqltype == SQL_C_SSHORT) ||
+        (sqltype == SQL_C_USHORT) || 
+        (sqltype == SQL_C_SLONG) ||
+        (sqltype == SQL_C_ULONG))
+    {
+        wxVariant val = m_data->GetCol(m_ColInfo[col].DbCol);
+        return val.GetLong();
+    }
+    wxFAIL_MSG (_T("unknown column, "));
+    return 0;
+}
+
+double wxDbGridTableBase::GetValueAsDouble(int row, int col)
+{
+    wxLogDebug(wxT("GetValueAsDouble() on %i,%i"),row,col);
+    ValidateRow(row);
+
+    if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
+    {
+        wxFAIL_MSG (_T("You can not use GetValueAsDouble for virtual columns"));
+        return 0.0;
+    }
+    int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype;
+    if ((sqltype == SQL_C_SSHORT) ||
+        (sqltype == SQL_C_USHORT) || 
+        (sqltype == SQL_C_SLONG) ||
+        (sqltype == SQL_C_ULONG) ||
+        (sqltype == SQL_C_FLOAT) ||
+        (sqltype == SQL_C_DOUBLE))
+    {
+        wxVariant val = m_data->GetCol(m_ColInfo[col].DbCol);
+        return val.GetDouble();
+    }
+    wxFAIL_MSG (_T("unknown column"));
+    return 0.0;
+}
+
+bool wxDbGridTableBase::GetValueAsBool(int row, int col)
+{
+    wxLogDebug(wxT("GetValueAsBool() on %i,%i"),row,col);
+    ValidateRow(row);
+
+    if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
+    {
+        wxFAIL_MSG (_T("You can not use GetValueAsBool for virtual columns"));
+        return 0;
+    }
+    int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype;
+    if ((sqltype == SQL_C_SSHORT) ||
+        (sqltype == SQL_C_USHORT) || 
+        (sqltype == SQL_C_SLONG) ||
+        (sqltype == SQL_C_ULONG))
+    {
+        wxVariant val = m_data->GetCol(m_ColInfo[col].DbCol);
+        return val.GetBool();
+    }
+    wxFAIL_MSG (_T("unknown column, "));
+    return 0;
+}
+
+void* wxDbGridTableBase::GetValueAsCustom(int row, int col, const wxString& typeName)
+{
+    wxLogDebug(wxT("GetValueAsCustom() on %i,%i"),row,col);
+    ValidateRow(row);
+    
+    if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
+    {
+        wxFAIL_MSG (_T("You can not use GetValueAsCustom for virtual columns"));
+        return NULL;
+    }
+    if (m_data->IsColNull(m_ColInfo[col].DbCol))
+        return NULL;
+
+    if (typeName == wxGRID_VALUE_DATETIME)
+    {
+        wxDbColDef *pColDefs = m_data->GetColDefs();
+        int sqltype = pColDefs[(m_ColInfo[col].DbCol)].SqlCtype;
+
+        if ((sqltype == SQL_C_DATE) ||
+            (sqltype == SQL_C_TIME) ||
+            (sqltype == SQL_C_TIMESTAMP))
+        {
+            wxVariant val = m_data->GetCol(m_ColInfo[col].DbCol);
+            return new wxDateTime(val.GetDateTime());
+        }
+    }
+    wxFAIL_MSG (_T("unknown column data type "));
+    return NULL;
+}
+
+
+void wxDbGridTableBase::SetValueAsCustom(int row, int col, const wxString& typeName, void* value)
+{
+    wxLogDebug(wxT("SetValueAsCustom() on %i,%i"),row,col);
+    ValidateRow(row);
+
+    if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
+    {
+        wxFAIL_MSG (_T("You can not use SetValueAsCustom for virtual columns"));
+        return;
+    }
+
+    if (typeName == wxGRID_VALUE_DATETIME)
+    {
+        int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype;
+        if ((sqltype == SQL_C_DATE) ||
+            (sqltype == SQL_C_TIME) ||
+            (sqltype == SQL_C_TIMESTAMP))
+        {
+            //FIXME: you can't dynamic_cast from (void *)
+            //wxDateTime *date = wxDynamicCast(value, wxDateTime);
+            wxDateTime *date = (wxDateTime *)value;
+            if (!date)
+            {
+                wxFAIL_MSG (_T("Failed to convert data"));
+                return;
+            }
+            wxVariant val(date);
+            m_rowmodified = true;
+            m_data->SetCol(m_ColInfo[col].DbCol,val);
+        }
+    }
+    wxFAIL_MSG (_T("unknown column data type"));
+    return ;
+}
+
+
+wxString wxDbGridTableBase::GetColLabelValue(int col)
+{
+    if (GetNumberCols() > col)
+    {
+        return m_ColInfo[col].Title;
+    }
+    wxFAIL_MSG (_T("unknown column"));
+    return wxString();
+}
+
+bool wxDbGridTableBase::IsEmptyCell(int row, int col)
+{
+    wxLogDebug(wxT("IsEmtpyCell on %i,%i"),row,col);
+
+    ValidateRow(row);
+    return m_data->IsColNull(m_ColInfo[col].DbCol);
+}
+
+
+wxString wxDbGridTableBase::GetValue(int row, int col)
+{
+    wxLogDebug(wxT("GetValue() on %i,%i"),row,col);
+    
+    ValidateRow(row);
+    wxVariant val = m_data->GetCol(m_ColInfo[col].DbCol);
+    wxLogDebug(wxT("\tReturning \"%s\"\n"),val.GetString().c_str());
+    
+    return val.GetString(); 
+}
+
+
+void wxDbGridTableBase::SetValue(int row, int col,const wxString& value)
+{
+    wxLogDebug(wxT("SetValue() on %i,%i"),row,col);
+
+    ValidateRow(row);
+    wxVariant val(value);
+
+    m_rowmodified = true;
+    m_data->SetCol(m_ColInfo[col].DbCol,val);
+}
+
+
+void wxDbGridTableBase::SetValueAsLong(int row, int col, long value)
+{
+    wxLogDebug(wxT("SetValueAsLong() on %i,%i"),row,col);
+
+    ValidateRow(row);
+    wxVariant val(value);
+
+    m_rowmodified = true;
+    m_data->SetCol(m_ColInfo[col].DbCol,val);
+}
+
+
+void wxDbGridTableBase::SetValueAsDouble(int row, int col, double value)
+{
+    wxLogDebug(wxT("SetValueAsDouble() on %i,%i"),row,col);
+
+    ValidateRow(row);
+    wxVariant val(value);
+
+    m_rowmodified = true;
+    m_data->SetCol(m_ColInfo[col].DbCol,val);
+
+}
+
+
+void wxDbGridTableBase::SetValueAsBool(int row, int col, bool value)
+{
+    wxLogDebug(wxT("SetValueAsBool() on %i,%i"),row,col);
+
+    ValidateRow(row);
+    wxVariant val(value);
+
+    m_rowmodified = true;
+    m_data->SetCol(m_ColInfo[col].DbCol,val);
+}
+
+
+void wxDbGridTableBase::ValidateRow(int row)
+{
+    wxLogDebug(wxT("ValidateRow(%i) currently on row (%i). Array count = %i"),row,m_row,m_keys.GetCount());
+
+    if (row == m_row)
+         return;
+    Writeback();
+
+    //We add to row as Count is unsigned!
+    if ((unsigned)(row+1) > m_keys.GetCount())
+    {
+        wxLogDebug(wxT("\trow key unknown"));
+        // Extend Array, iterate through data filling with keys
+        m_data->SetRowMode(wxDbTable::WX_ROW_MODE_QUERY);
+        int trow;
+        for (trow = m_keys.GetCount(); trow <= row; trow++)
+        {
+            wxLogDebug(wxT("Fetching row %i.."), trow);
+            bool ret = m_data->GetNext();
+
+            wxLogDebug(wxT(" ...success=(%i)"),ret);
+            GenericKey k = m_data->GetKey();
+            m_keys.Add(k);
+        }
+        m_row = row;
+    }
+    else
+    {
+        wxLogDebug(wxT("\trow key known centering data"));
+        GenericKey k = m_keys.Item(row);
+        m_data->SetRowMode(wxDbTable::WX_ROW_MODE_INDIVIDUAL);
+        m_data->ClearMemberVars();
+        m_data->SetKey(k);
+        if (!m_data->QueryOnKeyFields())
+        {
+            wxDbLogExtendedErrorMsg("ODBC error during Query()\n\n", m_data->GetDb(),__FILE__,__LINE__);
+        }
+
+        m_data->GetNext();
+
+        m_row = row;
+    }
+    m_rowmodified = false;
+}
+
+bool wxDbGridTableBase::Writeback() const
+{
+    if (!m_rowmodified)
+    {
+        return true;
+    }
+
+    bool result=true;
+    wxLogDebug(wxT("\trow key unknown"));
+
+// FIXME: this code requires dbtable support for record status 
+#if 0
+    switch (m_data->get_ModifiedStatus())
+    {
+        case wxDbTable::UpdatePending:
+            result = m_data->Update();
+           break;
+        case wxDbTable::InsertPending:
+            result = (m_data->Insert() == SQL_SUCCESS);
+        break;
+        default:
+            //Nothing
+        break;
+    }
+#else
+    wxLogDebug(wxT("WARNING : Row writeback not implemented "));
+#endif
+    return result;
+}
+
+#include <wx/arrimpl.cpp>
+
+WX_DEFINE_OBJARRAY(keyarray);
+
+#endif  // #if wxUSE_NEW_GRID
+#endif  // #if wxUSE_ODBC
+