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