Massive cleanup of the code.
[wxWidgets.git] / samples / db / dbtest.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: dbtest.cpp
3 // Purpose: wxWindows database demo app
4 // Author: George Tasker
5 // Modified by:
6 // Created: 1998
7 // RCS-ID: $Id$
8 // Copyright: (c) 1998 Remstar International, Inc.
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 /*
13 * SYNOPSIS START
14
15 This sample program demonstrates the cross-platform ODBC database classes
16 donated by the development team at Remstar International.
17
18 The table this sample is based on is developer contact table, and shows
19 some of the simple uses of the database classes wxDb and wxDbTable.
20
21 * SYNOPSIS END
22 */
23
24 #ifdef __GNUG__
25 #pragma implementation "dbtest.h"
26 #endif
27
28 #include "wx/wxprec.h"
29
30 #ifdef __BORLANDC__
31 #pragma hdrstop
32 #endif //__BORLANDC__
33
34 #ifndef WX_PRECOMP
35 #include <wx/wx.h>
36 #endif //WX_PRECOMP
37
38 #ifdef __WXGTK__
39 #include "db.xpm"
40 #endif
41
42 #include <stdio.h> /* Included strictly for reading the text file with the database parameters */
43
44 #include <wx/db.h> /* Required in the file which will get the data source connection */
45 #include <wx/dbtable.h> /* Has the wxDbTable object from which all data objects will inherit their data table functionality */
46
47 extern wxDbList WXDLLEXPORT *PtrBegDbList; /* from db.cpp, used in getting back error results from db connections */
48
49 #include "dbtest.h" /* Header file for this demonstration program */
50 #include "listdb.h" /* Code to support the "Lookup" button on the editor dialog */
51
52 IMPLEMENT_APP(DatabaseDemoApp)
53
54 extern wxChar ListDB_Selection[]; /* Used to return the first column value for the selected line from the listDB routines */
55 extern wxChar ListDB_Selection2[]; /* Used to return the second column value for the selected line from the listDB routines */
56
57 const char *GetExtendedDBErrorMsg(wxDb *pDb, char *ErrFile, int ErrLine)
58 {
59 static wxString msg;
60 msg = wxT("");
61
62 wxString tStr;
63
64 if (ErrFile || ErrLine)
65 {
66 msg += wxT("File: ");
67 msg += ErrFile;
68 msg += wxT(" Line: ");
69 tStr.Printf(wxT("%d"),ErrLine);
70 msg += tStr.c_str();
71 msg += wxT("\n");
72 }
73
74 msg.Append (wxT("\nODBC errors:\n"));
75 msg += wxT("\n");
76
77 // Display errors for this connection
78 int i;
79 for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
80 {
81 if (pDb->errorList[i])
82 {
83 msg.Append(pDb->errorList[i]);
84 if (wxStrcmp(pDb->errorList[i],wxT("")) != 0)
85 msg.Append(wxT("\n"));
86 // Clear the errmsg buffer so the next error will not
87 // end up showing the previous error that have occurred
88 wxStrcpy(pDb->errorList[i],wxT(""));
89 }
90 }
91 msg += wxT("\n");
92
93 return msg.c_str();
94 } // GetExtendedDBErrorMsg
95
96
97 bool DatabaseDemoApp::OnInit()
98 {
99 DbConnectInf = NULL;
100
101 // Create the main frame window
102 DemoFrame = new DatabaseDemoFrame(NULL, wxT("wxWindows Database Demo"), wxPoint(50, 50), wxSize(537, 480));
103
104 // Give it an icon
105 DemoFrame->SetIcon(wxICON(db));
106
107 // Make a menubar
108 wxMenu *file_menu = new wxMenu;
109 file_menu->Append(FILE_CREATE, wxT("&Create CONTACT table"));
110 file_menu->Append(FILE_RECREATE_TABLE, wxT("&Recreate CONTACT table"));
111 file_menu->Append(FILE_RECREATE_INDEXES, wxT("&Recreate CONTACT indexes"));
112 file_menu->Append(FILE_EXIT, wxT("E&xit"));
113
114 wxMenu *edit_menu = new wxMenu;
115 edit_menu->Append(EDIT_PARAMETERS, wxT("&Parameters..."));
116
117 wxMenu *about_menu = new wxMenu;
118 about_menu->Append(ABOUT_DEMO, wxT("&About"));
119
120 wxMenuBar *menu_bar = new wxMenuBar;
121 menu_bar->Append(file_menu, wxT("&File"));
122 menu_bar->Append(edit_menu, wxT("&Edit"));
123 menu_bar->Append(about_menu, wxT("&About"));
124 DemoFrame->SetMenuBar(menu_bar);
125
126 params.ODBCSource[0] = 0;
127 params.UserName[0] = 0;
128 params.Password[0] = 0;
129 params.DirPath[0] = 0;
130
131 // Show the frame
132 DemoFrame->Show(TRUE);
133
134 ReadParamFile(params);
135
136 // Passing NULL for the SQL environment handle causes
137 // the wxDbConnectInf constructor to obtain a handle
138 // for you.
139 //
140 // WARNING: Be certain that you do not free this handle
141 // directly with SQLFreeEnv(). Use either the
142 // method ::FreeHenv() or delete the DbConnectInf.
143 DbConnectInf = new wxDbConnectInf(NULL, params.ODBCSource, params.UserName,
144 params.Password, params.DirPath);
145
146 if (!DbConnectInf || !DbConnectInf->GetHenv())
147 {
148 wxMessageBox(wxT("Unable to define data source connection info."), wxT("DB CONNECTION ERROR..."),wxOK | wxICON_EXCLAMATION);
149 delete DbConnectInf;
150 }
151
152
153 READONLY_DB = wxDbGetConnection(DbConnectInf);
154 if (READONLY_DB == 0)
155 {
156 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);
157 DemoFrame->BuildParameterDialog(NULL);
158 DbConnectInf->SetDsn("");
159 DbConnectInf->SetUid("");
160 DbConnectInf->SetPassword("");
161 wxMessageBox(wxT("Now exiting program.\n\nRestart program to try any new settings."),wxT("Notice..."),wxOK | wxICON_INFORMATION);
162 return(FALSE);
163 }
164
165 DemoFrame->BuildEditorDialog();
166
167 // Show the frame
168 DemoFrame->Refresh();
169
170 return TRUE;
171 } // DatabaseDemoApp::OnInit()
172
173
174 bool DatabaseDemoApp::ReadParamFile(Cparameters &params)
175 {
176 FILE *paramFile;
177 if ((paramFile = fopen(PARAM_FILENAME, wxT("r"))) == NULL)
178 {
179 wxString tStr;
180 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);
181 wxMessageBox(tStr,wxT("File I/O Error..."),wxOK | wxICON_EXCLAMATION);
182
183 DemoFrame->BuildParameterDialog(NULL);
184 if ((paramFile = fopen(PARAM_FILENAME, wxT("r"))) == NULL)
185 return FALSE;
186 }
187
188 wxChar buffer[1000+1];
189 fgets(buffer, sizeof(params.ODBCSource), paramFile);
190 buffer[wxStrlen(buffer)-1] = wxT('\0');
191 wxStrcpy(params.ODBCSource,buffer);
192
193 fgets(buffer, sizeof(params.UserName), paramFile);
194 buffer[wxStrlen(buffer)-1] = wxT('\0');
195 wxStrcpy(params.UserName,buffer);
196
197 fgets(buffer, sizeof(params.Password), paramFile);
198 buffer[wxStrlen(buffer)-1] = wxT('\0');
199 wxStrcpy(params.Password,buffer);
200
201 fgets(buffer, sizeof(params.DirPath), paramFile);
202 buffer[wxStrlen(buffer)-1] = wxT('\0');
203 wxStrcpy(params.DirPath,buffer);
204
205 fclose(paramFile);
206
207 return TRUE;
208 } // DatabaseDemoApp::ReadParamFile()
209
210
211 bool DatabaseDemoApp::WriteParamFile(Cparameters &params)
212 {
213 FILE *paramFile;
214 if ((paramFile = fopen(PARAM_FILENAME, wxT("wt"))) == NULL)
215 {
216 wxString tStr;
217 tStr.Printf(wxT("Unable to write/overwrite '%s'."),PARAM_FILENAME);
218 wxMessageBox(tStr,wxT("File I/O Error..."),wxOK | wxICON_EXCLAMATION);
219 return FALSE;
220 }
221
222 fputs(wxGetApp().params.ODBCSource, paramFile);
223 fputc(wxT('\n'), paramFile);
224 fputs(wxGetApp().params.UserName, paramFile);
225 fputc(wxT('\n'), paramFile);
226 fputs(wxGetApp().params.Password, paramFile);
227 fputc(wxT('\n'), paramFile);
228 fputs(wxGetApp().params.DirPath, paramFile);
229 fputc(wxT('\n'), paramFile);
230 fclose(paramFile);
231
232 return TRUE;
233 } // DatabaseDemoApp::WriteParamFile()
234
235
236 void DatabaseDemoApp::CreateDataTable(bool recreate)
237 {
238 bool Ok = TRUE;
239 if (recreate)
240 Ok = (wxMessageBox(wxT("Any data currently residing in the table will be erased.\n\nAre you sure?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
241
242 if (!Ok)
243 return;
244
245 wxBeginBusyCursor();
246
247 bool success = TRUE;
248
249 // Use a temporary instance of a new Ccontact table object
250 // for creating the table within the datasource.
251 Ccontact *Contact = new Ccontact();
252
253 if (!Contact)
254 {
255 wxEndBusyCursor();
256 wxMessageBox(wxT("Error allocating memory for 'Ccontact'object.\n\nTable was not created."),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
257 return;
258 }
259
260 if (!Contact->CreateTable(recreate))
261 {
262 wxEndBusyCursor();
263 wxString tStr;
264 tStr = wxT("Error creating CONTACTS table.\nTable was not created.\n\n");
265 tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
266 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
267 success = FALSE;
268 }
269 else
270 {
271 if (!Contact->CreateIndexes())
272 {
273 wxEndBusyCursor();
274 wxString tStr;
275 tStr = wxT("Error creating CONTACTS indexes.\nIndexes will be unavailable.\n\n");
276 tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
277 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
278 success = FALSE;
279 }
280 }
281 while (wxIsBusy())
282 wxEndBusyCursor();
283
284 delete Contact;
285 Contact = NULL;
286
287 if (success)
288 wxMessageBox(wxT("Table and index(es) were successfully created."),wxT("Notice..."),wxOK | wxICON_INFORMATION);
289 } // DatabaseDemoApp::CreateDataTable()
290
291
292 BEGIN_EVENT_TABLE(DatabaseDemoFrame, wxFrame)
293 EVT_MENU(FILE_CREATE, DatabaseDemoFrame::OnCreate)
294 EVT_MENU(FILE_RECREATE_TABLE, DatabaseDemoFrame::OnRecreateTable)
295 EVT_MENU(FILE_RECREATE_INDEXES, DatabaseDemoFrame::OnRecreateIndexes)
296 EVT_MENU(FILE_EXIT, DatabaseDemoFrame::OnExit)
297 EVT_MENU(EDIT_PARAMETERS, DatabaseDemoFrame::OnEditParameters)
298 EVT_MENU(ABOUT_DEMO, DatabaseDemoFrame::OnAbout)
299 EVT_CLOSE(DatabaseDemoFrame::OnCloseWindow)
300 END_EVENT_TABLE()
301
302
303 // DatabaseDemoFrame constructor
304 DatabaseDemoFrame::DatabaseDemoFrame(wxFrame *frame, const wxString& title,
305 const wxPoint& pos, const wxSize& size):
306 wxFrame(frame, -1, title, pos, size)
307 {
308 // Put any code in necessary for initializing the main frame here
309 pEditorDlg = NULL;
310 pParamDlg = NULL;
311 } // DatabaseDemoFrame constructor
312
313
314 void DatabaseDemoFrame::OnCreate(wxCommandEvent& event)
315 {
316 wxGetApp().CreateDataTable(FALSE);
317 } // DatabaseDemoFrame::OnCreate()
318
319
320 void DatabaseDemoFrame::OnRecreateTable(wxCommandEvent& event)
321 {
322 wxGetApp().CreateDataTable(TRUE);
323 } // DatabaseDemoFrame::OnRecreate()
324
325
326 void DatabaseDemoFrame::OnRecreateIndexes(wxCommandEvent& event)
327 {
328 // Using a new connection to the database so as not to disturb
329 // the current cursors on the table in use in the editor dialog
330 Ccontact *Contact = new Ccontact();
331
332 if (!Contact)
333 {
334 wxEndBusyCursor();
335 wxMessageBox(wxT("Error allocating memory for 'Ccontact'object.\n\nTable could not be opened."),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
336 return;
337 }
338
339 if (!Contact->CreateIndexes())
340 {
341 wxEndBusyCursor();
342 wxString tStr;
343 tStr = wxT("Error creating CONTACTS indexes.\nNew indexes will be unavailable.\n\n");
344 tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
345 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
346 }
347
348 delete Contact;
349 Contact = NULL;
350 } // DatabaseDemoFrame::OnRecreateIndexes()
351
352 void DatabaseDemoFrame::OnExit(wxCommandEvent& event)
353 {
354 Close();
355 } // DatabaseDemoFrame::OnExit()
356
357
358 void DatabaseDemoFrame::OnEditParameters(wxCommandEvent& event)
359 {
360 if ((pEditorDlg->mode != mCreate) && (pEditorDlg->mode != mEdit))
361 BuildParameterDialog(this);
362 else
363 wxMessageBox(wxT("Cannot change database parameters while creating or editing a record"),wxT("Notice..."),wxOK | wxICON_INFORMATION);
364 } // DatabaseDemoFrame::OnEditParameters()
365
366
367 void DatabaseDemoFrame::OnAbout(wxCommandEvent& event)
368 {
369 wxMessageBox(wxT("wxWindows sample program for database classes\n\nContributed on 27 July 1998"),wxT("About..."),wxOK | wxICON_INFORMATION);
370 } // DatabaseDemoFrame::OnAbout()
371
372
373 // Put any additional checking necessary to make certain it is alright
374 // to close the program here that is not done elsewhere
375 void DatabaseDemoFrame::OnCloseWindow(wxCloseEvent& event)
376 {
377 // Clean up time
378 if (pEditorDlg && pEditorDlg->Close())
379 pEditorDlg = NULL;
380 else
381 {
382 if (pEditorDlg)
383 {
384 event.Veto();
385 return;
386 }
387 }
388
389 // This function will close all the connections to the database that have been
390 // previously cached.
391 wxDbCloseConnections();
392
393 // Deletion of the wxDbConnectInf instance must be the LAST thing done that
394 // has anything to do with the database. Deleting this before disconnecting,
395 // freeing/closing connections, etc will result in a crash!
396 delete wxGetApp().DbConnectInf;
397 wxGetApp().DbConnectInf = NULL;
398
399 this->Destroy();
400
401 } // DatabaseDemoFrame::OnCloseWindow()
402
403
404 void DatabaseDemoFrame::BuildEditorDialog()
405 {
406 pEditorDlg = NULL;
407 pEditorDlg = new CeditorDlg(this);
408 if (pEditorDlg)
409 {
410 pEditorDlg->Initialize();
411 if (!pEditorDlg->initialized)
412 {
413 pEditorDlg->Close();
414 pEditorDlg = NULL;
415 wxMessageBox(wxT("Unable to initialize the editor dialog for some reason"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
416 Close();
417 }
418 }
419 else
420 {
421 wxMessageBox(wxT("Unable to create the editor dialog for some reason"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
422 Close();
423 }
424 } // DatabaseDemoFrame::BuildEditorDialog()
425
426
427 void DatabaseDemoFrame::BuildParameterDialog(wxWindow *parent)
428 {
429 pParamDlg = new CparameterDlg(parent);
430
431 if (!pParamDlg)
432 wxMessageBox(wxT("Unable to create the parameter dialog for some reason"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
433 } // DatabaseDemoFrame::BuildParameterDialog()
434
435
436 /*
437 * Constructor note: If no wxDb object is passed in, a new connection to the database
438 * is created for this instance of Ccontact. This can be a slow process depending
439 * on the database engine being used, and some database engines have a limit on the
440 * number of connections (either hard limits, or license restricted) so care should
441 * be used to use as few connections as is necessary.
442 *
443 * IMPORTANT: Objects which share a wxDb pointer are ALL acted upon whenever a member
444 * function of pDb is called (i.e. CommitTrans() or RollbackTrans(), so if modifying
445 * or creating a table objects which use the same pDb, know that all the objects
446 * will be committed or rolled back when any of the objects has this function call made.
447 */
448 Ccontact::Ccontact (wxDb *pwxDb) : wxDbTable(pwxDb ? pwxDb : wxDbGetConnection(wxGetApp().DbConnectInf),
449 CONTACT_TABLE_NAME, CONTACT_NO_COLS, wxT(""),
450 !wxDB_QUERY_ONLY, wxGetApp().DbConnectInf->GetDefaultDir())
451 {
452 // This is used to represent whether the database connection should be released
453 // when this instance of the object is deleted. If using the same connection
454 // for multiple instance of database objects, then the connection should only be
455 // released when the last database instance using the connection is deleted
456 freeDbConn = !pwxDb;
457
458 SetupColumns();
459
460 } // Ccontact Constructor
461
462
463 void Ccontact::Initialize()
464 {
465 Name[0] = 0;
466 Addr1[0] = 0;
467 Addr2[0] = 0;
468 City[0] = 0;
469 State[0] = 0;
470 PostalCode[0] = 0;
471 Country[0] = 0;
472 JoinDate.year = 1980;
473 JoinDate.month = 1;
474 JoinDate.day = 1;
475 JoinDate.hour = 0;
476 JoinDate.minute = 0;
477 JoinDate.second = 0;
478 JoinDate.fraction = 0;
479 NativeLanguage = langENGLISH;
480 IsDeveloper = FALSE;
481 Contributions = 0;
482 LinesOfCode = 0L;
483 } // Ccontact::Initialize
484
485
486 Ccontact::~Ccontact()
487 {
488 if (freeDbConn)
489 {
490 if (!wxDbFreeConnection(GetDb()))
491 {
492 wxString tStr;
493 tStr = wxT("Unable to Free the Ccontact data table handle\n\n");
494 tStr += GetExtendedDBErrorMsg(GetDb(),__FILE__,__LINE__);
495 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
496 }
497 }
498 } // Ccontract destructor
499
500
501 /*
502 * Handles setting up all the connections for the interface from the wxDbTable
503 * functions to interface to the data structure used to store records in
504 * memory, and for all the column definitions that define the table structure
505 */
506 void Ccontact::SetupColumns()
507 {
508 // NOTE: Columns now are 8 character names, as that is all dBase can support. Longer
509 // names can be used for other database engines
510 SetColDefs ( 0,wxT("NAME"), DB_DATA_TYPE_VARCHAR, Name, SQL_C_CHAR, sizeof(Name), TRUE, TRUE); // Primary index
511 SetColDefs ( 1,wxT("ADDRESS1"), DB_DATA_TYPE_VARCHAR, Addr1, SQL_C_CHAR, sizeof(Addr1), FALSE,TRUE);
512 SetColDefs ( 2,wxT("ADDRESS2"), DB_DATA_TYPE_VARCHAR, Addr2, SQL_C_CHAR, sizeof(Addr2), FALSE,TRUE);
513 SetColDefs ( 3,wxT("CITY"), DB_DATA_TYPE_VARCHAR, City, SQL_C_CHAR, sizeof(City), FALSE,TRUE);
514 SetColDefs ( 4,wxT("STATE"), DB_DATA_TYPE_VARCHAR, State, SQL_C_CHAR, sizeof(State), FALSE,TRUE);
515 SetColDefs ( 5,wxT("POSTCODE"), DB_DATA_TYPE_VARCHAR, PostalCode, SQL_C_CHAR, sizeof(PostalCode), FALSE,TRUE);
516 SetColDefs ( 6,wxT("COUNTRY"), DB_DATA_TYPE_VARCHAR, Country, SQL_C_CHAR, sizeof(Country), FALSE,TRUE);
517 SetColDefs ( 7,wxT("JOINDATE"), DB_DATA_TYPE_DATE, &JoinDate, SQL_C_TIMESTAMP, sizeof(JoinDate), FALSE,TRUE);
518 SetColDefs ( 8,wxT("IS_DEV"), DB_DATA_TYPE_INTEGER, &IsDeveloper, SQL_C_BOOLEAN(IsDeveloper), sizeof(IsDeveloper), FALSE,TRUE);
519 SetColDefs ( 9,wxT("CONTRIBS"), DB_DATA_TYPE_INTEGER, &Contributions, SQL_C_USHORT, sizeof(Contributions), FALSE,TRUE);
520 SetColDefs (10,wxT("LINE_CNT"), DB_DATA_TYPE_INTEGER, &LinesOfCode, SQL_C_ULONG, sizeof(LinesOfCode), FALSE,TRUE);
521 SetColDefs (11,wxT("LANGUAGE"), DB_DATA_TYPE_INTEGER, &NativeLanguage, SQL_C_ENUM, sizeof(NativeLanguage), FALSE,TRUE);
522 } // Ccontact::SetupColumns
523
524
525 bool Ccontact::CreateIndexes(void)
526 {
527 // This index could easily be accomplished with an "orderBy" clause,
528 // but is done to show how to construct a non-primary index.
529 wxString indexName;
530 wxDbIdxDef idxDef[2];
531
532 bool Ok = TRUE;
533
534 wxStrcpy(idxDef[0].ColName, "IS_DEV");
535 idxDef[0].Ascending = TRUE;
536
537 wxStrcpy(idxDef[1].ColName, "NAME");
538 idxDef[1].Ascending = TRUE;
539
540 indexName = GetTableName();
541 indexName += "_IDX1";
542 Ok = CreateIndex(indexName.c_str(), TRUE, 2, idxDef);
543
544 return Ok;
545 } // Ccontact::CreateIndexes()
546
547
548 /*
549 * Having a function to do a query on the primary key (and possibly others) is
550 * very efficient and tighter coding so that it is available where ever the object
551 * is. Great for use with multiple tables when not using views or outer joins
552 */
553 bool Ccontact::FetchByName(const wxString &name)
554 {
555 whereStr.Printf(wxT("NAME = '%s'"),name);
556 SetWhereClause(whereStr.c_str());
557 SetOrderByClause(wxT(""));
558
559 if (!Query())
560 return(FALSE);
561
562 // Fetch the record
563 return(GetNext());
564
565 } // Ccontact::FetchByName()
566
567
568 /*
569 *
570 * ************* DIALOGS ***************
571 *
572 */
573
574
575 /* CeditorDlg constructor
576 *
577 * Creates the dialog used for creating/editing/deleting/copying a Ccontact object.
578 * This dialog actually is drawn in the main frame of the program
579 *
580 * An instance of Ccontact is created - "Contact" - which is used to hold the Ccontact
581 * object that is currently being worked with.
582 */
583
584 BEGIN_EVENT_TABLE(CeditorDlg, wxPanel)
585 EVT_BUTTON(-1, CeditorDlg::OnButton)
586 EVT_CLOSE(CeditorDlg::OnCloseWindow)
587 END_EVENT_TABLE()
588
589 CeditorDlg::CeditorDlg(wxWindow *parent) : wxPanel (parent, 0, 0, 537, 480)
590 {
591 // Since the ::OnCommand() function is overridden, this prevents the widget
592 // detection in ::OnCommand() until all widgets have been initialized to prevent
593 // uninitialized pointers from crashing the program
594 widgetPtrsSet = FALSE;
595
596 initialized = FALSE;
597
598 Contact = NULL;
599
600 Show(FALSE);
601 } // CeditorDlg constructor
602
603
604 void CeditorDlg::OnCloseWindow(wxCloseEvent& event)
605 {
606 // Clean up time
607 if ((mode != mCreate) && (mode != mEdit))
608 {
609 if (Contact)
610 {
611 delete Contact;
612 Contact = NULL;
613 }
614 this->Destroy();
615 }
616 else
617 {
618 wxMessageBox(wxT("Must finish processing the current record being created/modified before exiting"),wxT("Notice..."),wxOK | wxICON_INFORMATION);
619 event.Veto();
620 }
621 } // CeditorDlg::OnCloseWindow()
622
623
624 void CeditorDlg::OnButton(wxCommandEvent &event)
625 {
626 wxWindow *win = (wxWindow*) event.GetEventObject();
627 OnCommand( *win, event );
628 } // CeditorDlg::OnButton()
629
630
631 void CeditorDlg::OnCommand(wxWindow& win, wxCommandEvent& event)
632 {
633 wxString widgetName;
634
635 widgetName = win.GetName();
636
637 if (!widgetPtrsSet)
638 return;
639
640 if (widgetName == pCreateBtn->GetName())
641 {
642 Contact->Initialize();
643 PutData();
644 SetMode( mCreate );
645 pNameTxt->SetValue(wxT(""));
646 pNameTxt->SetFocus();
647 return;
648 }
649
650 if (widgetName == pEditBtn->GetName())
651 {
652 saveName = Contact->Name;
653 SetMode( mEdit );
654 pNameTxt->SetFocus();
655 return;
656 }
657
658 if (widgetName == pCopyBtn->GetName())
659 {
660 SetMode(mCreate);
661 pNameTxt->SetValue(wxT(""));
662 pNameTxt->SetFocus();
663
664 return;
665 }
666
667 if (widgetName == pDeleteBtn->GetName())
668 {
669 bool Ok = (wxMessageBox(wxT("Are you sure?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
670
671 if (!Ok)
672 return;
673
674 if (Ok && Contact->Delete())
675 {
676 // NOTE: Deletions are not finalized until a CommitTrans() is performed.
677 // If the commit were not performed, the program will continue to
678 // show the table contents as if they were deleted until this instance
679 // of Ccontact is deleted. If the Commit wasn't performed, the
680 // database will automatically Rollback the changes when the database
681 // connection is terminated
682 Contact->GetDb()->CommitTrans();
683
684 // Try to get the row that followed the just deleted row in the orderBy sequence
685 if (!GetNextRec())
686 {
687 // There was now row (in sequence) after the just deleted row, so get the
688 // row which preceded the just deleted row
689 if (!GetPrevRec())
690 {
691 // There are now no rows remaining, so clear the dialog widgets
692 Contact->Initialize();
693 PutData();
694 }
695 }
696 SetMode(mode); // force reset of button enable/disable
697 }
698 else
699 // Delete failed
700 Contact->GetDb()->RollbackTrans();
701
702 SetMode(mView);
703 return;
704 }
705
706 if (widgetName == pSaveBtn->GetName())
707 {
708 Save();
709 return;
710 }
711
712 if (widgetName == pCancelBtn->GetName())
713 {
714 bool Ok = (wxMessageBox(wxT("Are you sure?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
715
716 if (!Ok)
717 return;
718
719 if (saveName.IsEmpty())
720 {
721 Contact->Initialize();
722 PutData();
723 SetMode(mView);
724 return;
725 }
726 else
727 {
728 // Requery previous record
729 if (Contact->FetchByName(saveName))
730 {
731 PutData();
732 SetMode(mView);
733 return;
734 }
735 }
736
737 // Previous record not available, retrieve first record in table
738 if (Contact->GetDb()->Dbms() != dbmsPOSTGRES && Contact->GetDb()->Dbms() != dbmsMY_SQL)
739 {
740 Contact->whereStr = wxT("NAME = (SELECT MIN(NAME) FROM ");
741 Contact->whereStr += Contact->GetTableName();
742 Contact->whereStr += wxT(")");
743 Contact->SetWhereClause(Contact->whereStr.c_str());
744 }
745 else
746 Contact->SetWhereClause(wxT(""));
747
748 if (!Contact->Query())
749 {
750 wxString tStr;
751 tStr = wxT("ODBC error during Query()\n\n");
752 tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
753 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
754 SetMode(mView);
755 return;
756 }
757 if (Contact->GetNext()) // Successfully read first record
758 {
759 PutData();
760 SetMode(mView);
761 return;
762 }
763 // No contacts are available, clear dialog
764 Contact->Initialize();
765 PutData();
766 SetMode(mView);
767 return;
768 } // Cancel Button
769
770 if (widgetName == pPrevBtn->GetName())
771 {
772 if (!GetPrevRec())
773 wxBell();
774 return;
775 } // Prev Button
776
777 if (widgetName == pNextBtn->GetName())
778 {
779 if (!GetNextRec())
780 wxBell();
781 return;
782 } // Next Button
783
784 if (widgetName == pQueryBtn->GetName())
785 {
786 // Display the query dialog box
787 wxChar qryWhere[DB_MAX_WHERE_CLAUSE_LEN+1];
788 wxStrcpy(qryWhere, (const wxChar*) Contact->qryWhereStr);
789 wxChar *tblName[] = {(wxChar *)CONTACT_TABLE_NAME, 0};
790 new CqueryDlg(GetParent(), Contact->GetDb(), tblName, qryWhere);
791
792 // Query the first record in the new record set and
793 // display it, if the query string has changed.
794 if (wxStrcmp(qryWhere, (const wxChar*) Contact->qryWhereStr))
795 {
796 Contact->whereStr.Empty();
797 Contact->SetOrderByClause("NAME");
798
799 if (Contact->GetDb()->Dbms() != dbmsPOSTGRES && Contact->GetDb()->Dbms() != dbmsMY_SQL)
800 {
801 Contact->whereStr = wxT("NAME = (SELECT MIN(NAME) FROM ");
802 Contact->whereStr += CONTACT_TABLE_NAME;
803 }
804
805 // Append the query where string (if there is one)
806 Contact->qryWhereStr = qryWhere;
807 if (wxStrlen(qryWhere))
808 {
809 Contact->whereStr += wxT(" WHERE ");
810 Contact->whereStr += Contact->qryWhereStr;
811 }
812 // Close the expression with a right paren
813 Contact->whereStr += wxT(")");
814 // Requery the table
815 Contact->SetWhereClause(Contact->whereStr.c_str());
816 if (!Contact->Query())
817 {
818 wxString tStr;
819 tStr = wxT("ODBC error during Query()\n\n");
820 tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
821 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
822 return;
823 }
824 // Display the first record from the query set
825 if (!Contact->GetNext())
826 Contact->Initialize();
827 PutData();
828 }
829
830 // Enable/Disable the reset button
831 pResetBtn->Enable(!Contact->qryWhereStr.IsEmpty());
832
833 return;
834 } // Query button
835
836
837 if (widgetName == pResetBtn->GetName())
838 {
839 // Clear the additional where criteria established by the query feature
840 Contact->qryWhereStr = wxT("");
841 Contact->SetOrderByClause(wxT("NAME"));
842
843 if (Contact->GetDb()->Dbms() != dbmsPOSTGRES && Contact->GetDb()->Dbms() != dbmsMY_SQL)
844 {
845 Contact->whereStr = wxT("NAME = (SELECT MIN(NAME) FROM ");
846 Contact->whereStr += CONTACT_TABLE_NAME;
847 Contact->whereStr += wxT(")");
848 }
849
850 Contact->SetWhereClause(Contact->whereStr.c_str());
851 if (!Contact->Query())
852 {
853 wxString tStr;
854 tStr = wxT("ODBC error during Query()\n\n");
855 tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
856 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
857 return;
858 }
859 if (!Contact->GetNext())
860 Contact->Initialize();
861 PutData();
862 pResetBtn->Enable(FALSE);
863
864 return;
865 } // Reset button
866
867
868 if (widgetName == pNameListBtn->GetName())
869 {
870 new ClookUpDlg(/* wxWindow *parent */ this,
871 /* wxChar *windowTitle */ wxT("Select contact name"),
872 /* wxChar *tableName */ (wxChar *) CONTACT_TABLE_NAME,
873 /* wxChar *dispCol1 */ wxT("NAME"),
874 /* wxChar *dispCol2 */ wxT("JOINDATE"),
875 /* wxChar *where */ wxT(""),
876 /* wxChar *orderBy */ wxT("NAME"),
877 /* wxDb *pDb */ wxGetApp().READONLY_DB,
878 /* const wxString &defDir */ wxGetApp().DbConnectInf->GetDefaultDir(),
879 /* bool distinctValues */ TRUE);
880
881 if (ListDB_Selection && wxStrlen(ListDB_Selection))
882 {
883 wxString w = wxT("NAME = '");
884 w += ListDB_Selection;
885 w += wxT("'");
886 GetRec(w);
887 }
888
889 return;
890 }
891 } // CeditorDlg::OnCommand()
892
893
894 bool CeditorDlg::Initialize()
895 {
896 // Create the data structure and a new database connection.
897 // (As there is not a pDb being passed in the constructor, a new database
898 // connection is created)
899 Contact = new Ccontact();
900
901 if (!Contact)
902 {
903 wxMessageBox(wxT("Unable to instantiate an instance of Ccontact"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
904 return FALSE;
905 }
906
907 // Check if the table exists or not. If it doesn't, ask the user if they want to
908 // create the table. Continue trying to create the table until it exists, or user aborts
909 while (!Contact->GetDb()->TableExists((wxChar *)CONTACT_TABLE_NAME,
910 wxGetApp().DbConnectInf->GetUserID(),
911 wxGetApp().DbConnectInf->GetDefaultDir()))
912 {
913 wxString tStr;
914 tStr.Printf(wxT("Unable to open the table '%s'.\n\nTable may need to be created...?\n\n"),CONTACT_TABLE_NAME);
915 tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
916 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
917
918 bool createTable = (wxMessageBox(wxT("Do you wish to try to create/clear the CONTACTS table?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
919
920 if (!createTable)
921 {
922 // Close();
923 return FALSE;
924 }
925 else
926 wxGetApp().CreateDataTable(TRUE);
927 }
928
929 // Tables must be "opened" before anything other than creating/deleting table can be done
930 if (!Contact->Open())
931 {
932 // Table does exist, or there was some problem opening it. Currently this should
933 // never fail, except in the case of the table not exisiting or the current
934 // user has insufficent privileges to access the table
935 #if 0
936 // This code is experimenting with a new function that will hopefully be available
937 // in the 2.4 release. This check will determine whether the open failing was due
938 // to the table not existing, or the users privileges being insufficient to
939 // open the table.
940 if (!Contact->GetDb()->TablePrivileges(CONTACT_TABLE_NAME,wxT("SELECT"),Contact->GetDb()->GetUsername(),Contact->GetDb()->GetUsername(),DbConnectInf->GetDefaultDir()))
941 {
942 wxString tStr;
943 tStr.Printf(wxT("Unable to open the table '%s'.\n\n"),CONTACT_TABLE_NAME);
944 tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
945 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
946 }
947 else
948 #endif
949 if (Contact->GetDb()->TableExists(CONTACT_TABLE_NAME, Contact->GetDb()->GetUsername(),
950 wxGetApp().DbConnectInf->GetDefaultDir()))
951 {
952 wxString tStr;
953 tStr.Printf(wxT("Unable to open the table '%s'.\n\n"),CONTACT_TABLE_NAME);
954 tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
955 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
956 }
957
958 return FALSE;
959 }
960
961 // Build the dialog
962
963 (void)new wxStaticBox(this, EDITOR_DIALOG_FN_GROUP, wxT(""), wxPoint(15, 1), wxSize(497, 69), 0, wxT("FunctionGrp"));
964 (void)new wxStaticBox(this, EDITOR_DIALOG_SEARCH_GROUP, wxT(""), wxPoint(417, 1), wxSize(95, 242), 0, wxT("SearchGrp"));
965
966 pCreateBtn = new wxButton(this, EDITOR_DIALOG_CREATE, wxT("&Create"), wxPoint( 25, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("CreateBtn"));
967 pEditBtn = new wxButton(this, EDITOR_DIALOG_EDIT, wxT("&Edit"), wxPoint(102, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("EditBtn"));
968 pDeleteBtn = new wxButton(this, EDITOR_DIALOG_DELETE, wxT("&Delete"), wxPoint(179, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("DeleteBtn"));
969 pCopyBtn = new wxButton(this, EDITOR_DIALOG_COPY, wxT("Cop&y"), wxPoint(256, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("CopyBtn"));
970 pSaveBtn = new wxButton(this, EDITOR_DIALOG_SAVE, wxT("&Save"), wxPoint(333, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("SaveBtn"));
971 pCancelBtn = new wxButton(this, EDITOR_DIALOG_CANCEL, wxT("C&ancel"), wxPoint(430, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("CancelBtn"));
972 pPrevBtn = new wxButton(this, EDITOR_DIALOG_PREV, wxT("<< &Prev"), wxPoint(430, 81), wxSize( 70, 35), 0, wxDefaultValidator, wxT("PrevBtn"));
973 pNextBtn = new wxButton(this, EDITOR_DIALOG_NEXT, wxT("&Next >>"), wxPoint(430, 121), wxSize( 70, 35), 0, wxDefaultValidator, wxT("NextBtn"));
974 pQueryBtn = new wxButton(this, EDITOR_DIALOG_QUERY, wxT("&Query"), wxPoint(430, 161), wxSize( 70, 35), 0, wxDefaultValidator, wxT("QueryBtn"));
975 pResetBtn = new wxButton(this, EDITOR_DIALOG_RESET, wxT("&Reset"), wxPoint(430, 200), wxSize( 70, 35), 0, wxDefaultValidator, wxT("ResetBtn"));
976 pNameMsg = new wxStaticText(this, EDITOR_DIALOG_NAME_MSG, wxT("Name:"), wxPoint( 17, 80), wxSize( -1, -1), 0, wxT("NameMsg"));
977 pNameTxt = new wxTextCtrl(this, EDITOR_DIALOG_NAME_TEXT, wxT(""), wxPoint( 17, 97), wxSize(308, 25), 0, wxDefaultValidator, wxT("NameTxt"));
978 pNameListBtn = new wxButton(this, EDITOR_DIALOG_LOOKUP, wxT("&Lookup"), wxPoint(333, 97), wxSize( 70, 24), 0, wxDefaultValidator, wxT("LookupBtn"));
979 pAddress1Msg = new wxStaticText(this, EDITOR_DIALOG_ADDRESS1_MSG, wxT("Address:"), wxPoint( 17, 130), wxSize( -1, -1), 0, wxT("Address1Msg"));
980 pAddress1Txt = new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT, wxT(""), wxPoint( 17, 147), wxSize(308, 25), 0, wxDefaultValidator, wxT("Address1Txt"));
981 pAddress2Msg = new wxStaticText(this, EDITOR_DIALOG_ADDRESS2_MSG, wxT("Address:"), wxPoint( 17, 180), wxSize( -1, -1), 0, wxT("Address2Msg"));
982 pAddress2Txt = new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT, wxT(""), wxPoint( 17, 197), wxSize(308, 25), 0, wxDefaultValidator, wxT("Address2Txt"));
983 pCityMsg = new wxStaticText(this, EDITOR_DIALOG_CITY_MSG, wxT("City:"), wxPoint( 17, 230), wxSize( -1, -1), 0, wxT("CityMsg"));
984 pCityTxt = new wxTextCtrl(this, EDITOR_DIALOG_CITY_TEXT, wxT(""), wxPoint( 17, 247), wxSize(225, 25), 0, wxDefaultValidator, wxT("CityTxt"));
985 pStateMsg = new wxStaticText(this, EDITOR_DIALOG_STATE_MSG, wxT("State:"), wxPoint(250, 230), wxSize( -1, -1), 0, wxT("StateMsg"));
986 pStateTxt = new wxTextCtrl(this, EDITOR_DIALOG_STATE_TEXT, wxT(""), wxPoint(250, 247), wxSize(153, 25), 0, wxDefaultValidator, wxT("StateTxt"));
987 pCountryMsg = new wxStaticText(this, EDITOR_DIALOG_COUNTRY_MSG, wxT("Country:"), wxPoint( 17, 280), wxSize( -1, -1), 0, wxT("CountryMsg"));
988 pCountryTxt = new wxTextCtrl(this, EDITOR_DIALOG_COUNTRY_TEXT, wxT(""), wxPoint( 17, 297), wxSize(225, 25), 0, wxDefaultValidator, wxT("CountryTxt"));
989 pPostalCodeMsg = new wxStaticText(this, EDITOR_DIALOG_POSTAL_MSG, wxT("Postal Code:"),wxPoint(250, 280), wxSize( -1, -1), 0, wxT("PostalCodeMsg"));
990 pPostalCodeTxt = new wxTextCtrl(this, EDITOR_DIALOG_POSTAL_TEXT, wxT(""), wxPoint(250, 297), wxSize(153, 25), 0, wxDefaultValidator, wxT("PostalCodeTxt"));
991
992 wxString choice_strings[5];
993 choice_strings[0] = wxT("English");
994 choice_strings[1] = wxT("French");
995 choice_strings[2] = wxT("German");
996 choice_strings[3] = wxT("Spanish");
997 choice_strings[4] = wxT("Other");
998
999 pNativeLangChoice = new wxChoice(this, EDITOR_DIALOG_LANG_CHOICE, wxPoint( 17, 346), wxSize(277, -1), 5, choice_strings);
1000 pNativeLangMsg = new wxStaticText(this, EDITOR_DIALOG_LANG_MSG, wxT("Native language:"), wxPoint( 17, 330), wxSize( -1, -1), 0, wxT("NativeLangMsg"));
1001
1002 wxString radio_strings[2];
1003 radio_strings[0] = wxT("No");
1004 radio_strings[1] = wxT("Yes");
1005 pDeveloperRadio = new wxRadioBox(this,EDITOR_DIALOG_DEVELOPER, wxT("Developer:"), wxPoint(303, 330), wxSize( -1, -1), 2, radio_strings, 2, wxHORIZONTAL);
1006 pJoinDateMsg = new wxStaticText(this, EDITOR_DIALOG_JOIN_MSG, wxT("Date joined:"), wxPoint( 17, 380), wxSize( -1, -1), 0, wxT("JoinDateMsg"));
1007 pJoinDateTxt = new wxTextCtrl(this, EDITOR_DIALOG_JOIN_TEXT, wxT(""), wxPoint( 17, 397), wxSize(150, 25), 0, wxDefaultValidator, wxT("JoinDateTxt"));
1008 pContribMsg = new wxStaticText(this, EDITOR_DIALOG_CONTRIB_MSG,wxT("Contributions:"), wxPoint(175, 380), wxSize( -1, -1), 0, wxT("ContribMsg"));
1009 pContribTxt = new wxTextCtrl(this, EDITOR_DIALOG_CONTRIB_TEXT, wxT(""), wxPoint(175, 397), wxSize(120, 25), 0, wxDefaultValidator, wxT("ContribTxt"));
1010 pLinesMsg = new wxStaticText(this, EDITOR_DIALOG_LINES_MSG, wxT("Lines of code:"), wxPoint(303, 380), wxSize( -1, -1), 0, wxT("LinesMsg"));
1011 pLinesTxt = new wxTextCtrl(this, EDITOR_DIALOG_LINES_TEXT, wxT(""), wxPoint(303, 397), wxSize(100, 25), 0, wxDefaultValidator, wxT("LinesTxt"));
1012
1013 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
1014 // handle all widget processing
1015 widgetPtrsSet = TRUE;
1016
1017 // Setup the orderBy and where clauses to return back a single record as the result set,
1018 // as there will only be one record being shown on the dialog at a time, this optimizes
1019 // network traffic by only returning a one row result
1020
1021 Contact->SetOrderByClause(wxT("NAME")); // field name to sort by
1022
1023 // The wxString "whereStr" is not a member of the wxDbTable object, it is a member variable
1024 // specifically in the Ccontact class. It is used here for simpler construction of a varying
1025 // length string, and then after the string is built, the wxDbTable member variable "where" is
1026 // assigned the pointer to the constructed string.
1027 //
1028 // The constructed where clause below has a sub-query within it "SELECT MIN(NAME) FROM %s"
1029 // to achieve a single row (in this case the first name in alphabetical order).
1030
1031 if (Contact->GetDb()->Dbms() != dbmsPOSTGRES && Contact->GetDb()->Dbms() != dbmsMY_SQL)
1032 {
1033 Contact->whereStr.Printf(wxT("NAME = (SELECT MIN(NAME) FROM %s)"),Contact->GetTableName());
1034 // NOTE: (const wxChar*) returns a pointer which may not be valid later, so this is short term use only
1035 Contact->SetWhereClause(Contact->whereStr);
1036 }
1037 else
1038 Contact->SetWhereClause(wxT(""));
1039
1040 // Perform the Query to get the result set.
1041 // NOTE: If there are no rows returned, that is a valid result, so Query() would return TRUE.
1042 // Only if there is a database error will Query() come back as FALSE
1043 if (!Contact->Query())
1044 {
1045 wxString tStr;
1046 tStr = wxT("ODBC error during Query()\n\n");
1047 tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
1048 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1049 // GetParent()->Close();
1050 return FALSE;
1051 }
1052
1053 // Since Query succeeded, now get the row that was returned
1054 if (!Contact->GetNext())
1055 // If the GetNext() failed at this point, then there are no rows to retrieve,
1056 // so clear the values in the members of "Contact" so that PutData() blanks the
1057 // widgets on the dialog
1058 Contact->Initialize();
1059
1060 SetMode(mView);
1061 PutData();
1062
1063 Show(TRUE);
1064
1065 initialized = TRUE;
1066 return TRUE;
1067 } // CeditorDlg::Initialize()
1068
1069
1070 void CeditorDlg::FieldsEditable()
1071 {
1072 pNameTxt->Enable((mode == mCreate) || (mode == mEdit));
1073 pAddress1Txt->Enable((mode == mCreate) || (mode == mEdit));
1074 pAddress2Txt->Enable((mode == mCreate) || (mode == mEdit));
1075 pCityTxt->Enable((mode == mCreate) || (mode == mEdit));
1076 pStateTxt->Enable((mode == mCreate) || (mode == mEdit));
1077 pPostalCodeTxt->Enable((mode == mCreate) || (mode == mEdit));
1078 pCountryTxt->Enable((mode == mCreate) || (mode == mEdit));
1079
1080 pJoinDateTxt->Enable((mode == mCreate) || (mode == mEdit));
1081 pContribTxt->Enable((mode == mCreate) || (mode == mEdit));
1082 pLinesTxt->Enable((mode == mCreate) || (mode == mEdit));
1083 pNativeLangChoice->Enable((mode == mCreate) || (mode == mEdit));
1084 pDeveloperRadio->Enable((mode == mCreate) || (mode == mEdit));
1085
1086 } // CeditorDlg::FieldsEditable()
1087
1088
1089 void CeditorDlg::SetMode(enum DialogModes m)
1090 {
1091 bool edit = FALSE;
1092
1093 mode = m;
1094 switch (mode)
1095 {
1096 case mCreate:
1097 case mEdit:
1098 edit = TRUE;
1099 break;
1100 case mView:
1101 case mSearch:
1102 edit = FALSE;
1103 break;
1104 default:
1105 break;
1106 };
1107
1108 if (widgetPtrsSet)
1109 {
1110 pCreateBtn->Enable( !edit );
1111 pEditBtn->Enable( !edit && (wxStrcmp(Contact->Name,wxT(""))!=0) );
1112 pDeleteBtn->Enable( !edit && (wxStrcmp(Contact->Name,wxT(""))!=0) );
1113 pCopyBtn->Enable( !edit && (wxStrcmp(Contact->Name,wxT(""))!=0) );
1114 pSaveBtn->Enable( edit );
1115 pCancelBtn->Enable( edit );
1116 pPrevBtn->Enable( !edit );
1117 pNextBtn->Enable( !edit );
1118 pQueryBtn->Enable( !edit );
1119 pResetBtn->Enable( !edit && !Contact->qryWhereStr.IsEmpty() );
1120 pNameListBtn->Enable( !edit );
1121 }
1122
1123 FieldsEditable();
1124 } // CeditorDlg::SetMode()
1125
1126
1127 bool CeditorDlg::PutData()
1128 {
1129 wxString tStr;
1130
1131 pNameTxt->SetValue(Contact->Name);
1132 pAddress1Txt->SetValue(Contact->Addr1);
1133 pAddress2Txt->SetValue(Contact->Addr2);
1134 pCityTxt->SetValue(Contact->City);
1135 pStateTxt->SetValue(Contact->State);
1136 pCountryTxt->SetValue(Contact->Country);
1137 pPostalCodeTxt->SetValue(Contact->PostalCode);
1138
1139 tStr.Printf(wxT("%d/%d/%d"),Contact->JoinDate.month,Contact->JoinDate.day,Contact->JoinDate.year);
1140 pJoinDateTxt->SetValue(tStr);
1141
1142 tStr.Printf(wxT("%d"),Contact->Contributions);
1143 pContribTxt->SetValue(tStr);
1144
1145 tStr.Printf(wxT("%lu"),Contact->LinesOfCode);
1146 pLinesTxt->SetValue(tStr);
1147
1148 pNativeLangChoice->SetSelection(Contact->NativeLanguage);
1149
1150 pDeveloperRadio->SetSelection(Contact->IsDeveloper);
1151
1152 return TRUE;
1153 } // Ceditor::PutData()
1154
1155
1156 /*
1157 * Reads the data out of all the widgets on the dialog. Some data evaluation is done
1158 * to ensure that there is a name entered and that the date field is valid.
1159 *
1160 * A return value of TRUE means that valid data was retrieved from the dialog, otherwise
1161 * invalid data was found (and a message was displayed telling the user what to fix), and
1162 * the data was not placed into the appropraite fields of Ccontact
1163 */
1164 bool CeditorDlg::GetData()
1165 {
1166 // Validate that the data currently entered into the widgets is valid data
1167
1168 wxString tStr;
1169 tStr = pNameTxt->GetValue();
1170 if (!wxStrcmp((const wxChar*) tStr,wxT("")))
1171 {
1172 wxMessageBox(wxT("A name is required for entry into the contact table"),wxT("Notice..."),wxOK | wxICON_INFORMATION);
1173 return FALSE;
1174 }
1175
1176 bool invalid = FALSE;
1177 int mm,dd,yyyy;
1178 int first, second;
1179
1180 tStr = pJoinDateTxt->GetValue();
1181 if (tStr.Freq(wxT('/')) != 2)
1182 invalid = TRUE;
1183
1184 // Find the month, day, and year tokens
1185 if (!invalid)
1186 {
1187 first = tStr.First(wxT('/'));
1188 second = tStr.Last(wxT('/'));
1189
1190 mm = atoi(tStr.SubString(0,first));
1191 dd = atoi(tStr.SubString(first+1,second));
1192 yyyy = atoi(tStr.SubString(second+1,tStr.Length()-1));
1193
1194 invalid = !(mm && dd && yyyy);
1195 }
1196
1197 // Force Year 2000 compliance
1198 if (!invalid && (yyyy < 1000))
1199 invalid = TRUE;
1200
1201 // Check the token ranges for validity
1202 if (!invalid)
1203 {
1204 if (yyyy > 9999)
1205 invalid = TRUE;
1206 else if ((mm < 1) || (mm > 12))
1207 invalid = TRUE;
1208 else
1209 {
1210 if (dd < 1)
1211 invalid = TRUE;
1212 else
1213 {
1214 int days[12] = {31,28,31,30,31,30,
1215 31,31,30,31,30,31};
1216 if (dd > days[mm-1])
1217 {
1218 invalid = TRUE;
1219 if ((dd == 29) && (mm == 2))
1220 {
1221 if (((yyyy % 4) == 0) && (((yyyy % 100) != 0) || ((yyyy % 400) == 0)))
1222 invalid = FALSE;
1223 }
1224 }
1225 }
1226 }
1227 }
1228
1229 if (!invalid)
1230 {
1231 Contact->JoinDate.month = mm;
1232 Contact->JoinDate.day = dd;
1233 Contact->JoinDate.year = yyyy;
1234 }
1235 else
1236 {
1237 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);
1238 return FALSE;
1239 }
1240
1241 tStr = pNameTxt->GetValue();
1242 wxStrcpy(Contact->Name,(const wxChar*) tStr);
1243 wxStrcpy(Contact->Addr1,pAddress1Txt->GetValue());
1244 wxStrcpy(Contact->Addr2,pAddress2Txt->GetValue());
1245 wxStrcpy(Contact->City,pCityTxt->GetValue());
1246 wxStrcpy(Contact->State,pStateTxt->GetValue());
1247 wxStrcpy(Contact->Country,pCountryTxt->GetValue());
1248 wxStrcpy(Contact->PostalCode,pPostalCodeTxt->GetValue());
1249
1250 Contact->Contributions = atoi(pContribTxt->GetValue());
1251 Contact->LinesOfCode = atol(pLinesTxt->GetValue());
1252
1253 Contact->NativeLanguage = (enum Language) pNativeLangChoice->GetSelection();
1254 Contact->IsDeveloper = pDeveloperRadio->GetSelection() > 0;
1255
1256 return TRUE;
1257 } // CeditorDlg::GetData()
1258
1259
1260 /*
1261 * Retrieve data from the dialog, verify the validity of the data, and if it is valid,
1262 * try to insert/update the data to the table based on the current 'mode' the dialog
1263 * is set to.
1264 *
1265 * A return value of TRUE means the insert/update was completed successfully, a return
1266 * value of FALSE means that Save() failed. If returning FALSE, then this function
1267 * has displayed a detailed error message for the user.
1268 */
1269 bool CeditorDlg::Save()
1270 {
1271 bool failed = FALSE;
1272
1273 // Read the data in the widgets of the dialog to get the user's data
1274 if (!GetData())
1275 failed = TRUE;
1276
1277 // Perform any other required validations necessary before saving
1278 if (!failed)
1279 {
1280 wxBeginBusyCursor();
1281
1282 if (mode == mCreate)
1283 {
1284 RETCODE result = Contact->Insert();
1285
1286 failed = (result != DB_SUCCESS);
1287 if (failed)
1288 {
1289 // Some errors may be expected, like a duplicate key, so handle those instances with
1290 // specific error messages.
1291 if (result == DB_ERR_INTEGRITY_CONSTRAINT_VIOL)
1292 {
1293 wxString tStr;
1294 tStr = wxT("A duplicate key value already exists in the table.\nUnable to save record\n\n");
1295 tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
1296 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1297 }
1298 else
1299 {
1300 // Some other unexpexted error occurred
1301 wxString tStr;
1302 tStr = wxT("Database insert failed\n\n");
1303 tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
1304 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1305 }
1306 }
1307 }
1308 else // mode == mEdit
1309 {
1310 Contact->whereStr.Printf("NAME = '%s'",saveName.c_str());
1311 if (!Contact->UpdateWhere(Contact->whereStr))
1312 {
1313 wxString tStr;
1314 tStr = wxT("Database update failed\n\n");
1315 tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
1316 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1317 failed = TRUE;
1318 }
1319 }
1320
1321 if (!failed)
1322 {
1323 Contact->GetDb()->CommitTrans();
1324 SetMode(mView); // Sets the dialog mode back to viewing after save is successful
1325 }
1326 else
1327 Contact->GetDb()->RollbackTrans();
1328
1329 wxEndBusyCursor();
1330 }
1331
1332 return !failed;
1333 } // CeditorDlg::Save()
1334
1335
1336 /*
1337 * Where this program is only showing a single row at a time in the dialog,
1338 * a special where clause must be built to find just the single row which,
1339 * in sequence, would follow the currently displayed row.
1340 */
1341 bool CeditorDlg::GetNextRec()
1342 {
1343 wxString w;
1344
1345 if (Contact->GetDb()->Dbms() != dbmsPOSTGRES && Contact->GetDb()->Dbms() != dbmsMY_SQL)
1346 {
1347 w = wxT("NAME = (SELECT MIN(NAME) FROM ");
1348 w += Contact->GetTableName();
1349 w += wxT(" WHERE NAME > '");
1350 }
1351 else
1352 w = wxT("(NAME > '");
1353
1354 w += Contact->Name;
1355 w += wxT("'");
1356
1357 // If a query where string is currently set, append that criteria
1358 if (!Contact->qryWhereStr.IsEmpty())
1359 {
1360 w += wxT(" AND (");
1361 w += Contact->qryWhereStr;
1362 w += wxT(")");
1363 }
1364
1365 w += wxT(")");
1366 return(GetRec(w));
1367
1368 } // CeditorDlg::GetNextRec()
1369
1370
1371 /*
1372 * Where this program is only showing a single row at a time in the dialog,
1373 * a special where clause must be built to find just the single row which,
1374 * in sequence, would precede the currently displayed row.
1375 */
1376 bool CeditorDlg::GetPrevRec()
1377 {
1378 wxString w;
1379
1380 if (Contact->GetDb()->Dbms() != dbmsPOSTGRES && Contact->GetDb()->Dbms() != dbmsMY_SQL)
1381 {
1382 w = wxT("NAME = (SELECT MAX(NAME) FROM ");
1383 w += Contact->GetTableName();
1384 w += wxT(" WHERE NAME < '");
1385 }
1386 else
1387 w = wxT("(NAME < '");
1388
1389 w += Contact->Name;
1390 w += wxT("'");
1391
1392 // If a query where string is currently set, append that criteria
1393 if (!Contact->qryWhereStr.IsEmpty())
1394 {
1395 w += wxT(" AND (");
1396 w += Contact->qryWhereStr;
1397 w += wxT(")");
1398 }
1399
1400 w += wxT(")");
1401
1402 return(GetRec(w));
1403
1404 } // CeditorDlg::GetPrevRec()
1405
1406
1407 /*
1408 * This function is here to avoid duplicating this same code in both the
1409 * GetPrevRec() and GetNextRec() functions
1410 */
1411 bool CeditorDlg::GetRec(const wxString &whereStr)
1412 {
1413 Contact->SetWhereClause(whereStr);
1414 Contact->SetOrderByClause(wxT("NAME"));
1415
1416 if (!Contact->Query())
1417 {
1418 wxString tStr;
1419 tStr = wxT("ODBC error during Query()\n\n");
1420 tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
1421 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1422
1423 return(FALSE);
1424 }
1425
1426 if (Contact->GetNext())
1427 {
1428 PutData();
1429 return(TRUE);
1430 }
1431 else
1432 return(FALSE);
1433 } // CeditorDlg::GetRec()
1434
1435
1436
1437 /*
1438 * CparameterDlg constructor
1439 */
1440
1441 BEGIN_EVENT_TABLE(CparameterDlg, wxDialog)
1442 EVT_BUTTON(PARAMETER_DIALOG_SAVE, CparameterDlg::OnButton)
1443 EVT_BUTTON(PARAMETER_DIALOG_CANCEL, CparameterDlg::OnButton)
1444 EVT_CLOSE(CparameterDlg::OnCloseWindow)
1445 END_EVENT_TABLE()
1446
1447 CparameterDlg::CparameterDlg(wxWindow *parent) : wxDialog (parent, PARAMETER_DIALOG, wxT("ODBC parameter settings"), wxPoint(-1, -1), wxSize(400, 325))
1448 {
1449 // Since the ::OnCommand() function is overridden, this prevents the widget
1450 // detection in ::OnCommand() until all widgets have been initialized to prevent
1451 // uninitialized pointers from crashing the program
1452 widgetPtrsSet = FALSE;
1453
1454 pParamODBCSourceMsg = new wxStaticText(this, PARAMETER_DIALOG_SOURCE_MSG, wxT("ODBC data sources:"), wxPoint( 10, 10), wxSize( -1, -1), 0, wxT("ParamODBCSourceMsg"));
1455 pParamODBCSourceList = new wxListBox(this, PARAMETER_DIALOG_SOURCE_LISTBOX, wxPoint( 10, 29), wxSize(285, 150), 0, 0, wxLB_SINGLE|wxLB_ALWAYS_SB, wxDefaultValidator, wxT("ParamODBCSourceList"));
1456 pParamUserNameMsg = new wxStaticText(this, PARAMETER_DIALOG_NAME_MSG, wxT("Database user name:"), wxPoint( 10, 193), wxSize( -1, -1), 0, wxT("ParamUserNameMsg"));
1457 pParamUserNameTxt = new wxTextCtrl(this, PARAMETER_DIALOG_NAME_TEXT, wxT(""), wxPoint(10, 209), wxSize( 140, 25), 0, wxDefaultValidator, wxT("ParamUserNameTxt"));
1458 pParamPasswordMsg = new wxStaticText(this, PARAMETER_DIALOG_PASSWORD_MSG, wxT("Password:"), wxPoint(156, 193), wxSize( -1, -1), 0, wxT("ParamPasswordMsg"));
1459 pParamPasswordTxt = new wxTextCtrl(this, PARAMETER_DIALOG_PASSWORD_TEXT, wxT(""), wxPoint(156, 209), wxSize( 140, 25), 0, wxDefaultValidator, wxT("ParamPasswordTxt"));
1460 pParamDirPathMsg = new wxStaticText(this, PARAMETER_DIALOG_DIRPATH_MSG, wxT("Directory:"), wxPoint( 10, 243), wxSize( -1, -1), 0, wxT("ParamDirPathMsg"));
1461 pParamDirPathTxt = new wxTextCtrl(this, PARAMETER_DIALOG_DIRPATH_TEXT, wxT(""), wxPoint( 10, 259), wxSize(140, 25), 0, wxDefaultValidator, wxT("ParamDirPathTxt"));
1462 pParamSaveBtn = new wxButton(this, PARAMETER_DIALOG_SAVE, wxT("&Save"), wxPoint(310, 21), wxSize( 70, 35), 0, wxDefaultValidator, wxT("ParamSaveBtn"));
1463 pParamCancelBtn = new wxButton(this, PARAMETER_DIALOG_CANCEL, wxT("C&ancel"), wxPoint(310, 66), wxSize( 70, 35), 0, wxDefaultValidator, wxT("ParamCancelBtn"));
1464
1465 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
1466 // handle all widget processing
1467 widgetPtrsSet = TRUE;
1468
1469 saved = FALSE;
1470 savedParamSettings = wxGetApp().params;
1471
1472 Centre(wxBOTH);
1473 PutData();
1474 ShowModal();
1475 } // CparameterDlg constructor
1476
1477
1478 void CparameterDlg::OnCloseWindow(wxCloseEvent& event)
1479 {
1480 // Put any additional checking necessary to make certain it is alright
1481 // to close the program here that is not done elsewhere
1482 if (!saved)
1483 {
1484 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);
1485
1486 if (!Ok)
1487 {
1488 event.Veto();
1489 return;
1490 }
1491
1492 wxGetApp().params = savedParamSettings;
1493 }
1494
1495 if (GetParent() != NULL)
1496 GetParent()->SetFocus();
1497
1498 while (wxIsBusy())
1499 wxEndBusyCursor();
1500
1501 Show(FALSE);
1502 SetReturnCode(0); // added so BoundsChecker would not report use of uninitialized variable
1503
1504 this->Destroy();
1505 } // CparameterDlg::OnCloseWindow()
1506
1507
1508 void CparameterDlg::OnButton( wxCommandEvent &event )
1509 {
1510 wxWindow *win = (wxWindow*) event.GetEventObject();
1511 OnCommand( *win, event );
1512 }
1513
1514
1515 void CparameterDlg::OnCommand(wxWindow& win, wxCommandEvent& event)
1516 {
1517 wxString widgetName;
1518
1519 widgetName = win.GetName();
1520
1521 if (!widgetPtrsSet)
1522 return;
1523
1524 if (widgetName == pParamSaveBtn->GetName())
1525 {
1526 if (Save())
1527 {
1528 wxString tStr;
1529 tStr = wxT("Database parameters have been saved.");
1530 if (GetParent() != NULL) // The parameter dialog was not called during startup due to a missing cfg file
1531 tStr += wxT("\nNew parameters will take effect the next time the program is started.");
1532 wxMessageBox(tStr,wxT("Notice..."),wxOK | wxICON_INFORMATION);
1533 saved = TRUE;
1534 Close();
1535 }
1536 return;
1537 }
1538
1539 if (widgetName == pParamCancelBtn->GetName())
1540 {
1541 Close();
1542 return;
1543 }
1544 } // CparameterDlg::OnCommand()
1545
1546
1547 bool CparameterDlg::PutData()
1548 {
1549 // Fill the data source list box
1550 FillDataSourceList();
1551
1552 // Fill in the fields from the params object
1553 if (wxGetApp().params.ODBCSource && wxStrlen(wxGetApp().params.ODBCSource))
1554 pParamODBCSourceList->SetStringSelection(wxGetApp().params.ODBCSource);
1555 pParamUserNameTxt->SetValue(wxGetApp().params.UserName);
1556 pParamPasswordTxt->SetValue(wxGetApp().params.Password);
1557 pParamDirPathTxt->SetValue(wxGetApp().params.DirPath);
1558 return TRUE;
1559 } // CparameterDlg::PutData()
1560
1561
1562 bool CparameterDlg::GetData()
1563 {
1564 wxString tStr;
1565 if (pParamODBCSourceList->GetStringSelection() != wxT(""))
1566 {
1567 tStr = pParamODBCSourceList->GetStringSelection();
1568 if (tStr.Length() > (sizeof(wxGetApp().params.ODBCSource)-1))
1569 {
1570 wxString errmsg;
1571 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());
1572 wxMessageBox(errmsg,wxT("Internal program error..."),wxOK | wxICON_EXCLAMATION);
1573 return FALSE;
1574 }
1575 wxStrcpy(wxGetApp().params.ODBCSource, tStr);
1576 }
1577 else
1578 return FALSE;
1579
1580 tStr = pParamUserNameTxt->GetValue();
1581 if (tStr.Length() > (sizeof(wxGetApp().params.UserName)-1))
1582 {
1583 wxString errmsg;
1584 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());
1585 wxMessageBox(errmsg,wxT("Internal program error..."),wxOK | wxICON_EXCLAMATION);
1586 return FALSE;
1587 }
1588 wxStrcpy(wxGetApp().params.UserName, tStr);
1589
1590 tStr = pParamPasswordTxt->GetValue();
1591 if (tStr.Length() > (sizeof(wxGetApp().params.Password)-1))
1592 {
1593 wxString errmsg;
1594 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());
1595 wxMessageBox(errmsg,wxT("Internal program error..."),wxOK | wxICON_EXCLAMATION);
1596 return FALSE;
1597 }
1598 wxStrcpy(wxGetApp().params.Password,tStr);
1599
1600 tStr = pParamDirPathTxt->GetValue();
1601 tStr.Replace(wxT("\\"),wxT("/"));
1602 if (tStr.Length() > (sizeof(wxGetApp().params.DirPath)-1))
1603 {
1604 wxString errmsg;
1605 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());
1606 wxMessageBox(errmsg,wxT("Internal program error..."),wxOK | wxICON_EXCLAMATION);
1607 return FALSE;
1608 }
1609 wxStrcpy(wxGetApp().params.DirPath,tStr);
1610 return TRUE;
1611 } // CparameterDlg::GetData()
1612
1613
1614 bool CparameterDlg::Save()
1615 {
1616 // Copy the current params in case user cancels changing
1617 // the params, so that we can reset them.
1618 if (!GetData())
1619 {
1620 wxGetApp().params = savedParamSettings;
1621 return FALSE;
1622 }
1623
1624 wxGetApp().WriteParamFile(wxGetApp().params);
1625
1626 return TRUE;
1627 } // CparameterDlg::Save()
1628
1629
1630 void CparameterDlg::FillDataSourceList()
1631 {
1632 wxChar Dsn[SQL_MAX_DSN_LENGTH + 1];
1633 wxChar DsDesc[255];
1634 wxStringList strList;
1635
1636 while (wxDbGetDataSource(wxGetApp().DbConnectInf->GetHenv(), Dsn,
1637 SQL_MAX_DSN_LENGTH+1, DsDesc, 255))
1638 strList.Add(Dsn);
1639
1640 strList.Sort();
1641 strList.Add(wxT(""));
1642 wxChar **p = strList.ListToArray();
1643
1644 int i;
1645 for (i = 0; wxStrlen(p[i]); i++)
1646 pParamODBCSourceList->Append(p[i]);
1647
1648 delete [] p;
1649 } // CparameterDlg::CparameterDlg::FillDataSourceList()
1650
1651
1652 BEGIN_EVENT_TABLE(CqueryDlg, wxDialog)
1653 EVT_BUTTON(-1, CqueryDlg::OnButton)
1654 EVT_CLOSE(CqueryDlg::OnCloseWindow)
1655 END_EVENT_TABLE()
1656
1657
1658 // CqueryDlg() constructor
1659 CqueryDlg::CqueryDlg(wxWindow *parent, wxDb *pDb, wxChar *tblName[], wxChar *pWhereArg) : wxDialog (parent, QUERY_DIALOG, wxT("Query"), wxPoint(-1, -1), wxSize(480, 360))
1660 {
1661 wxBeginBusyCursor();
1662
1663 colInf = 0;
1664 dbTable = 0;
1665 masterTableName = tblName[0];
1666 widgetPtrsSet = FALSE;
1667 pDB = pDb;
1668
1669 // Initialize the WHERE clause from the string passed in
1670 pWhere = pWhereArg; // Save a pointer to the output buffer
1671 if (wxStrlen(pWhere) > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN) // Check the length of the buffer passed in
1672 {
1673 wxString s;
1674 s.Printf(wxT("Maximum where clause length exceeded.\nLength must be less than %d"), DB_MAX_WHERE_CLAUSE_LEN+1);
1675 wxMessageBox(s,wxT("Error..."),wxOK | wxICON_EXCLAMATION);
1676 Close();
1677 return;
1678 }
1679
1680 pQueryCol1Msg = new wxStaticText(this, QUERY_DIALOG_COL_MSG, wxT("Column 1:"), wxPoint( 10, 10), wxSize( 69, 16), 0, wxT("QueryCol1Msg"));
1681 pQueryCol1Choice = new wxChoice(this, QUERY_DIALOG_COL_CHOICE, wxPoint( 10, 27), wxSize(250, 27), 0, 0, 0, wxDefaultValidator, wxT("QueryCol1Choice"));
1682 pQueryNotMsg = new wxStaticText(this, QUERY_DIALOG_NOT_MSG, wxT("NOT"), wxPoint(268, 10), wxSize( -1, -1), 0, wxT("QueryNotMsg"));
1683 pQueryNotCheck = new wxCheckBox(this, QUERY_DIALOG_NOT_CHECKBOX, wxT(""), wxPoint(275, 37), wxSize( 20, 20), 0, wxDefaultValidator, wxT("QueryNotCheck"));
1684
1685 wxString choice_strings[9];
1686 choice_strings[0] = wxT("=");
1687 choice_strings[1] = wxT("<");
1688 choice_strings[2] = wxT(">");
1689 choice_strings[3] = wxT("<=");
1690 choice_strings[4] = wxT(">=");
1691 choice_strings[5] = wxT("Begins");
1692 choice_strings[6] = wxT("Contains");
1693 choice_strings[7] = wxT("Like");
1694 choice_strings[8] = wxT("Between");
1695
1696 pQueryOperatorMsg = new wxStaticText(this, QUERY_DIALOG_OP_MSG, wxT("Operator:"), wxPoint(305, 10), wxSize( -1, -1), 0, wxT("QueryOperatorMsg"));
1697 pQueryOperatorChoice = new wxChoice(this, QUERY_DIALOG_OP_CHOICE, wxPoint(305, 27), wxSize( 80, 27), 9, choice_strings, 0, wxDefaultValidator, wxT("QueryOperatorChoice"));
1698 pQueryCol2Msg = new wxStaticText(this, QUERY_DIALOG_COL2_MSG, wxT("Column 2:"), wxPoint( 10, 65), wxSize( 69, 16), 0, wxT("QueryCol2Msg"));
1699 pQueryCol2Choice = new wxChoice(this, QUERY_DIALOG_COL2_CHOICE, wxPoint( 10, 82), wxSize(250, 27), 0, 0, 0, wxDefaultValidator, wxT("QueryCol2Choice"));
1700 pQuerySqlWhereMsg = new wxStaticText(this, QUERY_DIALOG_WHERE_MSG, wxT("SQL where clause:"), wxPoint( 10, 141), wxSize( -1, -1), 0, wxT("QuerySqlWhereMsg"));
1701 pQuerySqlWhereMtxt = new wxTextCtrl(this, QUERY_DIALOG_WHERE_TEXT, wxT(""), wxPoint( 10, 159), wxSize(377, 134), wxTE_MULTILINE, wxDefaultValidator, wxT("QuerySqlWhereMtxt"));
1702 pQueryAddBtn = new wxButton(this, QUERY_DIALOG_ADD, wxT("&Add"), wxPoint(406, 24), wxSize( 56, 26), 0, wxDefaultValidator, wxT("QueryAddBtn"));
1703 pQueryAndBtn = new wxButton(this, QUERY_DIALOG_AND, wxT("A&nd"), wxPoint(406, 58), wxSize( 56, 26), 0, wxDefaultValidator, wxT("QueryAndBtn"));
1704 pQueryOrBtn = new wxButton(this, QUERY_DIALOG_OR, wxT("&Or"), wxPoint(406, 92), wxSize( 56, 26), 0, wxDefaultValidator, wxT("QueryOrBtn"));
1705 pQueryLParenBtn = new wxButton(this, QUERY_DIALOG_LPAREN, wxT("("), wxPoint(406, 126), wxSize( 26, 26), 0, wxDefaultValidator, wxT("QueryLParenBtn"));
1706 pQueryRParenBtn = new wxButton(this, QUERY_DIALOG_RPAREN, wxT(")"), wxPoint(436, 126), wxSize( 26, 26), 0, wxDefaultValidator, wxT("QueryRParenBtn"));
1707 pQueryDoneBtn = new wxButton(this, QUERY_DIALOG_DONE, wxT("&Done"), wxPoint(406, 185), wxSize( 56, 26), 0, wxDefaultValidator, wxT("QueryDoneBtn"));
1708 pQueryClearBtn = new wxButton(this, QUERY_DIALOG_CLEAR, wxT("C&lear"), wxPoint(406, 218), wxSize( 56, 26), 0, wxDefaultValidator, wxT("QueryClearBtn"));
1709 pQueryCountBtn = new wxButton(this, QUERY_DIALOG_COUNT, wxT("&Count"), wxPoint(406, 252), wxSize( 56, 26), 0, wxDefaultValidator, wxT("QueryCountBtn"));
1710 pQueryValue1Msg = new wxStaticText(this, QUERY_DIALOG_VALUE1_MSG, wxT("Value:"), wxPoint(277, 66), wxSize( -1, -1), 0, wxT("QueryValue1Msg"));
1711 pQueryValue1Txt = new wxTextCtrl(this, QUERY_DIALOG_VALUE1_TEXT, wxT(""), wxPoint(277, 83), wxSize(108, 25), 0, wxDefaultValidator, wxT("QueryValue1Txt"));
1712 pQueryValue2Msg = new wxStaticText(this, QUERY_DIALOG_VALUE2_MSG, wxT("AND"), wxPoint(238, 126), wxSize( -1, -1), 0, wxT("QueryValue2Msg"));
1713 pQueryValue2Txt = new wxTextCtrl(this, QUERY_DIALOG_VALUE2_TEXT, wxT(""), wxPoint(277, 120), wxSize(108, 25), 0, wxDefaultValidator, wxT("QueryValue2Txt"));
1714 pQueryHintGrp = new wxStaticBox(this, QUERY_DIALOG_HINT_GROUP, wxT(""), wxPoint( 10, 291), wxSize(377, 40), 0, wxT("QueryHintGrp"));
1715 pQueryHintMsg = new wxStaticText(this, QUERY_DIALOG_HINT_MSG, wxT(""), wxPoint( 16, 306), wxSize( -1, -1), 0, wxT("QueryHintMsg"));
1716
1717 widgetPtrsSet = TRUE;
1718 // Initialize the dialog
1719 wxString qualName;
1720 pQueryCol2Choice->Append(wxT("VALUE -->"));
1721 colInf = pDB->GetColumns(tblName);
1722
1723 if (!colInf)
1724 {
1725 wxEndBusyCursor();
1726 wxString tStr;
1727 tStr = wxT("ODBC error during GetColumns()\n\n");
1728 tStr += GetExtendedDBErrorMsg(pDb,__FILE__,__LINE__);
1729 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
1730 return;
1731 }
1732
1733 int i;
1734 for (i = 0; colInf[i].colName && wxStrlen(colInf[i].colName); i++)
1735 {
1736 // If there is more than one table being queried, qualify
1737 // the column names with the table name prefix.
1738 if (tblName[1] && wxStrlen(tblName[1]))
1739 {
1740 qualName.Printf(wxT("%s.%s"), colInf[i].tableName, colInf[i].colName);
1741 pQueryCol1Choice->Append(qualName);
1742 pQueryCol2Choice->Append(qualName);
1743 }
1744 else // Single table query, append just the column names
1745 {
1746 pQueryCol1Choice->Append(colInf[i].colName);
1747 pQueryCol2Choice->Append(colInf[i].colName);
1748 }
1749 }
1750
1751 pQueryCol1Choice->SetSelection(0);
1752 pQueryCol2Choice->SetSelection(0);
1753 pQueryOperatorChoice->SetSelection(0);
1754
1755 pQueryValue2Msg->Show(FALSE);
1756 pQueryValue2Txt->Show(FALSE);
1757
1758 pQueryHintMsg->SetLabel(langQRY_EQ);
1759
1760 pQuerySqlWhereMtxt->SetValue(pWhere);
1761
1762 wxEndBusyCursor();
1763
1764 // Display the dialog window
1765 Centre(wxBOTH);
1766 ShowModal();
1767 } // CqueryDlg() constructor
1768
1769
1770 CqueryDlg::~CqueryDlg()
1771 {
1772 } // CqueryDlg::~CqueryDlg() destructor
1773
1774
1775 void CqueryDlg::OnButton(wxCommandEvent &event)
1776 {
1777 wxWindow *win = (wxWindow*) event.GetEventObject();
1778 OnCommand( *win, event );
1779 } // CqueryDlg::OnButton()
1780
1781
1782 void CqueryDlg::OnCommand(wxWindow& win, wxCommandEvent& event)
1783 {
1784 // Widget pointers won't be set when the dialog is constructed.
1785 // Control is passed through this function once for each widget on
1786 // a dialog as the dialog is constructed.
1787 if (!widgetPtrsSet)
1788 return;
1789
1790 wxString widgetName = win.GetName();
1791
1792 // Operator choice box
1793 if (widgetName == pQueryOperatorChoice->GetName())
1794 {
1795 // Set the help text
1796 switch((qryOp) pQueryOperatorChoice->GetSelection())
1797 {
1798 case qryOpEQ:
1799 pQueryHintMsg->SetLabel(langQRY_EQ);
1800 break;
1801 case qryOpLT:
1802 pQueryHintMsg->SetLabel(langQRY_LT);
1803 break;
1804 case qryOpGT:
1805 pQueryHintMsg->SetLabel(langQRY_GT);
1806 break;
1807 case qryOpLE:
1808 pQueryHintMsg->SetLabel(langQRY_LE);
1809 break;
1810 case qryOpGE:
1811 pQueryHintMsg->SetLabel(langQRY_GE);
1812 break;
1813 case qryOpBEGINS:
1814 pQueryHintMsg->SetLabel(langQRY_BEGINS);
1815 break;
1816 case qryOpCONTAINS:
1817 pQueryHintMsg->SetLabel(langQRY_CONTAINS);
1818 break;
1819 case qryOpLIKE:
1820 pQueryHintMsg->SetLabel(langQRY_LIKE);
1821 break;
1822 case qryOpBETWEEN:
1823 pQueryHintMsg->SetLabel(langQRY_BETWEEN);
1824 break;
1825 }
1826
1827 // Hide the value2 widget
1828 pQueryValue2Msg->Show(FALSE); // BETWEEN will show this widget
1829 pQueryValue2Txt->Show(FALSE); // BETWEEN will show this widget
1830
1831 // Disable the NOT operator for <, <=, >, >=
1832 switch((qryOp) pQueryOperatorChoice->GetSelection())
1833 {
1834 case qryOpLT:
1835 case qryOpGT:
1836 case qryOpLE:
1837 case qryOpGE:
1838 pQueryNotCheck->SetValue(0);
1839 pQueryNotCheck->Enable(FALSE);
1840 break;
1841 default:
1842 pQueryNotCheck->Enable(TRUE);
1843 break;
1844 }
1845
1846 // Manipulate the dialog to handle the selected operator
1847 switch((qryOp) pQueryOperatorChoice->GetSelection())
1848 {
1849 case qryOpEQ:
1850 case qryOpLT:
1851 case qryOpGT:
1852 case qryOpLE:
1853 case qryOpGE:
1854 pQueryCol2Choice->Enable(TRUE);
1855 if (pQueryCol2Choice->GetSelection()) // Column name is highlighted
1856 {
1857 pQueryValue1Msg->Show(FALSE);
1858 pQueryValue1Txt->Show(FALSE);
1859 }
1860 else // "Value" is highlighted
1861 {
1862 pQueryValue1Msg->Show(TRUE);
1863 pQueryValue1Txt->Show(TRUE);
1864 pQueryValue1Txt->SetFocus();
1865 }
1866 break;
1867 case qryOpBEGINS:
1868 case qryOpCONTAINS:
1869 case qryOpLIKE:
1870 pQueryCol2Choice->SetSelection(0);
1871 pQueryCol2Choice->Enable(FALSE);
1872 pQueryValue1Msg->Show(TRUE);
1873 pQueryValue1Txt->Show(TRUE);
1874 pQueryValue1Txt->SetFocus();
1875 break;
1876 case qryOpBETWEEN:
1877 pQueryCol2Choice->SetSelection(0);
1878 pQueryCol2Choice->Enable(FALSE);
1879 pQueryValue2Msg->Show(TRUE);
1880 pQueryValue2Txt->Show(TRUE);
1881 pQueryValue1Msg->Show(TRUE);
1882 pQueryValue1Txt->Show(TRUE);
1883 pQueryValue1Txt->SetFocus();
1884 break;
1885 }
1886
1887 return;
1888
1889 } // Operator choice box
1890
1891 // Column 2 choice
1892 if (widgetName == pQueryCol2Choice->GetName())
1893 {
1894 if (pQueryCol2Choice->GetSelection()) // Column name is highlighted
1895 {
1896 pQueryValue1Msg->Show(FALSE);
1897 pQueryValue1Txt->Show(FALSE);
1898 }
1899 else // "Value" is highlighted
1900 {
1901 pQueryValue1Msg->Show(TRUE);
1902 pQueryValue1Txt->Show(TRUE);
1903 pQueryValue1Txt->SetFocus();
1904 }
1905 return;
1906 } // Column 2 choice
1907
1908 // Add button
1909 if (widgetName == pQueryAddBtn->GetName())
1910 {
1911 ProcessAddBtn();
1912 return;
1913 } // Add button
1914
1915 // And button
1916 if (widgetName == pQueryAndBtn->GetName())
1917 {
1918 AppendToWhere(wxT(" AND\n"));
1919 return;
1920 } // And button
1921
1922 // Or button
1923 if (widgetName == pQueryOrBtn->GetName())
1924 {
1925 AppendToWhere(wxT(" OR\n"));
1926 return;
1927 } // Or button
1928
1929 // Left Paren button
1930 if (widgetName == pQueryLParenBtn->GetName())
1931 {
1932 AppendToWhere(wxT("("));
1933 return;
1934 } // Left Paren button
1935
1936 // Right paren button
1937 if (widgetName == pQueryRParenBtn->GetName())
1938 {
1939 AppendToWhere(wxT(")"));
1940 return;
1941 } // Right Paren button
1942
1943 // Done button
1944 if (widgetName == pQueryDoneBtn->GetName())
1945 {
1946 // Be sure the where clause will not overflow the output buffer
1947 if (wxStrlen(pQuerySqlWhereMtxt->GetValue()) > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN)
1948 {
1949 wxString s;
1950 s.Printf(wxT("Maximum where clause length exceeded.\nLength must be less than %d"), DB_MAX_WHERE_CLAUSE_LEN+1);
1951 wxMessageBox(s,wxT("Error..."),wxOK | wxICON_EXCLAMATION);
1952 return;
1953 }
1954 // Validate the where clause for things such as matching parens
1955 if (!ValidateWhereClause())
1956 return;
1957 // Copy the where clause to the output buffer and exit
1958 wxStrcpy(pWhere, pQuerySqlWhereMtxt->GetValue());
1959 Close();
1960 return;
1961 } // Done button
1962
1963 // Clear button
1964 if (widgetName == pQueryClearBtn->GetName())
1965 {
1966 bool Ok = (wxMessageBox(wxT("Are you sure you wish to clear the Query?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
1967
1968 if (Ok)
1969 pQuerySqlWhereMtxt->SetValue(wxT(""));
1970 return;
1971 } // Clear button
1972
1973 // Count button
1974 if (widgetName == pQueryCountBtn->GetName())
1975 {
1976 wxBeginBusyCursor();
1977 ProcessCountBtn();
1978 wxEndBusyCursor();
1979 return;
1980 } // Count button
1981
1982 } // CqueryDlg::OnCommand
1983
1984
1985 void CqueryDlg::OnCloseWindow(wxCloseEvent& event)
1986 {
1987 // Clean up
1988 if (colInf)
1989 {
1990 delete [] colInf;
1991 colInf = 0;
1992 }
1993
1994 if (dbTable)
1995 {
1996 delete dbTable;
1997 dbTable = 0;
1998 }
1999
2000 GetParent()->SetFocus();
2001 while (wxIsBusy())
2002 wxEndBusyCursor();
2003
2004 Show(FALSE);
2005 SetReturnCode(1); // added so BoundsChecker would not report use of uninitialized variable
2006
2007 this->Destroy();
2008 } // CqueryDlg::OnCloseWindow()
2009
2010
2011 void CqueryDlg::AppendToWhere(wxChar *s)
2012 {
2013 wxString whereStr = pQuerySqlWhereMtxt->GetValue();
2014 whereStr += s;
2015 pQuerySqlWhereMtxt->SetValue(whereStr);
2016 } // CqueryDlg::AppendToWhere()
2017
2018
2019 void CqueryDlg::ProcessAddBtn()
2020 {
2021 qryOp oper = (qryOp) pQueryOperatorChoice->GetSelection();
2022
2023 // Verify that eveything is filled in correctly
2024 if (pQueryCol2Choice->GetSelection() == 0) // "Value" is selected
2025 {
2026 // Verify that value 1 is filled in
2027 if (wxStrlen(pQueryValue1Txt->GetValue()) == 0)
2028 {
2029 wxBell();
2030 pQueryValue1Txt->SetFocus();
2031 return;
2032 }
2033 // For the BETWEEN operator, value 2 must be filled in as well
2034 if (oper == qryOpBETWEEN &&
2035 wxStrlen(pQueryValue2Txt->GetValue()) == 0)
2036 {
2037 wxBell();
2038 pQueryValue2Txt->SetFocus();
2039 return;
2040 }
2041 }
2042
2043 // Build the expression and append it to the where clause window
2044 wxString s = pQueryCol1Choice->GetStringSelection();
2045
2046 if (pQueryNotCheck->GetValue() && (oper != qryOpEQ))
2047 s += wxT(" NOT");
2048
2049 switch(oper)
2050 {
2051 case qryOpEQ:
2052 if (pQueryNotCheck->GetValue()) // NOT box is checked
2053 s += wxT(" <>");
2054 else
2055 s += wxT(" =");
2056 break;
2057 case qryOpLT:
2058 s += wxT(" <");
2059 break;
2060 case qryOpGT:
2061 s += wxT(" >");
2062 break;
2063 case qryOpLE:
2064 s += wxT(" <=");
2065 break;
2066 case qryOpGE:
2067 s += wxT(" >=");
2068 break;
2069 case qryOpBEGINS:
2070 case qryOpCONTAINS:
2071 case qryOpLIKE:
2072 s += wxT(" LIKE");
2073 break;
2074 case qryOpBETWEEN:
2075 s += wxT(" BETWEEN");
2076 break;
2077 }
2078
2079 s += wxT(" ");
2080
2081 int col1Idx = pQueryCol1Choice->GetSelection();
2082
2083 bool quote = FALSE;
2084 if (colInf[col1Idx].sqlDataType == SQL_VARCHAR ||
2085 oper == qryOpBEGINS ||
2086 oper == qryOpCONTAINS ||
2087 oper == qryOpLIKE)
2088 quote = TRUE;
2089
2090 if (pQueryCol2Choice->GetSelection()) // Column name
2091 s += pQueryCol2Choice->GetStringSelection();
2092 else // Column 2 is a "value"
2093 {
2094 if (quote)
2095 s += wxT("'");
2096 if (oper == qryOpCONTAINS)
2097 s += wxT("%");
2098 s += pQueryValue1Txt->GetValue();
2099 if (oper == qryOpCONTAINS || oper == qryOpBEGINS)
2100 s += wxT("%");
2101 if (quote)
2102 s += wxT("'");
2103 }
2104
2105 if (oper == qryOpBETWEEN)
2106 {
2107 s += wxT(" AND ");
2108 if (quote)
2109 s += wxT("'");
2110 s += pQueryValue2Txt->GetValue();
2111 if (quote)
2112 s += wxT("'");
2113 }
2114
2115 AppendToWhere((wxChar*) (const wxChar*) s);
2116
2117 } // CqueryDlg::ProcessAddBtn()
2118
2119
2120 void CqueryDlg::ProcessCountBtn()
2121 {
2122 if (!ValidateWhereClause())
2123 return;
2124
2125 if (dbTable == 0) // wxDbTable object needs to be created and opened
2126 {
2127 if (!(dbTable = new wxDbTable(pDB, masterTableName, 0, wxT(""),
2128 !wxDB_QUERY_ONLY,
2129 wxGetApp().DbConnectInf->GetDefaultDir())))
2130 {
2131 wxMessageBox(wxT("Memory allocation failed creating a wxDbTable object."),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
2132 return;
2133 }
2134 if (!dbTable->Open())
2135 {
2136 wxString tStr;
2137 tStr = wxT("ODBC error during Open()\n\n");
2138 tStr += GetExtendedDBErrorMsg(dbTable->GetDb(),__FILE__,__LINE__);
2139 wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
2140 return;
2141 }
2142 }
2143
2144 // Count() with WHERE clause
2145 wxString whereStr;
2146
2147 whereStr = pQuerySqlWhereMtxt->GetValue();
2148 dbTable->SetWhereClause(whereStr.c_str());
2149
2150 ULONG whereCnt = dbTable->Count();
2151
2152 // Count() of all records in the table
2153 dbTable->SetWhereClause(wxT(""));
2154 ULONG totalCnt = dbTable->Count();
2155
2156 if (whereCnt > 0 || totalCnt == 0)
2157 {
2158 wxString tStr;
2159 tStr.Printf(wxT("%lu of %lu records match the query criteria."),whereCnt,totalCnt);
2160 wxMessageBox(tStr,wxT("Notice..."),wxOK | wxICON_INFORMATION);
2161 }
2162 else
2163 {
2164 wxString tStr;
2165 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);
2166 wxMessageBox(tStr,wxT("Notice..."),wxOK | wxICON_INFORMATION);
2167 }
2168
2169 // After a wxMessageBox, the focus does not necessarily return to the
2170 // window which was the focus when the message box popped up, so return
2171 // focus to the Query dialog for certain
2172 SetFocus();
2173
2174 } // CqueryDlg::ProcessCountBtn()
2175
2176
2177 bool CqueryDlg::ValidateWhereClause()
2178 {
2179 wxString where = pQuerySqlWhereMtxt->GetValue();
2180
2181 if (where.Freq(wxT('(')) != where.Freq(wxT(')')))
2182 {
2183 wxMessageBox(wxT("There are mismatched parenthesis in the constructed where clause"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
2184 return(FALSE);
2185 }
2186 // After a wxMessageBox, the focus does not necessarily return to the
2187 // window which was the focus when the message box popped up, so return
2188 // focus to the Query dialog for certain
2189 SetFocus();
2190
2191 return(TRUE);
2192
2193 } // CqueryDlg::ValidateWhereClause()
2194
2195
2196
2197
2198 /*
2199 TEST CODE FOR TESTING THE wxDbCreateDataSource() FUNCTION
2200
2201 int result = 0;
2202 result = wxDbCreateDataSource(wxT("Microsoft Access Driver (*.mdb)"),wxT("GLT-TEST2"),wxT("GLT-Descrip"),FALSE,wxT(""),this);
2203 if (!result)
2204 {
2205 // check for errors caused by ConfigDSN based functions
2206 DWORD retcode = 0;
2207 WORD cb;
2208 wxChar errMsg[500+1];
2209 errMsg[0] = wxT('\0');
2210
2211 SQLInstallerError(1,&retcode,errMsg,500,&cb);
2212
2213 wxMessageBox(wxT("FAILED creating data source"),wxT("FAILED"));
2214 }
2215 else
2216 wxMessageBox(wxT("SUCCEEDED creating data source"),wxT("SUCCESS"));
2217 */
2218
2219