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