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