]> git.saurik.com Git - wxWidgets.git/blob - src/common/dbgrid.cpp
Typecast before endian adjustements.
[wxWidgets.git] / src / common / dbgrid.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: dbgrid.cpp
3 // Purpose: Displays a wxDbTable in a wxGrid.
4 // Author: Roger Gammans, Paul Gammans
5 // Modified by:
6 // Created:
7 // RCS-ID: $Id$
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 ///////////////////////////////////////////////////////////////////////////////
13
14 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
15 #pragma implementation "dbgrid.h"
16 #endif
17
18 #include "wx/wxprec.h"
19
20 #ifdef __BORLANDC__
21 #pragma hdrstop
22 #endif
23
24
25 #if wxUSE_ODBC
26 #if wxUSE_GRID
27
28 #ifndef WX_PRECOMP
29 #include "wx/textctrl.h"
30 #include "wx/dc.h"
31 #endif // WX_PRECOMP
32
33 #include "wx/generic/gridctrl.h"
34 #include "wx/dbgrid.h"
35
36 // DLL options compatibility check:
37 #include "wx/app.h"
38 WX_CHECK_BUILD_OPTIONS("wxDbGrid")
39
40
41 wxDbGridCellAttrProvider::wxDbGridCellAttrProvider()
42 {
43 m_data=NULL;
44 m_ColInfo=NULL;
45 }
46
47 wxDbGridCellAttrProvider::wxDbGridCellAttrProvider(wxDbTable *tab, wxDbGridColInfoBase* ColInfo)
48 {
49 m_data=tab;
50 m_ColInfo=ColInfo;
51 }
52
53 wxDbGridCellAttrProvider::~wxDbGridCellAttrProvider()
54 {
55 }
56
57 wxGridCellAttr *wxDbGridCellAttrProvider::GetAttr(int row, int col,
58 wxGridCellAttr::wxAttrKind kind) const
59 {
60 wxGridCellAttr *attr = wxGridCellAttrProvider::GetAttr(row,col,kind);
61
62 if (m_data && m_ColInfo && (m_data->GetNumberOfColumns() > m_ColInfo[col].DbCol))
63 {
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))
68 {
69 switch(kind)
70 {
71 case (wxGridCellAttr::Any):
72 if (!attr)
73 {
74 attr = new wxGridCellAttr;
75 // Store so we don't keep creating / deleting this...
76 wxDbGridCellAttrProvider * self = wxConstCast(this, wxDbGridCellAttrProvider) ;
77 attr->IncRef();
78 self->SetColAttr(attr, col);
79 attr->SetReadOnly();
80 }
81 else
82 {
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)))
87 {
88 wxGridCellAttr *attrtomerge = attr;
89 attr = new wxGridCellAttr;
90 attr->SetKind(wxGridCellAttr::Merged);
91 attr->MergeWith(attrtomerge);
92 attr->SetReadOnly();
93 attrtomerge->DecRef();
94 }
95 attr->SetReadOnly();
96 }
97 break;
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
101 if (!attr)
102 {
103 attr = new wxGridCellAttr;
104 wxDbGridCellAttrProvider * self = wxConstCast(this, wxDbGridCellAttrProvider) ;
105 attr->IncRef();
106 self->SetColAttr(attr, col);
107 }
108 attr->SetReadOnly();
109 break;
110 default:
111 //Dont add RO for...
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.
117 break;
118 }
119 }
120
121 }
122 return attr;
123 }
124
125 void wxDbGridCellAttrProvider::AssignDbTable(wxDbTable *tab)
126 {
127 m_data = tab;
128 }
129
130 wxDbGridTableBase::wxDbGridTableBase(wxDbTable *tab, wxDbGridColInfo* ColInfo,
131 int count, bool takeOwnership) :
132 m_keys(),
133 m_data(tab),
134 m_dbowner(takeOwnership),
135 m_rowmodified(false)
136 {
137
138 if (count == wxUSE_QUERY)
139 {
140 m_rowtotal = m_data ? m_data->Count() : 0;
141 }
142 else
143 {
144 m_rowtotal = count;
145 }
146 // m_keys.Size(m_rowtotal);
147 m_row = -1;
148 if (ColInfo)
149 {
150 m_nocols = ColInfo->Length();
151 m_ColInfo = new wxDbGridColInfoBase[m_nocols];
152 //Do Copy.
153 wxDbGridColInfo *ptr = ColInfo;
154 int i =0;
155 while (ptr && i < m_nocols)
156 {
157 m_ColInfo[i] = ptr->m_data;
158 ptr = ptr->m_next;
159 i++;
160 }
161 #ifdef __WXDEBUG__
162 if (ptr)
163 {
164 wxLogDebug(wxT("NoCols over length after traversing %i items"),i);
165 }
166 if (i < m_nocols)
167 {
168 wxLogDebug(wxT("NoCols under length after traversing %i items"),i);
169 }
170 #endif
171 }
172 }
173
174 wxDbGridTableBase::~wxDbGridTableBase()
175 {
176 wxDbGridCellAttrProvider *provider;
177
178 //Can't check for update here as
179
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());
184 if (provider)
185 {
186 provider->AssignDbTable(NULL);
187 }
188 delete [] m_ColInfo;
189
190 Writeback();
191 if (m_dbowner)
192 {
193 delete m_data;
194 }
195 }
196
197 bool wxDbGridTableBase::CanHaveAttributes()
198 {
199 if (!GetAttrProvider())
200 {
201 // use the default attr provider by default
202 SetAttrProvider(new wxDbGridCellAttrProvider(m_data, m_ColInfo));
203 }
204 return true;
205 }
206
207
208 bool wxDbGridTableBase::AssignDbTable(wxDbTable *tab, int count, bool takeOwnership)
209 {
210 wxDbGridCellAttrProvider *provider;
211
212 //Remove Information from grid about old data
213 if (GetView())
214 {
215 wxGrid *grid = GetView();
216 grid->BeginBatch();
217 grid->ClearSelection();
218 if (grid->IsCellEditControlEnabled())
219 {
220 grid->DisableCellEditControl();
221 }
222 wxGridTableMessage msg(this, wxGRIDTABLE_NOTIFY_ROWS_DELETED,0,m_rowtotal);
223 grid->ProcessTableMessage(msg);
224 }
225
226 //reset our internals...
227 Writeback();
228 if (m_dbowner)
229 {
230 delete m_data;
231 }
232 m_keys.Empty();
233 m_data = tab;
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());
238 if (provider)
239 {
240 provider->AssignDbTable(m_data);
241 }
242
243 if (count == wxUSE_QUERY)
244 {
245 m_rowtotal = m_data ? m_data->Count() : 0;
246 }
247 else
248 {
249 m_rowtotal = count;
250 }
251 m_row = -1;
252
253 //Add Information to grid about new data
254 if (GetView())
255 {
256 wxGrid * grid = GetView();
257 wxGridTableMessage msg(this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_rowtotal);
258 grid->ProcessTableMessage(msg);
259 grid->EndBatch();
260 }
261 m_dbowner = takeOwnership;
262 m_rowmodified = false;
263 return true;
264 }
265
266 wxString wxDbGridTableBase::GetTypeName(int WXUNUSED(row), int col)
267 {
268 if (GetNumberCols() > col)
269 {
270 if (m_ColInfo[col].wxtypename == wxGRID_VALUE_DBAUTO)
271 {
272 if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
273 {
274 wxFAIL_MSG (_T("You can not use wxGRID_VALUE_DBAUTO for virtual columns"));
275 }
276 switch(m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype)
277 {
278 case SQL_C_CHAR:
279 case SQL_C_WCHAR:
280 return wxGRID_VALUE_STRING;
281 case SQL_C_SHORT:
282 case SQL_C_SSHORT:
283 return wxGRID_VALUE_NUMBER;
284 case SQL_C_USHORT:
285 return wxGRID_VALUE_NUMBER;
286 case SQL_C_LONG:
287 case SQL_C_SLONG:
288 return wxGRID_VALUE_NUMBER;
289 case SQL_C_ULONG:
290 return wxGRID_VALUE_NUMBER;
291 case SQL_C_FLOAT:
292 return wxGRID_VALUE_FLOAT;
293 case SQL_C_DOUBLE:
294 return wxGRID_VALUE_FLOAT;
295 case SQL_C_DATE:
296 return wxGRID_VALUE_DATETIME;
297 case SQL_C_TIME:
298 return wxGRID_VALUE_DATETIME;
299 case SQL_C_TIMESTAMP:
300 return wxGRID_VALUE_DATETIME;
301 default:
302 return wxGRID_VALUE_STRING;
303 }
304 }
305 else
306 {
307 return m_ColInfo[col].wxtypename;
308 }
309 }
310 wxFAIL_MSG (_T("unknown column"));
311 return wxString();
312 }
313
314 bool wxDbGridTableBase::CanGetValueAs(int row, int col, const wxString& typeName)
315 {
316 wxLogDebug(wxT("CanGetValueAs() on %i,%i"),row,col);
317 //Is this needed? As it will be validated on GetValueAsXXXX
318 ValidateRow(row);
319
320 if (typeName == wxGRID_VALUE_STRING)
321 {
322 //FIXME ummm What about blob field etc.
323 return true;
324 }
325
326 if (m_data->IsColNull((UWORD)m_ColInfo[col].DbCol))
327 {
328 return false;
329 }
330
331 if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
332 {
333 //If a virtual column then we can't find it's type. we have to
334 // return false to get using wxVariant.
335 return false;
336 }
337 int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype;
338
339 if (typeName == wxGRID_VALUE_DATETIME)
340 {
341 if ((sqltype == SQL_C_DATE) ||
342 (sqltype == SQL_C_TIME) ||
343 (sqltype == SQL_C_TIMESTAMP))
344 {
345 return true;
346 }
347 return false;
348 }
349 if (typeName == wxGRID_VALUE_NUMBER)
350 {
351 if ((sqltype == SQL_C_SSHORT) ||
352 (sqltype == SQL_C_USHORT) ||
353 (sqltype == SQL_C_SLONG) ||
354 (sqltype == SQL_C_ULONG))
355 {
356 return true;
357 }
358 return false;
359 }
360 if (typeName == wxGRID_VALUE_FLOAT)
361 {
362 if ((sqltype == SQL_C_SSHORT) ||
363 (sqltype == SQL_C_USHORT) ||
364 (sqltype == SQL_C_SLONG) ||
365 (sqltype == SQL_C_ULONG) ||
366 (sqltype == SQL_C_FLOAT) ||
367 (sqltype == SQL_C_DOUBLE))
368 {
369 return true;
370 }
371 return false;
372 }
373 return false;
374 }
375
376 bool wxDbGridTableBase::CanSetValueAs(int WXUNUSED(row), int col, const wxString& typeName)
377 {
378 if (typeName == wxGRID_VALUE_STRING)
379 {
380 //FIXME ummm What about blob field etc.
381 return true;
382 }
383
384 if (!(m_data->GetColDefs()[(m_ColInfo[col].DbCol)].Updateable))
385 {
386 return false;
387 }
388
389 if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
390 {
391 //If a virtual column then we can't find it's type. we have to faulse to
392 //get using wxVairent.
393 return false;
394 }
395
396 int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype;
397 if (typeName == wxGRID_VALUE_DATETIME)
398 {
399 if ((sqltype == SQL_C_DATE) ||
400 (sqltype == SQL_C_TIME) ||
401 (sqltype == SQL_C_TIMESTAMP))
402 {
403 return true;
404 }
405 return false;
406 }
407 if (typeName == wxGRID_VALUE_NUMBER)
408 {
409 if ((sqltype == SQL_C_SSHORT) ||
410 (sqltype == SQL_C_USHORT) ||
411 (sqltype == SQL_C_SLONG) ||
412 (sqltype == SQL_C_ULONG))
413 {
414 return true;
415 }
416 return false;
417 }
418 if (typeName == wxGRID_VALUE_FLOAT)
419 {
420 if ((sqltype == SQL_C_SSHORT) ||
421 (sqltype == SQL_C_USHORT) ||
422 (sqltype == SQL_C_SLONG) ||
423 (sqltype == SQL_C_ULONG) ||
424 (sqltype == SQL_C_FLOAT) ||
425 (sqltype == SQL_C_DOUBLE))
426 {
427 return true;
428 }
429 return false;
430 }
431 return false;
432 }
433
434 long wxDbGridTableBase::GetValueAsLong(int row, int col)
435 {
436 ValidateRow(row);
437
438 if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
439 {
440 wxFAIL_MSG (_T("You can not use GetValueAsLong for virtual columns"));
441 return 0;
442 }
443 int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype;
444 if ((sqltype == SQL_C_SSHORT) ||
445 (sqltype == SQL_C_USHORT) ||
446 (sqltype == SQL_C_SLONG) ||
447 (sqltype == SQL_C_ULONG))
448 {
449 wxVariant val = m_data->GetCol(m_ColInfo[col].DbCol);
450 return val.GetLong();
451 }
452 wxFAIL_MSG (_T("unknown column, "));
453 return 0;
454 }
455
456 double wxDbGridTableBase::GetValueAsDouble(int row, int col)
457 {
458 wxLogDebug(wxT("GetValueAsDouble() on %i,%i"),row,col);
459 ValidateRow(row);
460
461 if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
462 {
463 wxFAIL_MSG (_T("You can not use GetValueAsDouble for virtual columns"));
464 return 0.0;
465 }
466 int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype;
467 if ((sqltype == SQL_C_SSHORT) ||
468 (sqltype == SQL_C_USHORT) ||
469 (sqltype == SQL_C_SLONG) ||
470 (sqltype == SQL_C_ULONG) ||
471 (sqltype == SQL_C_FLOAT) ||
472 (sqltype == SQL_C_DOUBLE))
473 {
474 wxVariant val = m_data->GetCol(m_ColInfo[col].DbCol);
475 return val.GetDouble();
476 }
477 wxFAIL_MSG (_T("unknown column"));
478 return 0.0;
479 }
480
481 bool wxDbGridTableBase::GetValueAsBool(int row, int col)
482 {
483 wxLogDebug(wxT("GetValueAsBool() on %i,%i"),row,col);
484 ValidateRow(row);
485
486 if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
487 {
488 wxFAIL_MSG (_T("You can not use GetValueAsBool for virtual columns"));
489 return 0;
490 }
491 int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype;
492 if ((sqltype == SQL_C_SSHORT) ||
493 (sqltype == SQL_C_USHORT) ||
494 (sqltype == SQL_C_SLONG) ||
495 (sqltype == SQL_C_ULONG))
496 {
497 wxVariant val = m_data->GetCol(m_ColInfo[col].DbCol);
498 return val.GetBool();
499 }
500 wxFAIL_MSG (_T("unknown column, "));
501 return 0;
502 }
503
504 void* wxDbGridTableBase::GetValueAsCustom(int row, int col, const wxString& typeName)
505 {
506 wxLogDebug(wxT("GetValueAsCustom() on %i,%i"),row,col);
507 ValidateRow(row);
508
509 if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
510 {
511 wxFAIL_MSG (_T("You can not use GetValueAsCustom for virtual columns"));
512 return NULL;
513 }
514 if (m_data->IsColNull((UWORD)m_ColInfo[col].DbCol))
515 return NULL;
516
517 if (typeName == wxGRID_VALUE_DATETIME)
518 {
519 wxDbColDef *pColDefs = m_data->GetColDefs();
520 int sqltype = pColDefs[(m_ColInfo[col].DbCol)].SqlCtype;
521
522 if ((sqltype == SQL_C_DATE) ||
523 (sqltype == SQL_C_TIME) ||
524 (sqltype == SQL_C_TIMESTAMP))
525 {
526 wxVariant val = m_data->GetCol(m_ColInfo[col].DbCol);
527 return new wxDateTime(val.GetDateTime());
528 }
529 }
530 wxFAIL_MSG (_T("unknown column data type "));
531 return NULL;
532 }
533
534
535 void wxDbGridTableBase::SetValueAsCustom(int row, int col, const wxString& typeName, void* value)
536 {
537 wxLogDebug(wxT("SetValueAsCustom() on %i,%i"),row,col);
538 ValidateRow(row);
539
540 if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol)
541 {
542 wxFAIL_MSG (_T("You can not use SetValueAsCustom for virtual columns"));
543 return;
544 }
545
546 if (typeName == wxGRID_VALUE_DATETIME)
547 {
548 int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype;
549 if ((sqltype == SQL_C_DATE) ||
550 (sqltype == SQL_C_TIME) ||
551 (sqltype == SQL_C_TIMESTAMP))
552 {
553 //FIXME: you can't dynamic_cast from (void *)
554 //wxDateTime *date = wxDynamicCast(value, wxDateTime);
555 wxDateTime *date = (wxDateTime *)value;
556 if (!date)
557 {
558 wxFAIL_MSG (_T("Failed to convert data"));
559 return;
560 }
561 wxVariant val(date);
562 m_rowmodified = true;
563 m_data->SetCol(m_ColInfo[col].DbCol,val);
564 }
565 }
566 wxFAIL_MSG (_T("unknown column data type"));
567 return ;
568 }
569
570
571 wxString wxDbGridTableBase::GetColLabelValue(int col)
572 {
573 if (GetNumberCols() > col)
574 {
575 return m_ColInfo[col].Title;
576 }
577 wxFAIL_MSG (_T("unknown column"));
578 return wxString();
579 }
580
581 bool wxDbGridTableBase::IsEmptyCell(int row, int col)
582 {
583 wxLogDebug(wxT("IsEmtpyCell on %i,%i"),row,col);
584
585 ValidateRow(row);
586 return m_data->IsColNull((UWORD)m_ColInfo[col].DbCol);
587 }
588
589
590 wxString wxDbGridTableBase::GetValue(int row, int col)
591 {
592 wxLogDebug(wxT("GetValue() on %i,%i"),row,col);
593
594 ValidateRow(row);
595 wxVariant val = m_data->GetCol(m_ColInfo[col].DbCol);
596 wxLogDebug(wxT("\tReturning \"%s\"\n"),val.GetString().c_str());
597
598 return val.GetString();
599 }
600
601
602 void wxDbGridTableBase::SetValue(int row, int col,const wxString& value)
603 {
604 wxLogDebug(wxT("SetValue() on %i,%i"),row,col);
605
606 ValidateRow(row);
607 wxVariant val(value);
608
609 m_rowmodified = true;
610 m_data->SetCol(m_ColInfo[col].DbCol,val);
611 }
612
613
614 void wxDbGridTableBase::SetValueAsLong(int row, int col, long value)
615 {
616 wxLogDebug(wxT("SetValueAsLong() on %i,%i"),row,col);
617
618 ValidateRow(row);
619 wxVariant val(value);
620
621 m_rowmodified = true;
622 m_data->SetCol(m_ColInfo[col].DbCol,val);
623 }
624
625
626 void wxDbGridTableBase::SetValueAsDouble(int row, int col, double value)
627 {
628 wxLogDebug(wxT("SetValueAsDouble() on %i,%i"),row,col);
629
630 ValidateRow(row);
631 wxVariant val(value);
632
633 m_rowmodified = true;
634 m_data->SetCol(m_ColInfo[col].DbCol,val);
635
636 }
637
638
639 void wxDbGridTableBase::SetValueAsBool(int row, int col, bool value)
640 {
641 wxLogDebug(wxT("SetValueAsBool() on %i,%i"),row,col);
642
643 ValidateRow(row);
644 wxVariant val(value);
645
646 m_rowmodified = true;
647 m_data->SetCol(m_ColInfo[col].DbCol,val);
648 }
649
650
651 void wxDbGridTableBase::ValidateRow(int row)
652 {
653 wxLogDebug(wxT("ValidateRow(%i) currently on row (%i). Array count = %i"),row,m_row,m_keys.GetCount());
654
655 if (row == m_row)
656 return;
657 Writeback();
658
659 //We add to row as Count is unsigned!
660 if ((unsigned)(row+1) > m_keys.GetCount())
661 {
662 wxLogDebug(wxT("\trow key unknown"));
663 // Extend Array, iterate through data filling with keys
664 m_data->SetRowMode(wxDbTable::WX_ROW_MODE_QUERY);
665 int trow;
666 for (trow = m_keys.GetCount(); trow <= row; trow++)
667 {
668 wxLogDebug(wxT("Fetching row %i.."), trow);
669 bool ret = m_data->GetNext();
670
671 wxLogDebug(wxT(" ...success=(%i)"),ret);
672 GenericKey k = m_data->GetKey();
673 m_keys.Add(k);
674 }
675 m_row = row;
676 }
677 else
678 {
679 wxLogDebug(wxT("\trow key known centering data"));
680 GenericKey k = m_keys.Item(row);
681 m_data->SetRowMode(wxDbTable::WX_ROW_MODE_INDIVIDUAL);
682 m_data->ClearMemberVars();
683 m_data->SetKey(k);
684 if (!m_data->QueryOnKeyFields())
685 {
686 wxDbLogExtendedErrorMsg(_T("ODBC error during Query()\n\n"), m_data->GetDb(),__TFILE__,__LINE__);
687 }
688
689 m_data->GetNext();
690
691 m_row = row;
692 }
693 m_rowmodified = false;
694 }
695
696 bool wxDbGridTableBase::Writeback() const
697 {
698 if (!m_rowmodified)
699 {
700 return true;
701 }
702
703 bool result=true;
704 wxLogDebug(wxT("\trow key unknown"));
705
706 // FIXME: this code requires dbtable support for record status
707 #if 0
708 switch (m_data->get_ModifiedStatus())
709 {
710 case wxDbTable::UpdatePending:
711 result = m_data->Update();
712 break;
713 case wxDbTable::InsertPending:
714 result = (m_data->Insert() == SQL_SUCCESS);
715 break;
716 default:
717 //Nothing
718 break;
719 }
720 #else
721 wxLogDebug(wxT("WARNING : Row writeback not implemented "));
722 #endif
723 return result;
724 }
725
726 #include "wx/arrimpl.cpp"
727
728 WX_DEFINE_EXPORTED_OBJARRAY(keyarray);
729
730 #endif // #if wxUSE_GRID
731 #endif // #if wxUSE_ODBC
732