1 /////////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Displays a wxDbTable in a wxGrid. 
   4 // Author:      Roger Gammans, Paul Gammans 
   8 // Copyright:   (c) 1999 The Computer Surgery (roger@computer-surgery.co.uk) 
   9 // Licence:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  11 // Branched From : dbgrid.cpp,v 1.18 2000/12/19 13:00:58 
  12 /////////////////////////////////////////////////////////////////////////////// 
  15     #pragma implementation "dbgrid.h" 
  18 #include "wx/wxprec.h" 
  29     #include "wx/textctrl.h" 
  33 #include "wx/generic/gridctrl.h" 
  34 #include "wx/dbgrid.h" 
  37 wxDbGridCellAttrProvider::wxDbGridCellAttrProvider() 
  43 wxDbGridCellAttrProvider::wxDbGridCellAttrProvider(wxDbTable 
*tab
, wxDbGridColInfoBase
* ColInfo
) 
  49 wxDbGridCellAttrProvider::~wxDbGridCellAttrProvider() 
  53 wxGridCellAttr 
*wxDbGridCellAttrProvider::GetAttr(int row
, int col
, 
  54                                       wxGridCellAttr::wxAttrKind  kind
) const 
  56     wxGridCellAttr 
*attr 
= wxGridCellAttrProvider::GetAttr(row
,col
,kind
); 
  58     if (m_data 
&& m_ColInfo 
&& (m_data
->GetNumberOfColumns() > m_ColInfo
[col
].DbCol
)) 
  60         //FIXME: this test could. 
  61         //  ??::InsertPending == m_data->get_ModifiedStatus() 
  62         //  and if InsertPending use colDef[].InsertAllowed 
  63         if (!(m_data
->GetColDefs()[(m_ColInfo
[col
].DbCol
)].Updateable
)) 
  67                 case (wxGridCellAttr::Any
): 
  70                         attr 
= new wxGridCellAttr
; 
  71                         // Store so we don't keep creating / deleting this... 
  72                         wxDbGridCellAttrProvider 
* self 
= wxConstCast(this, wxDbGridCellAttrProvider
) ; 
  74                         self
->SetColAttr(attr
, col
); 
  79                         //We now must check what we were returned. and do the right thing (tm) 
  80                         wxGridCellAttr::wxAttrKind attrkind 
= attr
->GetKind(); 
  81                         if ((attrkind 
== (wxGridCellAttr::Default
)) || (attrkind 
== (wxGridCellAttr::Cell
)) || 
  82                             (attrkind 
== (wxGridCellAttr::Col
))) 
  84                                 wxGridCellAttr 
*attrtomerge 
= attr
; 
  85                                 attr 
= new wxGridCellAttr
; 
  86                                 attr
->SetKind(wxGridCellAttr::Merged
); 
  87                                 attr
->MergeWith(attrtomerge
); 
  89                                 attrtomerge
->DecRef(); 
  94                 case (wxGridCellAttr::Col
): 
  95                     //As we must have a Coll, and were setting Coll attributes 
  96                     // we can based on wxdbTable's so just set RO if attr valid 
  99                         attr 
= new wxGridCellAttr
; 
 100                         wxDbGridCellAttrProvider 
* self 
= wxConstCast(this, wxDbGridCellAttrProvider
) ; 
 102                         self
->SetColAttr(attr
, col
); 
 108                     //  wxGridCellAttr::Cell - Not required, will inherit on merge from row. 
 109                     //  wxGridCellAttr::Row - If wxDbtable ever supports row locking could add 
 110                     //                        support to make RO on a row basis also. 
 111                     //  wxGridCellAttr::Default - Don't edit this ! or all cell with a attr will become readonly 
 112                     //  wxGridCellAttr::Merged - This should never be asked for. 
 121 void wxDbGridCellAttrProvider::AssignDbTable(wxDbTable 
*tab
) 
 126 wxDbGridTableBase::wxDbGridTableBase(wxDbTable 
*tab
, wxDbGridColInfo
*  ColInfo
, 
 127                      int count
, bool takeOwnership
)  : 
 130     m_dbowner(takeOwnership
), 
 134     if (count 
== wxUSE_QUERY
) 
 136         m_rowtotal 
