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