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