= m_data 
? m_data
->Count() : 0; 
 142 //    m_keys.Size(m_rowtotal); 
 146         m_nocols 
= ColInfo
->Length(); 
 147         m_ColInfo 
= new wxDbGridColInfoBase
[m_nocols
]; 
 149         wxDbGridColInfo 
*ptr 
= ColInfo
; 
 151         while (ptr 
&& i 
< m_nocols
) 
 153             m_ColInfo
[i
] = ptr
->m_data
; 
 160             wxLogDebug(wxT("NoCols over length after traversing %i items"),i
); 
 164             wxLogDebug(wxT("NoCols under length after traversing %i items"),i
); 
 170 wxDbGridTableBase::~wxDbGridTableBase() 
 172     wxDbGridCellAttrProvider 
*provider
; 
 174     //Can't check for update here as 
 176     //FIXME: should i remove m_ColInfo and m_data from m_attrProvider if a wxDbGridAttrProvider 
 177 //    if ((provider = dynamic_cast<wxDbGridCellAttrProvider *>(GetAttrProvider()))) 
 178      // Using C casting for now until we can support dynamic_cast with wxWindows 
 179     provider 
= (wxDbGridCellAttrProvider 
*)(GetAttrProvider()); 
 182         provider
->AssignDbTable(NULL
); 
 193 bool wxDbGridTableBase::CanHaveAttributes() 
 195     if (!GetAttrProvider()) 
 197         // use the default attr provider by default 
 198         SetAttrProvider(new wxDbGridCellAttrProvider(m_data
, m_ColInfo
)); 
 204 bool wxDbGridTableBase::AssignDbTable(wxDbTable 
*tab
, int count
, bool takeOwnership
) 
 206     wxDbGridCellAttrProvider 
*provider
; 
 208     //Remove Information from grid about old data 
 211         wxGrid 
*grid 
= GetView(); 
 213         grid
->ClearSelection(); 
 214         if (grid
->IsCellEditControlEnabled()) 
 216             grid
->DisableCellEditControl(); 
 218         wxGridTableMessage 
msg(this, wxGRIDTABLE_NOTIFY_ROWS_DELETED
,0,m_rowtotal
); 
 219         grid
->ProcessTableMessage(msg
); 
 222     //reset our internals... 
 230     //FIXME: Remove dynamic_cast before sumision to wxwin 
 231 //    if ((provider = dynamic_cast<wxDbGridCellAttrProvider *> (GetAttrProvider()))) 
 232      // Using C casting for now until we can support dynamic_cast with wxWindows 
 233     provider 
= (wxDbGridCellAttrProvider 
*)(GetAttrProvider()); 
 236         provider
->AssignDbTable(m_data
); 
 239     if (count 
== wxUSE_QUERY
) 
 241         m_rowtotal 
= m_data 
? m_data
->Count() : 0; 
 249     //Add Information to grid about new data 
 252         wxGrid 
* grid 
= GetView(); 
 253         wxGridTableMessage 
msg(this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED
, m_rowtotal
); 
 254         grid
->ProcessTableMessage(msg
); 
 257     m_dbowner 
= takeOwnership
; 
 258     m_rowmodified 
= FALSE
; 
 262 wxString 
wxDbGridTableBase::GetTypeName(int row
, int col
) 
 267     if (GetNumberCols() > col
) 
 269         if (m_ColInfo
[col
].wxtypename 
== wxGRID_VALUE_DBAUTO
) 
 271             if (m_data
->GetNumberOfColumns() <= m_ColInfo
[col
].DbCol
) 
 273                 wxFAIL_MSG (_T("You can not use wxGRID_VALUE_DBAUTO for virtual columns")); 
 275             switch(m_data
->GetColDefs()[(m_ColInfo
[col
].DbCol
)].SqlCtype
) 
 278                     return wxGRID_VALUE_STRING
