1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxWindows database demo app
4 // Author: George Tasker
8 // Copyright: (c) 1998 Remstar International, Inc.
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
15 This sample program demonstrates the cross-platform ODBC database classes
16 donated by the development team at Remstar International.
18 The table this sample is based on is developer contact table, and shows
19 some of the simple uses of the database classes wxDB and wxTable.
27 #pragma implementation "dbtest.h"
30 #include "wx/wxprec.h"
44 #include <stdio.h> // Included strictly for reading the text file with the database parameters
46 #include <wx/db.h> // Required in the file which will get the data source connection
47 #include <wx/dbtable.h> // Has the wxTable object from which all data objects will inherit their data table functionality
49 extern DbList
* WXDLLEXPORT PtrBegDbList
; // from db.cpp, used in getting back error results from db connections
51 #include "dbtest.h" // Header file for this demonstration program
52 #include "listdb.h" // Code to support the "Lookup" button on the editor dialog
54 IMPLEMENT_APP(DatabaseDemoApp
)
56 extern char ListDB_Selection
[]; // Used to return the first column value for the selected line from the listDB routines
57 extern char ListDB_Selection2
[]; // Used to return the second column value for the selected line from the listDB routines
59 DatabaseDemoFrame
*DemoFrame
; // Pointer to the main frame
62 /* Pointer to the main database connection used in the program. This
63 * pointer would normally be used for doing things as database lookups
64 * for user login names and passwords, getting workstation settings, etc.
67 * For each database object created which uses this wxDB pointer
68 * connection to the database, when a CommitTrans() or RollBackTrans()
69 * will commit or rollback EVERY object which uses this wxDB pointer.
71 * To allow each table object (those derived from wxTable) to be
72 * individually committed or rolled back, you MUST use a different
73 * instance of wxDB in the constructor of the table. Doing so creates
74 * more overhead, and will use more database connections (some DBs have
75 * connection limits...), so use connections sparringly.
77 * It is recommended that one "main" database connection be created for
78 * the entire program to use for READ-ONLY database accesses, but for each
79 * table object which will do a CommitTrans() or RollbackTrans() that a
80 * new wxDB object be created and used for it.
86 * This function will return the exact string(s) from the database engine
87 * indicating all error conditions which have just occured during the
88 * last call to the database engine.
90 * This demo uses the returned string by displaying it in a wxMessageBox. The
91 * formatting therefore is not the greatest, but this is just a demo, not a
92 * finished product. :-) gt
94 * NOTE: The value returned by this function is for temporary use only and
95 * should be copied for long term use
97 char *GetExtendedDBErrorMsg(char *ErrFile
, int ErrLine
)
103 if (ErrFile
|| ErrLine
)
110 tStr
.Printf("%d",ErrLine
);
111 msg
+= tStr
.GetData();
116 msg
.Append ("\nODBC ERRORS\n");
119 // Scan through each database connection displaying
120 // any ODBC errors that have occured.
121 for (DbList
*pDbList
= PtrBegDbList
; pDbList
; pDbList
= pDbList
->PtrNext
)
123 // Skip over any free connections
126 // Display errors for this connection
127 for (int i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
129 if (pDbList
->PtrDb
->errorList
[i
])
131 msg
.Append(pDbList
->PtrDb
->errorList
[i
]);
132 if (strcmp(pDbList
->PtrDb
->errorList
[i
],"") != 0)
139 return (char*) (const char*) msg
;
140 } // GetExtendedDBErrorMsg
143 bool DatabaseDemoApp::OnInit()
145 // Create the main frame window
146 DemoFrame
= new DatabaseDemoFrame(NULL
, "wxWindows Database Demo", wxPoint(50, 50), wxSize(537, 480));
149 DemoFrame
->SetIcon(wxICON(db
));
152 wxMenu
*file_menu
= new wxMenu
;
153 file_menu
->Append(FILE_CREATE
, "&Create contact table");
154 file_menu
->Append(FILE_EXIT
, "E&xit");
156 wxMenu
*edit_menu
= new wxMenu
;
157 edit_menu
->Append(EDIT_PARAMETERS
, "&Parameters...");
159 wxMenu
*about_menu
= new wxMenu
;
160 about_menu
->Append(ABOUT_DEMO
, "&About");
162 wxMenuBar
*menu_bar
= new wxMenuBar
;
163 menu_bar
->Append(file_menu
, "&File");
164 menu_bar
->Append(edit_menu
, "&Edit");
165 menu_bar
->Append(about_menu
, "&About");
166 DemoFrame
->SetMenuBar(menu_bar
);
168 // Initialize the ODBC Environment for Database Operations
169 if (SQLAllocEnv(&DbConnectInf
.Henv
) != SQL_SUCCESS
)
171 wxMessageBox("A problem occured while trying to get a connection to the data source","DB CONNECTION ERROR",wxOK
| wxICON_EXCLAMATION
);
176 if ((paramFile
= fopen(paramFilename
, "r")) == NULL
)
179 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
);
180 wxMessageBox(tStr
,"File I/O Error...",wxOK
| wxICON_EXCLAMATION
);
181 DemoFrame
->BuildParameterDialog(NULL
);
182 if ((paramFile
= fopen(paramFilename
, "r")) == NULL
)
187 fgets(buffer
, sizeof(params
.ODBCSource
), paramFile
);
188 buffer
[strlen(buffer
)-1] = '\0';
189 strcpy(params
.ODBCSource
,buffer
);
191 fgets(buffer
, sizeof(params
.UserName
), paramFile
);
192 buffer
[strlen(buffer
)-1] = '\0';
193 strcpy(params
.UserName
,buffer
);
195 fgets(buffer
, sizeof(params
.Password
), paramFile
);
196 buffer
[strlen(buffer
)-1] = '\0';
197 strcpy(params
.Password
,buffer
);
201 // Connect to datasource
202 strcpy(DbConnectInf
.Dsn
, params
.ODBCSource
); // ODBC data source name (created with ODBC Administrator under Win95/NT)
203 strcpy(DbConnectInf
.Uid
, params
.UserName
); // database username - must already exist in the data source
204 strcpy(DbConnectInf
.AuthStr
, params
.Password
); // password database username
205 READONLY_DB
= GetDbConnection(&DbConnectInf
);
206 if (READONLY_DB
== 0)
208 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
);
209 DemoFrame
->BuildParameterDialog(NULL
);
210 strcpy(DbConnectInf
.Dsn
, "");
211 strcpy(DbConnectInf
.Uid
, "");
212 strcpy(DbConnectInf
.AuthStr
, "");
213 wxMessageBox("Now exiting program.\n\nRestart program to try any new settings.","Notice...",wxOK
| wxICON_INFORMATION
);
217 DemoFrame
->BuildEditorDialog();
220 DemoFrame
->Show(TRUE
);
223 } // DatabaseDemoApp::OnInit()
225 BEGIN_EVENT_TABLE(DatabaseDemoFrame
, wxFrame
)
226 EVT_MENU(FILE_CREATE
, DatabaseDemoFrame::OnCreate
)
227 EVT_MENU(FILE_EXIT
, DatabaseDemoFrame::OnExit
)
228 EVT_MENU(EDIT_PARAMETERS
, DatabaseDemoFrame::OnEditParameters
)
229 EVT_MENU(ABOUT_DEMO
, DatabaseDemoFrame::OnAbout
)
230 EVT_CLOSE(DatabaseDemoFrame::OnCloseWindow
)
233 // DatabaseDemoFrame constructor
234 DatabaseDemoFrame::DatabaseDemoFrame(wxFrame
*frame
, const wxString
& title
,
235 const wxPoint
& pos
, const wxSize
& size
):
236 wxFrame(frame
, -1, title
, pos
, size
)
238 // Put any code in necessary for initializing the main frame here
241 void DatabaseDemoFrame::OnCreate(wxCommandEvent
& event
)
246 void DatabaseDemoFrame::OnExit(wxCommandEvent
& event
)
251 void DatabaseDemoFrame::OnEditParameters(wxCommandEvent
& event
)
253 if ((pEditorDlg
->mode
!= mCreate
) && (pEditorDlg
->mode
!= mEdit
))
254 BuildParameterDialog(this);
256 wxMessageBox("Cannot change database parameters while creating or editing a record","Notice...",wxOK
| wxICON_INFORMATION
);
259 void DatabaseDemoFrame::OnAbout(wxCommandEvent
& event
)
261 wxMessageBox("wxWindows sample program for database classes\n\nContributed on 27 July 1998","About...",wxOK
| wxICON_INFORMATION
);
264 void DatabaseDemoFrame::OnCloseWindow(wxCloseEvent
& event
)
266 // Put any additional checking necessary to make certain it is alright
267 // to close the program here that is not done elsewhere
270 } // DatabaseDemoFrame::OnClose()
273 void DatabaseDemoFrame::CreateDataTable()
275 bool Ok
= (wxMessageBox("Any data currently residing in the table will be erased.\n\nAre you sure?","Confirm",wxYES_NO
|wxICON_QUESTION
) == wxYES
);
284 Ccontact
*Contact
= new Ccontact();
288 wxMessageBox("Error allocating memory for 'Ccontact'object.\n\nTable was not created.","Error...",wxOK
| wxICON_EXCLAMATION
);
292 if (!Contact
->CreateTable())
296 tStr
= "Error creating CONTACTS table.\nTable was not created.\n\n";
297 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
298 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
303 if (!Contact
->CreateIndexes())
307 tStr
= "Error creating CONTACTS indexes.\nIndexes will be unavailable.\n\n";
308 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
309 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
318 wxMessageBox("Table and index(es) were successfully created.","Notice...",wxOK
| wxICON_INFORMATION
);
319 } // DatabaseDemoFrame::CreateDataTable()
322 void DatabaseDemoFrame::BuildEditorDialog()
324 pEditorDlg
= new CeditorDlg(this);
326 wxMessageBox("Unable to create the editor dialog for some reason","Error...",wxOK
| wxICON_EXCLAMATION
);
327 } // DatabaseDemoFrame::BuildEditorDialog()
330 void DatabaseDemoFrame::BuildParameterDialog(wxWindow
*parent
)
332 pParamDlg
= new CparameterDlg(parent
);
335 wxMessageBox("Unable to create the parameter dialog for some reason","Error...",wxOK
| wxICON_EXCLAMATION
);
336 } // DatabaseDemoFrame::BuildParameterDialog()
340 * Constructor note: If no wxDB object is passed in, a new connection to the database
341 * is created for this instance of Ccontact. This can be a slow process depending
342 * on the database engine being used, and some database engines have a limit on the
343 * number of connections (either hard limits, or license restricted) so care should
344 * be used to use as few connections as is necessary.
345 * IMPORTANT: Objects which share a wxDB pointer are ALL acted upon whenever a member
346 * function of pDb is called (i.e. CommitTrans() or RollbackTrans(), so if modifying
347 * or creating a table objects which use the same pDb, know that all the objects
348 * will be committed or rolled back when any of the objects has this function call made.
350 Ccontact::Ccontact (wxDB
*pwxDB
) : wxTable(pwxDB
? pwxDB
: GetDbConnection(&DbConnectInf
),CONTACT_TABLE_NAME
,CONTACT_NO_COLS
)
352 // This is used to represent whether the database connection should be released
353 // when this instance of the object is deleted. If using the same connection
354 // for multiple instance of database objects, then the connection should only be
355 // released when the last database instance using the connection is deleted
360 } // Ccontact Constructor
363 void Ccontact::Initialize()
372 JoinDate
.year
= 1980;
378 JoinDate
.fraction
= 0;
379 NativeLanguage
= langENGLISH
;
383 } // Ccontact::Initialize
386 Ccontact::~Ccontact()
390 if (!FreeDbConnection(pDb
))
393 tStr
= "Unable to Free the Ccontact data table handle\n\n";
394 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
395 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
398 } // Ccontract destructor
402 * Handles setting up all the connections for the interface from the wxTable
403 * functions to interface to the data structure used to store records in
404 * memory, and for all the column definitions that define the table structure
406 void Ccontact::SetupColumns()
408 SetColDefs ( 0,"NAME", DB_DATA_TYPE_VARCHAR
, Name
, SQL_C_CHAR
, sizeof(Name
), TRUE
, TRUE
); // Primary index
409 SetColDefs ( 1,"ADDRESS1", DB_DATA_TYPE_VARCHAR
, Addr1
, SQL_C_CHAR
, sizeof(Addr1
), FALSE
,TRUE
);
410 SetColDefs ( 2,"ADDRESS2", DB_DATA_TYPE_VARCHAR
, Addr2
, SQL_C_CHAR
, sizeof(Addr2
), FALSE
,TRUE
);
411 SetColDefs ( 3,"CITY", DB_DATA_TYPE_VARCHAR
, City
, SQL_C_CHAR
, sizeof(City
), FALSE
,TRUE
);
412 SetColDefs ( 4,"STATE", DB_DATA_TYPE_VARCHAR
, State
, SQL_C_CHAR
, sizeof(State
), FALSE
,TRUE
);
413 SetColDefs ( 5,"POSTAL_CODE", DB_DATA_TYPE_VARCHAR
, PostalCode
, SQL_C_CHAR
, sizeof(PostalCode
), FALSE
,TRUE
);
414 SetColDefs ( 6,"COUNTRY", DB_DATA_TYPE_VARCHAR
, Country
, SQL_C_CHAR
, sizeof(Country
), FALSE
,TRUE
);
415 SetColDefs ( 7,"JOIN_DATE", DB_DATA_TYPE_DATE
, &JoinDate
, SQL_C_TIMESTAMP
, sizeof(JoinDate
), FALSE
,TRUE
);
416 SetColDefs ( 8,"NATIVE_LANGUAGE", DB_DATA_TYPE_INTEGER
, &NativeLanguage
, SQL_C_ENUM
, sizeof(NativeLanguage
), FALSE
,TRUE
);
417 SetColDefs ( 9,"IS_DEVELOPER", DB_DATA_TYPE_INTEGER
, &IsDeveloper
, SQL_C_BOOLEAN
, sizeof(bool), FALSE
,TRUE
);
418 SetColDefs (10,"CONTRIBUTIONS", DB_DATA_TYPE_INTEGER
, &Contributions
, SQL_C_USHORT
, sizeof(Contributions
), FALSE
,TRUE
);
419 SetColDefs (11,"LINES_OF_CODE", DB_DATA_TYPE_INTEGER
, &LinesOfCode
, SQL_C_ULONG
, sizeof(LinesOfCode
), FALSE
,TRUE
);
420 } // Ccontact::SetupColumns
423 bool Ccontact::CreateIndexes(void)
425 // This index could easily be accomplished with an "orderBy" clause,
426 // but is done to show how to construct a non-primary index.
432 strcpy(idxDef
[0].ColName
, "IS_DEVELOPER");
433 idxDef
[0].Ascending
= TRUE
;
435 strcpy(idxDef
[1].ColName
, "NAME");
436 idxDef
[1].Ascending
= TRUE
;
438 indexName
= CONTACT_TABLE_NAME
;
439 indexName
+= "_IDX1";
440 Ok
= CreateIndex((char*) (const char*) indexName
, TRUE
, 2, idxDef
);
443 } // Ccontact::CreateIndexes()
447 * Having a function to do a query on the primary key (and possibly others) is
448 * very efficient and tighter coding so that it is available where ever the object
449 * is. Great for use with multiple tables when not using views or outer joins
451 bool Ccontact::FetchByName(char *name
)
453 whereStr
.Printf("NAME = '%s'",name
);
454 where
= (char*) (const char*) this->whereStr
;
463 } // Ccontact::FetchByName()
468 * ************* DIALOGS ***************
473 /* CeditorDlg constructor
475 * Creates the dialog used for creating/editing/deleting/copying a Ccontact object.
476 * This dialog actually is drawn in the main frame of the program
478 * An instance of Ccontact is created - "Contact" - which is used to hold the Ccontact
479 * object that is currently being worked with.
482 BEGIN_EVENT_TABLE(CeditorDlg
, wxPanel
)
483 EVT_BUTTON(-1, CeditorDlg::OnButton
)
486 CeditorDlg::CeditorDlg(wxWindow
*parent
) : wxPanel (parent
, 1, 1, 460, 455)
488 // Since the ::OnCommand() function is overridden, this prevents the widget
489 // detection in ::OnCommand() until all widgets have been initialized to prevent
490 // uninitialized pointers from crashing the program
491 widgetPtrsSet
= FALSE
;
493 // Create the data structure and a new database connection.
494 // (As there is not a pDb being passed in the constructor, a new database
495 // connection is created)
496 Contact
= new Ccontact();
500 wxMessageBox("Unable to instantiate an instance of Ccontact","Error...",wxOK
| wxICON_EXCLAMATION
);
504 // Check if the table exists or not. If it doesn't, ask the user if they want to
505 // create the table. Continue trying to create the table until it exists, or user aborts
506 while (!Contact
->pDb
->TableExists((char *)CONTACT_TABLE_NAME
))
509 tStr
.Printf("Unable to open the table '%s'.\n\nTable may need to be created...?\n\n",CONTACT_TABLE_NAME
);
510 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
511 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
513 bool createTable
= (wxMessageBox("Do you wish to try to create/clear the CONTACTS table?","Confirm",wxYES_NO
|wxICON_QUESTION
) == wxYES
);
523 DemoFrame
->CreateDataTable();
526 // Tables must be "opened" before anything other than creating/deleting table can be done
527 if (!Contact
->Open())
529 // Table does exist, there was some problem opening it. Currently this should
530 // never fail, except in the case of the table not exisiting. Open() basically
531 // only sets up variable/pointer values, other than checking for table existence.
532 if (Contact
->pDb
->TableExists((char *)CONTACT_TABLE_NAME
))
535 tStr
.Printf("Unable to open the table '%s'.\n\n",CONTACT_TABLE_NAME
);
536 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
537 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
547 wxStaticBox
*FunctionGrp
= new wxStaticBox(this, EDITOR_DIALOG_FN_GROUP
, "", wxPoint(15, 1), wxSize(497, 69), 0, "FunctionGrp");
548 wxStaticBox
*SearchGrp
= new wxStaticBox(this, EDITOR_DIALOG_SEARCH_GROUP
, "", wxPoint(417, 1), wxSize(95, 242), 0, "SearchGrp");
550 pCreateBtn
= new wxButton(this, EDITOR_DIALOG_CREATE
, "&Create", wxPoint(25, 21), wxSize(70, 35), 0, wxDefaultValidator
, "CreateBtn");
551 pEditBtn
= new wxButton(this, EDITOR_DIALOG_EDIT
, "&Edit", wxPoint(102, 21), wxSize(70, 35), 0, wxDefaultValidator
, "EditBtn");
552 pDeleteBtn
= new wxButton(this, EDITOR_DIALOG_DELETE
, "&Delete", wxPoint(179, 21), wxSize(70, 35), 0, wxDefaultValidator
, "DeleteBtn");
553 pCopyBtn
= new wxButton(this, EDITOR_DIALOG_COPY
, "Cop&y", wxPoint(256, 21), wxSize(70, 35), 0, wxDefaultValidator
, "CopyBtn");
554 pSaveBtn
= new wxButton(this, EDITOR_DIALOG_SAVE
, "&Save", wxPoint(333, 21), wxSize(70, 35), 0, wxDefaultValidator
, "SaveBtn");
555 pCancelBtn
= new wxButton(this, EDITOR_DIALOG_CANCEL
, "C&ancel", wxPoint(430, 21), wxSize(70, 35), 0, wxDefaultValidator
, "CancelBtn");
557 pPrevBtn
= new wxButton(this, EDITOR_DIALOG_PREV
, "<< &Prev", wxPoint(430, 81), wxSize(70, 35), 0, wxDefaultValidator
, "PrevBtn");
558 pNextBtn
= new wxButton(this, EDITOR_DIALOG_NEXT
, "&Next >>", wxPoint(430, 121), wxSize(70, 35), 0, wxDefaultValidator
, "NextBtn");
559 pQueryBtn
= new wxButton(this, EDITOR_DIALOG_QUERY
, "&Query", wxPoint(430, 161), wxSize(70, 35), 0, wxDefaultValidator
, "QueryBtn");
560 pResetBtn
= new wxButton(this, EDITOR_DIALOG_RESET
, "&Reset", wxPoint(430, 200), wxSize(70, 35), 0, wxDefaultValidator
, "ResetBtn");
562 pNameMsg
= new wxStaticText(this, EDITOR_DIALOG_NAME_MSG
, "Name:", wxPoint(17, 80), wxSize(-1, -1), 0, "NameMsg");
563 pNameTxt
= new wxTextCtrl(this, EDITOR_DIALOG_NAME_TEXT
, "", wxPoint(17, 97), wxSize(308, 25), 0, wxDefaultValidator
, "NameTxt");
564 pNameListBtn
= new wxButton(this, EDITOR_DIALOG_LOOKUP
, "&Lookup", wxPoint(333, 99), wxSize(70, 24), 0, wxDefaultValidator
, "LookupBtn");
566 pAddress1Msg
= new wxStaticText(this, EDITOR_DIALOG_ADDRESS1_MSG
, "Address:", wxPoint(17, 130), wxSize(-1, -1), 0, "Address1Msg");
567 pAddress1Txt
= new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT
, "", wxPoint(17, 147), wxSize(308, 25), 0, wxDefaultValidator
, "Address1Txt");
569 pAddress2Msg
= new wxStaticText(this, EDITOR_DIALOG_ADDRESS2_MSG
, "Address:", wxPoint(17, 180), wxSize(-1, -1), 0, "Address2Msg");
570 pAddress2Txt
= new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT
, "", wxPoint(17, 197), wxSize(308, 25), 0, wxDefaultValidator
, "Address2Txt");
572 pCityMsg
= new wxStaticText(this, EDITOR_DIALOG_CITY_MSG
, "City:", wxPoint(17, 230), wxSize(-1, -1), 0, "CityMsg");
573 pCityTxt
= new wxTextCtrl(this, EDITOR_DIALOG_CITY_TEXT
, "", wxPoint(17, 247), wxSize(225, 25), 0, wxDefaultValidator
, "CityTxt");
575 pStateMsg
= new wxStaticText(this, EDITOR_DIALOG_STATE_MSG
, "State:", wxPoint(250, 230), wxSize(-1, -1), 0, "StateMsg");
576 pStateTxt
= new wxTextCtrl(this, EDITOR_DIALOG_STATE_TEXT
, "", wxPoint(250, 247), wxSize(153, 25), 0, wxDefaultValidator
, "StateTxt");
578 pCountryMsg
= new wxStaticText(this, EDITOR_DIALOG_COUNTRY_MSG
, "Country:", wxPoint(17, 280), wxSize(-1, -1), 0, "CountryMsg");
579 pCountryTxt
= new wxTextCtrl(this, EDITOR_DIALOG_COUNTRY_TEXT
, "", wxPoint(17, 297), wxSize(225, 25), 0, wxDefaultValidator
, "CountryTxt");
581 pPostalCodeMsg
= new wxStaticText(this, EDITOR_DIALOG_POSTAL_MSG
, "Postal Code:", wxPoint(250, 280), wxSize(-1, -1), 0, "PostalCodeMsg");
582 pPostalCodeTxt
= new wxTextCtrl(this, EDITOR_DIALOG_POSTAL_TEXT
, "", wxPoint(250, 297), wxSize(153, 25), 0, wxDefaultValidator
, "PostalCodeTxt");
584 wxString choice_strings
[5];
585 choice_strings
[0] = "English";
586 choice_strings
[1] = "French";
587 choice_strings
[2] = "German";
588 choice_strings
[3] = "Spanish";
589 choice_strings
[4] = "Other";
590 pNativeLangChoice
= new wxChoice(this, EDITOR_DIALOG_LANG_CHOICE
, wxPoint(17, 346), wxSize(277, -1), 5, choice_strings
);
591 pNativeLangMsg
= new wxStaticText(this, EDITOR_DIALOG_LANG_MSG
, "Native language:", wxPoint(17, 330), wxSize(-1, -1), 0, "NativeLangMsg");
593 wxString radio_strings
[2];
594 radio_strings
[0] = "No";
595 radio_strings
[1] = "Yes";
596 pDeveloperRadio
= new wxRadioBox(this,EDITOR_DIALOG_DEVELOPER
,"Developer:",wxPoint(303,330),wxSize(-1,-1),2,radio_strings
,2,wxHORIZONTAL
);
598 pJoinDateMsg
= new wxStaticText(this, EDITOR_DIALOG_JOIN_MSG
, "Date joined:", wxPoint(17, 380), wxSize(-1, -1), 0, "JoinDateMsg");
599 pJoinDateTxt
= new wxTextCtrl(this, EDITOR_DIALOG_JOIN_TEXT
, "", wxPoint(17, 397), wxSize(150, 25), 0, wxDefaultValidator
, "JoinDateTxt");
601 pContribMsg
= new wxStaticText(this, EDITOR_DIALOG_CONTRIB_MSG
, "Contributions:", wxPoint(175, 380), wxSize(-1, -1), 0, "ContribMsg");
602 pContribTxt
= new wxTextCtrl(this, EDITOR_DIALOG_CONTRIB_TEXT
, "", wxPoint(175, 397), wxSize(120, 25), 0, wxDefaultValidator
, "ContribTxt");
604 pLinesMsg
= new wxStaticText(this, EDITOR_DIALOG_LINES_MSG
, "Lines of code:", wxPoint(303, 380), wxSize(-1, -1), 0, "LinesMsg");
605 pLinesTxt
= new wxTextCtrl(this, EDITOR_DIALOG_LINES_TEXT
, "", wxPoint(303, 397), wxSize(100, 25), 0, wxDefaultValidator
, "LinesTxt");
607 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
608 // handle all widget processing
609 widgetPtrsSet
= TRUE
;
611 // Setup the orderBy and where clauses to return back a single record as the result set,
612 // as there will only be one record being shown on the dialog at a time, this optimizes
613 // network traffic by only returning a one row result
615 Contact
->orderBy
= "NAME"; // field name to sort by
617 // The wxString "whereStr" is not a member of the wxTable object, it is a member variable
618 // specifically in the Ccontact class. It is used here for simpler construction of a varying
619 // length string, and then after the string is built, the wxTable member variable "where" is
620 // assigned the pointer to the constructed string.
622 // The constructed where clause below has a sub-query within it "SELECT MIN(NAME) FROM %s"
623 // to achieve a single row (in this case the first name in alphabetical order).
625 Contact
->whereStr
.Printf("NAME = 'Robert'",Contact
->tableName
);
627 Contact->whereStr.Printf("NAME = (SELECT MIN(NAME) FROM %s)",Contact->tableName);
630 // NOTE: (const char*) returns a pointer which may not be valid later, so this is short term use only
631 Contact
->where
= (char*) (const char*) Contact
->whereStr
;
633 // Perform the Query to get the result set.
634 // NOTE: If there are no rows returned, that is a valid result, so Query() would return TRUE.
635 // Only if there is a database error will Query() come back as FALSE
636 if (!Contact
->Query())
639 tStr
= "ODBC error during Query()\n\n";
640 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
641 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
642 GetParent()->Close();
646 // Since Query succeeded, now get the row that was returned
647 if (!Contact
->GetNext())
648 // If the GetNext() failed at this point, then there are no rows to retrieve,
649 // so clear the values in the members of "Contact" so that PutData() blanks the
650 // widgets on the dialog
651 Contact
->Initialize();
657 } // CeditorDlg constructor
660 bool CeditorDlg::OnClose()
663 if ((mode
!= mCreate
) && (mode
!= mEdit
))
671 wxMessageBox("Must finish processing the current record being created/modified before exiting","Notice...",wxOK
| wxICON_INFORMATION
);
674 } // CeditorDlg::OnClose()
677 void CeditorDlg::OnButton( wxCommandEvent
&event
)
679 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
680 OnCommand( *win
, event
);
683 void CeditorDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
687 widgetName
= win
.GetName();
692 if (widgetName
== pCreateBtn
->GetName())
694 Contact
->Initialize();
697 pNameTxt
->SetValue("");
698 pNameTxt
->SetFocus();
702 if (widgetName
== pEditBtn
->GetName())
704 saveName
= Contact
->Name
;
706 pNameTxt
->SetFocus();
710 if (widgetName
== pCopyBtn
->GetName())
713 pNameTxt
->SetValue("");
714 pNameTxt
->SetFocus();
718 if (widgetName
== pDeleteBtn
->GetName())
720 bool Ok
= (wxMessageBox("Are you sure?","Confirm",wxYES_NO
|wxICON_QUESTION
) == wxYES
);
725 if (Ok
&& Contact
->Delete())
727 // NOTE: Deletions are not finalized until a CommitTrans() is performed.
728 // If the commit were not performed, the program will continue to
729 // show the table contents as if they were deleted until this instance
730 // of Ccontact is deleted. If the Commit wasn't performed, the
731 // database will automatically Rollback the changes when the database
732 // connection is terminated
733 Contact
->pDb
->CommitTrans();
735 // Try to get the row that followed the just deleted row in the orderBy sequence
738 // There was now row (in sequence) after the just deleted row, so get the
739 // row which preceded the just deleted row
742 // There are now no rows remaining, so clear the dialog widgets
743 Contact
->Initialize();
747 SetMode(mode
); // force reset of button enable/disable
751 Contact
->pDb
->RollbackTrans();
757 if (widgetName
== pSaveBtn
->GetName())
763 if (widgetName
== pCancelBtn
->GetName())
765 bool Ok
= (wxMessageBox("Are you sure?","Confirm",wxYES_NO
|wxICON_QUESTION
) == wxYES
);
770 if (!strcmp((const char*) saveName
,""))
772 Contact
->Initialize();
779 // Requery previous record
780 if (Contact
->FetchByName((char*) (const char*) saveName
))
788 // Previous record not available, retrieve first record in table
789 Contact
->whereStr
= "NAME = 'Robert' ";
791 Contact->whereStr = "NAME = (SELECT MIN(NAME) FROM ";
792 Contact->whereStr += Contact->tableName;
793 Contact->whereStr += ")";
795 Contact
->where
= (char*) (const char*) Contact
->whereStr
;
796 if (!Contact
->Query())
799 tStr
= "ODBC error during Query()\n\n";
800 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
801 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
805 if (Contact
->GetNext()) // Successfully read first record
811 // No contacts are available, clear dialog
812 Contact
->Initialize();
818 if (widgetName
== pPrevBtn
->GetName())
825 if (widgetName
== pNextBtn
->GetName())
832 if (widgetName
== pQueryBtn
->GetName())
834 // Display the query dialog box
835 char qryWhere
[DB_MAX_WHERE_CLAUSE_LEN
+1];
836 strcpy(qryWhere
, (const char*) Contact
->qryWhereStr
);
837 char *tblName
[] = {(char *)CONTACT_TABLE_NAME
, 0};
838 new CqueryDlg(GetParent(), Contact
->pDb
, tblName
, qryWhere
);
840 // Query the first record in the new record set and
841 // display it, if the query string has changed.
842 if (strcmp(qryWhere
, (const char*) Contact
->qryWhereStr
))
844 Contact
->orderBy
= "NAME";
846 Contact->whereStr = "NAME = (SELECT MIN(NAME) FROM ";
847 Contact->whereStr += CONTACT_TABLE_NAME;
849 // Append the query where string (if there is one)
850 Contact
->qryWhereStr
= qryWhere
;
851 if (strlen(qryWhere
))
853 Contact
->whereStr
+= " WHERE ";
854 Contact
->whereStr
+= Contact
->qryWhereStr
;
856 // Close the expression with a right paren
857 Contact
->whereStr
+= ")";
859 Contact
->where
= (char*) (const char*) Contact
->whereStr
;
860 if (!Contact
->Query())
863 tStr
= "ODBC error during Query()\n\n";
864 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
865 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
868 // Display the first record from the query set
869 if (!Contact
->GetNext())
870 Contact
->Initialize();
874 // Enable/Disable the reset button
875 pResetBtn
->Enable(!Contact
->qryWhereStr
.IsEmpty());
881 if (widgetName
== pResetBtn
->GetName())
883 // Clear the additional where criteria established by the query feature
884 Contact
->qryWhereStr
= "";
886 // Query the first record in the table
887 Contact
->orderBy
= "NAME";
888 Contact
->whereStr
= "NAME = 'Robert' ";
890 Contact->whereStr = "NAME = (SELECT MIN(NAME) FROM ";
891 Contact->whereStr += CONTACT_TABLE_NAME;
892 Contact->whereStr += ")";
894 Contact
->where
= (char*) (const char*) Contact
->whereStr
;
895 if (!Contact
->Query())
898 tStr
= "ODBC error during Query()\n\n";
899 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
900 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
903 if (!Contact
->GetNext())
904 Contact
->Initialize();
906 pResetBtn
->Enable(FALSE
);
912 if (widgetName
== pNameListBtn
->GetName())
914 new ClookUpDlg(/* wxWindow *parent */ this,
915 /* char *windowTitle */ "Select contact name",
916 /* char *tableName */ (char *) CONTACT_TABLE_NAME
,
917 /* char *dispCol1 */ "NAME",
918 /* char *dispCol2 */ "JOIN_DATE",
919 /* char *where */ "",
920 /* char *orderBy */ "NAME",
921 /* bool distinctValues */ TRUE
);
923 if (ListDB_Selection
&& strlen(ListDB_Selection
))
925 wxString w
= "NAME = '";
926 w
+= ListDB_Selection
;
928 GetRec((char*) (const char*) w
);
934 } // CeditorDlg::OnCommand()
937 void CeditorDlg::FieldsEditable()
939 pNameTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
940 pAddress1Txt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
941 pAddress2Txt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
942 pCityTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
943 pStateTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
944 pPostalCodeTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
945 pCountryTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
947 pJoinDateTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
948 pContribTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
949 pLinesTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
950 pNativeLangChoice
->Enable((mode
== mCreate
) || (mode
== mEdit
));
951 pDeveloperRadio
->Enable((mode
== mCreate
) || (mode
== mEdit
));
953 } // CeditorDlg::FieldsEditable()
956 void CeditorDlg::SetMode(enum DialogModes m
)
977 pCreateBtn
->Enable( !edit
);
978 pEditBtn
->Enable( !edit
&& (strcmp(Contact
->Name
,"")!=0) );
979 pDeleteBtn
->Enable( !edit
&& (strcmp(Contact
->Name
,"")!=0) );
980 pCopyBtn
->Enable( !edit
&& (strcmp(Contact
->Name
,"")!=0) );
981 pSaveBtn
->Enable( edit
);
982 pCancelBtn
->Enable( edit
);
983 pPrevBtn
->Enable( !edit
);
984 pNextBtn
->Enable( !edit
);
985 pQueryBtn
->Enable( !edit
);
986 pResetBtn
->Enable( !edit
&& !Contact
->qryWhereStr
.IsEmpty() );
987 pNameListBtn
->Enable( !edit
);
991 } // CeditorDlg::SetMode()
994 bool CeditorDlg::PutData()
998 pNameTxt
->SetValue(Contact
->Name
);
999 pAddress1Txt
->SetValue(Contact
->Addr1
);
1000 pAddress2Txt
->SetValue(Contact
->Addr2
);
1001 pCityTxt
->SetValue(Contact
->City
);
1002 pStateTxt
->SetValue(Contact
->State
);
1003 pCountryTxt
->SetValue(Contact
->Country
);
1004 pPostalCodeTxt
->SetValue(Contact
->PostalCode
);
1006 tStr
.Printf("%d/%d/%d",Contact
->JoinDate
.month
,Contact
->JoinDate
.day
,Contact
->JoinDate
.year
);
1007 pJoinDateTxt
->SetValue(tStr
);
1009 tStr
.Printf("%d",Contact
->Contributions
);
1010 pContribTxt
->SetValue(tStr
);
1012 tStr
.Printf("%lu",Contact
->LinesOfCode
);
1013 pLinesTxt
->SetValue(tStr
);
1015 pNativeLangChoice
->SetSelection(Contact
->NativeLanguage
);
1017 pDeveloperRadio
->SetSelection(Contact
->IsDeveloper
);
1020 } // Ceditor::PutData()
1024 * Reads the data out of all the widgets on the dialog. Some data evaluation is done
1025 * to ensure that there is a name entered and that the date field is valid.
1027 * A return value of TRUE means that valid data was retrieved from the dialog, otherwise
1028 * invalid data was found (and a message was displayed telling the user what to fix), and
1029 * the data was not placed into the appropraite fields of Ccontact
1031 bool CeditorDlg::GetData()
1033 // Validate that the data currently entered into the widgets is valid data
1036 tStr
= pNameTxt
->GetValue();
1037 if (!strcmp((const char*) tStr
,""))
1039 wxMessageBox("A name is required for entry into the contact table","Notice...",wxOK
| wxICON_INFORMATION
);
1043 bool invalid
= FALSE
;
1047 tStr
= pJoinDateTxt
->GetValue();
1048 if (tStr
.Freq('/') != 2)
1051 // Find the month, day, and year tokens
1054 first
= tStr
.First('/');
1055 second
= tStr
.Last('/');
1057 mm
= atoi(tStr
.SubString(0,first
));
1058 dd
= atoi(tStr
.SubString(first
+1,second
));
1059 yyyy
= atoi(tStr
.SubString(second
+1,tStr
.Length()-1));
1061 invalid
= !(mm
&& dd
&& yyyy
);
1064 // Force Year 2000 compliance
1065 if (!invalid
&& (yyyy
< 1000))
1068 // Check the token ranges for validity
1073 else if ((mm
< 1) || (mm
> 12))
1081 int days
[12] = {31,28,31,30,31,30,
1083 if (dd
> days
[mm
-1])
1086 if ((dd
== 29) && (mm
== 2))
1088 if (((yyyy
% 4) == 0) && (((yyyy
% 100) != 0) || ((yyyy
% 400) == 0)))
1098 Contact
->JoinDate
.month
= mm
;
1099 Contact
->JoinDate
.day
= dd
;
1100 Contact
->JoinDate
.year
= yyyy
;
1104 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
);
1108 tStr
= pNameTxt
->GetValue();
1109 strcpy(Contact
->Name
,(const char*) tStr
);
1110 strcpy(Contact
->Addr1
,pAddress1Txt
->GetValue());
1111 strcpy(Contact
->Addr2
,pAddress2Txt
->GetValue());
1112 strcpy(Contact
->City
,pCityTxt
->GetValue());
1113 strcpy(Contact
->State
,pStateTxt
->GetValue());
1114 strcpy(Contact
->Country
,pCountryTxt
->GetValue());
1115 strcpy(Contact
->PostalCode
,pPostalCodeTxt
->GetValue());
1117 Contact
->Contributions
= atoi(pContribTxt
->GetValue());
1118 Contact
->LinesOfCode
= atol(pLinesTxt
->GetValue());
1120 Contact
->NativeLanguage
= (enum Language
) pNativeLangChoice
->GetSelection();
1121 Contact
->IsDeveloper
= (bool) pDeveloperRadio
->GetSelection();
1124 } // CeditorDlg::GetData()
1128 * Retrieve data from the dialog, verify the validity of the data, and if it is valid,
1129 * try to insert/update the data to the table based on the current 'mode' the dialog
1132 * A return value of TRUE means the insert/update was completed successfully, a return
1133 * value of FALSE means that Save() failed. If returning FALSE, then this function
1134 * has displayed a detailed error message for the user.
1136 bool CeditorDlg::Save()
1138 bool failed
= FALSE
;
1140 // Read the data in the widgets of the dialog to get the user's data
1144 // Perform any other required validations necessary before saving
1149 wxBeginBusyCursor();
1151 if (mode
== mCreate
)
1153 RETCODE result
= Contact
->Insert();
1155 failed
= (result
!= DB_SUCCESS
);
1158 // Some errors may be expected, like a duplicate key, so handle those instances with
1159 // specific error messages.
1160 if (result
== DB_ERR_INTEGRITY_CONSTRAINT_VIOL
)
1163 tStr
= "A duplicate key value already exists in the table.\nUnable to save record\n\n";
1164 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
1165 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
1169 // Some other unexpexted error occurred
1171 tStr
= "Database insert failed\n\n";
1172 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
1173 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
1177 else // mode == mEdit
1179 if (!Contact
->Update())
1182 tStr
= "Database update failed\n\n";
1183 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
1184 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
1191 Contact
->pDb
->CommitTrans();
1192 SetMode(mView
); // Sets the dialog mode back to viewing after save is successful
1195 Contact
->pDb
->RollbackTrans();
1201 } // CeditorDlg::Save()
1205 * Where this program is only showing a single row at a time in the dialog,
1206 * a special where clause must be built to find just the single row which,
1207 * in sequence, would follow the currently displayed row.
1209 bool CeditorDlg::GetNextRec()
1214 w = "NAME = (SELECT MIN(NAME) FROM ";
1216 w
= "NAME = (SELECT NAME FROM ";
1217 w
+= Contact
->tableName
;
1218 w
+= " WHERE NAME > '";
1222 // If a query where string is currently set, append that criteria
1223 if (!Contact
->qryWhereStr
.IsEmpty())
1226 w
+= Contact
->qryWhereStr
;
1231 return(GetRec((char*) (const char*) w
));
1233 } // CeditorDlg::GetNextRec()
1237 * Where this program is only showing a single row at a time in the dialog,
1238 * a special where clause must be built to find just the single row which,
1239 * in sequence, would precede the currently displayed row.
1241 bool CeditorDlg::GetPrevRec()
1245 w
= "NAME = (SELECT MAX(NAME) FROM ";
1246 w
+= Contact
->tableName
;
1247 w
+= " WHERE NAME < '";
1251 // If a query where string is currently set, append that criteria
1252 if (!Contact
->qryWhereStr
.IsEmpty())
1255 w
+= Contact
->qryWhereStr
;
1261 return(GetRec((char*) (const char*)w
));
1263 } // CeditorDlg::GetPrevRec()
1267 * This function is here to avoid duplicating this same code in both the
1268 * GetPrevRec() and GetNextRec() functions
1270 bool CeditorDlg::GetRec(char *whereStr
)
1272 Contact
->where
= whereStr
;
1273 Contact
->orderBy
= "NAME";
1275 if (!Contact
->Query())
1278 tStr
= "ODBC error during Query()\n\n";
1279 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
1280 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
1285 if (Contact
->GetNext())
1292 } // CeditorDlg::GetRec()
1297 * CparameterDlg constructor
1299 CparameterDlg::CparameterDlg(wxWindow
*parent
) : wxDialog (parent
, PARAMETER_DIALOG
, "ODBC parameter settings", wxPoint(-1, -1), wxSize(400, 275))
1301 // Since the ::OnCommand() function is overridden, this prevents the widget
1302 // detection in ::OnCommand() until all widgets have been initialized to prevent
1303 // uninitialized pointers from crashing the program
1304 widgetPtrsSet
= FALSE
;
1306 pParamODBCSourceMsg
= new wxStaticText(this, PARAMETER_DIALOG_SOURCE_MSG
, "ODBC data sources:", wxPoint(10, 10), wxSize(-1, -1), 0, "ParamODBCSourceMsg");
1307 pParamODBCSourceList
= new wxListBox(this, PARAMETER_DIALOG_SOURCE_LISTBOX
, wxPoint(10, 29), wxSize(285, 150), 0, 0, wxLB_SINGLE
|wxLB_ALWAYS_SB
, wxDefaultValidator
, "ParamODBCSourceList");
1309 pParamUserNameMsg
= new wxStaticText(this, PARAMETER_DIALOG_NAME_MSG
, "Database user name:", wxPoint(10, 193), wxSize(-1, -1), 0, "ParamUserNameMsg");
1310 pParamUserNameTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_NAME_TEXT
, "", wxPoint(10, 209), wxSize(140, 25), 0, wxDefaultValidator
, "ParamUserNameTxt");
1312 pParamPasswordMsg
= new wxStaticText(this, PARAMETER_DIALOG_PASSWORD_MSG
, "Password:", wxPoint(156, 193), wxSize(-1, -1), 0, "ParamPasswordMsg");
1313 pParamPasswordTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_PASSWORD_TEXT
, "", wxPoint(156, 209), wxSize(140, 25), 0, wxDefaultValidator
, "ParamPasswordTxt");
1315 pParamSaveBtn
= new wxButton(this, PARAMETER_DIALOG_SAVE
, "&Save", wxPoint(310, 21), wxSize(70, 35), 0, wxDefaultValidator
, "ParamSaveBtn");
1316 pParamCancelBtn
= new wxButton(this, PARAMETER_DIALOG_CANCEL
, "C&ancel", wxPoint(310, 66), wxSize(70, 35), 0, wxDefaultValidator
, "ParamCancelBtn");
1318 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
1319 // handle all widget processing
1320 widgetPtrsSet
= TRUE
;
1323 savedParamSettings
= wxGetApp().params
;
1328 } // CparameterDlg constructor
1331 bool CparameterDlg::OnClose()
1333 // Put any additional checking necessary to make certain it is alright
1334 // to close the program here that is not done elsewhere
1337 bool Ok
= (wxMessageBox("No changes have been saved.\n\nAre you sure you wish exit the parameter screen?","Confirm",wxYES_NO
|wxICON_QUESTION
) == wxYES
);
1342 wxGetApp().params
= savedParamSettings
;
1345 if (GetParent() != NULL
)
1346 GetParent()->SetFocus();
1348 } // Cparameter::OnClose()
1351 void CparameterDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
1353 wxString widgetName
;
1355 widgetName
= win
.GetName();
1360 if (widgetName
== pParamSaveBtn
->GetName())
1365 tStr
= "Database parameters have been saved.";
1366 if (GetParent() != NULL
) // The parameter dialog was not called during startup due to a missing cfg file
1367 tStr
+= "\nNew parameters will take effect the next time the program is started.";
1368 wxMessageBox(tStr
,"Notice...",wxOK
| wxICON_INFORMATION
);
1375 if (widgetName
== pParamCancelBtn
->GetName())
1380 } // CparameterDlg::OnCommand()
1383 bool CparameterDlg::PutData()
1385 // Fill the data source list box
1386 FillDataSourceList();
1388 // Fill in the fields from the params object
1389 pParamODBCSourceList
->SetStringSelection(wxGetApp().params
.ODBCSource
);
1390 pParamUserNameTxt
->SetValue(wxGetApp().params
.UserName
);
1391 pParamPasswordTxt
->SetValue(wxGetApp().params
.Password
);
1393 } // CparameterDlg::PutData()
1396 bool CparameterDlg::GetData()
1399 if (pParamODBCSourceList
->GetStringSelection())
1401 tStr
= pParamODBCSourceList
->GetStringSelection();
1402 if (tStr
.Length() > (sizeof(wxGetApp().params
.ODBCSource
)-1))
1405 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());
1406 wxMessageBox(errmsg
,"Internal program error...",wxOK
| wxICON_EXCLAMATION
);
1409 strcpy(wxGetApp().params
.ODBCSource
, tStr
);
1414 tStr
= pParamUserNameTxt
->GetValue();
1415 if (tStr
.Length() > (sizeof(wxGetApp().params
.UserName
)-1))
1418 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());
1419 wxMessageBox(errmsg
,"Internal program error...",wxOK
| wxICON_EXCLAMATION
);
1422 strcpy(wxGetApp().params
.UserName
, tStr
);
1424 tStr
= pParamPasswordTxt
->GetValue();
1425 if (tStr
.Length() > (sizeof(wxGetApp().params
.Password
)-1))
1428 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());
1429 wxMessageBox(errmsg
,"Internal program error...",wxOK
| wxICON_EXCLAMATION
);
1432 strcpy(wxGetApp().params
.Password
,tStr
);
1434 } // CparameterDlg::GetData()
1437 bool CparameterDlg::Save()
1439 Cparameters saveParams
= wxGetApp().params
;
1442 wxGetApp().params
= saveParams
;
1447 if ((paramFile
= fopen(paramFilename
, "wt")) == NULL
)
1450 tStr
.Printf("Unable to write/overwrite '%s'.",paramFilename
);
1451 wxMessageBox(tStr
,"File I/O Error...",wxOK
| wxICON_EXCLAMATION
);
1455 fputs(wxGetApp().params
.ODBCSource
, paramFile
);
1456 fputc('\n', paramFile
);
1457 fputs(wxGetApp().params
.UserName
, paramFile
);
1458 fputc('\n', paramFile
);
1459 fputs(wxGetApp().params
.Password
, paramFile
);
1460 fputc('\n', paramFile
);
1464 } // CparameterDlg::Save()
1467 void CparameterDlg::FillDataSourceList()
1469 char Dsn
[SQL_MAX_DSN_LENGTH
+ 1];
1471 wxStringList strList
;
1473 while(GetDataSource(DbConnectInf
.Henv
, Dsn
, SQL_MAX_DSN_LENGTH
+1, DsDesc
, 255))
1478 char **p
= strList
.ListToArray();
1480 for (int i
= 0; strlen(p
[i
]); i
++)
1481 pParamODBCSourceList
->Append(p
[i
]);
1482 } // CparameterDlg::CparameterDlg::FillDataSourceList()
1485 BEGIN_EVENT_TABLE(CqueryDlg
, wxDialog
)
1486 EVT_BUTTON(-1, CqueryDlg::OnButton
)
1489 // CqueryDlg() constructor
1490 CqueryDlg::CqueryDlg(wxWindow
*parent
, wxDB
*pDb
, char *tblName
[], char *pWhereArg
) : wxDialog (parent
, QUERY_DIALOG
, "Query", wxPoint(-1, -1), wxSize(480, 360))
1492 wxBeginBusyCursor();
1496 masterTableName
= tblName
[0];
1497 widgetPtrsSet
= FALSE
;
1500 // Initialize the WHERE clause from the string passed in
1501 pWhere
= pWhereArg
; // Save a pointer to the output buffer
1502 if (strlen(pWhere
) > DB_MAX_WHERE_CLAUSE_LEN
) // Check the length of the buffer passed in
1505 s
.Printf("Maximum where clause length exceeded.\nLength must be less than %d", DB_MAX_WHERE_CLAUSE_LEN
+1);
1506 wxMessageBox(s
,"Error...",wxOK
| wxICON_EXCLAMATION
);
1511 pQueryCol1Msg
= new wxStaticText(this, QUERY_DIALOG_COL_MSG
, "Column 1:", wxPoint(10, 10), wxSize(69, 16), 0, "QueryCol1Msg");
1512 pQueryCol1Choice
= new wxChoice(this, QUERY_DIALOG_COL_CHOICE
, wxPoint(10, 27), wxSize(250, 27), 0, 0, 0, wxDefaultValidator
, "QueryCol1Choice");
1514 pQueryNotMsg
= new wxStaticText(this, QUERY_DIALOG_NOT_MSG
, "NOT", wxPoint(268, 10), wxSize(-1, -1), 0, "QueryNotMsg");
1515 pQueryNotCheck
= new wxCheckBox(this, QUERY_DIALOG_NOT_CHECKBOX
, "", wxPoint(275, 37), wxSize(20, 20), 0, wxDefaultValidator
, "QueryNotCheck");
1517 wxString choice_strings
[9];
1518 choice_strings
[0] = "=";
1519 choice_strings
[1] = "<";
1520 choice_strings
[2] = ">";
1521 choice_strings
[3] = "<=";
1522 choice_strings
[4] = ">=";
1523 choice_strings
[5] = "Begins";
1524 choice_strings
[6] = "Contains";
1525 choice_strings
[7] = "Like";
1526 choice_strings
[8] = "Between";
1527 pQueryOperatorMsg
= new wxStaticText(this, QUERY_DIALOG_OP_MSG
, "Operator:", wxPoint(305, 10), wxSize(-1, -1), 0, "QueryOperatorMsg");
1528 pQueryOperatorChoice
= new wxChoice(this, QUERY_DIALOG_OP_CHOICE
, wxPoint(305, 27), wxSize(80, 27), 9, choice_strings
, 0, wxDefaultValidator
, "QueryOperatorChoice");
1530 pQueryCol2Msg
= new wxStaticText(this, QUERY_DIALOG_COL2_MSG
, "Column 2:", wxPoint(10, 65), wxSize(69, 16), 0, "QueryCol2Msg");
1531 pQueryCol2Choice
= new wxChoice(this, QUERY_DIALOG_COL2_CHOICE
, wxPoint(10, 82), wxSize(250, 27), 0, 0, 0, wxDefaultValidator
, "QueryCol2Choice");
1533 pQuerySqlWhereMsg
= new wxStaticText(this, QUERY_DIALOG_WHERE_MSG
, "SQL where clause:", wxPoint(10, 141), wxSize(-1, -1), 0, "QuerySqlWhereMsg");
1534 pQuerySqlWhereMtxt
= new wxTextCtrl(this, QUERY_DIALOG_WHERE_TEXT
, "", wxPoint(10, 159), wxSize(377, 134), wxTE_MULTILINE
, wxDefaultValidator
, "QuerySqlWhereMtxt");
1536 pQueryAddBtn
= new wxButton(this, QUERY_DIALOG_ADD
, "&Add", wxPoint(406, 24), wxSize(56, 26), 0, wxDefaultValidator
, "QueryAddBtn");
1537 pQueryAndBtn
= new wxButton(this, QUERY_DIALOG_AND
, "A&nd", wxPoint(406, 58), wxSize(56, 26), 0, wxDefaultValidator
, "QueryAndBtn");
1538 pQueryOrBtn
= new wxButton(this, QUERY_DIALOG_OR
, "&Or", wxPoint(406, 92), wxSize(56, 26), 0, wxDefaultValidator
, "QueryOrBtn");
1540 pQueryLParenBtn
= new wxButton(this, QUERY_DIALOG_LPAREN
, "(", wxPoint(406, 126), wxSize(26, 26), 0, wxDefaultValidator
, "QueryLParenBtn");
1541 pQueryRParenBtn
= new wxButton(this, QUERY_DIALOG_RPAREN
, ")", wxPoint(436, 126), wxSize(26, 26), 0, wxDefaultValidator
, "QueryRParenBtn");
1543 pQueryDoneBtn
= new wxButton(this, QUERY_DIALOG_DONE
, "&Done", wxPoint(406, 185), wxSize(56, 26), 0, wxDefaultValidator
, "QueryDoneBtn");
1544 pQueryClearBtn
= new wxButton(this, QUERY_DIALOG_CLEAR
, "C&lear", wxPoint(406, 218), wxSize(56, 26), 0, wxDefaultValidator
, "QueryClearBtn");
1545 pQueryCountBtn
= new wxButton(this, QUERY_DIALOG_COUNT
, "&Count", wxPoint(406, 252), wxSize(56, 26), 0, wxDefaultValidator
, "QueryCountBtn");
1547 pQueryValue1Msg
= new wxStaticText(this, QUERY_DIALOG_VALUE1_MSG
, "Value:", wxPoint(277, 66), wxSize(-1, -1), 0, "QueryValue1Msg");
1548 pQueryValue1Txt
= new wxTextCtrl(this, QUERY_DIALOG_VALUE1_TEXT
, "", wxPoint(277, 83), wxSize(108, 25), 0, wxDefaultValidator
, "QueryValue1Txt");
1550 pQueryValue2Msg
= new wxStaticText(this, QUERY_DIALOG_VALUE2_MSG
, "AND", wxPoint(238, 126), wxSize(-1, -1), 0, "QueryValue2Msg");
1551 pQueryValue2Txt
= new wxTextCtrl(this, QUERY_DIALOG_VALUE2_TEXT
, "", wxPoint(277, 120), wxSize(108, 25), 0, wxDefaultValidator
, "QueryValue2Txt");
1553 pQueryHintGrp
= new wxStaticBox(this, QUERY_DIALOG_HINT_GROUP
, "", wxPoint(10, 291), wxSize(377, 40), 0, "QueryHintGrp");
1554 pQueryHintMsg
= new wxStaticText(this, QUERY_DIALOG_HINT_MSG
, "", wxPoint(16, 306), wxSize(-1, -1), 0, "QueryHintMsg");
1556 widgetPtrsSet
= TRUE
;
1557 // Initialize the dialog
1559 pQueryCol2Choice
->Append("VALUE -->");
1560 colInf
= pDB
->GetColumns(tblName
);
1561 for (int i
= 0; colInf
[i
].colName
&& strlen(colInf
[i
].colName
); i
++)
1563 // If there is more than one table being queried, qualify
1564 // the column names with the table name prefix.
1565 if (tblName
[1] && strlen(tblName
[1]))
1567 qualName
.Printf("%s.%s", colInf
[i
].tableName
, colInf
[i
].colName
);
1568 pQueryCol1Choice
->Append(qualName
);
1569 pQueryCol2Choice
->Append(qualName
);
1571 else // Single table query, append just the column names
1573 pQueryCol1Choice
->Append(colInf
[i
].colName
);
1574 pQueryCol2Choice
->Append(colInf
[i
].colName
);
1578 pQueryCol1Choice
->SetSelection(0);
1579 pQueryCol2Choice
->SetSelection(0);
1580 pQueryOperatorChoice
->SetSelection(0);
1582 pQueryValue2Msg
->Show(FALSE
);
1583 pQueryValue2Txt
->Show(FALSE
);
1585 pQueryHintMsg
->SetLabel(langQRY_EQ
);
1587 pQuerySqlWhereMtxt
->SetValue(pWhere
);
1591 // Display the dialog window
1595 } // CqueryDlg() constructor
1598 void CqueryDlg::OnButton( wxCommandEvent
&event
)
1600 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
1601 OnCommand( *win
, event
);
1604 void CqueryDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
1606 // Widget pointers won't be set when the dialog is constructed.
1607 // Control is passed through this function once for each widget on
1608 // a dialog as the dialog is constructed.
1612 wxString widgetName
= win
.GetName();
1614 // Operator choice box
1615 if (widgetName
== pQueryOperatorChoice
->GetName())
1617 // Set the help text
1618 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
1621 pQueryHintMsg
->SetLabel(langQRY_EQ
);
1624 pQueryHintMsg
->SetLabel(langQRY_LT
);
1627 pQueryHintMsg
->SetLabel(langQRY_GT
);
1630 pQueryHintMsg
->SetLabel(langQRY_LE
);
1633 pQueryHintMsg
->SetLabel(langQRY_GE
);
1636 pQueryHintMsg
->SetLabel(langQRY_BEGINS
);
1639 pQueryHintMsg
->SetLabel(langQRY_CONTAINS
);
1642 pQueryHintMsg
->SetLabel(langQRY_LIKE
);
1645 pQueryHintMsg
->SetLabel(langQRY_BETWEEN
);
1649 // Hide the value2 widget
1650 pQueryValue2Msg
->Show(FALSE
); // BETWEEN will show this widget
1651 pQueryValue2Txt
->Show(FALSE
); // BETWEEN will show this widget
1653 // Disable the NOT operator for <, <=, >, >=
1654 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
1660 pQueryNotCheck
->SetValue(0);
1661 pQueryNotCheck
->Enable(FALSE
);
1664 pQueryNotCheck
->Enable(TRUE
);
1668 // Manipulate the dialog to handle the selected operator
1669 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
1676 pQueryCol2Choice
->Enable(TRUE
);
1677 if (pQueryCol2Choice
->GetSelection()) // Column name is highlighted
1679 pQueryValue1Msg
->Show(FALSE
);
1680 pQueryValue1Txt
->Show(FALSE
);
1682 else // "Value" is highlighted
1684 pQueryValue1Msg
->Show(TRUE
);
1685 pQueryValue1Txt
->Show(TRUE
);
1686 pQueryValue1Txt
->SetFocus();
1692 pQueryCol2Choice
->SetSelection(0);
1693 pQueryCol2Choice
->Enable(FALSE
);
1694 pQueryValue1Msg
->Show(TRUE
);
1695 pQueryValue1Txt
->Show(TRUE
);
1696 pQueryValue1Txt
->SetFocus();
1699 pQueryCol2Choice
->SetSelection(0);
1700 pQueryCol2Choice
->Enable(FALSE
);
1701 pQueryValue2Msg
->Show(TRUE
);
1702 pQueryValue2Txt
->Show(TRUE
);
1703 pQueryValue1Msg
->Show(TRUE
);
1704 pQueryValue1Txt
->Show(TRUE
);
1705 pQueryValue1Txt
->SetFocus();
1711 } // Operator choice box
1714 if (widgetName
== pQueryCol2Choice
->GetName())
1716 if (pQueryCol2Choice
->GetSelection()) // Column name is highlighted
1718 pQueryValue1Msg
->Show(FALSE
);
1719 pQueryValue1Txt
->Show(FALSE
);
1721 else // "Value" is highlighted
1723 pQueryValue1Msg
->Show(TRUE
);
1724 pQueryValue1Txt
->Show(TRUE
);
1725 pQueryValue1Txt
->SetFocus();
1729 } // Column 2 choice
1732 if (widgetName
== pQueryAddBtn
->GetName())
1740 if (widgetName
== pQueryAndBtn
->GetName())
1742 AppendToWhere(" AND\n");
1748 if (widgetName
== pQueryOrBtn
->GetName())
1750 AppendToWhere(" OR\n");
1755 // Left Paren button
1756 if (widgetName
== pQueryLParenBtn
->GetName())
1761 } // Left Paren button
1763 // Right paren button
1764 if (widgetName
== pQueryRParenBtn
->GetName())
1769 } // Right Paren button
1772 if (widgetName
== pQueryDoneBtn
->GetName())
1774 // Be sure the where clause will not overflow the output buffer
1775 if (strlen(pQuerySqlWhereMtxt
->GetValue()) > DB_MAX_WHERE_CLAUSE_LEN
)
1778 s
.Printf("Maximum where clause length exceeded.\nLength must be less than %d", DB_MAX_WHERE_CLAUSE_LEN
+1);
1779 wxMessageBox(s
,"Error...",wxOK
| wxICON_EXCLAMATION
);
1782 // Validate the where clause for things such as matching parens
1783 if (!ValidateWhereClause())
1785 // Copy the where clause to the output buffer and exit
1786 strcpy(pWhere
, pQuerySqlWhereMtxt
->GetValue());
1793 if (widgetName
== pQueryClearBtn
->GetName())
1795 bool Ok
= (wxMessageBox("Are you sure you wish to clear the Query?","Confirm",wxYES_NO
|wxICON_QUESTION
) == wxYES
);
1798 pQuerySqlWhereMtxt
->SetValue("");
1804 if (widgetName
== pQueryCountBtn
->GetName())
1806 wxBeginBusyCursor();
1813 } // CqueryDlg::OnCommand
1816 bool CqueryDlg::OnClose()
1831 GetParent()->SetFocus();
1835 } // CqueryDlg::OnClose()
1838 bool CqueryDlg::SetWidgetPtrs()
1842 abort = abort || !(pQueryCol1Choice = (wxChoice *)GetWidgetPtr("QueryCol1Choice",this));
1843 abort = abort || !(pQueryNotCheck = (wxCheckBox *)GetWidgetPtr("QueryNotCheck",this));
1844 abort = abort || !(pQueryOperatorChoice = (wxChoice *)GetWidgetPtr("QueryOperatorChoice",this));
1845 abort = abort || !(pQueryCol2Choice = (wxChoice *)GetWidgetPtr("QueryCol2Choice",this));
1846 abort = abort || !(pQueryValue1Txt = (wxTextCtrl *)GetWidgetPtr("QueryValue1Txt",this));
1847 abort = abort || !(pQueryValue2Txt = (wxTextCtrl *)GetWidgetPtr("QueryValue2Txt",this));
1848 abort = abort || !(pQuerySqlWhereMtxt = (wxMultiText *)GetWidgetPtr("QuerySqlWhereMtxt",this));
1849 abort = abort || !(pQueryAddBtn = (wxButton *)GetWidgetPtr("QueryAddBtn",this));
1850 abort = abort || !(pQueryAndBtn = (wxButton *)GetWidgetPtr("QueryAndBtn",this));
1851 abort = abort || !(pQueryOrBtn = (wxButton *)GetWidgetPtr("QueryOrBtn",this));
1852 abort = abort || !(pQueryLParenBtn = (wxButton *)GetWidgetPtr("QueryLParenBtn",this));
1853 abort = abort || !(pQueryRParenBtn = (wxButton *)GetWidgetPtr("QueryRParenBtn",this));
1854 abort = abort || !(pQueryDoneBtn = (wxButton *)GetWidgetPtr("QueryDoneBtn",this));
1855 abort = abort || !(pQueryClearBtn = (wxButton *)GetWidgetPtr("QueryClearBtn",this));
1856 abort = abort || !(pQueryCountBtn = (wxButton *)GetWidgetPtr("QueryCountBtn",this));
1857 abort = abort || !(pQueryHelpBtn = (wxButton *)GetWidgetPtr("QueryHelpBtn",this));
1858 abort = abort || !(pQueryHintMsg = (wxStaticText *)GetWidgetPtr("QueryHintMsg",this));
1862 return(widgetPtrsSet = !abort);
1864 } // CqueryDlg::SetWidgetPtrs
1867 void CqueryDlg::AppendToWhere(char *s
)
1869 wxString whereStr
= pQuerySqlWhereMtxt
->GetValue();
1871 pQuerySqlWhereMtxt
->SetValue(whereStr
);
1873 } // CqueryDlg::AppendToWhere()
1876 void CqueryDlg::ProcessAddBtn()
1878 qryOp oper
= (qryOp
) pQueryOperatorChoice
->GetSelection();
1880 // Verify that eveything is filled in correctly
1881 if (pQueryCol2Choice
->GetSelection() == 0) // "Value" is selected
1883 // Verify that value 1 is filled in
1884 if (strlen(pQueryValue1Txt
->GetValue()) == 0)
1887 pQueryValue1Txt
->SetFocus();
1890 // For the BETWEEN operator, value 2 must be filled in as well
1891 if (oper
== qryOpBETWEEN
&&
1892 strlen(pQueryValue2Txt
->GetValue()) == 0)
1895 pQueryValue2Txt
->SetFocus();
1900 // Build the expression and append it to the where clause window
1901 wxString s
= pQueryCol1Choice
->GetStringSelection();
1903 if (pQueryNotCheck
->GetValue() && (oper
!= qryOpEQ
))
1909 if (pQueryNotCheck
->GetValue()) // NOT box is checked
1938 int col1Idx
= pQueryCol1Choice
->GetSelection();
1941 if (colInf
[col1Idx
].sqlDataType
== SQL_VARCHAR
||
1942 oper
== qryOpBEGINS
||
1943 oper
== qryOpCONTAINS
||
1947 if (pQueryCol2Choice
->GetSelection()) // Column name
1948 s
+= pQueryCol2Choice
->GetStringSelection();
1949 else // Column 2 is a "value"
1953 if (oper
== qryOpCONTAINS
)
1955 s
+= pQueryValue1Txt
->GetValue();
1956 if (oper
== qryOpCONTAINS
|| oper
== qryOpBEGINS
)
1962 if (oper
== qryOpBETWEEN
)
1967 s
+= pQueryValue2Txt
->GetValue();
1972 AppendToWhere((char*) (const char*) s
);
1974 } // CqueryDlg::ProcessAddBtn()
1977 void CqueryDlg::ProcessCountBtn()
1979 if (!ValidateWhereClause())
1982 if (dbTable
== 0) // wxTable object needs to be created and opened
1984 if (!(dbTable
= new wxTable(pDB
, masterTableName
, 0)))
1986 wxMessageBox("Memory allocation failed creating a wxTable object.","Error...",wxOK
| wxICON_EXCLAMATION
);
1989 if (!dbTable
->Open())
1992 tStr
= "ODBC error during Open()\n\n";
1993 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
1994 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
1999 // Count() with WHERE clause
2000 dbTable
->where
= (char*) (const char*) pQuerySqlWhereMtxt
->GetValue();
2001 ULONG whereCnt
= dbTable
->Count();
2003 // Count() of all records in the table
2005 ULONG totalCnt
= dbTable
->Count();
2007 if (whereCnt
> 0 || totalCnt
== 0)
2010 tStr
.Printf("%lu of %lu records match the query criteria.",whereCnt
,totalCnt
);
2011 wxMessageBox(tStr
,"Notice...",wxOK
| wxICON_INFORMATION
);
2016 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
);
2017 wxMessageBox(tStr
,"Notice...",wxOK
| wxICON_INFORMATION
);
2020 // After a wxMessageBox, the focus does not necessarily return to the
2021 // window which was the focus when the message box popped up, so return
2022 // focus to the Query dialog for certain
2025 } // CqueryDlg::ProcessCountBtn()
2028 bool CqueryDlg::ValidateWhereClause()
2030 wxString where
= pQuerySqlWhereMtxt
->GetValue();
2032 if (where
.Freq('(') != where
.Freq(')'))
2034 wxMessageBox("There are mismatched parenthesis in the constructed where clause","Error...",wxOK
| wxICON_EXCLAMATION
);
2037 // After a wxMessageBox, the focus does not necessarily return to the
2038 // window which was the focus when the message box popped up, so return
2039 // focus to the Query dialog for certain
2044 } // CqueryDlg::ValidateWhereClause()