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