; 
 280                     return wxGRID_VALUE_NUMBER
; 
 282                     return wxGRID_VALUE_NUMBER
; 
 284                     return wxGRID_VALUE_NUMBER
; 
 286                     return wxGRID_VALUE_NUMBER
; 
 288                     return wxGRID_VALUE_FLOAT
; 
 290                     return wxGRID_VALUE_FLOAT
; 
 292                     return wxGRID_VALUE_DATETIME
; 
 294                     return wxGRID_VALUE_DATETIME
; 
 295                 case SQL_C_TIMESTAMP
: 
 296                     return wxGRID_VALUE_DATETIME
; 
 298                     return wxGRID_VALUE_STRING
; 
 303             return m_ColInfo
[col
].wxtypename
; 
 306     wxFAIL_MSG (_T("unknown column")); 
 310 bool wxDbGridTableBase::CanGetValueAs(int row
, int col
, const wxString
& typeName
) 
 312     wxLogDebug(wxT("CanGetValueAs() on %i,%i"),row
,col
); 
 313     //Is this needed? As it will be validated on GetValueAsXXXX 
 316     if (typeName 
== wxGRID_VALUE_STRING
) 
 318         //FIXME ummm What about blob field etc. 
 322     if (m_data
->IsColNull(m_ColInfo
[col
].DbCol
)) 
 327     if (m_data
->GetNumberOfColumns() <= m_ColInfo
[col
].DbCol
) 
 329         //If a virtual column then we can't find it's type. we have to 
 330         // return FALSE to get using wxVariant. 
 333     int sqltype 
= m_data
->GetColDefs()[(m_ColInfo
[col
].DbCol
)].SqlCtype
; 
 335     if (typeName 
== wxGRID_VALUE_DATETIME
) 
 337         if ((sqltype 
== SQL_C_DATE
) || 
 338             (sqltype 
== SQL_C_TIME
) || 
 339             (sqltype 
== SQL_C_TIMESTAMP
)) 
 345     if (typeName 
== wxGRID_VALUE_NUMBER
) 
 347         if ((sqltype 
== SQL_C_SSHORT
) || 
 348             (sqltype 
== SQL_C_USHORT
) || 
 349             (sqltype 
== SQL_C_SLONG
)  || 
 350             (sqltype 
== SQL_C_ULONG
)) 
 356     if (typeName 
== wxGRID_VALUE_FLOAT
) 
 358         if ((sqltype 
== SQL_C_SSHORT
) || 
 359             (sqltype 
== SQL_C_USHORT
) || 
 360             (sqltype 
== SQL_C_SLONG
)  || 
 361             (sqltype 
== SQL_C_ULONG
)  || 
 362             (sqltype 
== SQL_C_FLOAT
)  || 
 363             (sqltype 
== SQL_C_DOUBLE
)) 
 372 bool wxDbGridTableBase::CanSetValueAs(int row
, int col
, const wxString
& typeName
) 
 374     //Is this needed? As will be validated on SetValueAsXXXX 
 377     if (m_data
->IsColNull(m_ColInfo
[col
].DbCol
)) 
 382     if (typeName 
== wxGRID_VALUE_STRING
) 
 384         //FIXME ummm What about blob field etc. 
 388     if (!(m_data
->GetColDefs()[(m_ColInfo
[col
].DbCol
)].Updateable
)) 
 393     if (m_data
->GetNumberOfColumns() <= m_ColInfo
[col
].DbCol
) 
 395         //If a virtual column then we can't find it's type. we have to faulse to 
 396         //get using wxVairent. 
 400     int sqltype 
