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 ///////////////////////////////////////////////////////////////////////////////
14 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
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"
36 // DLL options compatibility check:
38 WX_CHECK_BUILD_OPTIONS("wxDbGrid")
41 wxDbGridCellAttrProvider::wxDbGridCellAttrProvider()
47 wxDbGridCellAttrProvider::wxDbGridCellAttrProvider(wxDbTable
*tab
, wxDbGridColInfoBase
* ColInfo
)
53 wxDbGridCellAttrProvider::~wxDbGridCellAttrProvider()
57 wxGridCellAttr
*wxDbGridCellAttrProvider::GetAttr(int row
, int col
,
58 wxGridCellAttr::wxAttrKind kind
) const
60 wxGridCellAttr
*attr
= wxGridCellAttrProvider::GetAttr(row
,col
,kind
);
62 if (m_data
&& m_ColInfo
&& (m_data
->GetNumberOfColumns() > m_ColInfo
[col
].DbCol
))
64 //FIXME: this test could.
65 // ??::InsertPending == m_data->get_ModifiedStatus()
66 // and if InsertPending use colDef[].InsertAllowed
67 if (!(m_data
->GetColDefs()[(m_ColInfo
[col
].DbCol
)].Updateable
))
71 case (wxGridCellAttr::Any
):
74 attr
= new wxGridCellAttr
;
75 // Store so we don't keep creating / deleting this...
76 wxDbGridCellAttrProvider
* self
= wxConstCast(this, wxDbGridCellAttrProvider
) ;
78 self
->SetColAttr(attr
, col
);
83 //We now must check what we were returned. and do the right thing (tm)
84 wxGridCellAttr::wxAttrKind attrkind
= attr
->GetKind();
85 if ((attrkind
== (wxGridCellAttr::Default
)) || (attrkind
== (wxGridCellAttr::Cell
)) ||
86 (attrkind
== (wxGridCellAttr::Col
)))
88 wxGridCellAttr
*attrtomerge
= attr
;
89 attr
= new wxGridCellAttr
;
90 attr
->SetKind(wxGridCellAttr::Merged
);
91 attr
->MergeWith(attrtomerge
);
93 attrtomerge
->DecRef();
98 case (wxGridCellAttr::Col
):
99 //As we must have a Coll, and were setting Coll attributes
100 // we can based on wxdbTable's so just set RO if attr valid
103 attr
= new wxGridCellAttr
;
104 wxDbGridCellAttrProvider
* self
= wxConstCast(this, wxDbGridCellAttrProvider
) ;
106 self
->SetColAttr(attr
, col
);
112 // wxGridCellAttr::Cell - Not required, will inherit on merge from row.
113 // wxGridCellAttr::Row - If wxDbtable ever supports row locking could add
114 // support to make RO on a row basis also.
115 // wxGridCellAttr::Default - Don't edit this ! or all cell with a attr will become readonly
116 // wxGridCellAttr::Merged - This should never be asked for.
125 void wxDbGridCellAttrProvider::AssignDbTable(wxDbTable
*tab
)
130 wxDbGridTableBase::wxDbGridTableBase(wxDbTable
*tab
, wxDbGridColInfo
* ColInfo
,
131 int count
, bool takeOwnership
) :
134 m_dbowner(takeOwnership
),
138 if (count
== wxUSE_QUERY
)
140 m_rowtotal
= m_data
? m_data
->Count() : 0;
146 // m_keys.Size(m_rowtotal);
150 m_nocols
= ColInfo
->Length();
151 m_ColInfo
= new wxDbGridColInfoBase
[m_nocols
];
153 wxDbGridColInfo
*ptr
= ColInfo
;
155 while (ptr
&& i
< m_nocols
)
157 m_ColInfo
[i
] = ptr
->m_data
;
164 wxLogDebug(wxT("NoCols over length after traversing %i items"),i
);
168 wxLogDebug(wxT("NoCols under length after traversing %i items"),i
);
174 wxDbGridTableBase::~wxDbGridTableBase()
176 wxDbGridCellAttrProvider
*provider
;
178 //Can't check for update here as
180 //FIXME: should i remove m_ColInfo and m_data from m_attrProvider if a wxDbGridAttrProvider
181 // if ((provider = dynamic_cast<wxDbGridCellAttrProvider *>(GetAttrProvider())))
182 // Using C casting for now until we can support dynamic_cast with wxWidgets
183 provider
= (wxDbGridCellAttrProvider
*)(GetAttrProvider());
186 provider
->AssignDbTable(NULL
);
197 bool wxDbGridTableBase::CanHaveAttributes()
199 if (!GetAttrProvider())
201 // use the default attr provider by default
202 SetAttrProvider(new wxDbGridCellAttrProvider(m_data
, m_ColInfo
));
208 bool wxDbGridTableBase::AssignDbTable(wxDbTable
*tab
, int count
, bool takeOwnership
)
210 wxDbGridCellAttrProvider
*provider
;
212 //Remove Information from grid about old data
215 wxGrid
*grid
= GetView();
217 grid
->ClearSelection();
218 if (grid
->IsCellEditControlEnabled())
220 grid
->DisableCellEditControl();
222 wxGridTableMessage
msg(this, wxGRIDTABLE_NOTIFY_ROWS_DELETED
,0,m_rowtotal
);
223 grid
->ProcessTableMessage(msg
);
226 //reset our internals...
234 //FIXME: Remove dynamic_cast before sumision to wxwin
235 // if ((provider = dynamic_cast<wxDbGridCellAttrProvider *> (GetAttrProvider())))
236 // Using C casting for now until we can support dynamic_cast with wxWidgets
237 provider
= (wxDbGridCellAttrProvider
*)(GetAttrProvider());
240 provider
->AssignDbTable(m_data
);
243 if (count
== wxUSE_QUERY
)
245 m_rowtotal
= m_data
? m_data
->Count() : 0;
253 //Add Information to grid about new data
256 wxGrid
* grid
= GetView();
257 wxGridTableMessage
msg(this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED
, m_rowtotal
);
258 grid
->ProcessTableMessage(msg
);
261 m_dbowner
= takeOwnership
;
262 m_rowmodified
= false;
266 wxString
wxDbGridTableBase::GetTypeName(int WXUNUSED(row
), int col
)
268 if (GetNumberCols() > col
)
270 if (m_ColInfo
[col
].wxtypename
== wxGRID_VALUE_DBAUTO
)
272 if (m_data
->GetNumberOfColumns() <= m_ColInfo
[col
].DbCol
)
274 wxFAIL_MSG (_T("You can not use wxGRID_VALUE_DBAUTO for virtual columns"));
276 switch(m_data
->GetColDefs()[(m_ColInfo
[col
].DbCol
)].SqlCtype
)
282 return wxGRID_VALUE_STRING
;
285 return wxGRID_VALUE_NUMBER
;
287 return wxGRID_VALUE_NUMBER
;
290 return wxGRID_VALUE_NUMBER
;
292 return wxGRID_VALUE_NUMBER
;
294 return wxGRID_VALUE_FLOAT
;
296 return wxGRID_VALUE_FLOAT
;
298 return wxGRID_VALUE_DATETIME
;
300 return wxGRID_VALUE_DATETIME
;
301 case SQL_C_TIMESTAMP
:
302 return wxGRID_VALUE_DATETIME
;
304 return wxGRID_VALUE_STRING
;
309 return m_ColInfo
[col
].wxtypename
;
312 wxFAIL_MSG (_T("unknown column"));
316 bool wxDbGridTableBase::CanGetValueAs(int row
, int col
, const wxString
& typeName
)
318 wxLogDebug(wxT("CanGetValueAs() on %i,%i"),row
,col
);
319 //Is this needed? As it will be validated on GetValueAsXXXX
322 if (typeName
== wxGRID_VALUE_STRING
)
324 //FIXME ummm What about blob field etc.
328 if (m_data
->IsColNull((UWORD
)m_ColInfo
[col
].DbCol
))
333 if (m_data
->GetNumberOfColumns() <= m_ColInfo
[col
].DbCol
)
335 //If a virtual column then we can't find it's type. we have to
336 // return false to get using wxVariant.
339 int sqltype
= m_data
->GetColDefs()[(m_ColInfo
[col
].DbCol
)].SqlCtype
;
341 if (typeName
== wxGRID_VALUE_DATETIME
)
343 if ((sqltype
== SQL_C_DATE
) ||
344 (sqltype
== SQL_C_TIME
) ||
345 (sqltype
== SQL_C_TIMESTAMP
))
351 if (typeName
== wxGRID_VALUE_NUMBER
)
353 if ((sqltype
== SQL_C_SSHORT
) ||
354 (sqltype
== SQL_C_USHORT
) ||
355 (sqltype
== SQL_C_SLONG
) ||
356 (sqltype
== SQL_C_ULONG
))
362 if (typeName
== wxGRID_VALUE_FLOAT
)
364 if ((sqltype
== SQL_C_SSHORT
) ||
365 (sqltype
== SQL_C_USHORT
) ||
366 (sqltype
== SQL_C_SLONG
) ||
367 (sqltype
== SQL_C_ULONG
) ||
368 (sqltype
== SQL_C_FLOAT
) ||
369 (sqltype
== SQL_C_DOUBLE
))
378 bool wxDbGridTableBase::CanSetValueAs(int WXUNUSED(row
), int col
, const wxString
& typeName
)
380 if (typeName
== wxGRID_VALUE_STRING
)
382 //FIXME ummm What about blob field etc.
386 if (!(m_data
->GetColDefs()[(m_ColInfo
[col
].DbCol
)].Updateable
))
391 if (m_data
->GetNumberOfColumns() <= m_ColInfo
[col
].DbCol
)
393 //If a virtual column then we can't find it's type. we have to faulse to
394 //get using wxVairent.
398 int sqltype
= m_data
->GetColDefs()[(m_ColInfo
[col
].DbCol
)].SqlCtype
;
399 if (typeName
== wxGRID_VALUE_DATETIME
)
401 if ((sqltype
== SQL_C_DATE
) ||
402 (sqltype
== SQL_C_TIME
) ||
403 (sqltype
== SQL_C_TIMESTAMP
))
409 if (typeName
== wxGRID_VALUE_NUMBER
)
411 if ((sqltype
== SQL_C_SSHORT
) ||
412 (sqltype
== SQL_C_USHORT
) ||
413 (sqltype
== SQL_C_SLONG
) ||
414 (sqltype
== SQL_C_ULONG
))
420 if (typeName
== wxGRID_VALUE_FLOAT
)
422 if ((sqltype
== SQL_C_SSHORT
) ||
423 (sqltype
== SQL_C_USHORT
) ||
424 (sqltype
== SQL_C_SLONG
) ||
425 (sqltype
== SQL_C_ULONG
) ||
426 (sqltype
== SQL_C_FLOAT
) ||
427 (sqltype
== SQL_C_DOUBLE
))
436 long wxDbGridTableBase::GetValueAsLong(int row
, int col
)
440 if (m_data
->GetNumberOfColumns() <= m_ColInfo
[col
].DbCol
)
442 wxFAIL_MSG (_T("You can not use GetValueAsLong for virtual columns"));
445 int sqltype
= m_data
->GetColDefs()[(m_ColInfo
[col
].DbCol
)].SqlCtype
;
446 if ((sqltype
== SQL_C_SSHORT
) ||
447 (sqltype
== SQL_C_USHORT
) ||
448 (sqltype
== SQL_C_SLONG
) ||
449 (sqltype
== SQL_C_ULONG
))
451 wxVariant val
= m_data
->GetColumn(m_ColInfo
[col
].DbCol
);
452 return val
.GetLong();
454 wxFAIL_MSG (_T("unknown column, "));
458 double wxDbGridTableBase::GetValueAsDouble(int row
, int col
)
460 wxLogDebug(wxT("GetValueAsDouble() on %i,%i"),row
,col
);
463 if (m_data
->GetNumberOfColumns() <= m_ColInfo
[col
].DbCol
)
465 wxFAIL_MSG (_T("You can not use GetValueAsDouble for virtual columns"));
468 int sqltype
= m_data
->GetColDefs()[(m_ColInfo
[col
].DbCol
)].SqlCtype
;
469 if ((sqltype
== SQL_C_SSHORT
) ||
470 (sqltype
== SQL_C_USHORT
) ||
471 (sqltype
== SQL_C_SLONG
) ||
472 (sqltype
== SQL_C_ULONG
) ||
473 (sqltype
== SQL_C_FLOAT
) ||
474 (sqltype
== SQL_C_DOUBLE
))
476 wxVariant val
= m_data
->GetColumn(m_ColInfo
[col
].DbCol
);
477 return val
.GetDouble();
479 wxFAIL_MSG (_T("unknown column"));
483 bool wxDbGridTableBase::GetValueAsBool(int row
, int col
)
485 wxLogDebug(wxT("GetValueAsBool() on %i,%i"),row
,col
);
488 if (m_data
->GetNumberOfColumns() <= m_ColInfo
[col
].DbCol
)
490 wxFAIL_MSG (_T("You can not use GetValueAsBool for virtual columns"));
493 int sqltype
= m_data
->GetColDefs()[(m_ColInfo
[col
].DbCol
)].SqlCtype
;
494 if ((sqltype
== SQL_C_SSHORT
) ||
495 (sqltype
== SQL_C_USHORT
) ||
496 (sqltype
== SQL_C_SLONG
) ||
497 (sqltype
== SQL_C_ULONG
))
499 wxVariant val
= m_data
->GetColumn(m_ColInfo
[col
].DbCol
);
500 return val
.GetBool();
502 wxFAIL_MSG (_T("unknown column, "));
506 void* wxDbGridTableBase::GetValueAsCustom(int row
, int col
, const wxString
& typeName
)
508 wxLogDebug(wxT("GetValueAsCustom() on %i,%i"),row
,col
);
511 if (m_data
->GetNumberOfColumns() <= m_ColInfo
[col
].DbCol
)
513 wxFAIL_MSG (_T("You can not use GetValueAsCustom for virtual columns"));
516 if (m_data
->IsColNull((UWORD
)m_ColInfo
[col
].DbCol
))
519 if (typeName
== wxGRID_VALUE_DATETIME
)
521 wxDbColDef
*pColDefs
= m_data
->GetColDefs();
522 int sqltype
= pColDefs
[(m_ColInfo
[col
].DbCol
)].SqlCtype
;
524 if ((sqltype
== SQL_C_DATE
) ||
525 (sqltype
== SQL_C_TIME
) ||
526 (sqltype
== SQL_C_TIMESTAMP
))
528 wxVariant val
= m_data
->GetColumn(m_ColInfo
[col
].DbCol
);
529 return new wxDateTime(val
.GetDateTime());
532 wxFAIL_MSG (_T("unknown column data type "));
537 void wxDbGridTableBase::SetValueAsCustom(int row
, int col
, const wxString
& typeName
, void* value
)
539 wxLogDebug(wxT("SetValueAsCustom() on %i,%i"),row
,col
);
542 if (m_data
->GetNumberOfColumns() <= m_ColInfo
[col
].DbCol
)
544 wxFAIL_MSG (_T("You can not use SetValueAsCustom for virtual columns"));
548 if (typeName
== wxGRID_VALUE_DATETIME
)
550 int sqltype
= m_data
->GetColDefs()[(m_ColInfo
[col
].DbCol
)].SqlCtype
;
551 if ((sqltype
== SQL_C_DATE
) ||
552 (sqltype
== SQL_C_TIME
) ||
553 (sqltype
== SQL_C_TIMESTAMP
))
555 //FIXME: you can't dynamic_cast from (void *)
556 //wxDateTime *date = wxDynamicCast(value, wxDateTime);
557 wxDateTime
*date
= (wxDateTime
*)value
;
560 wxFAIL_MSG (_T("Failed to convert data"));
564 m_rowmodified
= true;
565 m_data
->SetColumn(m_ColInfo
[col
].DbCol
,val
);
568 wxFAIL_MSG (_T("unknown column data type"));
573 wxString
wxDbGridTableBase::GetColLabelValue(int col
)
575 if (GetNumberCols() > col
)
577 return m_ColInfo
[col
].Title
;
579 wxFAIL_MSG (_T("unknown column"));
583 bool wxDbGridTableBase::IsEmptyCell(int row
, int col
)
585 wxLogDebug(wxT("IsEmtpyCell on %i,%i"),row
,col
);
588 return m_data
->IsColNull((UWORD
)m_ColInfo
[col
].DbCol
);
592 wxString
wxDbGridTableBase::GetValue(int row
, int col
)
594 wxLogDebug(wxT("GetValue() on %i,%i"),row
,col
);
597 wxVariant val
= m_data
->GetColumn(m_ColInfo
[col
].DbCol
);
598 wxLogDebug(wxT("\tReturning \"%s\"\n"),val
.GetString().c_str());
600 return val
.GetString();
604 void wxDbGridTableBase::SetValue(int row
, int col
,const wxString
& value
)
606 wxLogDebug(wxT("SetValue() on %i,%i"),row
,col
);
609 wxVariant
val(value
);
611 m_rowmodified
= true;
612 m_data
->SetColumn(m_ColInfo
[col
].DbCol
,val
);
616 void wxDbGridTableBase::SetValueAsLong(int row
, int col
, long value
)
618 wxLogDebug(wxT("SetValueAsLong() on %i,%i"),row
,col
);
621 wxVariant
val(value
);
623 m_rowmodified
= true;
624 m_data
->SetColumn(m_ColInfo
[col
].DbCol
,val
);
628 void wxDbGridTableBase::SetValueAsDouble(int row
, int col
, double value
)
630 wxLogDebug(wxT("SetValueAsDouble() on %i,%i"),row
,col
);
633 wxVariant
val(value
);
635 m_rowmodified
= true;
636 m_data
->SetColumn(m_ColInfo
[col
].DbCol
,val
);
641 void wxDbGridTableBase::SetValueAsBool(int row
, int col
, bool value
)
643 wxLogDebug(wxT("SetValueAsBool() on %i,%i"),row
,col
);
646 wxVariant
val(value
);
648 m_rowmodified
= true;
649 m_data
->SetColumn(m_ColInfo
[col
].DbCol
,val
);
653 void wxDbGridTableBase::ValidateRow(int row
)
655 wxLogDebug(wxT("ValidateRow(%i) currently on row (%i). Array count = %i"),row
,m_row
,m_keys
.GetCount());
661 //We add to row as Count is unsigned!
662 if ((unsigned)(row
+1) > m_keys
.GetCount())
664 wxLogDebug(wxT("\trow key unknown"));
665 // Extend Array, iterate through data filling with keys
666 m_data
->SetRowMode(wxDbTable::WX_ROW_MODE_QUERY
);
668 for (trow
= m_keys
.GetCount(); trow
<= row
; trow
++)
670 wxLogDebug(wxT("Fetching row %i.."), trow
);
671 bool ret
= m_data
->GetNext();
673 wxLogDebug(wxT(" ...success=(%i)"),ret
);
674 GenericKey k
= m_data
->GetKey();
681 wxLogDebug(wxT("\trow key known centering data"));
682 GenericKey k
= m_keys
.Item(row
);
683 m_data
->SetRowMode(wxDbTable::WX_ROW_MODE_INDIVIDUAL
);
684 m_data
->ClearMemberVars();
686 if (!m_data
->QueryOnKeyFields())
688 wxDbLogExtendedErrorMsg(_T("ODBC error during Query()\n\n"), m_data
->GetDb(),__TFILE__
,__LINE__
);
695 m_rowmodified
= false;
698 bool wxDbGridTableBase::Writeback() const
706 wxLogDebug(wxT("\trow key unknown"));
708 // FIXME: this code requires dbtable support for record status
710 switch (m_data
->get_ModifiedStatus())
712 case wxDbTable::UpdatePending
:
713 result
= m_data
->Update();
715 case wxDbTable::InsertPending
:
716 result
= (m_data
->Insert() == SQL_SUCCESS
);
723 wxLogDebug(wxT("WARNING : Row writeback not implemented "));
728 #include "wx/arrimpl.cpp"
730 WX_DEFINE_EXPORTED_OBJARRAY(keyarray
);
732 #endif // #if wxUSE_GRID
733 #endif // #if wxUSE_ODBC