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