= m_data
->GetColDefs()[(m_ColInfo
[col
].DbCol
)].SqlCtype
; 
 401     if (typeName 
== wxGRID_VALUE_DATETIME
) 
 403         if ((sqltype 
== SQL_C_DATE
) || 
 404             (sqltype 
== SQL_C_TIME
) || 
 405             (sqltype 
== SQL_C_TIMESTAMP
)) 
 411     if (typeName 
== wxGRID_VALUE_NUMBER
) 
 413         if ((sqltype 
== SQL_C_SSHORT
) || 
 414             (sqltype 
== SQL_C_USHORT
) || 
 415             (sqltype 
== SQL_C_SLONG
)  || 
 416             (sqltype 
== SQL_C_ULONG
)) 
 422     if (typeName 
== wxGRID_VALUE_FLOAT
) 
 424         if ((sqltype 
== SQL_C_SSHORT
) || 
 425             (sqltype 
== SQL_C_USHORT
) || 
 426             (sqltype 
== SQL_C_SLONG
)  || 
 427             (sqltype 
== SQL_C_ULONG
)  || 
 428             (sqltype 
== SQL_C_FLOAT
)  || 
 429             (sqltype 
== SQL_C_DOUBLE
)) 
 438 long wxDbGridTableBase::GetValueAsLong(int row
, int col
) 
 442     if (m_data
->GetNumberOfColumns() <= m_ColInfo
[col
].DbCol
) 
 444         wxFAIL_MSG (_T("You can not use GetValueAsLong for virtual columns")); 
 447     int sqltype 
= m_data
->GetColDefs()[(m_ColInfo
[col
].DbCol
)].SqlCtype
; 
 448     if ((sqltype 
== SQL_C_SSHORT
) || 
 449         (sqltype 
== SQL_C_USHORT
) || 
 450         (sqltype 
== SQL_C_SLONG
) || 
 451         (sqltype 
== SQL_C_ULONG
)) 
 453         wxVariant val 
= m_data
->GetCol(m_ColInfo
[col
].DbCol
); 
 454         return val
.GetLong(); 
 456     wxFAIL_MSG (_T("unknown column, ")); 
 460 double wxDbGridTableBase::GetValueAsDouble(int row
, int col
) 
 462     wxLogDebug(wxT("GetValueAsDouble() on %i,%i"),row
,col
); 
 465     if (m_data
->GetNumberOfColumns() <= m_ColInfo
[col
].DbCol
) 
 467         wxFAIL_MSG (_T("You can not use GetValueAsDouble for virtual columns")); 
 470     int sqltype 
= m_data
->GetColDefs()[(m_ColInfo
[col
].DbCol
)].SqlCtype
; 
 471     if ((sqltype 
== SQL_C_SSHORT
) || 
 472         (sqltype 
== SQL_C_USHORT
) || 
 473         (sqltype 
== SQL_C_SLONG
) || 
 474         (sqltype 
== SQL_C_ULONG
) || 
 475         (sqltype 
== SQL_C_FLOAT
) || 
 476         (sqltype 
== SQL_C_DOUBLE
)) 
 478         wxVariant val 
= m_data
->GetCol(m_ColInfo
[col
].DbCol
); 
 479         return val
.GetDouble(); 
 481     wxFAIL_MSG (_T("unknown column")); 
 485 bool wxDbGridTableBase::GetValueAsBool(int row
, int col
) 
 487     wxLogDebug(wxT("GetValueAsBool() on %i,%i"),row
,col
); 
 490     if (m_data
->GetNumberOfColumns() <= m_ColInfo
[col
].DbCol
) 
 492         wxFAIL_MSG (_T("You can not use GetValueAsBool for virtual columns")); 
 495     int sqltype 
= m_data
->GetColDefs()[(m_ColInfo
[col
].DbCol
)].SqlCtype
; 
 496     if ((sqltype 
== SQL_C_SSHORT
) || 
 497         (sqltype 
== SQL_C_USHORT
) || 
 498         (sqltype 
== SQL_C_SLONG
) || 
 499         (sqltype 
== SQL_C_ULONG
)) 
 501         wxVariant val 
