Removed TABs that had gotten in to the source
[wxWidgets.git] / samples / db / dbtest.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: dbtest.cpp
3 // Purpose: wxWindows database demo app
4 // Author: George Tasker
5 // Modified by:
6 // Created: 1998
7 // RCS-ID: $Id$
8 // Copyright: (c) 1998 Remstar International, Inc.
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 /*
13 * SYNOPSIS START
14
15 This sample program demonstrates the cross-platform ODBC database classes
16 donated by the development team at Remstar International.
17
18 The table this sample is based on is developer contact table, and shows
19 some of the simple uses of the database classes wxDb and wxDbTable.
20
21 * SYNOPSIS END
22 */
23
24 #ifdef __GNUG__
25 #pragma implementation "dbtest.h"
26 #endif
27
28 #include "wx/wxprec.h"
29
30 #ifdef __BORLANDC__
31 #pragma hdrstop
32 #endif //__BORLANDC__
33
34 #ifndef WX_PRECOMP
35 #include <wx/wx.h>
36 #endif //WX_PRECOMP
37
38 #ifdef __WXGTK__
39 #include "db.xpm"
40 #endif
41
42 #include <stdio.h> /* Included strictly for reading the text file with the database parameters */
43
44 //#include <wx/db.h> /* Required in the file which will get the data source connection */
45 //#include <wx/dbtable.h> /* Has the wxDbTable object from which all data objects will inherit their data table functionality */
46
47 //extern wxDbList WXDLLEXPORT *PtrBegDbList; /* from db.cpp, used in getting back error results from db connections */
48
49 #include "dbtest.h" /* Header file for this demonstration program */
50 #include "listdb.h" /* Code to support the "Lookup" button on the editor dialog */
51
52 IMPLEMENT_APP(DatabaseDemoApp)
53
54 extern wxChar ListDB_Selection[]; /* Used to return the first column value for the selected line from the listDB routines */
55 extern wxChar ListDB_Selection2[]; /* Used to return the second column value for the selected line from the listDB routines */
56
57
58 #if !wxUSE_ODBC
59 #error Sample cannot be compiled unless setup.h has wxUSE_ODBC set to 1
60 #endif
61
62
63 const char *GetExtendedDBErrorMsg(wxDb *pDb, char *ErrFile, int ErrLine)
64 {
65 static wxString msg;
66 msg = wxT("");
67
68 wxString tStr;
69
70 if (ErrFile || ErrLine)
71 {
72 msg += wxT("File: ");
73 msg += ErrFile;
74 msg += wxT(" Line: ");
75 tStr.Printf(wxT("%d"),ErrLine);
76 msg += tStr.c_str();
77 msg += wxT("\n");
78 }
79
80 msg.Append (wxT("\nODBC errors:\n"));
81 msg += wxT("\n");
82
83 // Display errors for this connection
84 int i;
85 for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
86 {
87 if (pDb->errorList[i])
88 {
89 msg.Append(pDb->errorList[i]);
90 if (wxStrcmp(pDb->errorList[i],wxT("")) != 0)
91 msg.Append(wxT("\n"));
92 // Clear the errmsg buffer so the next error will not
93 // end up showing the previous error that have occurred
94 wxStrcpy(pDb->errorList[i],wxT(""));
95 }
96 }
97 msg += wxT("\n");
98
99 return msg.c_str();
100 } // GetExtendedDBErrorMsg
101
102
103 bool DataTypeSupported(wxDb *pDb, SWORD datatype)
104 {
105 wxDbSqlTypeInfo sqlTypeInfo;
106
107 bool breakpoint = FALSE;
108
109 if (pDb->GetDataTypeInfo(datatype, sqlTypeInfo))
110 breakpoint = TRUE;
111
112 return breakpoint;
113
114 } // GetDataTypesSupported();
115
116
117
118 void CheckSupportForAllDataTypes(wxDb *pDb)
119 {
120 wxLogMessage("\nThe following datatypes are supported by the\ndatabase you are currently connected to:");
121 #ifdef SQL_C_BINARY
122 if (DataTypeSupported(pDb,SQL_C_BINARY))
123 wxLogMessage("SQL_C_BINARY");
124 #endif
125 #ifdef SQL_C_BIT
126 if (DataTypeSupported(pDb,SQL_C_BIT))
127 wxLogMessage("SQL_C_BIT");
128 #endif
129 #ifdef SQL_C_BOOKMARK
130 if (DataTypeSupported(pDb,SQL_C_BOOKMARK))
131 wxLogMessage("SQL_C_BOOKMARK");
132 #endif
133 #ifdef SQL_C_CHAR
134 if (DataTypeSupported(pDb,SQL_C_CHAR))
135 wxLogMessage("SQL_C_CHAR");
136 #endif
137 #ifdef SQL_C_DATE
138 if (DataTypeSupported(pDb,SQL_C_DATE))
139 wxLogMessage("SQL_C_DATE");
140 #endif
141 #ifdef SQL_C_DEFAULT
142 if (DataTypeSupported(pDb,SQL_C_DEFAULT))
143 wxLogMessage("SQL_C_DEFAULT");
144 #endif
145 #ifdef SQL_C_DOUBLE
146 if (DataTypeSupported(pDb,SQL_C_DOUBLE))
147 wxLogMessage("SQL_C_DOUBLE");
148 #endif
149 #ifdef SQL_C_FLOAT
150 if (DataTypeSupported(pDb,SQL_C_FLOAT))
151 wxLogMessage("SQL_C_FLOAT");
152 #endif
153 #ifdef SQL_C_GUID
154 if (DataTypeSupported(pDb,SQL_C_GUID))
155 wxLogMessage("SQL_C_GUID");
156 #endif
157 #ifdef SQL_C_INTERVAL_DAY
158 if (DataTypeSupported(pDb,SQL_C_INTERVAL_DAY))
159 wxLogMessage("SQL_C_INTERVAL_DAY");
160 #endif
161 #ifdef SQL_C_INTERVAL_DAY_TO_HOUR
162 if (DataTypeSupported(pDb,SQL_C_INTERVAL_DAY_TO_HOUR))
163 wxLogMessage("SQL_C_INTERVAL_DAY_TO_HOUR");
164 #endif
165 #ifdef SQL_C_INTERVAL_DAY_TO_MINUTE
166 if (DataTypeSupported(pDb,SQL_C_INTERVAL_DAY_TO_MINUTE))
167 wxLogMessage("SQL_C_INTERVAL_DAY_TO_MINUTE");
168 #endif
169 #ifdef SQL_C_INTERVAL_DAY_TO_SECOND
170 if (DataTypeSupported(pDb,SQL_C_INTERVAL_DAY_TO_SECOND))
171 wxLogMessage("SQL_C_INTERVAL_DAY_TO_SECOND");
172 #endif
173 #ifdef SQL_C_INTERVAL_HOUR
174 if (DataTypeSupported(pDb,SQL_C_INTERVAL_HOUR))
175 wxLogMessage("SQL_C_INTERVAL_HOUR");
176 #endif
177 #ifdef SQL_C_INTERVAL_HOUR_TO_MINUTE
178 if (DataTypeSupported(pDb,SQL_C_INTERVAL_HOUR_TO_MINUTE))
179 wxLogMessage("SQL_C_INTERVAL_HOUR_TO_MINUTE");
180 #endif
181 #ifdef SQL_C_INTERVAL_HOUR_TO_SECOND
182 if (DataTypeSupported(pDb,SQL_C_INTERVAL_HOUR_TO_SECOND))
183 wxLogMessage("SQL_C_INTERVAL_HOUR_TO_SECOND");
184 #endif
185 #ifdef SQL_C_INTERVAL_MINUTE
186 if (DataTypeSupported(pDb,SQL_C_INTERVAL_MINUTE))
187 wxLogMessage("SQL_C_INTERVAL_MINUTE");
188 #endif
189 #ifdef SQL_C_INTERVAL_MINUTE_TO_SECOND
190 if (DataTypeSupported(pDb,SQL_C_INTERVAL_MINUTE_TO_SECOND))
191 wxLogMessage("SQL_C_INTERVAL_MINUTE_TO_SECOND");
192 #endif
193 #ifdef SQL_C_INTERVAL_MONTH
194 if (DataTypeSupported(pDb,SQL_C_INTERVAL_MONTH))
195 wxLogMessage("SQL_C_INTERVAL_MONTH");
196 #endif
197 #ifdef SQL_C_INTERVAL_SECOND
198 if (DataTypeSupported(pDb,SQL_C_INTERVAL_SECOND))
199 wxLogMessage("SQL_C_INTERVAL_SECOND");
200 #endif
201 #ifdef SQL_C_INTERVAL_YEAR
202 if (DataTypeSupported(pDb,SQL_C_INTERVAL_YEAR))
203 wxLogMessage("SQL_C_INTERVAL_YEAR");
204 #endif
205 #ifdef SQL_C_INTERVAL_YEAR_TO_MONTH
206 if (DataTypeSupported(pDb,SQL_C_INTERVAL_YEAR_TO_MONTH))
207 wxLogMessage("SQL_C_INTERVAL_YEAR_TO_MONTH");
208 #endif
209 #ifdef SQL_C_LONG
210 if (DataTypeSupported(pDb,SQL_C_LONG))
211 wxLogMessage("SQL_C_LONG");
212 #endif
213 #ifdef SQL_C_NUMERIC
214 if (DataTypeSupported(pDb,SQL_C_NUMERIC))
215 wxLogMessage("SQL_C_NUMERIC");
216 #endif
217 #ifdef SQL_C_SBIGINT
218 if (DataTypeSupported(pDb,SQL_C_SBIGINT))
219 wxLogMessage("SQL_C_SBIGINT");
220 #endif
221 #ifdef SQL_C_SHORT
222 if (DataTypeSupported(pDb,SQL_C_SHORT))
223 wxLogMessage("SQL_C_SHORT");
224 #endif
225 #ifdef SQL_C_SLONG
226 if (DataTypeSupported(pDb,SQL_C_SLONG))
227 wxLogMessage("SQL_C_SLONG");
228 #endif
229 #ifdef SQL_C_SSHORT
230 if (DataTypeSupported(pDb,SQL_C_SSHORT))
231 wxLogMessage("SQL_C_SSHORT");
232 #endif
233 #ifdef SQL_C_STINYINT
234 if (DataTypeSupported(pDb,SQL_C_STINYINT))
235 wxLogMessage("SQL_C_STINYINT");
236 #endif
237 #ifdef SQL_C_TIME
238 if (DataTypeSupported(pDb,SQL_C_TIME))
239 wxLogMessage("SQL_C_TIME");
240 #endif
241 #ifdef SQL_C_TIMESTAMP
242 if (DataTypeSupported(pDb,SQL_C_TIMESTAMP))
243 wxLogMessage("SQL_C_TIMESTAMP");
244 #endif
245 #ifdef SQL_C_TINYINT
246 if (DataTypeSupported(pDb,SQL_C_TINYINT))
247 wxLogMessage("SQL_C_TINYINT");
248 #endif
249 #ifdef SQL_C_TYPE_DATE
250 if (DataTypeSupported(pDb,SQL_C_TYPE_DATE))
251 wxLogMessage("SQL_C_TYPE_DATE");
252 #endif
253 #ifdef SQL_C_TYPE_TIME
254 if (DataTypeSupported(pDb,SQL_C_TYPE_TIME))
255 wxLogMessage("SQL_C_TYPE_TIME");
256 #endif
257 #ifdef SQL_C_TYPE_TIMESTAMP
258 if (DataTypeSupported(pDb,SQL_C_TYPE_TIMESTAMP))
259 wxLogMessage("SQL_C_TYPE_TIMESTAMP");
260 #endif
261 #ifdef SQL_C_UBIGINT
262 if (DataTypeSupported(pDb,SQL_C_UBIGINT))
263 wxLogMessage("SQL_C_UBIGINT");
264 #endif
265 #ifdef SQL_C_ULONG
266 if (DataTypeSupported(pDb,SQL_C_ULONG))
267 wxLogMessage("SQL_C_ULONG");
268 #endif
269 #ifdef SQL_C_USHORT
270 if (DataTypeSupported(pDb,SQL_C_USHORT))
271 wxLogMessage("SQL_C_USHORT");
272 #endif
273 #ifdef SQL_C_UTINYINT
274 if (DataTypeSupported(pDb,SQL_C_UTINYINT))
275 wxLogMessage("SQL_C_UTINYINT");
276 #endif
277 #ifdef SQL_C_VARBOOKMARK
278 if (DataTypeSupported(pDb,SQL_C_VARBOOKMARK))
279 wxLogMessage("SQL_C_VARBOOKMARK");
280 #endif
281
282 // Extended SQL types
283 #ifdef SQL_DATE
284 if (DataTypeSupported(pDb,SQL_DATE))
285 wxLogMessage("SQL_DATE");
286 #endif
287 #ifdef SQL_INTERVAL
288 if (DataTypeSupported(pDb,SQL_INTERVAL))
289 wxLogMessage("SQL_INTERVAL");
290 #endif
291 #ifdef SQL_TIME
292 if (DataTypeSupported(pDb,SQL_TIME))
293 wxLogMessage("SQL_TIME");
294 #endif
295 #ifdef SQL_TIMESTAMP
296 if (DataTypeSupported(pDb,SQL_TIMESTAMP))
297 wxLogMessage("SQL_TIMESTAMP");
298 #endif
299 #ifdef SQL_LONGVARCHAR
300 if (DataTypeSupported(pDb,SQL_LONGVARCHAR))
301 wxLogMessage("SQL_LONGVARCHAR");
302 #endif
303 #ifdef SQL_BINARY
304 if (DataTypeSupported(pDb,SQL_BINARY))
305 wxLogMessage("SQL_BINARY");
306 #endif
307 #ifdef SQL_VARBINARY
308 if (DataTypeSupported(pDb,SQL_VARBINARY))
309 wxLogMessage("SQL_VARBINARY");
310 #endif
311 #ifdef SQL_LONGVARBINARY
312 if (DataTypeSupported(pDb,SQL_LONGVARBINARY))
313 wxLogMessage("SQL_LONGVARBINARY");
314 #endif
315 #ifdef SQL_BIGINT
316 if (DataTypeSupported(pDb,SQL_BIGINT))
317 wxLogMessage("SQL_BIGINT");
318 #endif
319 #ifdef SQL_TINYINT
320 if (DataTypeSupported(pDb,SQL_TINYINT))
321 wxLogMessage("SQL_TINYINT");
322 #endif
323 #ifdef SQL_BIT
324 if (DataTypeSupported(pDb,SQL_BIT))
325 wxLogMessage("SQL_BIT");
326 #endif
327 #ifdef SQL_GUID
328 if (DataTypeSupported(pDb,SQL_GUID))
329 wxLogMessage("SQL_GUID");
330 #endif
331
332 #ifdef SQL_CHAR
333 if (DataTypeSupported(pDb,SQL_CHAR))
334 wxLogMessage("SQL_CHAR");
335 #endif
336 #ifdef SQL_INTEGER
337 if (DataTypeSupported(pDb,SQL_INTEGER))
338 wxLogMessage("SQL_INTEGER");
339 #endif
340 #ifdef SQL_SMALLINT
341 if (DataTypeSupported(pDb,SQL_SMALLINT))
342 wxLogMessage("SQL_SMALLINT");
343 #endif
344 #ifdef SQL_REAL
345 if (DataTypeSupported(pDb,SQL_REAL))
346 wxLogMessage("SQL_REAL");
347 #endif
348 #ifdef SQL_DOUBLE
349 if (DataTypeSupported(pDb,SQL_DOUBLE))
350 wxLogMessage("SQL_DOUBLE");
351 #endif
352 #ifdef SQL_NUMERIC
353 if (DataTypeSupported(pDb,SQL_NUMERIC))
354 wxLogMessage("SQL_NUMERIC");
355 #endif
356 #ifdef SQL_DATE
357 if (DataTypeSupported(pDb,SQL_DATE))
358 wxLogMessage("SQL_DATE");
359 #endif
360 #ifdef SQL_TIME
361 if (DataTypeSupported(pDb,SQL_TIME))
362 wxLogMessage("SQL_TIME");
363 #endif
364 #ifdef SQL_TIMESTAMP
365 if (DataTypeSupported(pDb,SQL_TIMESTAMP))
366 wxLogMessage("SQL_TIMESTAMP");
367 #endif
368 #ifdef SQL_VARCHAR
369 if (DataTypeSupported(pDb,SQL_VARCHAR))
370 wxLogMessage("SQL_VARCHAR");
371 #endif
372
373 // UNICODE
374 #ifdef SQL_C_TCHAR
375 if (DataTypeSupported(pDb,SQL_C_TCHAR))
376 wxLogMessage("SQL_C_TCHAR (Unicode support is possible)");
377 #endif
378
379 wxLogMessage("\n");
380 } // CheckSupportForAllDataTypes()
381
382
383 bool DatabaseDemoApp::OnInit()
384 {
385 DbConnectInf = NULL;
386 Contact = NULL;
387
388 // Create the main frame window
389 DemoFrame = new DatabaseDemoFrame(NULL, wxT("wxWindows Database Demo"), wxPoint(50, 50), wxSize(537, 480));
390
391 // Give it an icon
392 DemoFrame->SetIcon(wxICON(db));
393
394 // Make a menubar
395 wxMenu *file_menu = new wxMenu;
396 file_menu->Append(FILE_CREATE, wxT("&Create CONTACT table"));
397 file_menu->Append(FILE_RECREATE_TABLE, wxT("&Recreate CONTACT table"));
398 file_menu->Append(FILE_RECREATE_INDEXES, wxT("&Recreate CONTACT indexes"));
399 file_menu->Append(FILE_EXIT, wxT("E&xit"));
400
401 wxMenu *edit_menu = new wxMenu;
402 edit_menu->Append(EDIT_PARAMETERS, wxT("&Parameters..."));
403
404 wxMenu *help_menu = new wxMenu;
405 help_menu->Append(HELP_ABOUT, wxT("&About"));
406
407 wxMenuBar *menu_bar = new wxMenuBar;
408 menu_bar->Append(file_menu, wxT("&File"));
409 menu_bar->Append(edit_menu, wxT("&Edit"));
410 menu_bar->Append(help_menu, wxT("&Help"));
411 DemoFrame->SetMenuBar(menu_bar);
412
413 params.ODBCSource[0] = 0;
414 params.UserName[0] = 0;
415 params.Password[0] = 0;
416 params.DirPath[0] = 0;
417
418 // Show the frame
419 DemoFrame->Show(TRUE);
420
421 // Passing NULL for the SQL environment handle causes
422 // the wxDbConnectInf constructor to obtain a handle
423 // for you.
424 //
425 // WARNING: Be certain that you do not free this handle
426 // directly with SQLFreeEnv(). Use either the
427 // method ::FreeHenv() or delete the DbConnectInf.
428 DbConnectInf = new wxDbConnectInf(NULL, params.ODBCSource, params.UserName,
429 params.Password, params.DirPath);
430
431 if (!DbConnectInf || !DbConnectInf->GetHenv())
432 {
433 wxMessageBox(wxT("Unable to define data source connection info."), wxT("DB CONNECTION ERROR..."),wxOK | wxICON_EXCLAMATION);
434 wxDELETE(DbConnectInf);
435 }
436
437 if (!ReadParamFile(params))
438 DemoFrame->BuildParameterDialog(NULL);
439
440 if (!wxStrlen(params.ODBCSource))
441 {
442 wxDELETE(DbConnectInf);
443 return(FALSE);
444 }
445
446 DbConnectInf->SetDsn(params.ODBCSource);
447 DbConnectInf->SetUserID(params.UserName);
448 DbConnectInf->SetPassword(params.Password);
449 DbConnectInf->SetDefaultDir(params.DirPath);
450
451 READONLY_DB = wxDbGetConnection(DbConnectInf);
452 if (READONLY_DB == 0)
453 {
454 wxMessageBox(wxT("Unable to connect to the data source.\n\nCheck the name of your data source to verify it has been correctly entered/spelled.\n\nWith some databases, the user name and password must\nbe created with full rights to the CONTACT table prior to making a connection\n(using tools provided by the database manufacturer)"), wxT("DB CONNECTION ERROR..."),wxOK | wxICON_EXCLAMATION);
455 DemoFrame->BuildParameterDialog(NULL);
456 wxDELETE(DbConnectInf);
457 wxMessageBox(wxT("Now exiting program.\n\nRestart program to try any new settings."),wxT("Notice..."),wxOK | wxICON_INFORMATION);
458 return(FALSE);
459 }
460
461 DemoFrame->BuildEditorDialog();
462
463 // Show the frame
464 DemoFrame->Refresh();
465
466 return TRUE;
467 } // DatabaseDemoApp::OnInit()
468
469
470 bool DatabaseDemoApp::ReadParamFile(Cparameters &params)
471 {
472 FILE *paramFile;
473 if ((paramFile = fopen(PARAM_FILENAME, wxT("r"))) == NULL)
474 {
475 wxString tStr;
476 tStr.Printf(wxT("Unable to open the parameter file '%s' for reading.\n\nYou must specify the data source, user name, and\npassword that will be used and save those settings."),PARAM_FILENAME);
477 wxMessageBox(tStr,wxT("File I/O Error..."),wxOK | wxICON_EXCLAMATION);
478
479 return FALSE;
480 }
481
482 wxChar buffer[1000+1];
483 fgets(buffer, sizeof(params.ODBCSource), paramFile);
484 buffer[wxStrlen(buffer)-1] = wxT('\0');
485 wxStrcpy(params.ODBCSource,buffer);
486
487 fgets(buffer, sizeof(params.UserName), paramFile);
488 buffer[wxStrlen(buffer)-1] = wxT('\0');
489 wxStrcpy(params.UserName,buffer);
490
491 fgets(buffer, sizeof(params.Password), paramFile);
492 buffer[wxStrlen(buffer)-1] = wxT('\0');
493 wxStrcpy(params.Password,buffer);
494
495 fgets(buffer, sizeof(params.DirPath), paramFile);
496 buffer[wxStrlen(buffer)-1] = wxT('\0');
497 wxStrcpy(params.DirPath,buffer);
498
499 fclose(paramFile);
500
501 return TRUE;
502 } // DatabaseDemoApp::ReadParamFile()
503
504
505 bool DatabaseDemoApp::WriteParamFile(Cparameters &params)
506 {
507 FILE *paramFile;
508 if ((paramFile = fopen(PARAM_FILENAME, wxT("wt"))) == NULL)
509 {
510 wxString tStr;
511 tStr.Printf(wxT("Unable to write/overwrite '%s'."),PARAM_FILENAME);
512 wxMessageBox(tStr,wxT("File I/O Error..."),wxOK | wxICON_EXCLAMATION);
513 return FALSE;
514 }
515
516 fputs(wxGetApp().params.ODBCSource, paramFile);
517 fputc(wxT('\n'), paramFile);
518 fputs(wxGetApp().params.UserName, paramFile);
519 fputc(wxT('\n'), paramFile);
520 fputs(wxGetApp().params.Password, paramFile);
521 fputc(wxT('\n'), paramFile);
522 fputs(wxGetApp().params.DirPath, paramFile);
523 fputc(wxT('\n'), paramFile);
524 fclose(paramFile);
525
526 return TRUE;
527 } // DatabaseDemoApp::WriteParamFile()
528
529
530 void DatabaseDemoApp::CreateDataTable(bool recreate)
531 {
532 bool Ok = TRUE;
533 if (recreate)
534 Ok = (wxMessageBox(wxT("Any data currently residing in the table will be erased.\n\nAre you sure?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
535
536 if (!Ok)
537 return;
538
539 wxBeginBusyCursor();
540
541 bool success = TRUE;
542
543 Contact->GetDb()->RollbackTrans(); // Make sure the current cursor is in a known/stable state
544
545 if (!Contact->CreateTable(recreate))
546 {
547 wxEndBusyCursor();
548 wxString tStr;
549 tStr = wxT("Error creating CONTACTS table.\nTable was not created.\n\n");
550 tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
551 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
552 success = FALSE;
553 }
554 else
555 {
556 if (!Contact->CreateIndexes(recreate))
557 {
558 wxEndBusyCursor();
559 wxString tStr;
560 tStr = wxT("Error creating CONTACTS indexes.\nIndexes will be unavailable.\n\n");
561 tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
562 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
563 success = FALSE;
564 }
565 }
566 while (wxIsBusy())
567 wxEndBusyCursor();
568
569 if (success)
570 wxMessageBox(wxT("Table and index(es) were successfully created."),wxT("Notice..."),wxOK | wxICON_INFORMATION);
571 } // DatabaseDemoApp::CreateDataTable()
572
573
574 BEGIN_EVENT_TABLE(DatabaseDemoFrame, wxFrame)
575 EVT_MENU(FILE_CREATE, DatabaseDemoFrame::OnCreate)
576 EVT_MENU(FILE_RECREATE_TABLE, DatabaseDemoFrame::OnRecreateTable)
577 EVT_MENU(FILE_RECREATE_INDEXES, DatabaseDemoFrame::OnRecreateIndexes)
578 EVT_MENU(FILE_EXIT, DatabaseDemoFrame::OnExit)
579 EVT_MENU(EDIT_PARAMETERS, DatabaseDemoFrame::OnEditParameters)
580 EVT_MENU(HELP_ABOUT, DatabaseDemoFrame::OnAbout)
581 EVT_CLOSE(DatabaseDemoFrame::OnCloseWindow)
582 END_EVENT_TABLE()
583
584
585 // DatabaseDemoFrame constructor
586 DatabaseDemoFrame::DatabaseDemoFrame(wxFrame *frame, const wxString& title,
587 const wxPoint& pos, const wxSize& size):
588 wxFrame(frame, -1, title, pos, size)
589 {
590 // Put any code in necessary for initializing the main frame here
591 pEditorDlg = NULL;
592 pParamDlg = NULL;
593
594 delete wxLog::SetActiveTarget(new wxLogStderr);
595
596 } // DatabaseDemoFrame constructor
597
598 DatabaseDemoFrame::~DatabaseDemoFrame()
599 {
600 delete wxLog::SetActiveTarget(NULL);
601 } // DatabaseDemoFrame destructor
602
603
604 void DatabaseDemoFrame::OnCreate(wxCommandEvent& event)
605 {
606 wxGetApp().CreateDataTable(FALSE);
607 } // DatabaseDemoFrame::OnCreate()
608
609
610 void DatabaseDemoFrame::OnRecreateTable(wxCommandEvent& event)
611 {
612 wxGetApp().CreateDataTable(TRUE);
613 } // DatabaseDemoFrame::OnRecreate()
614
615
616 void DatabaseDemoFrame::OnRecreateIndexes(wxCommandEvent& event)
617 {
618 wxGetApp().Contact->GetDb()->RollbackTrans(); // Make sure the current cursor is in a known/stable state
619
620 if (!wxGetApp().Contact->CreateIndexes(true))
621 {
622 while (wxIsBusy())
623 wxEndBusyCursor();
624 wxString tStr;
625 tStr = wxT("Error creating CONTACTS indexes.\nNew indexes will be unavailable.\n\n");
626 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
627 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
628 }
629 else
630 wxMessageBox(wxT("Index(es) were successfully recreated."),wxT("Notice..."),wxOK | wxICON_INFORMATION);
631
632 } // DatabaseDemoFrame::OnRecreateIndexes()
633
634
635 void DatabaseDemoFrame::OnExit(wxCommandEvent& event)
636 {
637 Close();
638 } // DatabaseDemoFrame::OnExit()
639
640
641 void DatabaseDemoFrame::OnEditParameters(wxCommandEvent& event)
642 {
643 if ((pEditorDlg->mode != mCreate) && (pEditorDlg->mode != mEdit))
644 BuildParameterDialog(this);
645 else
646 wxMessageBox(wxT("Cannot change database parameters while creating or editing a record"),wxT("Notice..."),wxOK | wxICON_INFORMATION);
647 } // DatabaseDemoFrame::OnEditParameters()
648
649
650 void DatabaseDemoFrame::OnAbout(wxCommandEvent& event)
651 {
652 wxMessageBox(wxT("wxWindows sample program for database classes\n\nContributed on 27 July 1998"),wxT("About..."),wxOK | wxICON_INFORMATION);
653 } // DatabaseDemoFrame::OnAbout()
654
655
656 // Put any additional checking necessary to make certain it is alright
657 // to close the program here that is not done elsewhere
658 void DatabaseDemoFrame::OnCloseWindow(wxCloseEvent& event)
659 {
660 // Clean up time
661 if (pEditorDlg && pEditorDlg->Close())
662 pEditorDlg = NULL;
663 else
664 {
665 if (pEditorDlg)
666 {
667 event.Veto();
668 return;
669 }
670 }
671
672 wxDELETE(wxGetApp().Contact);
673
674 // This function will close all the connections to the database that have been
675 // previously cached.
676 wxDbCloseConnections();
677
678 // Deletion of the wxDbConnectInf instance must be the LAST thing done that
679 // has anything to do with the database. Deleting this before disconnecting,
680 // freeing/closing connections, etc will result in a crash!
681 wxDELETE(wxGetApp().DbConnectInf);
682
683 this->Destroy();
684
685 } // DatabaseDemoFrame::OnCloseWindow()
686
687
688 void DatabaseDemoFrame::BuildEditorDialog()
689 {
690 pEditorDlg = NULL;
691 pEditorDlg = new CeditorDlg(this);
692 if (pEditorDlg)
693 {
694 pEditorDlg->Initialize();
695 if (!pEditorDlg->initialized)
696 {
697 pEditorDlg->Close();
698 pEditorDlg = NULL;
699 wxMessageBox(wxT("Unable to initialize the editor dialog for some reason"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
700 Close();
701 }
702 }
703 else
704 {
705 wxMessageBox(wxT("Unable to create the editor dialog for some reason"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
706 Close();
707 }
708 } // DatabaseDemoFrame::BuildEditorDialog()
709
710
711 void DatabaseDemoFrame::BuildParameterDialog(wxWindow *parent)
712 {
713 pParamDlg = new CparameterDlg(parent);
714
715 if (!pParamDlg)
716 wxMessageBox(wxT("Unable to create the parameter dialog for some reason"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
717 } // DatabaseDemoFrame::BuildParameterDialog()
718
719
720 /*
721 * Constructor note: If no wxDb object is passed in, a new connection to the database
722 * is created for this instance of Ccontact. This can be a slow process depending
723 * on the database engine being used, and some database engines have a limit on the
724 * number of connections (either hard limits, or license restricted) so care should
725 * be used to use as few connections as is necessary.
726 *
727 * IMPORTANT: Objects which share a wxDb pointer are ALL acted upon whenever a member
728 * function of pDb is called (i.e. CommitTrans() or RollbackTrans(), so if modifying
729 * or creating a table objects which use the same pDb, know that all the objects
730 * will be committed or rolled back when any of the objects has this function call made.
731 */
732 Ccontact::Ccontact (wxDb *pwxDb) : wxDbTable(pwxDb ? pwxDb : wxDbGetConnection(wxGetApp().DbConnectInf),
733 CONTACT_TABLE_NAME, CONTACT_NO_COLS, wxT(""),
734 !wxDB_QUERY_ONLY, wxGetApp().DbConnectInf->GetDefaultDir())
735 {
736 // This is used to represent whether the database connection should be released
737 // when this instance of the object is deleted. If using the same connection
738 // for multiple instance of database objects, then the connection should only be
739 // released when the last database instance using the connection is deleted
740 freeDbConn = !pwxDb;
741
742 if (GetDb())
743 GetDb()->SetSqlLogging(sqlLogON);
744
745 SetupColumns();
746
747 } // Ccontact Constructor
748
749
750 void Ccontact::Initialize()
751 {
752 Name[0] = 0;
753 Addr1[0] = 0;
754 Addr2[0] = 0;
755 City[0] = 0;
756 State[0] = 0;
757 PostalCode[0] = 0;
758 Country[0] = 0;
759 JoinDate.year = 1980;
760 JoinDate.month = 1;
761 JoinDate.day = 1;
762 JoinDate.hour = 0;
763 JoinDate.minute = 0;
764 JoinDate.second = 0;
765 JoinDate.fraction = 0;
766 NativeLanguage = langENGLISH;
767 IsDeveloper = FALSE;
768 Contributions = 0;
769 LinesOfCode = 0L;
770 } // Ccontact::Initialize
771
772
773 Ccontact::~Ccontact()
774 {
775 if (freeDbConn)
776 {
777 if (!wxDbFreeConnection(GetDb()))
778 {
779 wxString tStr;
780 tStr = wxT("Unable to Free the Ccontact data table handle\n\n");
781 tStr += GetExtendedDBErrorMsg(GetDb(),__FILE__,__LINE__);
782 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
783 }
784 }
785 } // Ccontract destructor
786
787
788 /*
789 * Handles setting up all the connections for the interface from the wxDbTable
790 * functions to interface to the data structure used to store records in
791 * memory, and for all the column definitions that define the table structure
792 */
793 void Ccontact::SetupColumns()
794 {
795 // NOTE: Columns now are 8 character names, as that is all dBase can support. Longer
796 // names can be used for other database engines
797 SetColDefs ( 0,wxT("NAME"), DB_DATA_TYPE_VARCHAR, Name, SQL_C_CHAR, sizeof(Name), TRUE, TRUE); // Primary index
798 SetColDefs ( 1,wxT("ADDRESS1"), DB_DATA_TYPE_VARCHAR, Addr1, SQL_C_CHAR, sizeof(Addr1), FALSE,TRUE);
799 SetColDefs ( 2,wxT("ADDRESS2"), DB_DATA_TYPE_VARCHAR, Addr2, SQL_C_CHAR, sizeof(Addr2), FALSE,TRUE);
800 SetColDefs ( 3,wxT("CITY"), DB_DATA_TYPE_VARCHAR, City, SQL_C_CHAR, sizeof(City), FALSE,TRUE);
801 SetColDefs ( 4,wxT("STATE"), DB_DATA_TYPE_VARCHAR, State, SQL_C_CHAR, sizeof(State), FALSE,TRUE);
802 SetColDefs ( 5,wxT("POSTCODE"), DB_DATA_TYPE_VARCHAR, PostalCode, SQL_C_CHAR, sizeof(PostalCode), FALSE,TRUE);
803 SetColDefs ( 6,wxT("COUNTRY"), DB_DATA_TYPE_VARCHAR, Country, SQL_C_CHAR, sizeof(Country), FALSE,TRUE);
804 SetColDefs ( 7,wxT("JOINDATE"), DB_DATA_TYPE_DATE, &JoinDate, SQL_C_TIMESTAMP, sizeof(JoinDate), FALSE,TRUE);
805 SetColDefs ( 8,wxT("IS_DEV"), DB_DATA_TYPE_INTEGER, &IsDeveloper, SQL_C_BOOLEAN(IsDeveloper), sizeof(IsDeveloper), FALSE,TRUE);
806 SetColDefs ( 9,wxT("CONTRIBS"), DB_DATA_TYPE_INTEGER, &Contributions, SQL_C_USHORT, sizeof(Contributions), FALSE,TRUE);
807 SetColDefs (10,wxT("LINE_CNT"), DB_DATA_TYPE_INTEGER, &LinesOfCode, SQL_C_ULONG, sizeof(LinesOfCode), FALSE,TRUE);
808 SetColDefs (11,wxT("LANGUAGE"), DB_DATA_TYPE_INTEGER, &NativeLanguage, SQL_C_ENUM, sizeof(NativeLanguage), FALSE,TRUE);
809 #if wxODBC_BLOB_EXPERIMENT > 0
810 SetColDefs (12,wxT("PICTURE"), DB_DATA_TYPE_BLOB, Picture, SQL_LONGVARBINARY, sizeof(Picture), FALSE,TRUE);
811 #endif
812 } // Ccontact::SetupColumns
813
814
815 bool Ccontact::CreateIndexes(bool recreate)
816 {
817 // This index could easily be accomplished with an "orderBy" clause,
818 // but is done to show how to construct a non-primary index.
819 wxString indexName;
820 wxDbIdxDef idxDef[2];
821
822 bool Ok = TRUE;
823
824 wxStrcpy(idxDef[0].ColName, "IS_DEV");
825 idxDef[0].Ascending = TRUE;
826
827 wxStrcpy(idxDef[1].ColName, "NAME");
828 idxDef[1].Ascending = TRUE;
829
830 indexName = GetTableName();
831 indexName += "_IDX1";
832 Ok = CreateIndex(indexName.c_str(), TRUE, 2, idxDef, recreate);
833
834 return Ok;
835 } // Ccontact::CreateIndexes()
836
837
838 /*
839 * Having a function to do a query on the primary key (and possibly others) is
840 * very efficient and tighter coding so that it is available where ever the object
841 * is. Great for use with multiple tables when not using views or outer joins
842 */
843 bool Ccontact::FetchByName(const wxString &name)
844 {
845 whereStr.Printf(wxT("NAME = '%s'"),name.c_str());
846 SetWhereClause(whereStr.c_str());
847 SetOrderByClause(wxT(""));
848
849 if (!Query())
850 return(FALSE);
851
852 // Fetch the record
853 return(GetNext());
854
855 } // Ccontact::FetchByName()
856
857
858 /*
859 *
860 * ************* DIALOGS ***************
861 *
862 */
863
864
865 /* CeditorDlg constructor
866 *
867 * Creates the dialog used for creating/editing/deleting/copying a Ccontact object.
868 * This dialog actually is drawn in the main frame of the program
869 *
870 * An instance of Ccontact is created - "Contact" - which is used to hold the Ccontact
871 * object that is currently being worked with.
872 */
873
874 BEGIN_EVENT_TABLE(CeditorDlg, wxPanel)
875 EVT_BUTTON(-1, CeditorDlg::OnButton)
876 EVT_CLOSE(CeditorDlg::OnCloseWindow)
877 END_EVENT_TABLE()
878
879 CeditorDlg::CeditorDlg(wxWindow *parent) : wxPanel (parent, 0, 0, 537, 480)
880 {
881 // Since the ::OnCommand() function is overridden, this prevents the widget
882 // detection in ::OnCommand() until all widgets have been initialized to prevent
883 // uninitialized pointers from crashing the program
884 widgetPtrsSet = FALSE;
885
886 initialized = FALSE;
887
888 SetMode(mView);
889
890 Show(FALSE);
891 } // CeditorDlg constructor
892
893
894 void CeditorDlg::OnCloseWindow(wxCloseEvent& event)
895 {
896 // Clean up time
897 if ((mode != mCreate) && (mode != mEdit))
898 {
899 this->Destroy();
900 }
901 else
902 {
903 wxMessageBox(wxT("Must finish processing the current record being created/modified before exiting"),wxT("Notice..."),wxOK | wxICON_INFORMATION);
904 event.Veto();
905 }
906 } // CeditorDlg::OnCloseWindow()
907
908
909 void CeditorDlg::OnButton(wxCommandEvent &event)
910 {
911 wxWindow *win = (wxWindow*) event.GetEventObject();
912 OnCommand( *win, event );
913 } // CeditorDlg::OnButton()
914
915
916 void CeditorDlg::OnCommand(wxWindow& win, wxCommandEvent& event)
917 {
918 wxString widgetName;
919
920 widgetName = win.GetName();
921
922 if (!widgetPtrsSet)
923 return;
924
925 if (widgetName == pCreateBtn->GetName())
926 {
927 wxGetApp().Contact->Initialize();
928 PutData();
929 SetMode( mCreate );
930 pNameTxt->SetValue(wxT(""));
931 pNameTxt->SetFocus();
932 return;
933 }
934
935 if (widgetName == pEditBtn->GetName())
936 {
937 saveName = wxGetApp().Contact->Name;
938 SetMode( mEdit );
939 pNameTxt->SetFocus();
940 return;
941 }
942
943 if (widgetName == pCopyBtn->GetName())
944 {
945 SetMode(mCreate);
946 pNameTxt->SetValue(wxT(""));
947 pNameTxt->SetFocus();
948 return;
949 }
950
951 if (widgetName == pDeleteBtn->GetName())
952 {
953 bool Ok = (wxMessageBox(wxT("Are you sure?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
954
955 if (!Ok)
956 return;
957
958 if (Ok && wxGetApp().Contact->Delete())
959 {
960 // NOTE: Deletions are not finalized until a CommitTrans() is performed.
961 // If the commit were not performed, the program will continue to
962 // show the table contents as if they were deleted until this instance
963 // of Ccontact is deleted. If the Commit wasn't performed, the
964 // database will automatically Rollback the changes when the database
965 // connection is terminated
966 wxGetApp().Contact->GetDb()->CommitTrans();
967
968 // Try to get the row that followed the just deleted row in the orderBy sequence
969 if (!GetNextRec())
970 {
971 // There was now row (in sequence) after the just deleted row, so get the
972 // row which preceded the just deleted row
973 if (!GetPrevRec())
974 {
975 // There are now no rows remaining, so clear the dialog widgets
976 wxGetApp().Contact->Initialize();
977 PutData();
978 }
979 }
980 SetMode(mode); // force reset of button enable/disable
981 }
982 else
983 // Delete failed
984 wxGetApp().Contact->GetDb()->RollbackTrans();
985
986 SetMode(mView);
987 return;
988 }
989
990 if (widgetName == pSaveBtn->GetName())
991 {
992 Save();
993 return;
994 }
995
996 if (widgetName == pCancelBtn->GetName())
997 {
998 bool Ok = (wxMessageBox(wxT("Are you sure?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
999
1000 if (!Ok)
1001 return;
1002
1003 if (saveName.IsEmpty())
1004 {
1005 wxGetApp().Contact->Initialize();
1006 PutData();
1007 SetMode(mView);
1008 return;
1009 }
1010 else
1011 {
1012 // Requery previous record
1013 if (wxGetApp().Contact->FetchByName(saveName))
1014 {
1015 PutData();
1016 SetMode(mView);
1017 return;
1018 }
1019 }
1020
1021 // Previous record not available, retrieve first record in table
1022 if (wxGetApp().Contact->GetDb()->Dbms() != dbmsPOSTGRES &&
1023 wxGetApp().Contact->GetDb()->Dbms() != dbmsMY_SQL)
1024 {
1025 wxGetApp().Contact->whereStr = wxT("NAME = (SELECT MIN(NAME) FROM ");
1026 wxGetApp().Contact->whereStr += wxGetApp().Contact->GetTableName();
1027 wxGetApp().Contact->whereStr += wxT(")");
1028 wxGetApp().Contact->SetWhereClause(wxGetApp().Contact->whereStr.c_str());
1029 }
1030 else
1031 wxGetApp().Contact->SetWhereClause(wxT(""));
1032
1033 if (!wxGetApp().Contact->Query())
1034 {
1035 wxString tStr;
1036 tStr = wxT("ODBC error during Query()\n\n");
1037 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1038 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1039 SetMode(mView);
1040 return;
1041 }
1042 if (wxGetApp().Contact->GetNext()) // Successfully read first record
1043 {
1044 PutData();
1045 SetMode(mView);
1046 return;
1047 }
1048 // No contacts are available, clear dialog
1049 wxGetApp().Contact->Initialize();
1050 PutData();
1051 SetMode(mView);
1052 return;
1053 } // Cancel Button
1054
1055 if (widgetName == pPrevBtn->GetName())
1056 {
1057 if (!GetPrevRec())
1058 wxBell();
1059 return;
1060 } // Prev Button
1061
1062 if (widgetName == pNextBtn->GetName())
1063 {
1064 if (!GetNextRec())
1065 wxBell();
1066 return;
1067 } // Next Button
1068
1069 if (widgetName == pQueryBtn->GetName())
1070 {
1071 // Display the query dialog box
1072 wxChar qryWhere[DB_MAX_WHERE_CLAUSE_LEN+1];
1073 wxStrcpy(qryWhere, (const wxChar*) wxGetApp().Contact->qryWhereStr);
1074 wxChar *tblName[] = {(wxChar *)CONTACT_TABLE_NAME, 0};
1075 new CqueryDlg(GetParent(), wxGetApp().Contact->GetDb(), tblName, qryWhere);
1076
1077 // Query the first record in the new record set and
1078 // display it, if the query string has changed.
1079 if (wxStrcmp(qryWhere, (const wxChar*) wxGetApp().Contact->qryWhereStr))
1080 {
1081 wxGetApp().Contact->whereStr.Empty();
1082 wxGetApp().Contact->SetOrderByClause("NAME");
1083
1084 if (wxGetApp().Contact->GetDb()->Dbms() != dbmsPOSTGRES &&
1085 wxGetApp().Contact->GetDb()->Dbms() != dbmsMY_SQL)
1086 {
1087 wxGetApp().Contact->whereStr = wxT("NAME = (SELECT MIN(NAME) FROM ");
1088 wxGetApp().Contact->whereStr += CONTACT_TABLE_NAME;
1089 }
1090
1091 // Append the query where string (if there is one)
1092 wxGetApp().Contact->qryWhereStr = qryWhere;
1093 if (wxStrlen(qryWhere))
1094 {
1095 wxGetApp().Contact->whereStr += wxT(" WHERE ");
1096 wxGetApp().Contact->whereStr += wxGetApp().Contact->qryWhereStr;
1097 }
1098 // Close the expression with a right paren
1099 wxGetApp().Contact->whereStr += wxT(")");
1100 // Requery the table
1101 wxGetApp().Contact->SetWhereClause(wxGetApp().Contact->whereStr.c_str());
1102 if (!wxGetApp().Contact->Query())
1103 {
1104 wxString tStr;
1105 tStr = wxT("ODBC error during Query()\n\n");
1106 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1107 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1108 return;
1109 }
1110 // Display the first record from the query set
1111 if (!wxGetApp().Contact->GetNext())
1112 wxGetApp().Contact->Initialize();
1113 PutData();
1114 }
1115
1116 // Enable/Disable the reset button
1117 pResetBtn->Enable(!wxGetApp().Contact->qryWhereStr.IsEmpty());
1118
1119 return;
1120 } // Query button
1121
1122
1123 if (widgetName == pResetBtn->GetName())
1124 {
1125 // Clear the additional where criteria established by the query feature
1126 wxGetApp().Contact->qryWhereStr = wxT("");
1127 wxGetApp().Contact->SetOrderByClause(wxT("NAME"));
1128
1129 if (wxGetApp().Contact->GetDb()->Dbms() != dbmsPOSTGRES &&
1130 wxGetApp().Contact->GetDb()->Dbms() != dbmsMY_SQL)
1131 {
1132 wxGetApp().Contact->whereStr = wxT("NAME = (SELECT MIN(NAME) FROM ");
1133 wxGetApp().Contact->whereStr += CONTACT_TABLE_NAME;
1134 wxGetApp().Contact->whereStr += wxT(")");
1135 }
1136
1137 wxGetApp().Contact->SetWhereClause(wxGetApp().Contact->whereStr.c_str());
1138 if (!wxGetApp().Contact->Query())
1139 {
1140 wxString tStr;
1141 tStr = wxT("ODBC error during Query()\n\n");
1142 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1143 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1144 return;
1145 }
1146 if (!wxGetApp().Contact->GetNext())
1147 wxGetApp().Contact->Initialize();
1148 PutData();
1149 pResetBtn->Enable(FALSE);
1150
1151 return;
1152 } // Reset button
1153
1154
1155 if (widgetName == pNameListBtn->GetName())
1156 {
1157 new ClookUpDlg(/* wxWindow *parent */ this,
1158 /* wxChar *windowTitle */ wxT("Select contact name"),
1159 /* wxChar *tableName */ (wxChar *) CONTACT_TABLE_NAME,
1160 /* wxChar *dispCol1 */ wxT("NAME"),
1161 /* wxChar *dispCol2 */ wxT("JOINDATE"),
1162 /* wxChar *where */ wxT(""),
1163 /* wxChar *orderBy */ wxT("NAME"),
1164 /* wxDb *pDb */ wxGetApp().READONLY_DB,
1165 /* const wxString &defDir */ wxGetApp().DbConnectInf->GetDefaultDir(),
1166 /* bool distinctValues */ TRUE);
1167
1168 if (ListDB_Selection && wxStrlen(ListDB_Selection))
1169 {
1170 wxString w = wxT("NAME = '");
1171 w += ListDB_Selection;
1172 w += wxT("'");
1173 GetRec(w);
1174 }
1175
1176 return;
1177 }
1178
1179 if (widgetName == pDataTypesBtn->GetName())
1180 {
1181 CheckSupportForAllDataTypes(wxGetApp().READONLY_DB);
1182 wxMessageBox("Support datatypes was dumped to stdout.");
1183 return;
1184 } // Data types Button
1185
1186 if (widgetName == pDbDiagsBtn->GetName())
1187 {
1188 DisplayDbDiagnostics(wxGetApp().READONLY_DB);
1189 wxMessageBox("Diagnostics info was dumped to stdout.");
1190 return;
1191 }
1192
1193 if (widgetName == pCatalogBtn->GetName())
1194 {
1195 if (wxGetApp().Contact->GetDb()->Catalog("","catalog.txt"))
1196 wxMessageBox("The file 'catalog.txt' was created.");
1197 else
1198 wxMessageBox("Creation of the file 'catalog.txt' was failed.");
1199 return;
1200 }
1201
1202 } // CeditorDlg::OnCommand()
1203
1204
1205 bool CeditorDlg::Initialize()
1206 {
1207 // Create the data structure and a new database connection.
1208 // (As there is not a pDb being passed in the constructor, a new database
1209 // connection is created)
1210 wxGetApp().Contact = new Ccontact();
1211
1212 if (!wxGetApp().Contact)
1213 {
1214 wxMessageBox(wxT("Unable to instantiate an instance of Ccontact"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
1215 return FALSE;
1216 }
1217
1218 // Check if the table exists or not. If it doesn't, ask the user if they want to
1219 // create the table. Continue trying to create the table until it exists, or user aborts
1220 while (!wxGetApp().Contact->GetDb()->TableExists((wxChar *)CONTACT_TABLE_NAME,
1221 wxGetApp().DbConnectInf->GetUserID(),
1222 wxGetApp().DbConnectInf->GetDefaultDir()))
1223 {
1224 wxString tStr;
1225 tStr.Printf(wxT("Unable to open the table '%s'.\n\nTable may need to be created...?\n\n"),CONTACT_TABLE_NAME);
1226 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1227 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1228
1229 bool createTable = (wxMessageBox(wxT("Do you wish to try to create/clear the CONTACTS table?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
1230
1231 if (!createTable)
1232 {
1233 // Close();
1234 return FALSE;
1235 }
1236 else
1237 wxGetApp().CreateDataTable(FALSE);
1238 }
1239
1240 // Tables must be "opened" before anything other than creating/deleting table can be done
1241 if (!wxGetApp().Contact->Open())
1242 {
1243 // Table does exist, or there was some problem opening it. Currently this should
1244 // never fail, except in the case of the table not exisiting or the current
1245 // user has insufficent privileges to access the table
1246 #if 1
1247 // This code is experimenting with a new function that will hopefully be available
1248 // in the 2.4 release. This check will determine whether the open failing was due
1249 // to the table not existing, or the users privileges being insufficient to
1250 // open the table.
1251 if (!wxGetApp().Contact->GetDb()->TablePrivileges(CONTACT_TABLE_NAME, wxT("SELECT"),
1252 wxGetApp().Contact->GetDb()->GetUsername(),
1253 wxGetApp().Contact->GetDb()->GetUsername(),
1254 wxGetApp().DbConnectInf->GetDefaultDir()))
1255 {
1256 wxString tStr;
1257 tStr.Printf(wxT("Unable to open the table '%s' (likely due to\ninsufficient privileges of the logged in user).\n\n"),CONTACT_TABLE_NAME);
1258 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1259 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1260 }
1261 else
1262 #endif
1263 if (!wxGetApp().Contact->GetDb()->TableExists(CONTACT_TABLE_NAME,
1264 wxGetApp().Contact->GetDb()->GetUsername(),
1265 wxGetApp().DbConnectInf->GetDefaultDir()))
1266 {
1267 wxString tStr;
1268 tStr.Printf(wxT("Unable to open the table '%s' as the table\ndoes not appear to exist in the tablespace available\nto the currently logged in user.\n\n"),CONTACT_TABLE_NAME);
1269 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1270 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1271 }
1272
1273 return FALSE;
1274 }
1275
1276 // Build the dialog
1277
1278 (void)new wxStaticBox(this, EDITOR_DIALOG_FN_GROUP, wxT(""), wxPoint(15, 1), wxSize(497, 69), 0, wxT("FunctionGrp"));
1279 (void)new wxStaticBox(this, EDITOR_DIALOG_SEARCH_GROUP, wxT(""), wxPoint(417, 1), wxSize(95, 242), 0, wxT("SearchGrp"));
1280
1281 pCreateBtn = new wxButton(this, EDITOR_DIALOG_CREATE, wxT("&Create"), wxPoint( 25, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("CreateBtn"));
1282 pEditBtn = new wxButton(this, EDITOR_DIALOG_EDIT, wxT("&Edit"), wxPoint(102, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("EditBtn"));
1283 pDeleteBtn = new wxButton(this, EDITOR_DIALOG_DELETE, wxT("&Delete"), wxPoint(179, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("DeleteBtn"));
1284 pCopyBtn = new wxButton(this, EDITOR_DIALOG_COPY, wxT("Cop&y"), wxPoint(256, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("CopyBtn"));
1285 pSaveBtn = new wxButton(this, EDITOR_DIALOG_SAVE, wxT("&Save"), wxPoint(333, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("SaveBtn"));
1286 pCancelBtn = new wxButton(this, EDITOR_DIALOG_CANCEL, wxT("C&ancel"), wxPoint(430, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("CancelBtn"));
1287 pPrevBtn = new wxButton(this, EDITOR_DIALOG_PREV, wxT("<< &Prev"), wxPoint(430, 81), wxSize( 70, 35), 0, wxDefaultValidator, wxT("PrevBtn"));
1288 pNextBtn = new wxButton(this, EDITOR_DIALOG_NEXT, wxT("&Next >>"), wxPoint(430, 121), wxSize( 70, 35), 0, wxDefaultValidator, wxT("NextBtn"));
1289 pQueryBtn = new wxButton(this, EDITOR_DIALOG_QUERY, wxT("&Query"), wxPoint(430, 161), wxSize( 70, 35), 0, wxDefaultValidator, wxT("QueryBtn"));
1290 pResetBtn = new wxButton(this, EDITOR_DIALOG_RESET, wxT("&Reset"), wxPoint(430, 200), wxSize( 70, 35), 0, wxDefaultValidator, wxT("ResetBtn"));
1291 pNameMsg = new wxStaticText(this, EDITOR_DIALOG_NAME_MSG, wxT("Name:"), wxPoint( 17, 80), wxSize( -1, -1), 0, wxT("NameMsg"));
1292 pNameTxt = new wxTextCtrl(this, EDITOR_DIALOG_NAME_TEXT, wxT(""), wxPoint( 17, 97), wxSize(308, 25), 0, wxDefaultValidator, wxT("NameTxt"));
1293 pNameListBtn = new wxButton(this, EDITOR_DIALOG_LOOKUP, wxT("&Lookup"), wxPoint(333, 97), wxSize( 70, 24), 0, wxDefaultValidator, wxT("LookupBtn"));
1294 pAddress1Msg = new wxStaticText(this, EDITOR_DIALOG_ADDRESS1_MSG, wxT("Address:"), wxPoint( 17, 130), wxSize( -1, -1), 0, wxT("Address1Msg"));
1295 pAddress1Txt = new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT, wxT(""), wxPoint( 17, 147), wxSize(308, 25), 0, wxDefaultValidator, wxT("Address1Txt"));
1296 pAddress2Msg = new wxStaticText(this, EDITOR_DIALOG_ADDRESS2_MSG, wxT("Address:"), wxPoint( 17, 180), wxSize( -1, -1), 0, wxT("Address2Msg"));
1297 pAddress2Txt = new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT, wxT(""), wxPoint( 17, 197), wxSize(308, 25), 0, wxDefaultValidator, wxT("Address2Txt"));
1298 pCityMsg = new wxStaticText(this, EDITOR_DIALOG_CITY_MSG, wxT("City:"), wxPoint( 17, 230), wxSize( -1, -1), 0, wxT("CityMsg"));
1299 pCityTxt = new wxTextCtrl(this, EDITOR_DIALOG_CITY_TEXT, wxT(""), wxPoint( 17, 247), wxSize(225, 25), 0, wxDefaultValidator, wxT("CityTxt"));
1300 pStateMsg = new wxStaticText(this, EDITOR_DIALOG_STATE_MSG, wxT("State:"), wxPoint(250, 230), wxSize( -1, -1), 0, wxT("StateMsg"));
1301 pStateTxt = new wxTextCtrl(this, EDITOR_DIALOG_STATE_TEXT, wxT(""), wxPoint(250, 247), wxSize(153, 25), 0, wxDefaultValidator, wxT("StateTxt"));
1302 pCountryMsg = new wxStaticText(this, EDITOR_DIALOG_COUNTRY_MSG, wxT("Country:"), wxPoint( 17, 280), wxSize( -1, -1), 0, wxT("CountryMsg"));
1303 pCountryTxt = new wxTextCtrl(this, EDITOR_DIALOG_COUNTRY_TEXT, wxT(""), wxPoint( 17, 297), wxSize(225, 25), 0, wxDefaultValidator, wxT("CountryTxt"));
1304 pPostalCodeMsg = new wxStaticText(this, EDITOR_DIALOG_POSTAL_MSG, wxT("Postal Code:"),wxPoint(250, 280), wxSize( -1, -1), 0, wxT("PostalCodeMsg"));
1305 pPostalCodeTxt = new wxTextCtrl(this, EDITOR_DIALOG_POSTAL_TEXT, wxT(""), wxPoint(250, 297), wxSize(153, 25), 0, wxDefaultValidator, wxT("PostalCodeTxt"));
1306
1307 wxString choice_strings[5];
1308 choice_strings[0] = wxT("English");
1309 choice_strings[1] = wxT("French");
1310 choice_strings[2] = wxT("German");
1311 choice_strings[3] = wxT("Spanish");
1312 choice_strings[4] = wxT("Other");
1313
1314 pNativeLangChoice = new wxChoice(this, EDITOR_DIALOG_LANG_CHOICE, wxPoint( 17, 346), wxSize(277, -1), 5, choice_strings);
1315 pNativeLangMsg = new wxStaticText(this, EDITOR_DIALOG_LANG_MSG, wxT("Native language:"), wxPoint( 17, 330), wxSize( -1, -1), 0, wxT("NativeLangMsg"));
1316
1317 wxString radio_strings[2];
1318 radio_strings[0] = wxT("No");
1319 radio_strings[1] = wxT("Yes");
1320 pDeveloperRadio = new wxRadioBox(this,EDITOR_DIALOG_DEVELOPER, wxT("Developer:"), wxPoint(303, 330), wxSize( -1, -1), 2, radio_strings, 2, wxHORIZONTAL);
1321 pJoinDateMsg = new wxStaticText(this, EDITOR_DIALOG_JOIN_MSG, wxT("Date joined:"), wxPoint( 17, 380), wxSize( -1, -1), 0, wxT("JoinDateMsg"));
1322 pJoinDateTxt = new wxTextCtrl(this, EDITOR_DIALOG_JOIN_TEXT, wxT(""), wxPoint( 17, 397), wxSize(150, 25), 0, wxDefaultValidator, wxT("JoinDateTxt"));
1323 pContribMsg = new wxStaticText(this, EDITOR_DIALOG_CONTRIB_MSG,wxT("Contributions:"), wxPoint(175, 380), wxSize( -1, -1), 0, wxT("ContribMsg"));
1324 pContribTxt = new wxTextCtrl(this, EDITOR_DIALOG_CONTRIB_TEXT, wxT(""), wxPoint(175, 397), wxSize(120, 25), 0, wxDefaultValidator, wxT("ContribTxt"));
1325 pLinesMsg = new wxStaticText(this, EDITOR_DIALOG_LINES_MSG, wxT("Lines of code:"), wxPoint(303, 380), wxSize( -1, -1), 0, wxT("LinesMsg"));
1326 pLinesTxt = new wxTextCtrl(this, EDITOR_DIALOG_LINES_TEXT, wxT(""), wxPoint(303, 397), wxSize(100, 25), 0, wxDefaultValidator, wxT("LinesTxt"));
1327
1328 pCatalogBtn = new wxButton(this, EDITOR_DIALOG_CATALOG, wxT("Catalo&g"), wxPoint(430, 287), wxSize( 70, 35), 0, wxDefaultValidator, wxT("CatalogBtn"));
1329 pDataTypesBtn = new wxButton(this, EDITOR_DIALOG_DATATYPES, wxT("Data&types"), wxPoint(430, 337), wxSize( 70, 35), 0, wxDefaultValidator, wxT("DataTypesBtn"));
1330 pDbDiagsBtn = new wxButton(this, EDITOR_DIALOG_DB_DIAGS, wxT("DB Dia&gs"), wxPoint(430, 387), wxSize( 70, 35), 0, wxDefaultValidator, wxT("DbDiagsBtn"));
1331
1332 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
1333 // handle all widget processing
1334 widgetPtrsSet = TRUE;
1335
1336 // Setup the orderBy and where clauses to return back a single record as the result set,
1337 // as there will only be one record being shown on the dialog at a time, this optimizes
1338 // network traffic by only returning a one row result
1339
1340 wxGetApp().Contact->SetOrderByClause(wxT("NAME")); // field name to sort by
1341
1342 // The wxString "whereStr" is not a member of the wxDbTable object, it is a member variable
1343 // specifically in the Ccontact class. It is used here for simpler construction of a varying
1344 // length string, and then after the string is built, the wxDbTable member variable "where" is
1345 // assigned the pointer to the constructed string.
1346 //
1347 // The constructed where clause below has a sub-query within it "SELECT MIN(NAME) FROM %s"
1348 // to achieve a single row (in this case the first name in alphabetical order).
1349
1350 if (wxGetApp().Contact->GetDb()->Dbms() != dbmsPOSTGRES &&
1351 wxGetApp().Contact->GetDb()->Dbms() != dbmsMY_SQL)
1352 {
1353 wxGetApp().Contact->whereStr.Printf(wxT("NAME = (SELECT MIN(NAME) FROM %s)"),
1354 wxGetApp().Contact->GetTableName().c_str());
1355 // NOTE: (const wxChar*) returns a pointer which may not be valid later, so this is short term use only
1356 wxGetApp().Contact->SetWhereClause(wxGetApp().Contact->whereStr);
1357 }
1358 else
1359 wxGetApp().Contact->SetWhereClause(wxT(""));
1360
1361 // Perform the Query to get the result set.
1362 // NOTE: If there are no rows returned, that is a valid result, so Query() would return TRUE.
1363 // Only if there is a database error will Query() come back as FALSE
1364 if (!wxGetApp().Contact->Query())
1365 {
1366 wxString tStr;
1367 tStr = wxT("ODBC error during Query()\n\n");
1368 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1369 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1370 return FALSE;
1371 }
1372
1373 // Since Query succeeded, now get the row that was returned
1374 if (!wxGetApp().Contact->GetNext())
1375 // If the GetNext() failed at this point, then there are no rows to retrieve,
1376 // so clear the values in the members of "Contact" so that PutData() blanks the
1377 // widgets on the dialog
1378 wxGetApp().Contact->Initialize();
1379 /*
1380 wxGetApp().Contact->GetDb()->RollbackTrans();
1381 */
1382 SetMode(mView);
1383 PutData();
1384
1385 Show(TRUE);
1386
1387 initialized = TRUE;
1388 return TRUE;
1389 } // CeditorDlg::Initialize()
1390
1391
1392 void CeditorDlg::FieldsEditable()
1393 {
1394 if (!widgetPtrsSet)
1395 return;
1396
1397 pNameTxt->Enable((mode == mCreate) || (mode == mEdit));
1398 pAddress1Txt->Enable((mode == mCreate) || (mode == mEdit));
1399 pAddress2Txt->Enable((mode == mCreate) || (mode == mEdit));
1400 pCityTxt->Enable((mode == mCreate) || (mode == mEdit));
1401 pStateTxt->Enable((mode == mCreate) || (mode == mEdit));
1402 pPostalCodeTxt->Enable((mode == mCreate) || (mode == mEdit));
1403 pCountryTxt->Enable((mode == mCreate) || (mode == mEdit));
1404
1405 pJoinDateTxt->Enable((mode == mCreate) || (mode == mEdit));
1406 pContribTxt->Enable((mode == mCreate) || (mode == mEdit));
1407 pLinesTxt->Enable((mode == mCreate) || (mode == mEdit));
1408 pNativeLangChoice->Enable((mode == mCreate) || (mode == mEdit));
1409 pDeveloperRadio->Enable((mode == mCreate) || (mode == mEdit));
1410
1411 } // CeditorDlg::FieldsEditable()
1412
1413
1414 void CeditorDlg::SetMode(enum DialogModes m)
1415 {
1416 bool edit = FALSE;
1417
1418 mode = m;
1419 switch (mode)
1420 {
1421 case mCreate:
1422 case mEdit:
1423 edit = TRUE;
1424 break;
1425 case mView:
1426 case mSearch:
1427 edit = FALSE;
1428 break;
1429 default:
1430 break;
1431 };
1432
1433 if (widgetPtrsSet)
1434 {
1435 pCreateBtn->Enable( !edit );
1436 pEditBtn->Enable( !edit && (wxStrcmp(wxGetApp().Contact->Name,wxT(""))!=0) );
1437 pDeleteBtn->Enable( !edit && (wxStrcmp(wxGetApp().Contact->Name,wxT(""))!=0) );
1438 pCopyBtn->Enable( !edit && (wxStrcmp(wxGetApp().Contact->Name,wxT(""))!=0) );
1439 pSaveBtn->Enable( edit );
1440 pCancelBtn->Enable( edit );
1441 pPrevBtn->Enable( !edit );
1442 pNextBtn->Enable( !edit );
1443 pQueryBtn->Enable( !edit );
1444 pResetBtn->Enable( !edit && !wxGetApp().Contact->qryWhereStr.IsEmpty() );
1445 pNameListBtn->Enable( !edit );
1446 }
1447
1448 FieldsEditable();
1449 } // CeditorDlg::SetMode()
1450
1451
1452 bool CeditorDlg::PutData()
1453 {
1454 wxString tStr;
1455
1456 pNameTxt->SetValue(wxGetApp().Contact->Name);
1457 pAddress1Txt->SetValue(wxGetApp().Contact->Addr1);
1458 pAddress2Txt->SetValue(wxGetApp().Contact->Addr2);
1459 pCityTxt->SetValue(wxGetApp().Contact->City);
1460 pStateTxt->SetValue(wxGetApp().Contact->State);
1461 pCountryTxt->SetValue(wxGetApp().Contact->Country);
1462 pPostalCodeTxt->SetValue(wxGetApp().Contact->PostalCode);
1463
1464 tStr.Printf(wxT("%d/%d/%d"),wxGetApp().Contact->JoinDate.month,wxGetApp().Contact->JoinDate.day,wxGetApp().Contact->JoinDate.year);
1465 pJoinDateTxt->SetValue(tStr);
1466
1467 tStr.Printf(wxT("%d"),wxGetApp().Contact->Contributions);
1468 pContribTxt->SetValue(tStr);
1469
1470 tStr.Printf(wxT("%lu"),wxGetApp().Contact->LinesOfCode);
1471 pLinesTxt->SetValue(tStr);
1472
1473 pNativeLangChoice->SetSelection(wxGetApp().Contact->NativeLanguage);
1474
1475 pDeveloperRadio->SetSelection(wxGetApp().Contact->IsDeveloper);
1476
1477 return TRUE;
1478 } // Ceditor::PutData()
1479
1480
1481 /*
1482 * Reads the data out of all the widgets on the dialog. Some data evaluation is done
1483 * to ensure that there is a name entered and that the date field is valid.
1484 *
1485 * A return value of TRUE means that valid data was retrieved from the dialog, otherwise
1486 * invalid data was found (and a message was displayed telling the user what to fix), and
1487 * the data was not placed into the appropraite fields of Ccontact
1488 */
1489 bool CeditorDlg::GetData()
1490 {
1491 // Validate that the data currently entered into the widgets is valid data
1492
1493 wxString tStr;
1494 tStr = pNameTxt->GetValue();
1495 if (!wxStrcmp((const wxChar*) tStr,wxT("")))
1496 {
1497 wxMessageBox(wxT("A name is required for entry into the contact table"),wxT("Notice..."),wxOK | wxICON_INFORMATION);
1498 return FALSE;
1499 }
1500
1501 bool invalid = FALSE;
1502 int mm,dd,yyyy;
1503 int first, second;
1504
1505 tStr = pJoinDateTxt->GetValue();
1506 if (tStr.Freq(wxT('/')) != 2)
1507 invalid = TRUE;
1508
1509 // Find the month, day, and year tokens
1510 if (!invalid)
1511 {
1512 first = tStr.First(wxT('/'));
1513 second = tStr.Last(wxT('/'));
1514
1515 mm = atoi(tStr.SubString(0,first));
1516 dd = atoi(tStr.SubString(first+1,second));
1517 yyyy = atoi(tStr.SubString(second+1,tStr.Length()-1));
1518
1519 invalid = !(mm && dd && yyyy);
1520 }
1521
1522 // Force Year 2000 compliance
1523 if (!invalid && (yyyy < 1000))
1524 invalid = TRUE;
1525
1526 // Check the token ranges for validity
1527 if (!invalid)
1528 {
1529 if (yyyy > 9999)
1530 invalid = TRUE;
1531 else if ((mm < 1) || (mm > 12))
1532 invalid = TRUE;
1533 else
1534 {
1535 if (dd < 1)
1536 invalid = TRUE;
1537 else
1538 {
1539 int days[12] = {31,28,31,30,31,30,
1540 31,31,30,31,30,31};
1541 if (dd > days[mm-1])
1542 {
1543 invalid = TRUE;
1544 if ((dd == 29) && (mm == 2))
1545 {
1546 if (((yyyy % 4) == 0) && (((yyyy % 100) != 0) || ((yyyy % 400) == 0)))
1547 invalid = FALSE;
1548 }
1549 }
1550 }
1551 }
1552 }
1553
1554 if (!invalid)
1555 {
1556 wxGetApp().Contact->JoinDate.month = mm;
1557 wxGetApp().Contact->JoinDate.day = dd;
1558 wxGetApp().Contact->JoinDate.year = yyyy;
1559 }
1560 else
1561 {
1562 wxMessageBox(wxT("Improper date format. Please check the date\nspecified and try again.\n\nNOTE: Dates are in american format (MM/DD/YYYY)"),wxT("Notice..."),wxOK | wxICON_INFORMATION);
1563 return FALSE;
1564 }
1565
1566 tStr = pNameTxt->GetValue();
1567 wxStrcpy(wxGetApp().Contact->Name,(const wxChar*) tStr);
1568 wxStrcpy(wxGetApp().Contact->Addr1,pAddress1Txt->GetValue());
1569 wxStrcpy(wxGetApp().Contact->Addr2,pAddress2Txt->GetValue());
1570 wxStrcpy(wxGetApp().Contact->City,pCityTxt->GetValue());
1571 wxStrcpy(wxGetApp().Contact->State,pStateTxt->GetValue());
1572 wxStrcpy(wxGetApp().Contact->Country,pCountryTxt->GetValue());
1573 wxStrcpy(wxGetApp().Contact->PostalCode,pPostalCodeTxt->GetValue());
1574
1575 wxGetApp().Contact->Contributions = atoi(pContribTxt->GetValue());
1576 wxGetApp().Contact->LinesOfCode = atol(pLinesTxt->GetValue());
1577
1578 wxGetApp().Contact->NativeLanguage = (enum Language) pNativeLangChoice->GetSelection();
1579 wxGetApp().Contact->IsDeveloper = pDeveloperRadio->GetSelection() > 0;
1580
1581 return TRUE;
1582 } // CeditorDlg::GetData()
1583
1584
1585 /*
1586 * Retrieve data from the dialog, verify the validity of the data, and if it is valid,
1587 * try to insert/update the data to the table based on the current 'mode' the dialog
1588 * is set to.
1589 *
1590 * A return value of TRUE means the insert/update was completed successfully, a return
1591 * value of FALSE means that Save() failed. If returning FALSE, then this function
1592 * has displayed a detailed error message for the user.
1593 */
1594 bool CeditorDlg::Save()
1595 {
1596 bool failed = FALSE;
1597
1598 // Read the data in the widgets of the dialog to get the user's data
1599 if (!GetData())
1600 failed = TRUE;
1601
1602 // Perform any other required validations necessary before saving
1603 if (!failed)
1604 {
1605 wxBeginBusyCursor();
1606
1607 if (mode == mCreate)
1608 {
1609 RETCODE result = wxGetApp().Contact->Insert();
1610
1611 failed = (result != DB_SUCCESS);
1612 if (failed)
1613 {
1614 // Some errors may be expected, like a duplicate key, so handle those instances with
1615 // specific error messages.
1616 if (result == DB_ERR_INTEGRITY_CONSTRAINT_VIOL)
1617 {
1618 wxString tStr;
1619 tStr = wxT("A duplicate key value already exists in the table.\nUnable to save record\n\n");
1620 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1621 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1622 }
1623 else
1624 {
1625 // Some other unexpected error occurred
1626 wxString tStr;
1627 tStr = wxT("Database insert failed\n\n");
1628 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1629 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1630 }
1631 }
1632 }
1633 else // mode == mEdit
1634 {
1635 wxGetApp().Contact->GetDb()->RollbackTrans();
1636 wxGetApp().Contact->whereStr.Printf("NAME = '%s'",saveName.c_str());
1637 if (!wxGetApp().Contact->UpdateWhere(wxGetApp().Contact->whereStr))
1638 {
1639 wxString tStr;
1640 tStr = wxT("Database update failed\n\n");
1641 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1642 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1643 failed = TRUE;
1644 }
1645 }
1646
1647 if (!failed)
1648 {
1649 wxGetApp().Contact->GetDb()->CommitTrans();
1650 SetMode(mView); // Sets the dialog mode back to viewing after save is successful
1651 }
1652 else
1653 wxGetApp().Contact->GetDb()->RollbackTrans();
1654
1655 wxEndBusyCursor();
1656 }
1657
1658 return !failed;
1659 } // CeditorDlg::Save()
1660
1661
1662 /*
1663 * Where this program is only showing a single row at a time in the dialog,
1664 * a special where clause must be built to find just the single row which,
1665 * in sequence, would follow the currently displayed row.
1666 */
1667 bool CeditorDlg::GetNextRec()
1668 {
1669 wxString w;
1670
1671 if (wxGetApp().Contact->GetDb()->Dbms() != dbmsPOSTGRES &&
1672 wxGetApp().Contact->GetDb()->Dbms() != dbmsMY_SQL)
1673 {
1674 w = wxT("NAME = (SELECT MIN(NAME) FROM ");
1675 w += wxGetApp().Contact->GetTableName();
1676 w += wxT(" WHERE NAME > '");
1677 }
1678 else
1679 w = wxT("(NAME > '");
1680
1681 w += wxGetApp().Contact->Name;
1682 w += wxT("'");
1683
1684 // If a query where string is currently set, append that criteria
1685 if (!wxGetApp().Contact->qryWhereStr.IsEmpty())
1686 {
1687 w += wxT(" AND (");
1688 w += wxGetApp().Contact->qryWhereStr;
1689 w += wxT(")");
1690 }
1691
1692 w += wxT(")");
1693 return(GetRec(w));
1694
1695 } // CeditorDlg::GetNextRec()
1696
1697
1698 /*
1699 * Where this program is only showing a single row at a time in the dialog,
1700 * a special where clause must be built to find just the single row which,
1701 * in sequence, would precede the currently displayed row.
1702 */
1703 bool CeditorDlg::GetPrevRec()
1704 {
1705 wxString w;
1706
1707 if (wxGetApp().Contact->GetDb()->Dbms() != dbmsPOSTGRES &&
1708 wxGetApp().Contact->GetDb()->Dbms() != dbmsMY_SQL)
1709 {
1710 w = wxT("NAME = (SELECT MAX(NAME) FROM ");
1711 w += wxGetApp().Contact->GetTableName();
1712 w += wxT(" WHERE NAME < '");
1713 }
1714 else
1715 w = wxT("(NAME < '");
1716
1717 w += wxGetApp().Contact->Name;
1718 w += wxT("'");
1719
1720 // If a query where string is currently set, append that criteria
1721 if (!wxGetApp().Contact->qryWhereStr.IsEmpty())
1722 {
1723 w += wxT(" AND (");
1724 w += wxGetApp().Contact->qryWhereStr;
1725 w += wxT(")");
1726 }
1727
1728 w += wxT(")");
1729
1730 return(GetRec(w));
1731
1732 } // CeditorDlg::GetPrevRec()
1733
1734
1735 /*
1736 * This function is here to avoid duplicating this same code in both the
1737 * GetPrevRec() and GetNextRec() functions
1738 */
1739 bool CeditorDlg::GetRec(const wxString &whereStr)
1740 {
1741 wxGetApp().Contact->SetWhereClause(whereStr);
1742 wxGetApp().Contact->SetOrderByClause(wxT("NAME"));
1743
1744 if (!wxGetApp().Contact->Query())
1745 {
1746 wxString tStr;
1747 tStr = wxT("ODBC error during Query()\n\n");
1748 tStr += GetExtendedDBErrorMsg(wxGetApp().Contact->GetDb(),__FILE__,__LINE__);
1749 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1750
1751 return(FALSE);
1752 }
1753
1754 if (wxGetApp().Contact->GetNext())
1755 {
1756 PutData();
1757 return(TRUE);
1758 }
1759 else
1760 return(FALSE);
1761 } // CeditorDlg::GetRec()
1762
1763
1764
1765 /*
1766 * CparameterDlg constructor
1767 */
1768
1769 BEGIN_EVENT_TABLE(CparameterDlg, wxDialog)
1770 EVT_BUTTON(PARAMETER_DIALOG_SAVE, CparameterDlg::OnButton)
1771 EVT_BUTTON(PARAMETER_DIALOG_CANCEL, CparameterDlg::OnButton)
1772 EVT_CLOSE(CparameterDlg::OnCloseWindow)
1773 END_EVENT_TABLE()
1774
1775 CparameterDlg::CparameterDlg(wxWindow *parent) : wxDialog (parent, PARAMETER_DIALOG, wxT("ODBC parameter settings"), wxPoint(-1, -1), wxSize(400, 325))
1776 {
1777 // Since the ::OnCommand() function is overridden, this prevents the widget
1778 // detection in ::OnCommand() until all widgets have been initialized to prevent
1779 // uninitialized pointers from crashing the program
1780 widgetPtrsSet = FALSE;
1781
1782 pParamODBCSourceMsg = new wxStaticText(this, PARAMETER_DIALOG_SOURCE_MSG, wxT("ODBC data sources:"), wxPoint( 10, 10), wxSize( -1, -1), 0, wxT("ParamODBCSourceMsg"));
1783 pParamODBCSourceList = new wxListBox(this, PARAMETER_DIALOG_SOURCE_LISTBOX, wxPoint( 10, 29), wxSize(285, 150), 0, 0, wxLB_SINGLE|wxLB_ALWAYS_SB, wxDefaultValidator, wxT("ParamODBCSourceList"));
1784 pParamUserNameMsg = new wxStaticText(this, PARAMETER_DIALOG_NAME_MSG, wxT("Database user name:"), wxPoint( 10, 193), wxSize( -1, -1), 0, wxT("ParamUserNameMsg"));
1785 pParamUserNameTxt = new wxTextCtrl(this, PARAMETER_DIALOG_NAME_TEXT, wxT(""), wxPoint(10, 209), wxSize( 140, 25), 0, wxDefaultValidator, wxT("ParamUserNameTxt"));
1786 pParamPasswordMsg = new wxStaticText(this, PARAMETER_DIALOG_PASSWORD_MSG, wxT("Password:"), wxPoint(156, 193), wxSize( -1, -1), 0, wxT("ParamPasswordMsg"));
1787 pParamPasswordTxt = new wxTextCtrl(this, PARAMETER_DIALOG_PASSWORD_TEXT, wxT(""), wxPoint(156, 209), wxSize( 140, 25), 0, wxDefaultValidator, wxT("ParamPasswordTxt"));
1788 pParamDirPathMsg = new wxStaticText(this, PARAMETER_DIALOG_DIRPATH_MSG, wxT("Directory:"), wxPoint( 10, 243), wxSize( -1, -1), 0, wxT("ParamDirPathMsg"));
1789 pParamDirPathTxt = new wxTextCtrl(this, PARAMETER_DIALOG_DIRPATH_TEXT, wxT(""), wxPoint( 10, 259), wxSize(140, 25), 0, wxDefaultValidator, wxT("ParamDirPathTxt"));
1790 pParamSaveBtn = new wxButton(this, PARAMETER_DIALOG_SAVE, wxT("&Save"), wxPoint(310, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("ParamSaveBtn"));
1791 pParamCancelBtn = new wxButton(this, PARAMETER_DIALOG_CANCEL, wxT("C&ancel"), wxPoint(310, 66), wxSize( 70, 35), 0, wxDefaultValidator, wxT("ParamCancelBtn"));
1792
1793 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
1794 // handle all widget processing
1795 widgetPtrsSet = TRUE;
1796
1797 saved = FALSE;
1798 savedParamSettings = wxGetApp().params;
1799
1800 Centre(wxBOTH);
1801 PutData();
1802 ShowModal();
1803 } // CparameterDlg constructor
1804
1805
1806 void CparameterDlg::OnCloseWindow(wxCloseEvent& event)
1807 {
1808 // Put any additional checking necessary to make certain it is alright
1809 // to close the program here that is not done elsewhere
1810 if (!saved)
1811 {
1812 bool Ok = (wxMessageBox(wxT("No changes have been saved.\n\nAre you sure you wish exit the parameter screen?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
1813
1814 if (!Ok)
1815 {
1816 event.Veto();
1817 return;
1818 }
1819
1820 wxGetApp().params = savedParamSettings;
1821 }
1822
1823 if (GetParent() != NULL)
1824 GetParent()->SetFocus();
1825
1826 while (wxIsBusy())
1827 wxEndBusyCursor();
1828
1829 Show(FALSE);
1830 SetReturnCode(0); // added so BoundsChecker would not report use of uninitialized variable
1831
1832 this->Destroy();
1833 } // CparameterDlg::OnCloseWindow()
1834
1835
1836 void CparameterDlg::OnButton( wxCommandEvent &event )
1837 {
1838 wxWindow *win = (wxWindow*) event.GetEventObject();
1839 OnCommand( *win, event );
1840 }
1841
1842
1843 void CparameterDlg::OnCommand(wxWindow& win, wxCommandEvent& event)
1844 {
1845 wxString widgetName;
1846
1847 widgetName = win.GetName();
1848
1849 if (!widgetPtrsSet)
1850 return;
1851
1852 if (widgetName == pParamSaveBtn->GetName())
1853 {
1854 if (Save())
1855 {
1856 wxString tStr;
1857 tStr = wxT("Database parameters have been saved.");
1858 if (GetParent() != NULL) // The parameter dialog was not called during startup due to a missing cfg file
1859 tStr += wxT("\nNew parameters will take effect the next time the program is started.");
1860 wxMessageBox(tStr,wxT("Notice..."),wxOK | wxICON_INFORMATION);
1861 saved = TRUE;
1862 Close();
1863 }
1864 return;
1865 }
1866
1867 if (widgetName == pParamCancelBtn->GetName())
1868 {
1869 Close();
1870 return;
1871 }
1872 } // CparameterDlg::OnCommand()
1873
1874
1875 bool CparameterDlg::PutData()
1876 {
1877 // Fill the data source list box
1878 FillDataSourceList();
1879
1880 // Fill in the fields from the params object
1881 if (wxGetApp().params.ODBCSource && wxStrlen(wxGetApp().params.ODBCSource))
1882 pParamODBCSourceList->SetStringSelection(wxGetApp().params.ODBCSource);
1883 pParamUserNameTxt->SetValue(wxGetApp().params.UserName);
1884 pParamPasswordTxt->SetValue(wxGetApp().params.Password);
1885 pParamDirPathTxt->SetValue(wxGetApp().params.DirPath);
1886 return TRUE;
1887 } // CparameterDlg::PutData()
1888
1889
1890 bool CparameterDlg::GetData()
1891 {
1892 wxString tStr;
1893 if (pParamODBCSourceList->GetStringSelection() != wxT(""))
1894 {
1895 tStr = pParamODBCSourceList->GetStringSelection();
1896 if (tStr.Length() > (sizeof(wxGetApp().params.ODBCSource)-1))
1897 {
1898 wxString errmsg;
1899 errmsg.Printf(wxT("ODBC Data source name is longer than the data structure to hold it.\n'Cparameter.ODBCSource' must have a larger character array\nto handle a data source with this long of a name\n\nThe data source currently selected is %d characters long."),tStr.Length());
1900 wxMessageBox(errmsg,wxT("Internal program error..."),wxOK | wxICON_EXCLAMATION);
1901 return FALSE;
1902 }
1903 wxStrcpy(wxGetApp().params.ODBCSource, tStr);
1904 }
1905 else
1906 return FALSE;
1907
1908 tStr = pParamUserNameTxt->GetValue();
1909 if (tStr.Length() > (sizeof(wxGetApp().params.UserName)-1))
1910 {
1911 wxString errmsg;
1912 errmsg.Printf(wxT("User name is longer than the data structure to hold it.\n'Cparameter.UserName' must have a larger character array\nto handle a data source with this long of a name\n\nThe user name currently specified is %d characters long."),tStr.Length());
1913 wxMessageBox(errmsg,wxT("Internal program error..."),wxOK | wxICON_EXCLAMATION);
1914 return FALSE;
1915 }
1916 wxStrcpy(wxGetApp().params.UserName, tStr);
1917
1918 tStr = pParamPasswordTxt->GetValue();
1919 if (tStr.Length() > (sizeof(wxGetApp().params.Password)-1))
1920 {
1921 wxString errmsg;
1922 errmsg.Printf(wxT("Password is longer than the data structure to hold it.\n'Cparameter.Password' must have a larger character array\nto handle a data source with this long of a name\n\nThe password currently specified is %d characters long."),tStr.Length());
1923 wxMessageBox(errmsg,wxT("Internal program error..."),wxOK | wxICON_EXCLAMATION);
1924 return FALSE;
1925 }
1926 wxStrcpy(wxGetApp().params.Password,tStr);
1927
1928 tStr = pParamDirPathTxt->GetValue();
1929 tStr.Replace(wxT("\\"),wxT("/"));
1930 if (tStr.Length() > (sizeof(wxGetApp().params.DirPath)-1))
1931 {
1932 wxString errmsg;
1933 errmsg.Printf(wxT("DirPath is longer than the data structure to hold it.\n'Cparameter.DirPath' must have a larger character array\nto handle a data source with this long of a name\n\nThe password currently specified is %d characters long."),tStr.Length());
1934 wxMessageBox(errmsg,wxT("Internal program error..."),wxOK | wxICON_EXCLAMATION);
1935 return FALSE;
1936 }
1937 wxStrcpy(wxGetApp().params.DirPath,tStr);
1938 return TRUE;
1939 } // CparameterDlg::GetData()
1940
1941
1942 bool CparameterDlg::Save()
1943 {
1944 // Copy the current params in case user cancels changing
1945 // the params, so that we can reset them.
1946 if (!GetData())
1947 {
1948 wxGetApp().params = savedParamSettings;
1949 return FALSE;
1950 }
1951
1952 wxGetApp().WriteParamFile(wxGetApp().params);
1953
1954 return TRUE;
1955 } // CparameterDlg::Save()
1956
1957
1958 void CparameterDlg::FillDataSourceList()
1959 {
1960 wxChar Dsn[SQL_MAX_DSN_LENGTH + 1];
1961 wxChar DsDesc[255];
1962 wxStringList strList;
1963
1964 while (wxDbGetDataSource(wxGetApp().DbConnectInf->GetHenv(), Dsn,
1965 SQL_MAX_DSN_LENGTH+1, DsDesc, 255))
1966 strList.Add(Dsn);
1967
1968 strList.Sort();
1969 strList.Add(wxT(""));
1970 wxChar **p = strList.ListToArray();
1971
1972 int i;
1973 for (i = 0; wxStrlen(p[i]); i++)
1974 pParamODBCSourceList->Append(p[i]);
1975
1976 wxDELETEA(p);
1977 } // CparameterDlg::FillDataSourceList()
1978
1979
1980 BEGIN_EVENT_TABLE(CqueryDlg, wxDialog)
1981 EVT_BUTTON(-1, CqueryDlg::OnButton)
1982 EVT_CLOSE(CqueryDlg::OnCloseWindow)
1983 END_EVENT_TABLE()
1984
1985
1986 // CqueryDlg() constructor
1987 CqueryDlg::CqueryDlg(wxWindow *parent, wxDb *pDb, wxChar *tblName[],
1988 const wxString &pWhereArg) :
1989 wxDialog (parent, QUERY_DIALOG, wxT("Query"), wxPoint(-1, -1), wxSize(480, 360))
1990 {
1991 wxBeginBusyCursor();
1992
1993 colInf = 0;
1994 dbTable = 0;
1995 masterTableName = tblName[0];
1996 widgetPtrsSet = FALSE;
1997 pDB = pDb;
1998
1999 // Initialize the WHERE clause from the string passed in
2000 pWhere = pWhereArg; // Save a pointer to the output buffer
2001 if (pWhere.Length() > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN) // Check the length of the buffer passed in
2002 {
2003 wxString s;
2004 s.Printf(wxT("Maximum where clause length exceeded.\nLength must be less than %d"), DB_MAX_WHERE_CLAUSE_LEN+1);
2005 wxMessageBox(s,wxT("Error..."),wxOK | wxICON_EXCLAMATION);
2006 Close();
2007 return;
2008 }
2009
2010 pQueryCol1Msg = new wxStaticText(this, QUERY_DIALOG_COL_MSG, wxT("Column 1:"), wxPoint( 10, 10), wxSize( 69, 16), 0, wxT("QueryCol1Msg"));
2011 pQueryCol1Choice = new wxChoice(this, QUERY_DIALOG_COL_CHOICE, wxPoint( 10, 27), wxSize(250, 27), 0, 0, 0, wxDefaultValidator, wxT("QueryCol1Choice"));
2012 pQueryNotMsg = new wxStaticText(this, QUERY_DIALOG_NOT_MSG, wxT("NOT"), wxPoint(268, 10), wxSize( -1, -1), 0, wxT("QueryNotMsg"));
2013 pQueryNotCheck = new wxCheckBox(this, QUERY_DIALOG_NOT_CHECKBOX, wxT(""), wxPoint(275, 37), wxSize( 20, 20), 0, wxDefaultValidator, wxT("QueryNotCheck"));
2014
2015 wxString choice_strings[9];
2016 choice_strings[0] = wxT("=");
2017 choice_strings[1] = wxT("<");
2018 choice_strings[2] = wxT(">");
2019 choice_strings[3] = wxT("<=");
2020 choice_strings[4] = wxT(">=");
2021 choice_strings[5] = wxT("Begins");
2022 choice_strings[6] = wxT("Contains");
2023 choice_strings[7] = wxT("Like");
2024 choice_strings[8] = wxT("Between");
2025
2026 pQueryOperatorMsg = new wxStaticText(this, QUERY_DIALOG_OP_MSG, wxT("Operator:"), wxPoint(305, 10), wxSize( -1, -1), 0, wxT("QueryOperatorMsg"));
2027 pQueryOperatorChoice = new wxChoice(this, QUERY_DIALOG_OP_CHOICE, wxPoint(305, 27), wxSize( 80, 27), 9, choice_strings, 0, wxDefaultValidator, wxT("QueryOperatorChoice"));
2028 pQueryCol2Msg = new wxStaticText(this, QUERY_DIALOG_COL2_MSG, wxT("Column 2:"), wxPoint( 10, 65), wxSize( 69, 16), 0, wxT("QueryCol2Msg"));
2029 pQueryCol2Choice = new wxChoice(this, QUERY_DIALOG_COL2_CHOICE, wxPoint( 10, 82), wxSize(250, 27), 0, 0, 0, wxDefaultValidator, wxT("QueryCol2Choice"));
2030 pQuerySqlWhereMsg = new wxStaticText(this, QUERY_DIALOG_WHERE_MSG, wxT("SQL where clause:"), wxPoint( 10, 141), wxSize( -1, -1), 0, wxT("QuerySqlWhereMsg"));
2031 pQuerySqlWhereMtxt = new wxTextCtrl(this, QUERY_DIALOG_WHERE_TEXT, wxT(""), wxPoint( 10, 159), wxSize(377, 134), wxTE_MULTILINE, wxDefaultValidator, wxT("QuerySqlWhereMtxt"));
2032 pQueryAddBtn = new wxButton(this, QUERY_DIALOG_ADD, wxT("&Add"), wxPoint(406, 24), wxSize( 56, 26), 0, wxDefaultValidator, wxT("QueryAddBtn"));
2033 pQueryAndBtn = new wxButton(this, QUERY_DIALOG_AND, wxT("A&nd"), wxPoint(406, 58), wxSize( 56, 26), 0, wxDefaultValidator, wxT("QueryAndBtn"));
2034 pQueryOrBtn = new wxButton(this, QUERY_DIALOG_OR, wxT("&Or"), wxPoint(406, 92), wxSize( 56, 26), 0, wxDefaultValidator, wxT("QueryOrBtn"));
2035 pQueryLParenBtn = new wxButton(this, QUERY_DIALOG_LPAREN, wxT("("), wxPoint(406, 126), wxSize( 26, 26), 0, wxDefaultValidator, wxT("QueryLParenBtn"));
2036 pQueryRParenBtn = new wxButton(this, QUERY_DIALOG_RPAREN, wxT(")"), wxPoint(436, 126), wxSize( 26, 26), 0, wxDefaultValidator, wxT("QueryRParenBtn"));
2037 pQueryDoneBtn = new wxButton(this, QUERY_DIALOG_DONE, wxT("&Done"), wxPoint(406, 185), wxSize( 56, 26), 0, wxDefaultValidator, wxT("QueryDoneBtn"));
2038 pQueryClearBtn = new wxButton(this, QUERY_DIALOG_CLEAR, wxT("C&lear"), wxPoint(406, 218), wxSize( 56, 26), 0, wxDefaultValidator, wxT("QueryClearBtn"));
2039 pQueryCountBtn = new wxButton(this, QUERY_DIALOG_COUNT, wxT("&Count"), wxPoint(406, 252), wxSize( 56, 26), 0, wxDefaultValidator, wxT("QueryCountBtn"));
2040 pQueryValue1Msg = new wxStaticText(this, QUERY_DIALOG_VALUE1_MSG, wxT("Value:"), wxPoint(277, 66), wxSize( -1, -1), 0, wxT("QueryValue1Msg"));
2041 pQueryValue1Txt = new wxTextCtrl(this, QUERY_DIALOG_VALUE1_TEXT, wxT(""), wxPoint(277, 83), wxSize(108, 25), 0, wxDefaultValidator, wxT("QueryValue1Txt"));
2042 pQueryValue2Msg = new wxStaticText(this, QUERY_DIALOG_VALUE2_MSG, wxT("AND"), wxPoint(238, 126), wxSize( -1, -1), 0, wxT("QueryValue2Msg"));
2043 pQueryValue2Txt = new wxTextCtrl(this, QUERY_DIALOG_VALUE2_TEXT, wxT(""), wxPoint(277, 120), wxSize(108, 25), 0, wxDefaultValidator, wxT("QueryValue2Txt"));
2044 pQueryHintGrp = new wxStaticBox(this, QUERY_DIALOG_HINT_GROUP, wxT(""), wxPoint( 10, 291), wxSize(377, 40), 0, wxT("QueryHintGrp"));
2045 pQueryHintMsg = new wxStaticText(this, QUERY_DIALOG_HINT_MSG, wxT(""), wxPoint( 16, 306), wxSize( -1, -1), 0, wxT("QueryHintMsg"));
2046
2047 widgetPtrsSet = TRUE;
2048 // Initialize the dialog
2049 wxString qualName;
2050 pQueryCol2Choice->Append(wxT("VALUE -->"));
2051 colInf = pDB->GetColumns(tblName);
2052
2053 if (!colInf)
2054 {
2055 wxEndBusyCursor();
2056 wxString tStr;
2057 tStr = wxT("ODBC error during GetColumns()\n\n");
2058 tStr += GetExtendedDBErrorMsg(pDb,__FILE__,__LINE__);
2059 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
2060 return;
2061 }
2062
2063 int i;
2064 for (i = 0; colInf[i].colName && wxStrlen(colInf[i].colName); i++)
2065 {
2066 // If there is more than one table being queried, qualify
2067 // the column names with the table name prefix.
2068 if (tblName[1] && wxStrlen(tblName[1]))
2069 {
2070 qualName.Printf(wxT("%s.%s"), colInf[i].tableName, colInf[i].colName);
2071 pQueryCol1Choice->Append(qualName);
2072 pQueryCol2Choice->Append(qualName);
2073 }
2074 else // Single table query, append just the column names
2075 {
2076 pQueryCol1Choice->Append(colInf[i].colName);
2077 pQueryCol2Choice->Append(colInf[i].colName);
2078 }
2079 }
2080
2081 pQueryCol1Choice->SetSelection(0);
2082 pQueryCol2Choice->SetSelection(0);
2083 pQueryOperatorChoice->SetSelection(0);
2084
2085 pQueryValue2Msg->Show(FALSE);
2086 pQueryValue2Txt->Show(FALSE);
2087
2088 pQueryHintMsg->SetLabel(langQRY_EQ);
2089
2090 pQuerySqlWhereMtxt->SetValue(pWhere.c_str());
2091
2092 wxEndBusyCursor();
2093
2094 // Display the dialog window
2095 Centre(wxBOTH);
2096 ShowModal();
2097 } // CqueryDlg() constructor
2098
2099
2100 CqueryDlg::~CqueryDlg()
2101 {
2102 } // CqueryDlg::~CqueryDlg() destructor
2103
2104
2105 void CqueryDlg::OnButton(wxCommandEvent &event)
2106 {
2107 wxWindow *win = (wxWindow*) event.GetEventObject();
2108 OnCommand( *win, event );
2109 } // CqueryDlg::OnButton()
2110
2111
2112 void CqueryDlg::OnCommand(wxWindow& win, wxCommandEvent& event)
2113 {
2114 // Widget pointers won't be set when the dialog is constructed.
2115 // Control is passed through this function once for each widget on
2116 // a dialog as the dialog is constructed.
2117 if (!widgetPtrsSet)
2118 return;
2119
2120 wxString widgetName = win.GetName();
2121
2122 // Operator choice box
2123 if (widgetName == pQueryOperatorChoice->GetName())
2124 {
2125 // Set the help text
2126 switch((qryOp) pQueryOperatorChoice->GetSelection())
2127 {
2128 case qryOpEQ:
2129 pQueryHintMsg->SetLabel(langQRY_EQ);
2130 break;
2131 case qryOpLT:
2132 pQueryHintMsg->SetLabel(langQRY_LT);
2133 break;
2134 case qryOpGT:
2135 pQueryHintMsg->SetLabel(langQRY_GT);
2136 break;
2137 case qryOpLE:
2138 pQueryHintMsg->SetLabel(langQRY_LE);
2139 break;
2140 case qryOpGE:
2141 pQueryHintMsg->SetLabel(langQRY_GE);
2142 break;
2143 case qryOpBEGINS:
2144 pQueryHintMsg->SetLabel(langQRY_BEGINS);
2145 break;
2146 case qryOpCONTAINS:
2147 pQueryHintMsg->SetLabel(langQRY_CONTAINS);
2148 break;
2149 case qryOpLIKE:
2150 pQueryHintMsg->SetLabel(langQRY_LIKE);
2151 break;
2152 case qryOpBETWEEN:
2153 pQueryHintMsg->SetLabel(langQRY_BETWEEN);
2154 break;
2155 }
2156
2157 // Hide the value2 widget
2158 pQueryValue2Msg->Show(FALSE); // BETWEEN will show this widget
2159 pQueryValue2Txt->Show(FALSE); // BETWEEN will show this widget
2160
2161 // Disable the NOT operator for <, <=, >, >=
2162 switch((qryOp) pQueryOperatorChoice->GetSelection())
2163 {
2164 case qryOpLT:
2165 case qryOpGT:
2166 case qryOpLE:
2167 case qryOpGE:
2168 pQueryNotCheck->SetValue(0);
2169 pQueryNotCheck->Enable(FALSE);
2170 break;
2171 default:
2172 pQueryNotCheck->Enable(TRUE);
2173 break;
2174 }
2175
2176 // Manipulate the dialog to handle the selected operator
2177 switch((qryOp) pQueryOperatorChoice->GetSelection())
2178 {
2179 case qryOpEQ:
2180 case qryOpLT:
2181 case qryOpGT:
2182 case qryOpLE:
2183 case qryOpGE:
2184 pQueryCol2Choice->Enable(TRUE);
2185 if (pQueryCol2Choice->GetSelection()) // Column name is highlighted
2186 {
2187 pQueryValue1Msg->Show(FALSE);
2188 pQueryValue1Txt->Show(FALSE);
2189 }
2190 else // "Value" is highlighted
2191 {
2192 pQueryValue1Msg->Show(TRUE);
2193 pQueryValue1Txt->Show(TRUE);
2194 pQueryValue1Txt->SetFocus();
2195 }
2196 break;
2197 case qryOpBEGINS:
2198 case qryOpCONTAINS:
2199 case qryOpLIKE:
2200 pQueryCol2Choice->SetSelection(0);
2201 pQueryCol2Choice->Enable(FALSE);
2202 pQueryValue1Msg->Show(TRUE);
2203 pQueryValue1Txt->Show(TRUE);
2204 pQueryValue1Txt->SetFocus();
2205 break;
2206 case qryOpBETWEEN:
2207 pQueryCol2Choice->SetSelection(0);
2208 pQueryCol2Choice->Enable(FALSE);
2209 pQueryValue2Msg->Show(TRUE);
2210 pQueryValue2Txt->Show(TRUE);
2211 pQueryValue1Msg->Show(TRUE);
2212 pQueryValue1Txt->Show(TRUE);
2213 pQueryValue1Txt->SetFocus();
2214 break;
2215 }
2216
2217 return;
2218
2219 } // Operator choice box
2220
2221 // Column 2 choice
2222 if (widgetName == pQueryCol2Choice->GetName())
2223 {
2224 if (pQueryCol2Choice->GetSelection()) // Column name is highlighted
2225 {
2226 pQueryValue1Msg->Show(FALSE);
2227 pQueryValue1Txt->Show(FALSE);
2228 }
2229 else // "Value" is highlighted
2230 {
2231 pQueryValue1Msg->Show(TRUE);
2232 pQueryValue1Txt->Show(TRUE);
2233 pQueryValue1Txt->SetFocus();
2234 }
2235 return;
2236 } // Column 2 choice
2237
2238 // Add button
2239 if (widgetName == pQueryAddBtn->GetName())
2240 {
2241 ProcessAddBtn();
2242 return;
2243 } // Add button
2244
2245 // And button
2246 if (widgetName == pQueryAndBtn->GetName())
2247 {
2248 AppendToWhere(wxT(" AND\n"));
2249 return;
2250 } // And button
2251
2252 // Or button
2253 if (widgetName == pQueryOrBtn->GetName())
2254 {
2255 AppendToWhere(wxT(" OR\n"));
2256 return;
2257 } // Or button
2258
2259 // Left Paren button
2260 if (widgetName == pQueryLParenBtn->GetName())
2261 {
2262 AppendToWhere(wxT("("));
2263 return;
2264 } // Left Paren button
2265
2266 // Right paren button
2267 if (widgetName == pQueryRParenBtn->GetName())
2268 {
2269 AppendToWhere(wxT(")"));
2270 return;
2271 } // Right Paren button
2272
2273 // Done button
2274 if (widgetName == pQueryDoneBtn->GetName())
2275 {
2276 // Be sure the where clause will not overflow the output buffer
2277 if (wxStrlen(pQuerySqlWhereMtxt->GetValue()) > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN)
2278 {
2279 wxString s;
2280 s.Printf(wxT("Maximum where clause length exceeded.\nLength must be less than %d"), DB_MAX_WHERE_CLAUSE_LEN+1);
2281 wxMessageBox(s,wxT("Error..."),wxOK | wxICON_EXCLAMATION);
2282 return;
2283 }
2284 // Validate the where clause for things such as matching parens
2285 if (!ValidateWhereClause())
2286 return;
2287 // Copy the where clause to the output buffer and exit
2288 pWhere = pQuerySqlWhereMtxt->GetValue();
2289 Close();
2290 return;
2291 } // Done button
2292
2293 // Clear button
2294 if (widgetName == pQueryClearBtn->GetName())
2295 {
2296 bool Ok = (wxMessageBox(wxT("Are you sure you wish to clear the Query?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
2297
2298 if (Ok)
2299 pQuerySqlWhereMtxt->SetValue(wxT(""));
2300 return;
2301 } // Clear button
2302
2303 // Count button
2304 if (widgetName == pQueryCountBtn->GetName())
2305 {
2306 wxBeginBusyCursor();
2307 ProcessCountBtn();
2308 wxEndBusyCursor();
2309 return;
2310 } // Count button
2311
2312 } // CqueryDlg::OnCommand
2313
2314
2315 void CqueryDlg::OnCloseWindow(wxCloseEvent& event)
2316 {
2317 // Clean up
2318 wxDELETEA(colInf);
2319
2320 wxDELETE(dbTable);
2321
2322 GetParent()->SetFocus();
2323 while (wxIsBusy())
2324 wxEndBusyCursor();
2325
2326 Show(FALSE);
2327 SetReturnCode(1); // added so BoundsChecker would not report use of uninitialized variable
2328
2329 this->Destroy();
2330 } // CqueryDlg::OnCloseWindow()
2331
2332
2333 void CqueryDlg::AppendToWhere(wxChar *s)
2334 {
2335 wxString whereStr = pQuerySqlWhereMtxt->GetValue();
2336 whereStr += s;
2337 pQuerySqlWhereMtxt->SetValue(whereStr);
2338 } // CqueryDlg::AppendToWhere()
2339
2340
2341 void CqueryDlg::ProcessAddBtn()
2342 {
2343 qryOp oper = (qryOp) pQueryOperatorChoice->GetSelection();
2344
2345 // Verify that eveything is filled in correctly
2346 if (pQueryCol2Choice->GetSelection() == 0) // "Value" is selected
2347 {
2348 // Verify that value 1 is filled in
2349 if (wxStrlen(pQueryValue1Txt->GetValue()) == 0)
2350 {
2351 wxBell();
2352 pQueryValue1Txt->SetFocus();
2353 return;
2354 }
2355 // For the BETWEEN operator, value 2 must be filled in as well
2356 if (oper == qryOpBETWEEN &&
2357 wxStrlen(pQueryValue2Txt->GetValue()) == 0)
2358 {
2359 wxBell();
2360 pQueryValue2Txt->SetFocus();
2361 return;
2362 }
2363 }
2364
2365 // Build the expression and append it to the where clause window
2366 wxString s = pQueryCol1Choice->GetStringSelection();
2367
2368 if (pQueryNotCheck->GetValue() && (oper != qryOpEQ))
2369 s += wxT(" NOT");
2370
2371 switch(oper)
2372 {
2373 case qryOpEQ:
2374 if (pQueryNotCheck->GetValue()) // NOT box is checked
2375 s += wxT(" <>");
2376 else
2377 s += wxT(" =");
2378 break;
2379 case qryOpLT:
2380 s += wxT(" <");
2381 break;
2382 case qryOpGT:
2383 s += wxT(" >");
2384 break;
2385 case qryOpLE:
2386 s += wxT(" <=");
2387 break;
2388 case qryOpGE:
2389 s += wxT(" >=");
2390 break;
2391 case qryOpBEGINS:
2392 case qryOpCONTAINS:
2393 case qryOpLIKE:
2394 s += wxT(" LIKE");
2395 break;
2396 case qryOpBETWEEN:
2397 s += wxT(" BETWEEN");
2398 break;
2399 }
2400
2401 s += wxT(" ");
2402
2403 int col1Idx = pQueryCol1Choice->GetSelection();
2404
2405 bool quote = FALSE;
2406 if (colInf[col1Idx].sqlDataType == SQL_VARCHAR ||
2407 oper == qryOpBEGINS ||
2408 oper == qryOpCONTAINS ||
2409 oper == qryOpLIKE)
2410 quote = TRUE;
2411
2412 if (pQueryCol2Choice->GetSelection()) // Column name
2413 s += pQueryCol2Choice->GetStringSelection();
2414 else // Column 2 is a "value"
2415 {
2416 if (quote)
2417 s += wxT("'");
2418 if (oper == qryOpCONTAINS)
2419 s += wxT("%");
2420 s += pQueryValue1Txt->GetValue();
2421 if (oper == qryOpCONTAINS || oper == qryOpBEGINS)
2422 s += wxT("%");
2423 if (quote)
2424 s += wxT("'");
2425 }
2426
2427 if (oper == qryOpBETWEEN)
2428 {
2429 s += wxT(" AND ");
2430 if (quote)
2431 s += wxT("'");
2432 s += pQueryValue2Txt->GetValue();
2433 if (quote)
2434 s += wxT("'");
2435 }
2436
2437 AppendToWhere((wxChar*) (const wxChar*) s);
2438
2439 } // CqueryDlg::ProcessAddBtn()
2440
2441
2442 void CqueryDlg::ProcessCountBtn()
2443 {
2444 if (!ValidateWhereClause())
2445 return;
2446
2447 if (!dbTable) // wxDbTable object needs to be created and opened
2448 {
2449 dbTable = new wxDbTable(pDB, masterTableName, 0, wxT(""),
2450 !wxDB_QUERY_ONLY,
2451 wxGetApp().DbConnectInf->GetDefaultDir());
2452 if (!dbTable)
2453 {
2454 wxMessageBox(wxT("Memory allocation failed creating a wxDbTable object."),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
2455 return;
2456 }
2457 if (!dbTable->Open())
2458 {
2459 wxString tStr;
2460 tStr = wxT("ODBC error during Open()\n\n");
2461 tStr += GetExtendedDBErrorMsg(dbTable->GetDb(),__FILE__,__LINE__);
2462 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
2463 return;
2464 }
2465 }
2466
2467 // Count() with WHERE clause
2468 wxString whereStr;
2469
2470 whereStr = pQuerySqlWhereMtxt->GetValue();
2471 dbTable->SetWhereClause(whereStr.c_str());
2472
2473 ULONG whereCnt = dbTable->Count();
2474
2475 // Count() of all records in the table
2476 dbTable->SetWhereClause(wxT(""));
2477 ULONG totalCnt = dbTable->Count();
2478
2479 if (whereCnt > 0 || totalCnt == 0)
2480 {
2481 wxString tStr;
2482 tStr.Printf(wxT("%lu of %lu records match the query criteria."),whereCnt,totalCnt);
2483 wxMessageBox(tStr,wxT("Notice..."),wxOK | wxICON_INFORMATION);
2484 }
2485 else
2486 {
2487 wxString tStr;
2488 tStr.Printf(wxT("%lu of %lu records match the query criteria.\n\nEither the criteria entered produced a result set\nwith no records, or there was a syntactical error\nin the clause you entered.\n\nPress the details button to see if any database errors were reported."),whereCnt,totalCnt);
2489 wxMessageBox(tStr,wxT("Notice..."),wxOK | wxICON_INFORMATION);
2490 }
2491
2492 // After a wxMessageBox, the focus does not necessarily return to the
2493 // window which was the focus when the message box popped up, so return
2494 // focus to the Query dialog for certain
2495 SetFocus();
2496
2497 } // CqueryDlg::ProcessCountBtn()
2498
2499
2500 bool CqueryDlg::ValidateWhereClause()
2501 {
2502 wxString where = pQuerySqlWhereMtxt->GetValue();
2503
2504 if (where.Freq(wxT('(')) != where.Freq(wxT(')')))
2505 {
2506 wxMessageBox(wxT("There are mismatched parenthesis in the constructed where clause"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
2507 return(FALSE);
2508 }
2509 // After a wxMessageBox, the focus does not necessarily return to the
2510 // window which was the focus when the message box popped up, so return
2511 // focus to the Query dialog for certain
2512 SetFocus();
2513
2514 return(TRUE);
2515
2516 } // CqueryDlg::ValidateWhereClause()
2517
2518
2519
2520 void DisplayDbDiagnostics(wxDb *pDb)
2521 {
2522 wxString s, t;
2523 bool comma = FALSE;
2524
2525 s = langDBINF_DB_NAME;
2526 s += pDb->dbInf.dbmsName;
2527 s += "\n";
2528
2529 s += langDBINF_DB_VER;
2530 s += pDb->dbInf.dbmsVer;
2531 s += "\n";
2532
2533 s += langDBINF_DRIVER_NAME;
2534 s += pDb->dbInf.driverName;
2535 s += "\n";
2536
2537 s += langDBINF_DRIVER_ODBC_VER;
2538 s += pDb->dbInf.odbcVer;
2539 s += "\n";
2540
2541 s += langDBINF_DRIVER_MGR_ODBC_VER;
2542 s += pDb->dbInf.drvMgrOdbcVer;
2543 s += "\n";
2544
2545 s += langDBINF_DRIVER_VER;
2546 s += pDb->dbInf.driverVer;
2547 s += "\n";
2548
2549 s += langDBINF_SERVER_NAME;
2550 s += pDb->dbInf.serverName;
2551 s += "\n";
2552
2553 s += langDBINF_FILENAME;
2554 s += pDb->dbInf.databaseName;
2555 s += "\n";
2556
2557 s += langDBINF_OUTER_JOINS;
2558 s += pDb->dbInf.outerJoins;
2559 s += "\n";
2560
2561 s += langDBINF_STORED_PROC;
2562 s += pDb->dbInf.procedureSupport;
2563 s += "\n";
2564
2565 if (pDb->dbInf.maxConnections)
2566 t.sprintf("%s%d\n", langDBINF_MAX_HDBC, pDb->dbInf.maxConnections);
2567 else
2568 t.sprintf("%s%s\n", langDBINF_MAX_HDBC, langDBINF_UNLIMITED);
2569 s += t;
2570
2571 if (pDb->dbInf.maxStmts)
2572 t.sprintf("%s%d\n", langDBINF_MAX_HSTMT, pDb->dbInf.maxStmts);
2573 else
2574 t.sprintf("%s%s\n", langDBINF_MAX_HSTMT, langDBINF_UNLIMITED);
2575 s += t;
2576
2577 s += langDBINF_API_LVL;
2578 switch(pDb->dbInf.apiConfLvl)
2579 {
2580 case SQL_OAC_NONE: s += langDBINF_NONE; break;
2581 case SQL_OAC_LEVEL1: s += langDBINF_LEVEL1; break;
2582 case SQL_OAC_LEVEL2: s += langDBINF_LEVEL2; break;
2583 }
2584 s += "\n";
2585
2586 s += langDBINF_CLI_LVL;
2587 switch(pDb->dbInf.cliConfLvl)
2588 {
2589 case SQL_OSCC_NOT_COMPLIANT: s += langDBINF_NOT_COMPLIANT; break;
2590 case SQL_OSCC_COMPLIANT: s += langDBINF_COMPLIANT; break;
2591 }
2592 s += "\n";
2593
2594 s += langDBINF_SQL_LVL;
2595 switch(pDb->dbInf.sqlConfLvl)
2596 {
2597 case SQL_OSC_MINIMUM: s += langDBINF_MIN_GRAMMAR; break;
2598 case SQL_OSC_CORE: s += langDBINF_CORE_GRAMMAR; break;
2599 case SQL_OSC_EXTENDED: s += langDBINF_EXT_GRAMMAR; break;
2600 }
2601 s += "\n";
2602
2603 s += langDBINF_COMMIT_BEHAVIOR;
2604 switch(pDb->dbInf.cursorCommitBehavior)
2605 {
2606 case SQL_CB_DELETE: s += langDBINF_DELETE_CURSORS; break;
2607 case SQL_CB_CLOSE: s += langDBINF_CLOSE_CURSORS; break;
2608 case SQL_CB_PRESERVE: s += langDBINF_PRESERVE_CURSORS; break;
2609 }
2610 s += "\n";
2611
2612 s += langDBINF_ROLLBACK_BEHAVIOR;
2613 switch(pDb->dbInf.cursorRollbackBehavior)
2614 {
2615 case SQL_CB_DELETE: s += langDBINF_DELETE_CURSORS; break;
2616 case SQL_CB_CLOSE: s += langDBINF_CLOSE_CURSORS; break;
2617 case SQL_CB_PRESERVE: s += langDBINF_PRESERVE_CURSORS; break;
2618 }
2619 s += "\n";
2620
2621 s += langDBINF_SUPP_NOT_NULL;
2622 switch(pDb->dbInf.supportNotNullClause)
2623 {
2624 case SQL_NNC_NULL: s += langNO; break;
2625 case SQL_NNC_NON_NULL: s += langYES; break;
2626 }
2627 s += "\n";
2628
2629 s += langDBINF_SUPP_IEF;
2630 s += pDb->dbInf.supportIEF;
2631 s += "\n";
2632
2633 // DEFAULT setting for "Transaction Isolation Level"
2634 s += langDBINF_TXN_ISOLATION;
2635 switch(pDb->dbInf.txnIsolation)
2636 {
2637 case SQL_TXN_READ_UNCOMMITTED: s += langDBINF_READ_UNCOMMITTED; break;
2638 case SQL_TXN_READ_COMMITTED: s += langDBINF_READ_COMMITTED; break;
2639 case SQL_TXN_REPEATABLE_READ: s += langDBINF_REPEATABLE_READ; break;
2640 case SQL_TXN_SERIALIZABLE: s += langDBINF_SERIALIZABLE; break;
2641 #ifdef ODBC_V20
2642 case SQL_TXN_VERSIONING: s += langDBINF_VERSIONING; break;
2643 #endif
2644 }
2645 s += "\n";
2646
2647 // CURRENT setting for "Transaction Isolation Level"
2648 long txnIsoLvl;
2649 s += langDBINF_TXN_ISOLATION_CURR;
2650 if (SQLGetConnectOption(pDb->GetHDBC(),SQL_TXN_ISOLATION,&txnIsoLvl) == SQL_SUCCESS)
2651 {
2652 switch(txnIsoLvl)
2653 {
2654 case SQL_TXN_READ_UNCOMMITTED: s += langDBINF_READ_UNCOMMITTED; break;
2655 case SQL_TXN_READ_COMMITTED: s += langDBINF_READ_COMMITTED; break;
2656 case SQL_TXN_REPEATABLE_READ: s += langDBINF_REPEATABLE_READ; break;
2657 case SQL_TXN_SERIALIZABLE: s += langDBINF_SERIALIZABLE; break;
2658 #ifdef ODBC_V20
2659 case SQL_TXN_VERSIONING: s += langDBINF_VERSIONING; break;
2660 #endif
2661 }
2662 }
2663 s += "\n";
2664
2665 comma = FALSE;
2666 s += langDBINF_TXN_ISOLATION_OPTS;
2667 if (pDb->dbInf.txnIsolationOptions & SQL_TXN_READ_UNCOMMITTED)
2668 {s += langDBINF_READ_UNCOMMITTED; comma++;}
2669 if (pDb->dbInf.txnIsolationOptions & SQL_TXN_READ_COMMITTED)
2670 {if (comma++) s += ", "; s += langDBINF_READ_COMMITTED;}
2671 if (pDb->dbInf.txnIsolationOptions & SQL_TXN_REPEATABLE_READ)
2672 {if (comma++) s += ", "; s += langDBINF_REPEATABLE_READ;}
2673 if (pDb->dbInf.txnIsolationOptions & SQL_TXN_SERIALIZABLE)
2674 {if (comma++) s += ", "; s += langDBINF_SERIALIZABLE;}
2675 #ifdef ODBC_V20
2676 if (pDb->dbInf.txnIsolationOptions & SQL_TXN_VERSIONING)
2677 {if (comma++) s += ", "; s += langDBINF_VERSIONING;}
2678 #endif
2679 s += "\n";
2680
2681 comma = FALSE;
2682 s += langDBINF_FETCH_DIRS;
2683 if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_NEXT)
2684 {s += langDBINF_NEXT; comma++;}
2685 if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_PRIOR)
2686 {if (comma++) s += ", "; s += langDBINF_PREV;}
2687 if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_FIRST)
2688 {if (comma++) s += ", "; s += langDBINF_FIRST;}
2689 if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_LAST)
2690 {if (comma++) s += ", "; s += langDBINF_LAST;}
2691 if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_ABSOLUTE)
2692 {if (comma++) s += ", "; s += langDBINF_ABSOLUTE;}
2693 if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_RELATIVE)
2694 {if (comma++) s += ", "; s += langDBINF_RELATIVE;}
2695 #ifdef ODBC_V20
2696 if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_RESUME)
2697 {if (comma++) s += ", "; s += langDBINF_RESUME;}
2698 #endif
2699 if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_BOOKMARK)
2700 {if (comma++) s += ", "; s += langDBINF_BOOKMARK;}
2701 s += "\n";
2702
2703 comma = FALSE;
2704 s += langDBINF_LOCK_TYPES;
2705 if (pDb->dbInf.lockTypes & SQL_LCK_NO_CHANGE)
2706 {s += langDBINF_NO_CHANGE; comma++;}
2707 if (pDb->dbInf.lockTypes & SQL_LCK_EXCLUSIVE)
2708 {if (comma++) s += ", "; s += langDBINF_EXCLUSIVE;}
2709 if (pDb->dbInf.lockTypes & SQL_LCK_UNLOCK)
2710 {if (comma++) s += ", "; s += langDBINF_UNLOCK;}
2711 s += "\n";
2712
2713 comma = FALSE;
2714 s += langDBINF_POS_OPERS;
2715 if (pDb->dbInf.posOperations & SQL_POS_POSITION)
2716 {s += langDBINF_POSITION; comma++;}
2717 if (pDb->dbInf.posOperations & SQL_POS_REFRESH)
2718 {if (comma++) s += ", "; s += langDBINF_REFRESH;}
2719 if (pDb->dbInf.posOperations & SQL_POS_UPDATE)
2720 {if (comma++) s += ", "; s += langDBINF_UPD;}
2721 if (pDb->dbInf.posOperations & SQL_POS_DELETE)
2722 {if (comma++) s += ", "; s += langDBINF_DEL;}
2723 if (pDb->dbInf.posOperations & SQL_POS_ADD)
2724 {if (comma++) s += ", "; s += langDBINF_ADD;}
2725 s += "\n";
2726
2727 comma = FALSE;
2728 s += langDBINF_POS_STMTS;
2729 if (pDb->dbInf.posStmts & SQL_PS_POSITIONED_DELETE)
2730 {s += langDBINF_POS_DEL; comma++;}
2731 if (pDb->dbInf.posStmts & SQL_PS_POSITIONED_UPDATE)
2732 {if (comma++) s += ", "; s += langDBINF_POS_UPD;}
2733 if (pDb->dbInf.posStmts & SQL_PS_SELECT_FOR_UPDATE)
2734 {if (comma++) s += ", "; s += langDBINF_SELECT_FOR_UPD;}
2735 s += "\n";
2736
2737 comma = FALSE;
2738 s += langDBINF_SCROLL_CONCURR;
2739 if (pDb->dbInf.scrollConcurrency & SQL_SCCO_READ_ONLY)
2740 {s += langDBINF_READ_ONLY; comma++;}
2741 if (pDb->dbInf.scrollConcurrency & SQL_SCCO_LOCK)
2742 {if (comma++) s += ", "; s += langDBINF_LOCK;}
2743 if (pDb->dbInf.scrollConcurrency & SQL_SCCO_OPT_ROWVER)
2744 {if (comma++) s += ", "; s += langDBINF_OPT_ROWVER;}
2745 if (pDb->dbInf.scrollConcurrency & SQL_SCCO_OPT_VALUES)
2746 {if (comma++) s += ", "; s += langDBINF_OPT_VALUES;}
2747 s += "\n";
2748
2749 comma = FALSE;
2750 s += langDBINF_SCROLL_OPTS;
2751 if (pDb->dbInf.scrollOptions & SQL_SO_FORWARD_ONLY)
2752 {s += langDBINF_FWD_ONLY; comma++;}
2753 if (pDb->dbInf.scrollOptions & SQL_SO_STATIC)
2754 {if (comma++) s += ", "; s += langDBINF_STATIC;}
2755 if (pDb->dbInf.scrollOptions & SQL_SO_KEYSET_DRIVEN)
2756 {if (comma++) s += ", "; s += langDBINF_KEYSET_DRIVEN;}
2757 if (pDb->dbInf.scrollOptions & SQL_SO_DYNAMIC)
2758 {if (comma++) s += ", "; s += langDBINF_DYNAMIC;}
2759 if (pDb->dbInf.scrollOptions & SQL_SO_MIXED)
2760 {if (comma++) s += ", "; s += langDBINF_MIXED;}
2761 s += "\n";
2762
2763 comma = FALSE;
2764 s += langDBINF_STATIC_SENS;
2765 if (pDb->dbInf.staticSensitivity & SQL_SS_ADDITIONS)
2766 {s += langDBINF_ADDITIONS; comma++;}
2767 if (pDb->dbInf.staticSensitivity & SQL_SS_DELETIONS)
2768 {if (comma++) s += ", "; s += langDBINF_DELETIONS;}
2769 if (pDb->dbInf.staticSensitivity & SQL_SS_UPDATES)
2770 {if (comma++) s += ", "; s += langDBINF_UPDATES;}
2771 s += "\n";
2772
2773
2774 s += langDBINF_TXN_CAPABLE;
2775 switch(pDb->dbInf.txnCapable)
2776 {
2777 case SQL_TC_NONE: s += langNO; break;
2778 case SQL_TC_DML: s += langDBINF_DML_ONLY; break;
2779 case SQL_TC_DDL_COMMIT: s += langDBINF_DDL_COMMIT; break;
2780 case SQL_TC_DDL_IGNORE: s += langDBINF_DDL_IGNORE; break;
2781 case SQL_TC_ALL: s += langDBINF_DDL_AND_DML; break;
2782 }
2783 s += "\n";
2784
2785 t.sprintf("%s%d\n", langDBINF_LOGIN_TIMEOUT, pDb->dbInf.loginTimeout);
2786 s += t;
2787
2788 // Oracle specific information
2789 if (pDb->Dbms() == dbmsORACLE)
2790 {
2791 s += "\n";
2792 s += langDBINF_ORACLE_BANNER;
2793 s += "\n";
2794
2795 // Oracle cache hit ratio
2796 SDWORD cb;
2797 ULONG dbBlockGets;
2798 pDb->ExecSql("SELECT VALUE FROM V$SYSSTAT WHERE NAME = 'db block gets'");
2799 pDb->GetNext();
2800 if (pDb->GetData(1, SQL_C_ULONG, &dbBlockGets, 0, &cb))
2801 {
2802 t.sprintf("%s: %lu\n", langDBINF_DB_BLOCK_GETS, dbBlockGets);
2803 s += t;
2804 }
2805
2806 ULONG consistentGets;
2807 pDb->ExecSql("SELECT VALUE FROM V$SYSSTAT WHERE NAME = 'consistent gets'");
2808 pDb->GetNext();
2809 if (pDb->GetData(1, SQL_C_ULONG, &consistentGets, 0, &cb))
2810 {
2811 t.sprintf("%s: %lu\n", langDBINF_CONSISTENT_GETS, consistentGets);
2812 s += t;
2813 }
2814
2815 ULONG physReads;
2816 pDb->ExecSql("SELECT VALUE FROM V$SYSSTAT WHERE NAME = 'physical reads'");
2817 pDb->GetNext();
2818 if (pDb->GetData(1, SQL_C_ULONG, &physReads, 0, &cb))
2819 {
2820 t.sprintf("%s: %lu\n", langDBINF_PHYSICAL_READS, physReads);
2821 s += t;
2822 }
2823
2824 ULONG hitRatio = (ULONG)((1.00 - ((float)physReads / (float)(dbBlockGets + consistentGets))) * 100.00);
2825 t.sprintf("*** %s: %lu%%\n", langDBINF_CACHE_HIT_RATIO, hitRatio);
2826 s += t;
2827
2828 // Tablespace information
2829 s += "\n";
2830 s += langDBINF_TABLESPACE_IO;
2831 s += "\n";
2832 ULONG physWrites;
2833 char tablespaceName[257];
2834 pDb->ExecSql("SELECT NAME,PHYRDS,PHYWRTS FROM V$DATAFILE, V$FILESTAT WHERE V$DATAFILE.FILE# = V$FILESTAT.FILE#");
2835 while (pDb->GetNext())
2836 {
2837 pDb->GetData(1, SQL_C_CHAR, tablespaceName, 257, &cb);
2838 pDb->GetData(2, SQL_C_ULONG, &physReads, 0, &cb);
2839 pDb->GetData(3, SQL_C_ULONG, &physWrites, 0, &cb);
2840 t.sprintf("%s\n\t%s: %lu\t%s: %lu\n", tablespaceName,
2841 langDBINF_PHYSICAL_READS, physReads, langDBINF_PHYSICAL_WRITES, physWrites);
2842 s += t;
2843 }
2844
2845 s += "\n";
2846 }
2847
2848 wxLogMessage(s);
2849
2850 } // DisplayDbDiagnostics()
2851
2852
2853
2854
2855 /*
2856 TEST CODE FOR TESTING THE wxDbCreateDataSource() FUNCTION
2857
2858 int result = 0;
2859 result = wxDbCreateDataSource(wxT("Microsoft Access Driver (*.mdb)"),wxT("GLT-TEST2"),wxT("GLT-Descrip"),FALSE,wxT(""),this);
2860 if (!result)
2861 {
2862 // check for errors caused by ConfigDSN based functions
2863 DWORD retcode = 0;
2864 WORD cb;
2865 wxChar errMsg[500+1];
2866 errMsg[0] = wxT('\0');
2867
2868 SQLInstallerError(1,&retcode,errMsg,500,&cb);
2869
2870 wxMessageBox(wxT("FAILED creating data source"),wxT("FAILED"));
2871 }
2872 else
2873 wxMessageBox(wxT("SUCCEEDED creating data source"),wxT("SUCCESS"));
2874 */
2875
2876