= m_data
->GetCol(m_ColInfo
[col
].DbCol
); 
 502         return val
.GetBool(); 
 504     wxFAIL_MSG (_T("unknown column, ")); 
 508 void* wxDbGridTableBase::GetValueAsCustom(int row
, int col
, const wxString
& typeName
) 
 510     wxLogDebug(wxT("GetValueAsCustom() on %i,%i"),row
,col
); 
 513     if (m_data
->GetNumberOfColumns() <= m_ColInfo
[col
].DbCol
) 
 515         wxFAIL_MSG (_T("You can not use GetValueAsCustom for virtual columns")); 
 518     if (m_data
->IsColNull(m_ColInfo
[col
].DbCol
)) 
 521     if (typeName 
== wxGRID_VALUE_DATETIME
) 
 523         wxDbColDef 
*pColDefs 
= m_data
->GetColDefs(); 
 524         int sqltype 
= pColDefs
[(m_ColInfo
[col
].DbCol
)].SqlCtype
; 
 526         if ((sqltype 
== SQL_C_DATE
) || 
 527             (sqltype 
== SQL_C_TIME
) || 
 528             (sqltype 
== SQL_C_TIMESTAMP
)) 
 530             wxVariant val 
= m_data
->GetCol(m_ColInfo
[col
].DbCol
); 
 531             return new wxDateTime(val
.GetDateTime()); 
 534     wxFAIL_MSG (_T("unknown column data type ")); 
 539 void wxDbGridTableBase::SetValueAsCustom(int row
, int col
, const wxString
& typeName
, void* value
) 
 541     wxLogDebug(wxT("SetValueAsCustom() on %i,%i"),row
,col
); 
 544     if (m_data
->GetNumberOfColumns() <= m_ColInfo
[col
].DbCol
) 
 546         wxFAIL_MSG (_T("You can not use SetValueAsCustom for virtual columns")); 
 550     if (typeName 
== wxGRID_VALUE_DATETIME
) 
 552         int sqltype 
= m_data
->GetColDefs()[(m_ColInfo
[col
].DbCol
)].SqlCtype
; 
 553         if ((sqltype 
== SQL_C_DATE
) || 
 554             (sqltype 
== SQL_C_TIME
) || 
 555             (sqltype 
== SQL_C_TIMESTAMP
)) 
 557             //FIXME: you can't dynamic_cast from (void *) 
 558             //wxDateTime *date = wxDynamicCast(value, wxDateTime); 
 559             wxDateTime 
*date 
= (wxDateTime 
*)value
; 
 562                 wxFAIL_MSG (_T("Failed to convert data")); 
 566             m_rowmodified 
= TRUE
; 
 567             m_data
->SetCol(m_ColInfo
[col
].DbCol
,val
); 
 570     wxFAIL_MSG (_T("unknown column data type")); 
 575 wxString 
wxDbGridTableBase::GetColLabelValue(int col
) 
 577     if (GetNumberCols() > col
) 
 579         return m_ColInfo
[col
].Title
; 
 581     wxFAIL_MSG (_T("unknown column")); 
 585 bool wxDbGridTableBase::IsEmptyCell(int row
, int col
) 
 587     wxLogDebug(wxT("IsEmtpyCell on %i,%i"),row
,col
); 
 590     return m_data
->IsColNull(m_ColInfo
[col
].DbCol
); 
 594 wxString 
wxDbGridTableBase::GetValue(int row
, int col
) 
 596     wxLogDebug(wxT("GetValue() on %i,%i"),row
,col
); 
 599     wxVariant val 
= m_data
->GetCol(m_ColInfo
[col
].DbCol
); 
 600     wxLogDebug(wxT("\tReturning \"%s\"\n"),val
.GetString().c_str()); 
 602     return val
.GetString(); 
 606 void wxDbGridTableBase::SetValue(int row
, int col
,const wxString
& value
) 
 608     wxLogDebug(wxT("SetValue() on %i,%i"),row
,col
); 
 611     wxVariant 
val(value
); 
 613     m_rowmodified 
= TRUE
; 
 614     m_data
->SetCol(m_ColInfo
[col
].DbCol
,val
); 
 618 void wxDbGridTableBase::SetValueAsLong(int row
, int col
, long value
) 
 620     wxLogDebug(wxT("SetValueAsLong() on %i,%i"),row
,col
); 
 623     wxVariant 
val(value
); 
 625     m_rowmodified 
= TRUE
; 
 626     m_data
->SetCol(m_ColInfo
[col
].DbCol
,val
); 
 630 void wxDbGridTableBase::SetValueAsDouble(int row
, int col
, double value
) 
 632     wxLogDebug(wxT("SetValueAsDouble() on %i,%i"),row
,col
); 
 635     wxVariant 
val(value
); 
 637     m_rowmodified 
= TRUE
; 
 638     m_data
->SetCol(m_ColInfo
[col
].DbCol
,val
); 
 643 void wxDbGridTableBase::SetValueAsBool(int row
, int col
, bool value
) 
 645     wxLogDebug(wxT("SetValueAsBool() on %i,%i"),row
,col
); 
 648     wxVariant 
val(value
); 
 650     m_rowmodified 
= TRUE
; 
 651     m_data
->SetCol(m_ColInfo
[col
].DbCol
,val
); 
 655 void wxDbGridTableBase::ValidateRow(int row
) 
 657     wxLogDebug(wxT("ValidateRow(%i) currently on row (%i). Array count = %i"),row
,m_row
,m_keys
.GetCount()); 
 663     //We add to row as Count is unsigned! 
 664     if ((unsigned)(row
+1) > m_keys
.GetCount()) 
 666         wxLogDebug(wxT("\trow key unknown")); 
 667         // Extend Array, iterate through data filling with keys 
 668         m_data
->SetRowMode(wxDbTable::WX_ROW_MODE_QUERY
); 
 670         for (trow 
= m_keys
.GetCount(); trow 
<= row
; trow
++) 
 672             wxLogDebug(wxT("Fetching row %i.."), trow
); 
 673             bool ret 
= m_data
->GetNext(); 
 675             wxLogDebug(wxT(" ...success=(%i)"),ret
); 
 676             GenericKey k 
= m_data
->GetKey(); 
 683         wxLogDebug(wxT("\trow key known centering data")); 
 684         GenericKey k 
= m_keys
.Item(row
); 
 685         m_data
->SetRowMode(wxDbTable::WX_ROW_MODE_INDIVIDUAL
); 
 686         m_data
->ClearMemberVars(); 
 688         if (!m_data
->QueryOnKeyFields()) 
 690             wxDbLogExtendedErrorMsg("ODBC error during Query()\n\n", m_data
->GetDb(),__FILE__
,__LINE__
); 
 697     m_rowmodified 
= FALSE
; 
 700 bool wxDbGridTableBase::Writeback() const 
 708     wxLogDebug(wxT("\trow key unknown")); 
 710 // FIXME: this code requires dbtable support for record status 
 712     switch (m_data
->get_ModifiedStatus()) 
 714         case wxDbTable::UpdatePending
: 
 715             result 
= m_data
->Update(); 
 717         case wxDbTable::InsertPending
: 
 718             result 
= (m_data
->Insert() == SQL_SUCCESS
); 
 725     wxLogDebug(wxT("WARNING : Row writeback not implemented ")); 
 730 #include <wx/arrimpl.cpp> 
 732 WX_DEFINE_OBJARRAY(keyarray
); 
 734 #endif  // #if wxUSE_NEW_GRID 
 735 #endif  // #if wxUSE_ODBC