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 */
61 /* Pointer to the main database connection used in the program. This
62 * pointer would normally be used for doing things as database lookups
63 * for user login names and passwords, getting workstation settings, etc.
66 * For each database object created which uses this wxDB pointer
67 * connection to the database, when a CommitTrans() or RollBackTrans()
68 * will commit or rollback EVERY object which uses this wxDB pointer.
70 * To allow each table object (those derived from wxTable) to be
71 * individually committed or rolled back, you MUST use a different
72 * instance of wxDB in the constructor of the table. Doing so creates
73 * more overhead, and will use more database connections (some DBs have
74 * connection limits...), so use connections sparringly.
76 * It is recommended that one "main" database connection be created for
77 * the entire program to use for READ-ONLY database accesses, but for each
78 * table object which will do a CommitTrans() or RollbackTrans() that a
79 * new wxDB object be created and used for it.
85 * This function will return the exact string(s) from the database engine
86 * indicating all error conditions which have just occured during the
87 * last call to the database engine.
89 * This demo uses the returned string by displaying it in a wxMessageBox. The
90 * formatting therefore is not the greatest, but this is just a demo, not a
91 * finished product. :-) gt
93 * NOTE: The value returned by this function is for temporary use only and
94 * should be copied for long term use
97 char *GetExtendedDBErrorMsg(char *ErrFile
, int ErrLine
)
103 if (ErrFile
|| ErrLine
)
108 tStr
.Printf("%d",ErrLine
);
109 msg
+= tStr
.GetData();
113 msg
.Append ("\nODBC errors:\n");
116 /* Scan through each database connection displaying
117 * any ODBC errors that have occured. */
118 for (DbList
*pDbList
= PtrBegDbList
; pDbList
; pDbList
= pDbList
->PtrNext
)
120 // Skip over any free connections
123 // Display errors for this connection
124 for (int i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
126 if (pDbList
->PtrDb
->errorList
[i
])
128 msg
.Append(pDbList
->PtrDb
->errorList
[i
]);
129 if (strcmp(pDbList
->PtrDb
->errorList
[i
],"") != 0)
136 return (char*) (const char*) msg
;
137 } // GetExtendedDBErrorMsg
140 bool DatabaseDemoApp::OnInit()
142 // Create the main frame window
143 DemoFrame
= new DatabaseDemoFrame(NULL
, "wxWindows Database Demo", wxPoint(50, 50), wxSize(537, 480));
146 DemoFrame
->SetIcon(wxICON(db
));
149 wxMenu
*file_menu
= new wxMenu
;
150 file_menu
->Append(FILE_CREATE
, "&Create contact table");
151 file_menu
->Append(FILE_EXIT
, "E&xit");
153 wxMenu
*edit_menu
= new wxMenu
;
154 edit_menu
->Append(EDIT_PARAMETERS
, "&Parameters...");
156 wxMenu
*about_menu
= new wxMenu
;
157 about_menu
->Append(ABOUT_DEMO
, "&About");
159 wxMenuBar
*menu_bar
= new wxMenuBar
;
160 menu_bar
->Append(file_menu
, "&File");
161 menu_bar
->Append(edit_menu
, "&Edit");
162 menu_bar
->Append(about_menu
, "&About");
163 DemoFrame
->SetMenuBar(menu_bar
);
165 // Initialize the ODBC Environment for Database Operations
166 if (SQLAllocEnv(&DbConnectInf
.Henv
) != SQL_SUCCESS
)
168 wxMessageBox("A problem occured while trying to get a connection to the data source","DB CONNECTION ERROR",wxOK
| wxICON_EXCLAMATION
);
173 if ((paramFile
= fopen(paramFilename
, "r")) == NULL
)
176 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
);
177 wxMessageBox(tStr
,"File I/O Error...",wxOK
| wxICON_EXCLAMATION
);
178 DemoFrame
->BuildParameterDialog(NULL
);
179 if ((paramFile
= fopen(paramFilename
, "r")) == NULL
)
184 fgets(buffer
, sizeof(params
.ODBCSource
), paramFile
);
185 buffer
[strlen(buffer
)-1] = '\0';
186 strcpy(params
.ODBCSource
,buffer
);
188 fgets(buffer
, sizeof(params
.UserName
), paramFile
);
189 buffer
[strlen(buffer
)-1] = '\0';
190 strcpy(params
.UserName
,buffer
);
192 fgets(buffer
, sizeof(params
.Password
), paramFile
);
193 buffer
[strlen(buffer
)-1] = '\0';
194 strcpy(params
.Password
,buffer
);
198 // Connect to datasource
199 strcpy(DbConnectInf
.Dsn
, params
.ODBCSource
); // ODBC data source name (created with ODBC Administrator under Win95/NT)
200 strcpy(DbConnectInf
.Uid
, params
.UserName
); // database username - must already exist in the data source
201 strcpy(DbConnectInf
.AuthStr
, params
.Password
); // password database username
202 READONLY_DB
= GetDbConnection(&DbConnectInf
);
203 if (READONLY_DB
== 0)
205 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
);
206 DemoFrame
->BuildParameterDialog(NULL
);
207 strcpy(DbConnectInf
.Dsn
, "");
208 strcpy(DbConnectInf
.Uid
, "");
209 strcpy(DbConnectInf
.AuthStr
, "");
210 wxMessageBox("Now exiting program.\n\nRestart program to try any new settings.","Notice...",wxOK
| wxICON_INFORMATION
);
214 DemoFrame
->BuildEditorDialog();
217 DemoFrame
->Show(TRUE
);
220 } // DatabaseDemoApp::OnInit()
222 BEGIN_EVENT_TABLE(DatabaseDemoFrame
, wxFrame
)
223 EVT_MENU(FILE_CREATE
, DatabaseDemoFrame::OnCreate
)
224 EVT_MENU(FILE_EXIT
, DatabaseDemoFrame::OnExit
)
225 EVT_MENU(EDIT_PARAMETERS
, DatabaseDemoFrame::OnEditParameters
)
226 EVT_MENU(ABOUT_DEMO
, DatabaseDemoFrame::OnAbout
)
227 EVT_CLOSE(DatabaseDemoFrame::OnCloseWindow
)
230 // DatabaseDemoFrame constructor
231 DatabaseDemoFrame::DatabaseDemoFrame(wxFrame
*frame
, const wxString
& title
,
232 const wxPoint
& pos
, const wxSize
& size
):
233 wxFrame(frame
, -1, title
, pos
, size
)
235 // Put any code in necessary for initializing the main frame here
238 void DatabaseDemoFrame::OnCreate(wxCommandEvent
& event
)
243 void DatabaseDemoFrame::OnExit(wxCommandEvent
& event
)
248 void DatabaseDemoFrame::OnEditParameters(wxCommandEvent
& event
)
250 if ((pEditorDlg
->mode
!= mCreate
) && (pEditorDlg
->mode
!= mEdit
))
251 BuildParameterDialog(this);
253 wxMessageBox("Cannot change database parameters while creating or editing a record","Notice...",wxOK
| wxICON_INFORMATION
);
256 void DatabaseDemoFrame::OnAbout(wxCommandEvent
& event
)
258 wxMessageBox("wxWindows sample program for database classes\n\nContributed on 27 July 1998","About...",wxOK
| wxICON_INFORMATION
);
261 void DatabaseDemoFrame::OnCloseWindow(wxCloseEvent
& event
)
263 // Put any additional checking necessary to make certain it is alright
264 // to close the program here that is not done elsewhere
267 } // DatabaseDemoFrame::OnCloseWindow()
270 void DatabaseDemoFrame::CreateDataTable()
272 bool Ok
= (wxMessageBox("Any data currently residing in the table will be erased.\n\nAre you sure?","Confirm",wxYES_NO
|wxICON_QUESTION
) == wxYES
);
281 Ccontact
*Contact
= new Ccontact();
285 wxMessageBox("Error allocating memory for 'Ccontact'object.\n\nTable was not created.","Error...",wxOK
| wxICON_EXCLAMATION
);
289 if (!Contact
->CreateTable())
293 tStr
= "Error creating CONTACTS table.\nTable was not created.\n\n";
294 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
295 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
300 if (!Contact
->CreateIndexes())
304 tStr
= "Error creating CONTACTS indexes.\nIndexes will be unavailable.\n\n";
305 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
306 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
315 wxMessageBox("Table and index(es) were successfully created.","Notice...",wxOK
| wxICON_INFORMATION
);
316 } // DatabaseDemoFrame::CreateDataTable()
319 void DatabaseDemoFrame::BuildEditorDialog()
321 pEditorDlg
= new CeditorDlg(this);
323 wxMessageBox("Unable to create the editor dialog for some reason","Error...",wxOK
| wxICON_EXCLAMATION
);
324 } // DatabaseDemoFrame::BuildEditorDialog()
327 void DatabaseDemoFrame::BuildParameterDialog(wxWindow
*parent
)
329 pParamDlg
= new CparameterDlg(parent
);
332 wxMessageBox("Unable to create the parameter dialog for some reason","Error...",wxOK
| wxICON_EXCLAMATION
);
333 } // DatabaseDemoFrame::BuildParameterDialog()
337 * Constructor note: If no wxDB object is passed in, a new connection to the database
338 * is created for this instance of Ccontact. This can be a slow process depending
339 * on the database engine being used, and some database engines have a limit on the
340 * number of connections (either hard limits, or license restricted) so care should
341 * be used to use as few connections as is necessary.
342 * IMPORTANT: Objects which share a wxDB pointer are ALL acted upon whenever a member
343 * function of pDb is called (i.e. CommitTrans() or RollbackTrans(), so if modifying
344 * or creating a table objects which use the same pDb, know that all the objects
345 * will be committed or rolled back when any of the objects has this function call made.
347 Ccontact::Ccontact (wxDB
*pwxDB
) : wxTable(pwxDB
? pwxDB
: GetDbConnection(&DbConnectInf
),CONTACT_TABLE_NAME
,CONTACT_NO_COLS
)
349 // This is used to represent whether the database connection should be released
350 // when this instance of the object is deleted. If using the same connection
351 // for multiple instance of database objects, then the connection should only be
352 // released when the last database instance using the connection is deleted
357 } // Ccontact Constructor
360 void Ccontact::Initialize()
369 JoinDate
.year
= 1980;
375 JoinDate
.fraction
= 0;
376 NativeLanguage
= langENGLISH
;
380 } // Ccontact::Initialize
383 Ccontact::~Ccontact()
387 if (!FreeDbConnection(pDb
))
390 tStr
= "Unable to Free the Ccontact data table handle\n\n";
391 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
392 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
395 } // Ccontract destructor
399 * Handles setting up all the connections for the interface from the wxTable
400 * functions to interface to the data structure used to store records in
401 * memory, and for all the column definitions that define the table structure
403 void Ccontact::SetupColumns()
405 SetColDefs ( 0,"NAME", DB_DATA_TYPE_VARCHAR
, Name
, SQL_C_CHAR
, sizeof(Name
), TRUE
, TRUE
); // Primary index
406 SetColDefs ( 1,"ADDRESS1", DB_DATA_TYPE_VARCHAR
, Addr1
, SQL_C_CHAR
, sizeof(Addr1
), FALSE
,TRUE
);
407 SetColDefs ( 2,"ADDRESS2", DB_DATA_TYPE_VARCHAR
, Addr2
, SQL_C_CHAR
, sizeof(Addr2
), FALSE
,TRUE
);
408 SetColDefs ( 3,"CITY", DB_DATA_TYPE_VARCHAR
, City
, SQL_C_CHAR
, sizeof(City
), FALSE
,TRUE
);
409 SetColDefs ( 4,"STATE", DB_DATA_TYPE_VARCHAR
, State
, SQL_C_CHAR
, sizeof(State
), FALSE
,TRUE
);
410 SetColDefs ( 5,"POSTAL_CODE", DB_DATA_TYPE_VARCHAR
, PostalCode
, SQL_C_CHAR
, sizeof(PostalCode
), FALSE
,TRUE
);
411 SetColDefs ( 6,"COUNTRY", DB_DATA_TYPE_VARCHAR
, Country
, SQL_C_CHAR
, sizeof(Country
), FALSE
,TRUE
);
412 SetColDefs ( 7,"JOIN_DATE", DB_DATA_TYPE_DATE
, &JoinDate
, SQL_C_TIMESTAMP
, sizeof(JoinDate
), FALSE
,TRUE
);
413 SetColDefs ( 8,"NATIVE_LANGUAGE", DB_DATA_TYPE_INTEGER
, &NativeLanguage
, SQL_C_ENUM
, sizeof(NativeLanguage
), FALSE
,TRUE
);
414 SetColDefs ( 9,"IS_DEVELOPER", DB_DATA_TYPE_INTEGER
, &IsDeveloper
, SQL_C_BOOLEAN
, sizeof(bool), FALSE
,TRUE
);
415 SetColDefs (10,"CONTRIBUTIONS", DB_DATA_TYPE_INTEGER
, &Contributions
, SQL_C_USHORT
, sizeof(Contributions
), FALSE
,TRUE
);
416 SetColDefs (11,"LINES_OF_CODE", DB_DATA_TYPE_INTEGER
, &LinesOfCode
, SQL_C_ULONG
, sizeof(LinesOfCode
), FALSE
,TRUE
);
417 } // Ccontact::SetupColumns
420 bool Ccontact::CreateIndexes(void)
422 // This index could easily be accomplished with an "orderBy" clause,
423 // but is done to show how to construct a non-primary index.
429 strcpy(idxDef
[0].ColName
, "IS_DEVELOPER");
430 idxDef
[0].Ascending
= TRUE
;
432 strcpy(idxDef
[1].ColName
, "NAME");
433 idxDef
[1].Ascending
= TRUE
;
435 indexName
= CONTACT_TABLE_NAME
;
436 indexName
+= "_IDX1";
437 Ok
= CreateIndex((char*) (const char*) indexName
, TRUE
, 2, idxDef
);
440 } // Ccontact::CreateIndexes()
444 * Having a function to do a query on the primary key (and possibly others) is
445 * very efficient and tighter coding so that it is available where ever the object
446 * is. Great for use with multiple tables when not using views or outer joins
448 bool Ccontact::FetchByName(char *name
)
450 whereStr
.Printf("NAME = '%s'",name
);
451 where
= (char*) (const char*) this->whereStr
;
460 } // Ccontact::FetchByName()
465 * ************* DIALOGS ***************
470 /* CeditorDlg constructor
472 * Creates the dialog used for creating/editing/deleting/copying a Ccontact object.
473 * This dialog actually is drawn in the main frame of the program
475 * An instance of Ccontact is created - "Contact" - which is used to hold the Ccontact
476 * object that is currently being worked with.
479 BEGIN_EVENT_TABLE(CeditorDlg
, wxPanel
)
480 EVT_BUTTON(-1, CeditorDlg::OnButton
)
483 CeditorDlg::CeditorDlg(wxWindow
*parent
) : wxPanel (parent
, 1, 1, 460, 455)
485 // Since the ::OnCommand() function is overridden, this prevents the widget
486 // detection in ::OnCommand() until all widgets have been initialized to prevent
487 // uninitialized pointers from crashing the program
488 widgetPtrsSet
= FALSE
;
490 // Create the data structure and a new database connection.
491 // (As there is not a pDb being passed in the constructor, a new database
492 // connection is created)
493 Contact
= new Ccontact();
497 wxMessageBox("Unable to instantiate an instance of Ccontact","Error...",wxOK
| wxICON_EXCLAMATION
);
501 // Check if the table exists or not. If it doesn't, ask the user if they want to
502 // create the table. Continue trying to create the table until it exists, or user aborts
503 while (!Contact
->pDb
->TableExists((char *)CONTACT_TABLE_NAME
))
506 tStr
.Printf("Unable to open the table '%s'.\n\nTable may need to be created...?\n\n",CONTACT_TABLE_NAME
);
507 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
508 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
510 bool createTable
= (wxMessageBox("Do you wish to try to create/clear the CONTACTS table?","Confirm",wxYES_NO
|wxICON_QUESTION
) == wxYES
);
520 DemoFrame
->CreateDataTable();
523 // Tables must be "opened" before anything other than creating/deleting table can be done
524 if (!Contact
->Open())
526 // Table does exist, there was some problem opening it. Currently this should
527 // never fail, except in the case of the table not exisiting. Open() basically
528 // only sets up variable/pointer values, other than checking for table existence.
529 if (Contact
->pDb
->TableExists((char *)CONTACT_TABLE_NAME
))
532 tStr
.Printf("Unable to open the table '%s'.\n\n",CONTACT_TABLE_NAME
);
533 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
534 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
544 (void)new wxStaticBox(this, EDITOR_DIALOG_FN_GROUP
, "", wxPoint(15, 1), wxSize(497, 69), 0, "FunctionGrp");
545 (void)new wxStaticBox(this, EDITOR_DIALOG_SEARCH_GROUP
, "", wxPoint(417, 1), wxSize(95, 242), 0, "SearchGrp");
547 pCreateBtn
= new wxButton(this, EDITOR_DIALOG_CREATE
, "&Create", wxPoint(25, 21), wxSize(70, 35), 0, wxDefaultValidator
, "CreateBtn");
548 pEditBtn
= new wxButton(this, EDITOR_DIALOG_EDIT
, "&Edit", wxPoint(102, 21), wxSize(70, 35), 0, wxDefaultValidator
, "EditBtn");
549 pDeleteBtn
= new wxButton(this, EDITOR_DIALOG_DELETE
, "&Delete", wxPoint(179, 21), wxSize(70, 35), 0, wxDefaultValidator
, "DeleteBtn");
550 pCopyBtn
= new wxButton(this, EDITOR_DIALOG_COPY
, "Cop&y", wxPoint(256, 21), wxSize(70, 35), 0, wxDefaultValidator
, "CopyBtn");
551 pSaveBtn
= new wxButton(this, EDITOR_DIALOG_SAVE
, "&Save", wxPoint(333, 21), wxSize(70, 35), 0, wxDefaultValidator
, "SaveBtn");
552 pCancelBtn
= new wxButton(this, EDITOR_DIALOG_CANCEL
, "C&ancel", wxPoint(430, 21), wxSize(70, 35), 0, wxDefaultValidator
, "CancelBtn");
554 pPrevBtn
= new wxButton(this, EDITOR_DIALOG_PREV
, "<< &Prev", wxPoint(430, 81), wxSize(70, 35), 0, wxDefaultValidator
, "PrevBtn");
555 pNextBtn
= new wxButton(this, EDITOR_DIALOG_NEXT
, "&Next >>", wxPoint(430, 121), wxSize(70, 35), 0, wxDefaultValidator
, "NextBtn");
556 pQueryBtn
= new wxButton(this, EDITOR_DIALOG_QUERY
, "&Query", wxPoint(430, 161), wxSize(70, 35), 0, wxDefaultValidator
, "QueryBtn");
557 pResetBtn
= new wxButton(this, EDITOR_DIALOG_RESET
, "&Reset", wxPoint(430, 200), wxSize(70, 35), 0, wxDefaultValidator
, "ResetBtn");
559 pNameMsg
= new wxStaticText(this, EDITOR_DIALOG_NAME_MSG
, "Name:", wxPoint(17, 80), wxSize(-1, -1), 0, "NameMsg");
560 pNameTxt
= new wxTextCtrl(this, EDITOR_DIALOG_NAME_TEXT
, "", wxPoint(17, 97), wxSize(308, 25), 0, wxDefaultValidator
, "NameTxt");
561 pNameListBtn
= new wxButton(this, EDITOR_DIALOG_LOOKUP
, "&Lookup", wxPoint(333, 99), wxSize(70, 24), 0, wxDefaultValidator
, "LookupBtn");
563 pAddress1Msg
= new wxStaticText(this, EDITOR_DIALOG_ADDRESS1_MSG
, "Address:", wxPoint(17, 130), wxSize(-1, -1), 0, "Address1Msg");
564 pAddress1Txt
= new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT
, "", wxPoint(17, 147), wxSize(308, 25), 0, wxDefaultValidator
, "Address1Txt");
566 pAddress2Msg
= new wxStaticText(this, EDITOR_DIALOG_ADDRESS2_MSG
, "Address:", wxPoint(17, 180), wxSize(-1, -1), 0, "Address2Msg");
567 pAddress2Txt
= new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT
, "", wxPoint(17, 197), wxSize(308, 25), 0, wxDefaultValidator
, "Address2Txt");
569 pCityMsg
= new wxStaticText(this, EDITOR_DIALOG_CITY_MSG
, "City:", wxPoint(17, 230), wxSize(-1, -1), 0, "CityMsg");
570 pCityTxt
= new wxTextCtrl(this, EDITOR_DIALOG_CITY_TEXT
, "", wxPoint(17, 247), wxSize(225, 25), 0, wxDefaultValidator
, "CityTxt");
572 pStateMsg
= new wxStaticText(this, EDITOR_DIALOG_STATE_MSG
, "State:", wxPoint(250, 230), wxSize(-1, -1), 0, "StateMsg");
573 pStateTxt
= new wxTextCtrl(this, EDITOR_DIALOG_STATE_TEXT
, "", wxPoint(250, 247), wxSize(153, 25), 0, wxDefaultValidator
, "StateTxt");
575 pCountryMsg
= new wxStaticText(this, EDITOR_DIALOG_COUNTRY_MSG
, "Country:", wxPoint(17, 280), wxSize(-1, -1), 0, "CountryMsg");
576 pCountryTxt
= new wxTextCtrl(this, EDITOR_DIALOG_COUNTRY_TEXT
, "", wxPoint(17, 297), wxSize(225, 25), 0, wxDefaultValidator
, "CountryTxt");
578 pPostalCodeMsg
= new wxStaticText(this, EDITOR_DIALOG_POSTAL_MSG
, "Postal Code:", wxPoint(250, 280), wxSize(-1, -1), 0, "PostalCodeMsg");
579 pPostalCodeTxt
= new wxTextCtrl(this, EDITOR_DIALOG_POSTAL_TEXT
, "", wxPoint(250, 297), wxSize(153, 25), 0, wxDefaultValidator
, "PostalCodeTxt");
581 wxString choice_strings
[5];
582 choice_strings
[0] = "English";
583 choice_strings
[1] = "French";
584 choice_strings
[2] = "German";
585 choice_strings
[3] = "Spanish";
586 choice_strings
[4] = "Other";
587 pNativeLangChoice
= new wxChoice(this, EDITOR_DIALOG_LANG_CHOICE
, wxPoint(17, 346), wxSize(277, -1), 5, choice_strings
);
588 pNativeLangMsg
= new wxStaticText(this, EDITOR_DIALOG_LANG_MSG
, "Native language:", wxPoint(17, 330), wxSize(-1, -1), 0, "NativeLangMsg");
590 wxString radio_strings
[2];
591 radio_strings
[0] = "No";
592 radio_strings
[1] = "Yes";
593 pDeveloperRadio
= new wxRadioBox(this,EDITOR_DIALOG_DEVELOPER
,"Developer:",wxPoint(303,330),wxSize(-1,-1),2,radio_strings
,2,wxHORIZONTAL
);
595 pJoinDateMsg
= new wxStaticText(this, EDITOR_DIALOG_JOIN_MSG
, "Date joined:", wxPoint(17, 380), wxSize(-1, -1), 0, "JoinDateMsg");
596 pJoinDateTxt
= new wxTextCtrl(this, EDITOR_DIALOG_JOIN_TEXT
, "", wxPoint(17, 397), wxSize(150, 25), 0, wxDefaultValidator
, "JoinDateTxt");
598 pContribMsg
= new wxStaticText(this, EDITOR_DIALOG_CONTRIB_MSG
, "Contributions:", wxPoint(175, 380), wxSize(-1, -1), 0, "ContribMsg");
599 pContribTxt
= new wxTextCtrl(this, EDITOR_DIALOG_CONTRIB_TEXT
, "", wxPoint(175, 397), wxSize(120, 25), 0, wxDefaultValidator
, "ContribTxt");
601 pLinesMsg
= new wxStaticText(this, EDITOR_DIALOG_LINES_MSG
, "Lines of code:", wxPoint(303, 380), wxSize(-1, -1), 0, "LinesMsg");
602 pLinesTxt
= new wxTextCtrl(this, EDITOR_DIALOG_LINES_TEXT
, "", wxPoint(303, 397), wxSize(100, 25), 0, wxDefaultValidator
, "LinesTxt");
604 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
605 // handle all widget processing
606 widgetPtrsSet
= TRUE
;
608 // Setup the orderBy and where clauses to return back a single record as the result set,
609 // as there will only be one record being shown on the dialog at a time, this optimizes
610 // network traffic by only returning a one row result
612 Contact
->orderBy
= "NAME"; // field name to sort by
614 // The wxString "whereStr" is not a member of the wxTable object, it is a member variable
615 // specifically in the Ccontact class. It is used here for simpler construction of a varying
616 // length string, and then after the string is built, the wxTable member variable "where" is
617 // assigned the pointer to the constructed string.
619 // The constructed where clause below has a sub-query within it "SELECT MIN(NAME) FROM %s"
620 // to achieve a single row (in this case the first name in alphabetical order).
622 // commented out because PostgreSQL can't do this
623 //Contact->whereStr.Printf("NAME = (SELECT MIN(NAME) FROM %s)",Contact->tableName);
625 // NOTE: (const char*) returns a pointer which may not be valid later, so this is short term use only
626 Contact
->where
= (char*) (const char*) Contact
->whereStr
;
628 // Perform the Query to get the result set.
629 // NOTE: If there are no rows returned, that is a valid result, so Query() would return TRUE.
630 // Only if there is a database error will Query() come back as FALSE
631 if (!Contact
->Query())
634 tStr
= "ODBC error during Query()\n\n";
635 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
636 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
637 GetParent()->Close();
641 // Since Query succeeded, now get the row that was returned
642 if (!Contact
->GetNext())
643 // If the GetNext() failed at this point, then there are no rows to retrieve,
644 // so clear the values in the members of "Contact" so that PutData() blanks the
645 // widgets on the dialog
646 Contact
->Initialize();
652 } // CeditorDlg constructor
655 void CeditorDlg::OnCloseWindow(wxCloseEvent
& event
)
658 if ((mode
!= mCreate
) && (mode
!= mEdit
))
666 wxMessageBox("Must finish processing the current record being created/modified before exiting","Notice...",wxOK
| wxICON_INFORMATION
);
669 } // CeditorDlg::OnCloseWindow()
672 void CeditorDlg::OnButton( wxCommandEvent
&event
)
674 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
675 OnCommand( *win
, event
);
678 void CeditorDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
682 widgetName
= win
.GetName();
687 if (widgetName
== pCreateBtn
->GetName())
689 Contact
->Initialize();
692 pNameTxt
->SetValue("");
693 pNameTxt
->SetFocus();
697 if (widgetName
== pEditBtn
->GetName())
699 saveName
= Contact
->Name
;
701 pNameTxt
->SetFocus();
705 if (widgetName
== pCopyBtn
->GetName())
708 pNameTxt
->SetValue("");
709 pNameTxt
->SetFocus();
713 if (widgetName
== pDeleteBtn
->GetName())
715 bool Ok
= (wxMessageBox("Are you sure?","Confirm",wxYES_NO
|wxICON_QUESTION
) == wxYES
);
720 if (Ok
&& Contact
->Delete())
722 // NOTE: Deletions are not finalized until a CommitTrans() is performed.
723 // If the commit were not performed, the program will continue to
724 // show the table contents as if they were deleted until this instance
725 // of Ccontact is deleted. If the Commit wasn't performed, the
726 // database will automatically Rollback the changes when the database
727 // connection is terminated
728 Contact
->pDb
->CommitTrans();
730 // Try to get the row that followed the just deleted row in the orderBy sequence
733 // There was now row (in sequence) after the just deleted row, so get the
734 // row which preceded the just deleted row
737 // There are now no rows remaining, so clear the dialog widgets
738 Contact
->Initialize();
742 SetMode(mode
); // force reset of button enable/disable
746 Contact
->pDb
->RollbackTrans();
752 if (widgetName
== pSaveBtn
->GetName())
758 if (widgetName
== pCancelBtn
->GetName())
760 bool Ok
= (wxMessageBox("Are you sure?","Confirm",wxYES_NO
|wxICON_QUESTION
) == wxYES
);
765 if (!strcmp((const char*) saveName
,""))
767 Contact
->Initialize();
774 // Requery previous record
775 if (Contact
->FetchByName((char*) (const char*) saveName
))
783 // commented out because PostgreSQL can't do this
785 // Previous record not available, retrieve first record in table
786 //Contact->whereStr = "NAME = (SELECT MIN(NAME) FROM ";
787 //Contact->whereStr += Contact->tableName;
788 //Contact->whereStr += ")";
790 Contact
->where
= (char*) (const char*) Contact
->whereStr
;
791 if (!Contact
->Query())
794 tStr
= "ODBC error during Query()\n\n";
795 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
796 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
800 if (Contact
->GetNext()) // Successfully read first record
806 // No contacts are available, clear dialog
807 Contact
->Initialize();
813 if (widgetName
== pPrevBtn
->GetName())
820 if (widgetName
== pNextBtn
->GetName())
827 if (widgetName
== pQueryBtn
->GetName())
829 // Display the query dialog box
830 char qryWhere
[DB_MAX_WHERE_CLAUSE_LEN
+1];
831 strcpy(qryWhere
, (const char*) Contact
->qryWhereStr
);
832 char *tblName
[] = {(char *)CONTACT_TABLE_NAME
, 0};
833 new CqueryDlg(GetParent(), Contact
->pDb
, tblName
, qryWhere
);
835 // Query the first record in the new record set and
836 // display it, if the query string has changed.
837 if (strcmp(qryWhere
, (const char*) Contact
->qryWhereStr
))
840 // commented out because PostgreSQL can't do this
841 Contact
->whereStr
= "";
842 //Contact->orderBy = "NAME";
843 //Contact->whereStr = "NAME = (SELECT MIN(NAME) FROM ";
844 //Contact->whereStr += CONTACT_TABLE_NAME;
846 // Append the query where string (if there is one)
847 Contact
->qryWhereStr
= qryWhere
;
848 if (strlen(qryWhere
))
850 Contact
->whereStr
+= " WHERE ";
851 Contact
->whereStr
+= Contact
->qryWhereStr
;
853 // Close the expression with a right paren
854 // Contact->whereStr += ")";
856 Contact
->where
= (char*) (const char*) Contact
->whereStr
;
857 if (!Contact
->Query())
860 tStr
= "ODBC error during Query()\n\n";
861 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
862 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
865 // Display the first record from the query set
866 if (!Contact
->GetNext())
867 Contact
->Initialize();
871 // Enable/Disable the reset button
872 pResetBtn
->Enable(!Contact
->qryWhereStr
.IsEmpty());
878 if (widgetName
== pResetBtn
->GetName())
880 // Clear the additional where criteria established by the query feature
881 Contact
->qryWhereStr
= "";
883 // Query the first record in the table
884 Contact
->orderBy
= "NAME";
886 // commented out because PostgreSQL can't do this
887 //Contact->whereStr = "NAME = (SELECT MIN(NAME) FROM ";
888 //Contact->whereStr += CONTACT_TABLE_NAME;
889 //Contact->whereStr += ")";
891 Contact
->where
= (char*) (const char*) Contact
->whereStr
;
892 if (!Contact
->Query())
895 tStr
= "ODBC error during Query()\n\n";
896 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
897 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
900 if (!Contact
->GetNext())
901 Contact
->Initialize();
903 pResetBtn
->Enable(FALSE
);
909 if (widgetName
== pNameListBtn
->GetName())
911 new ClookUpDlg(/* wxWindow *parent */ this,
912 /* char *windowTitle */ "Select contact name",
913 /* char *tableName */ (char *) CONTACT_TABLE_NAME
,
914 /* char *dispCol1 */ "NAME",
915 /* char *dispCol2 */ "JOIN_DATE",
916 /* char *where */ "",
917 /* char *orderBy */ "NAME",
918 /* bool distinctValues */ TRUE
);
920 if (ListDB_Selection
&& strlen(ListDB_Selection
))
922 wxString w
= "NAME = '";
923 w
+= ListDB_Selection
;
925 GetRec((char*) (const char*) w
);
931 } // CeditorDlg::OnCommand()
934 void CeditorDlg::FieldsEditable()
936 pNameTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
937 pAddress1Txt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
938 pAddress2Txt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
939 pCityTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
940 pStateTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
941 pPostalCodeTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
942 pCountryTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
944 pJoinDateTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
945 pContribTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
946 pLinesTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
947 pNativeLangChoice
->Enable((mode
== mCreate
) || (mode
== mEdit
));
948 pDeveloperRadio
->Enable((mode
== mCreate
) || (mode
== mEdit
));
950 } // CeditorDlg::FieldsEditable()
953 void CeditorDlg::SetMode(enum DialogModes m
)
974 pCreateBtn
->Enable( !edit
);
975 pEditBtn
->Enable( !edit
&& (strcmp(Contact
->Name
,"")!=0) );
976 pDeleteBtn
->Enable( !edit
&& (strcmp(Contact
->Name
,"")!=0) );
977 pCopyBtn
->Enable( !edit
&& (strcmp(Contact
->Name
,"")!=0) );
978 pSaveBtn
->Enable( edit
);
979 pCancelBtn
->Enable( edit
);
980 pPrevBtn
->Enable( !edit
);
981 pNextBtn
->Enable( !edit
);
982 pQueryBtn
->Enable( !edit
);
983 pResetBtn
->Enable( !edit
&& !Contact
->qryWhereStr
.IsEmpty() );
984 pNameListBtn
->Enable( !edit
);
988 } // CeditorDlg::SetMode()
991 bool CeditorDlg::PutData()
995 pNameTxt
->SetValue(Contact
->Name
);
996 pAddress1Txt
->SetValue(Contact
->Addr1
);
997 pAddress2Txt
->SetValue(Contact
->Addr2
);
998 pCityTxt
->SetValue(Contact
->City
);
999 pStateTxt
->SetValue(Contact
->State
);
1000 pCountryTxt
->SetValue(Contact
->Country
);
1001 pPostalCodeTxt
->SetValue(Contact
->PostalCode
);
1003 tStr
.Printf("%d/%d/%d",Contact
->JoinDate
.month
,Contact
->JoinDate
.day
,Contact
->JoinDate
.year
);
1004 pJoinDateTxt
->SetValue(tStr
);
1006 tStr
.Printf("%d",Contact
->Contributions
);
1007 pContribTxt
->SetValue(tStr
);
1009 tStr
.Printf("%lu",Contact
->LinesOfCode
);
1010 pLinesTxt
->SetValue(tStr
);
1012 pNativeLangChoice
->SetSelection(Contact
->NativeLanguage
);
1014 pDeveloperRadio
->SetSelection(Contact
->IsDeveloper
);
1017 } // Ceditor::PutData()
1021 * Reads the data out of all the widgets on the dialog. Some data evaluation is done
1022 * to ensure that there is a name entered and that the date field is valid.
1024 * A return value of TRUE means that valid data was retrieved from the dialog, otherwise
1025 * invalid data was found (and a message was displayed telling the user what to fix), and
1026 * the data was not placed into the appropraite fields of Ccontact
1028 bool CeditorDlg::GetData()
1030 // Validate that the data currently entered into the widgets is valid data
1033 tStr
= pNameTxt
->GetValue();
1034 if (!strcmp((const char*) tStr
,""))
1036 wxMessageBox("A name is required for entry into the contact table","Notice...",wxOK
| wxICON_INFORMATION
);
1040 bool invalid
= FALSE
;
1044 tStr
= pJoinDateTxt
->GetValue();
1045 if (tStr
.Freq('/') != 2)
1048 // Find the month, day, and year tokens
1051 first
= tStr
.First('/');
1052 second
= tStr
.Last('/');
1054 mm
= atoi(tStr
.SubString(0,first
));
1055 dd
= atoi(tStr
.SubString(first
+1,second
));
1056 yyyy
= atoi(tStr
.SubString(second
+1,tStr
.Length()-1));
1058 invalid
= !(mm
&& dd
&& yyyy
);
1061 // Force Year 2000 compliance
1062 if (!invalid
&& (yyyy
< 1000))
1065 // Check the token ranges for validity
1070 else if ((mm
< 1) || (mm
> 12))
1078 int days
[12] = {31,28,31,30,31,30,
1080 if (dd
> days
[mm
-1])
1083 if ((dd
== 29) && (mm
== 2))
1085 if (((yyyy
% 4) == 0) && (((yyyy
% 100) != 0) || ((yyyy
% 400) == 0)))
1095 Contact
->JoinDate
.month
= mm
;
1096 Contact
->JoinDate
.day
= dd
;
1097 Contact
->JoinDate
.year
= yyyy
;
1101 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
);
1105 tStr
= pNameTxt
->GetValue();
1106 strcpy(Contact
->Name
,(const char*) tStr
);
1107 strcpy(Contact
->Addr1
,pAddress1Txt
->GetValue());
1108 strcpy(Contact
->Addr2
,pAddress2Txt
->GetValue());
1109 strcpy(Contact
->City
,pCityTxt
->GetValue());
1110 strcpy(Contact
->State
,pStateTxt
->GetValue());
1111 strcpy(Contact
->Country
,pCountryTxt
->GetValue());
1112 strcpy(Contact
->PostalCode
,pPostalCodeTxt
->GetValue());
1114 Contact
->Contributions
= atoi(pContribTxt
->GetValue());
1115 Contact
->LinesOfCode
= atol(pLinesTxt
->GetValue());
1117 Contact
->NativeLanguage
= (enum Language
) pNativeLangChoice
->GetSelection();
1118 Contact
->IsDeveloper
= (bool) pDeveloperRadio
->GetSelection();
1121 } // CeditorDlg::GetData()
1125 * Retrieve data from the dialog, verify the validity of the data, and if it is valid,
1126 * try to insert/update the data to the table based on the current 'mode' the dialog
1129 * A return value of TRUE means the insert/update was completed successfully, a return
1130 * value of FALSE means that Save() failed. If returning FALSE, then this function
1131 * has displayed a detailed error message for the user.
1133 bool CeditorDlg::Save()
1135 bool failed
= FALSE
;
1137 // Read the data in the widgets of the dialog to get the user's data
1141 // Perform any other required validations necessary before saving
1146 wxBeginBusyCursor();
1148 if (mode
== mCreate
)
1150 RETCODE result
= Contact
->Insert();
1152 failed
= (result
!= DB_SUCCESS
);
1155 // Some errors may be expected, like a duplicate key, so handle those instances with
1156 // specific error messages.
1157 if (result
== DB_ERR_INTEGRITY_CONSTRAINT_VIOL
)
1160 tStr
= "A duplicate key value already exists in the table.\nUnable to save record\n\n";
1161 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
1162 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
1166 // Some other unexpexted error occurred
1168 tStr
= "Database insert failed\n\n";
1169 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
1170 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
1174 else // mode == mEdit
1176 if (!Contact
->Update())
1179 tStr
= "Database update failed\n\n";
1180 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
1181 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
1188 Contact
->pDb
->CommitTrans();
1189 SetMode(mView
); // Sets the dialog mode back to viewing after save is successful
1192 Contact
->pDb
->RollbackTrans();
1198 } // CeditorDlg::Save()
1202 * Where this program is only showing a single row at a time in the dialog,
1203 * a special where clause must be built to find just the single row which,
1204 * in sequence, would follow the currently displayed row.
1206 bool CeditorDlg::GetNextRec()
1210 // commented out because PostgreSQL can't do this
1211 //w = "NAME = (SELECT MIN(NAME) FROM ";
1212 //w += Contact->tableName;
1213 // w += " WHERE NAME > '";
1218 // If a query where string is currently set, append that criteria
1219 if (!Contact
->qryWhereStr
.IsEmpty())
1222 w
+= Contact
->qryWhereStr
;
1227 return(GetRec((char*) (const char*) w
));
1229 } // CeditorDlg::GetNextRec()
1233 * Where this program is only showing a single row at a time in the dialog,
1234 * a special where clause must be built to find just the single row which,
1235 * in sequence, would precede the currently displayed row.
1237 bool CeditorDlg::GetPrevRec()
1241 // commented out because PostgreSQL can't do this
1242 //w = "NAME = (SELECT MAX(NAME) FROM ";
1243 //w += Contact->tableName;
1244 //w += " WHERE NAME < '";
1249 // If a query where string is currently set, append that criteria
1250 if (!Contact
->qryWhereStr
.IsEmpty())
1253 w
+= Contact
->qryWhereStr
;
1259 return(GetRec((char*) (const char*)w
));
1261 } // CeditorDlg::GetPrevRec()
1265 * This function is here to avoid duplicating this same code in both the
1266 * GetPrevRec() and GetNextRec() functions
1268 bool CeditorDlg::GetRec(char *whereStr
)
1270 Contact
->where
= whereStr
;
1271 Contact
->orderBy
= "NAME";
1273 if (!Contact
->Query())
1276 tStr
= "ODBC error during Query()\n\n";
1277 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
1278 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
1283 if (Contact
->GetNext())
1290 } // CeditorDlg::GetRec()
1295 * CparameterDlg constructor
1298 BEGIN_EVENT_TABLE(CparameterDlg
, wxDialog
)
1299 EVT_CLOSE(CparameterDlg::OnCloseWindow
)
1302 CparameterDlg::CparameterDlg(wxWindow
*parent
) : wxDialog (parent
, PARAMETER_DIALOG
, "ODBC parameter settings", wxPoint(-1, -1), wxSize(400, 275))
1304 // Since the ::OnCommand() function is overridden, this prevents the widget
1305 // detection in ::OnCommand() until all widgets have been initialized to prevent
1306 // uninitialized pointers from crashing the program
1307 widgetPtrsSet
= FALSE
;
1309 pParamODBCSourceMsg
= new wxStaticText(this, PARAMETER_DIALOG_SOURCE_MSG
, "ODBC data sources:", wxPoint(10, 10), wxSize(-1, -1), 0, "ParamODBCSourceMsg");
1310 pParamODBCSourceList
= new wxListBox(this, PARAMETER_DIALOG_SOURCE_LISTBOX
, wxPoint(10, 29), wxSize(285, 150), 0, 0, wxLB_SINGLE
|wxLB_ALWAYS_SB
, wxDefaultValidator
, "ParamODBCSourceList");
1312 pParamUserNameMsg
= new wxStaticText(this, PARAMETER_DIALOG_NAME_MSG
, "Database user name:", wxPoint(10, 193), wxSize(-1, -1), 0, "ParamUserNameMsg");
1313 pParamUserNameTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_NAME_TEXT
, "", wxPoint(10, 209), wxSize(140, 25), 0, wxDefaultValidator
, "ParamUserNameTxt");
1315 pParamPasswordMsg
= new wxStaticText(this, PARAMETER_DIALOG_PASSWORD_MSG
, "Password:", wxPoint(156, 193), wxSize(-1, -1), 0, "ParamPasswordMsg");
1316 pParamPasswordTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_PASSWORD_TEXT
, "", wxPoint(156, 209), wxSize(140, 25), 0, wxDefaultValidator
, "ParamPasswordTxt");
1318 pParamSaveBtn
= new wxButton(this, PARAMETER_DIALOG_SAVE
, "&Save", wxPoint(310, 21), wxSize(70, 35), 0, wxDefaultValidator
, "ParamSaveBtn");
1319 pParamCancelBtn
= new wxButton(this, PARAMETER_DIALOG_CANCEL
, "C&ancel", wxPoint(310, 66), wxSize(70, 35), 0, wxDefaultValidator
, "ParamCancelBtn");
1321 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
1322 // handle all widget processing
1323 widgetPtrsSet
= TRUE
;
1326 savedParamSettings
= wxGetApp().params
;
1331 } // CparameterDlg constructor
1334 void CparameterDlg::OnCloseWindow(wxCloseEvent
& event
)
1336 // Put any additional checking necessary to make certain it is alright
1337 // to close the program here that is not done elsewhere
1340 bool Ok
= (wxMessageBox("No changes have been saved.\n\nAre you sure you wish exit the parameter screen?","Confirm",wxYES_NO
|wxICON_QUESTION
) == wxYES
);
1348 wxGetApp().params
= savedParamSettings
;
1351 if (GetParent() != NULL
)
1352 GetParent()->SetFocus();
1355 } // Cparameter::OnCloseWindow()
1358 void CparameterDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
1360 wxString widgetName
;
1362 widgetName
= win
.GetName();
1367 if (widgetName
== pParamSaveBtn
->GetName())
1372 tStr
= "Database parameters have been saved.";
1373 if (GetParent() != NULL
) // The parameter dialog was not called during startup due to a missing cfg file
1374 tStr
+= "\nNew parameters will take effect the next time the program is started.";
1375 wxMessageBox(tStr
,"Notice...",wxOK
| wxICON_INFORMATION
);
1382 if (widgetName
== pParamCancelBtn
->GetName())
1387 } // CparameterDlg::OnCommand()
1390 bool CparameterDlg::PutData()
1392 // Fill the data source list box
1393 FillDataSourceList();
1395 // Fill in the fields from the params object
1396 pParamODBCSourceList
->SetStringSelection(wxGetApp().params
.ODBCSource
);
1397 pParamUserNameTxt
->SetValue(wxGetApp().params
.UserName
);
1398 pParamPasswordTxt
->SetValue(wxGetApp().params
.Password
);
1400 } // CparameterDlg::PutData()
1403 bool CparameterDlg::GetData()
1406 if (pParamODBCSourceList
->GetStringSelection())
1408 tStr
= pParamODBCSourceList
->GetStringSelection();
1409 if (tStr
.Length() > (sizeof(wxGetApp().params
.ODBCSource
)-1))
1412 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());
1413 wxMessageBox(errmsg
,"Internal program error...",wxOK
| wxICON_EXCLAMATION
);
1416 strcpy(wxGetApp().params
.ODBCSource
, tStr
);
1421 tStr
= pParamUserNameTxt
->GetValue();
1422 if (tStr
.Length() > (sizeof(wxGetApp().params
.UserName
)-1))
1425 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());
1426 wxMessageBox(errmsg
,"Internal program error...",wxOK
| wxICON_EXCLAMATION
);
1429 strcpy(wxGetApp().params
.UserName
, tStr
);
1431 tStr
= pParamPasswordTxt
->GetValue();
1432 if (tStr
.Length() > (sizeof(wxGetApp().params
.Password
)-1))
1435 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());
1436 wxMessageBox(errmsg
,"Internal program error...",wxOK
| wxICON_EXCLAMATION
);
1439 strcpy(wxGetApp().params
.Password
,tStr
);
1441 } // CparameterDlg::GetData()
1444 bool CparameterDlg::Save()
1446 Cparameters saveParams
= wxGetApp().params
;
1449 wxGetApp().params
= saveParams
;
1454 if ((paramFile
= fopen(paramFilename
, "wt")) == NULL
)
1457 tStr
.Printf("Unable to write/overwrite '%s'.",paramFilename
);
1458 wxMessageBox(tStr
,"File I/O Error...",wxOK
| wxICON_EXCLAMATION
);
1462 fputs(wxGetApp().params
.ODBCSource
, paramFile
);
1463 fputc('\n', paramFile
);
1464 fputs(wxGetApp().params
.UserName
, paramFile
);
1465 fputc('\n', paramFile
);
1466 fputs(wxGetApp().params
.Password
, paramFile
);
1467 fputc('\n', paramFile
);
1471 } // CparameterDlg::Save()
1474 void CparameterDlg::FillDataSourceList()
1476 char Dsn
[SQL_MAX_DSN_LENGTH
+ 1];
1478 wxStringList strList
;
1480 while(GetDataSource(DbConnectInf
.Henv
, Dsn
, SQL_MAX_DSN_LENGTH
+1, DsDesc
, 255))
1485 char **p
= strList
.ListToArray();
1487 for (int i
= 0; strlen(p
[i
]); i
++)
1488 pParamODBCSourceList
->Append(p
[i
]);
1489 } // CparameterDlg::CparameterDlg::FillDataSourceList()
1492 BEGIN_EVENT_TABLE(CqueryDlg
, wxDialog
)
1493 EVT_BUTTON(-1, CqueryDlg::OnButton
)
1494 EVT_CLOSE(CqueryDlg::OnCloseWindow
)
1497 // CqueryDlg() constructor
1498 CqueryDlg::CqueryDlg(wxWindow
*parent
, wxDB
*pDb
, char *tblName
[], char *pWhereArg
) : wxDialog (parent
, QUERY_DIALOG
, "Query", wxPoint(-1, -1), wxSize(480, 360))
1500 wxBeginBusyCursor();
1504 masterTableName
= tblName
[0];
1505 widgetPtrsSet
= FALSE
;
1508 // Initialize the WHERE clause from the string passed in
1509 pWhere
= pWhereArg
; // Save a pointer to the output buffer
1510 if (strlen(pWhere
) > DB_MAX_WHERE_CLAUSE_LEN
) // Check the length of the buffer passed in
1513 s
.Printf("Maximum where clause length exceeded.\nLength must be less than %d", DB_MAX_WHERE_CLAUSE_LEN
+1);
1514 wxMessageBox(s
,"Error...",wxOK
| wxICON_EXCLAMATION
);
1519 pQueryCol1Msg
= new wxStaticText(this, QUERY_DIALOG_COL_MSG
, "Column 1:", wxPoint(10, 10), wxSize(69, 16), 0, "QueryCol1Msg");
1520 pQueryCol1Choice
= new wxChoice(this, QUERY_DIALOG_COL_CHOICE
, wxPoint(10, 27), wxSize(250, 27), 0, 0, 0, wxDefaultValidator
, "QueryCol1Choice");
1522 pQueryNotMsg
= new wxStaticText(this, QUERY_DIALOG_NOT_MSG
, "NOT", wxPoint(268, 10), wxSize(-1, -1), 0, "QueryNotMsg");
1523 pQueryNotCheck
= new wxCheckBox(this, QUERY_DIALOG_NOT_CHECKBOX
, "", wxPoint(275, 37), wxSize(20, 20), 0, wxDefaultValidator
, "QueryNotCheck");
1525 wxString choice_strings
[9];
1526 choice_strings
[0] = "=";
1527 choice_strings
[1] = "<";
1528 choice_strings
[2] = ">";
1529 choice_strings
[3] = "<=";
1530 choice_strings
[4] = ">=";
1531 choice_strings
[5] = "Begins";
1532 choice_strings
[6] = "Contains";
1533 choice_strings
[7] = "Like";
1534 choice_strings
[8] = "Between";
1535 pQueryOperatorMsg
= new wxStaticText(this, QUERY_DIALOG_OP_MSG
, "Operator:", wxPoint(305, 10), wxSize(-1, -1), 0, "QueryOperatorMsg");
1536 pQueryOperatorChoice
= new wxChoice(this, QUERY_DIALOG_OP_CHOICE
, wxPoint(305, 27), wxSize(80, 27), 9, choice_strings
, 0, wxDefaultValidator
, "QueryOperatorChoice");
1538 pQueryCol2Msg
= new wxStaticText(this, QUERY_DIALOG_COL2_MSG
, "Column 2:", wxPoint(10, 65), wxSize(69, 16), 0, "QueryCol2Msg");
1539 pQueryCol2Choice
= new wxChoice(this, QUERY_DIALOG_COL2_CHOICE
, wxPoint(10, 82), wxSize(250, 27), 0, 0, 0, wxDefaultValidator
, "QueryCol2Choice");
1541 pQuerySqlWhereMsg
= new wxStaticText(this, QUERY_DIALOG_WHERE_MSG
, "SQL where clause:", wxPoint(10, 141), wxSize(-1, -1), 0, "QuerySqlWhereMsg");
1542 pQuerySqlWhereMtxt
= new wxTextCtrl(this, QUERY_DIALOG_WHERE_TEXT
, "", wxPoint(10, 159), wxSize(377, 134), wxTE_MULTILINE
, wxDefaultValidator
, "QuerySqlWhereMtxt");
1544 pQueryAddBtn
= new wxButton(this, QUERY_DIALOG_ADD
, "&Add", wxPoint(406, 24), wxSize(56, 26), 0, wxDefaultValidator
, "QueryAddBtn");
1545 pQueryAndBtn
= new wxButton(this, QUERY_DIALOG_AND
, "A&nd", wxPoint(406, 58), wxSize(56, 26), 0, wxDefaultValidator
, "QueryAndBtn");
1546 pQueryOrBtn
= new wxButton(this, QUERY_DIALOG_OR
, "&Or", wxPoint(406, 92), wxSize(56, 26), 0, wxDefaultValidator
, "QueryOrBtn");
1548 pQueryLParenBtn
= new wxButton(this, QUERY_DIALOG_LPAREN
, "(", wxPoint(406, 126), wxSize(26, 26), 0, wxDefaultValidator
, "QueryLParenBtn");
1549 pQueryRParenBtn
= new wxButton(this, QUERY_DIALOG_RPAREN
, ")", wxPoint(436, 126), wxSize(26, 26), 0, wxDefaultValidator
, "QueryRParenBtn");
1551 pQueryDoneBtn
= new wxButton(this, QUERY_DIALOG_DONE
, "&Done", wxPoint(406, 185), wxSize(56, 26), 0, wxDefaultValidator
, "QueryDoneBtn");
1552 pQueryClearBtn
= new wxButton(this, QUERY_DIALOG_CLEAR
, "C&lear", wxPoint(406, 218), wxSize(56, 26), 0, wxDefaultValidator
, "QueryClearBtn");
1553 pQueryCountBtn
= new wxButton(this, QUERY_DIALOG_COUNT
, "&Count", wxPoint(406, 252), wxSize(56, 26), 0, wxDefaultValidator
, "QueryCountBtn");
1555 pQueryValue1Msg
= new wxStaticText(this, QUERY_DIALOG_VALUE1_MSG
, "Value:", wxPoint(277, 66), wxSize(-1, -1), 0, "QueryValue1Msg");
1556 pQueryValue1Txt
= new wxTextCtrl(this, QUERY_DIALOG_VALUE1_TEXT
, "", wxPoint(277, 83), wxSize(108, 25), 0, wxDefaultValidator
, "QueryValue1Txt");
1558 pQueryValue2Msg
= new wxStaticText(this, QUERY_DIALOG_VALUE2_MSG
, "AND", wxPoint(238, 126), wxSize(-1, -1), 0, "QueryValue2Msg");
1559 pQueryValue2Txt
= new wxTextCtrl(this, QUERY_DIALOG_VALUE2_TEXT
, "", wxPoint(277, 120), wxSize(108, 25), 0, wxDefaultValidator
, "QueryValue2Txt");
1561 pQueryHintGrp
= new wxStaticBox(this, QUERY_DIALOG_HINT_GROUP
, "", wxPoint(10, 291), wxSize(377, 40), 0, "QueryHintGrp");
1562 pQueryHintMsg
= new wxStaticText(this, QUERY_DIALOG_HINT_MSG
, "", wxPoint(16, 306), wxSize(-1, -1), 0, "QueryHintMsg");
1564 widgetPtrsSet
= TRUE
;
1565 // Initialize the dialog
1567 pQueryCol2Choice
->Append("VALUE -->");
1568 colInf
= pDB
->GetColumns(tblName
);
1569 for (int i
= 0; colInf
[i
].colName
&& strlen(colInf
[i
].colName
); i
++)
1571 // If there is more than one table being queried, qualify
1572 // the column names with the table name prefix.
1573 if (tblName
[1] && strlen(tblName
[1]))
1575 qualName
.Printf("%s.%s", colInf
[i
].tableName
, colInf
[i
].colName
);
1576 pQueryCol1Choice
->Append(qualName
);
1577 pQueryCol2Choice
->Append(qualName
);
1579 else // Single table query, append just the column names
1581 pQueryCol1Choice
->Append(colInf
[i
].colName
);
1582 pQueryCol2Choice
->Append(colInf
[i
].colName
);
1586 pQueryCol1Choice
->SetSelection(0);
1587 pQueryCol2Choice
->SetSelection(0);
1588 pQueryOperatorChoice
->SetSelection(0);
1590 pQueryValue2Msg
->Show(FALSE
);
1591 pQueryValue2Txt
->Show(FALSE
);
1593 pQueryHintMsg
->SetLabel(langQRY_EQ
);
1595 pQuerySqlWhereMtxt
->SetValue(pWhere
);
1599 // Display the dialog window
1603 } // CqueryDlg() constructor
1606 void CqueryDlg::OnButton( wxCommandEvent
&event
)
1608 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
1609 OnCommand( *win
, event
);
1612 void CqueryDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
1614 // Widget pointers won't be set when the dialog is constructed.
1615 // Control is passed through this function once for each widget on
1616 // a dialog as the dialog is constructed.
1620 wxString widgetName
= win
.GetName();
1622 // Operator choice box
1623 if (widgetName
== pQueryOperatorChoice
->GetName())
1625 // Set the help text
1626 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
1629 pQueryHintMsg
->SetLabel(langQRY_EQ
);
1632 pQueryHintMsg
->SetLabel(langQRY_LT
);
1635 pQueryHintMsg
->SetLabel(langQRY_GT
);
1638 pQueryHintMsg
->SetLabel(langQRY_LE
);
1641 pQueryHintMsg
->SetLabel(langQRY_GE
);
1644 pQueryHintMsg
->SetLabel(langQRY_BEGINS
);
1647 pQueryHintMsg
->SetLabel(langQRY_CONTAINS
);
1650 pQueryHintMsg
->SetLabel(langQRY_LIKE
);
1653 pQueryHintMsg
->SetLabel(langQRY_BETWEEN
);
1657 // Hide the value2 widget
1658 pQueryValue2Msg
->Show(FALSE
); // BETWEEN will show this widget
1659 pQueryValue2Txt
->Show(FALSE
); // BETWEEN will show this widget
1661 // Disable the NOT operator for <, <=, >, >=
1662 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
1668 pQueryNotCheck
->SetValue(0);
1669 pQueryNotCheck
->Enable(FALSE
);
1672 pQueryNotCheck
->Enable(TRUE
);
1676 // Manipulate the dialog to handle the selected operator
1677 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
1684 pQueryCol2Choice
->Enable(TRUE
);
1685 if (pQueryCol2Choice
->GetSelection()) // Column name is highlighted
1687 pQueryValue1Msg
->Show(FALSE
);
1688 pQueryValue1Txt
->Show(FALSE
);
1690 else // "Value" is highlighted
1692 pQueryValue1Msg
->Show(TRUE
);
1693 pQueryValue1Txt
->Show(TRUE
);
1694 pQueryValue1Txt
->SetFocus();
1700 pQueryCol2Choice
->SetSelection(0);
1701 pQueryCol2Choice
->Enable(FALSE
);
1702 pQueryValue1Msg
->Show(TRUE
);
1703 pQueryValue1Txt
->Show(TRUE
);
1704 pQueryValue1Txt
->SetFocus();
1707 pQueryCol2Choice
->SetSelection(0);
1708 pQueryCol2Choice
->Enable(FALSE
);
1709 pQueryValue2Msg
->Show(TRUE
);
1710 pQueryValue2Txt
->Show(TRUE
);
1711 pQueryValue1Msg
->Show(TRUE
);
1712 pQueryValue1Txt
->Show(TRUE
);
1713 pQueryValue1Txt
->SetFocus();
1719 } // Operator choice box
1722 if (widgetName
== pQueryCol2Choice
->GetName())
1724 if (pQueryCol2Choice
->GetSelection()) // Column name is highlighted
1726 pQueryValue1Msg
->Show(FALSE
);
1727 pQueryValue1Txt
->Show(FALSE
);
1729 else // "Value" is highlighted
1731 pQueryValue1Msg
->Show(TRUE
);
1732 pQueryValue1Txt
->Show(TRUE
);
1733 pQueryValue1Txt
->SetFocus();
1737 } // Column 2 choice
1740 if (widgetName
== pQueryAddBtn
->GetName())
1748 if (widgetName
== pQueryAndBtn
->GetName())
1750 AppendToWhere(" AND\n");
1756 if (widgetName
== pQueryOrBtn
->GetName())
1758 AppendToWhere(" OR\n");
1763 // Left Paren button
1764 if (widgetName
== pQueryLParenBtn
->GetName())
1769 } // Left Paren button
1771 // Right paren button
1772 if (widgetName
== pQueryRParenBtn
->GetName())
1777 } // Right Paren button
1780 if (widgetName
== pQueryDoneBtn
->GetName())
1782 // Be sure the where clause will not overflow the output buffer
1783 if (strlen(pQuerySqlWhereMtxt
->GetValue()) > DB_MAX_WHERE_CLAUSE_LEN
)
1786 s
.Printf("Maximum where clause length exceeded.\nLength must be less than %d", DB_MAX_WHERE_CLAUSE_LEN
+1);
1787 wxMessageBox(s
,"Error...",wxOK
| wxICON_EXCLAMATION
);
1790 // Validate the where clause for things such as matching parens
1791 if (!ValidateWhereClause())
1793 // Copy the where clause to the output buffer and exit
1794 strcpy(pWhere
, pQuerySqlWhereMtxt
->GetValue());
1801 if (widgetName
== pQueryClearBtn
->GetName())
1803 bool Ok
= (wxMessageBox("Are you sure you wish to clear the Query?","Confirm",wxYES_NO
|wxICON_QUESTION
) == wxYES
);
1806 pQuerySqlWhereMtxt
->SetValue("");
1812 if (widgetName
== pQueryCountBtn
->GetName())
1814 wxBeginBusyCursor();
1821 } // CqueryDlg::OnCommand
1824 void CqueryDlg::OnCloseWindow(wxCloseEvent
& event
)
1839 GetParent()->SetFocus();
1844 } // CqueryDlg::OnCloseWindow()
1847 bool CqueryDlg::SetWidgetPtrs()
1851 abort = abort || !(pQueryCol1Choice = (wxChoice *)GetWidgetPtr("QueryCol1Choice",this));
1852 abort = abort || !(pQueryNotCheck = (wxCheckBox *)GetWidgetPtr("QueryNotCheck",this));
1853 abort = abort || !(pQueryOperatorChoice = (wxChoice *)GetWidgetPtr("QueryOperatorChoice",this));
1854 abort = abort || !(pQueryCol2Choice = (wxChoice *)GetWidgetPtr("QueryCol2Choice",this));
1855 abort = abort || !(pQueryValue1Txt = (wxTextCtrl *)GetWidgetPtr("QueryValue1Txt",this));
1856 abort = abort || !(pQueryValue2Txt = (wxTextCtrl *)GetWidgetPtr("QueryValue2Txt",this));
1857 abort = abort || !(pQuerySqlWhereMtxt = (wxMultiText *)GetWidgetPtr("QuerySqlWhereMtxt",this));
1858 abort = abort || !(pQueryAddBtn = (wxButton *)GetWidgetPtr("QueryAddBtn",this));
1859 abort = abort || !(pQueryAndBtn = (wxButton *)GetWidgetPtr("QueryAndBtn",this));
1860 abort = abort || !(pQueryOrBtn = (wxButton *)GetWidgetPtr("QueryOrBtn",this));
1861 abort = abort || !(pQueryLParenBtn = (wxButton *)GetWidgetPtr("QueryLParenBtn",this));
1862 abort = abort || !(pQueryRParenBtn = (wxButton *)GetWidgetPtr("QueryRParenBtn",this));
1863 abort = abort || !(pQueryDoneBtn = (wxButton *)GetWidgetPtr("QueryDoneBtn",this));
1864 abort = abort || !(pQueryClearBtn = (wxButton *)GetWidgetPtr("QueryClearBtn",this));
1865 abort = abort || !(pQueryCountBtn = (wxButton *)GetWidgetPtr("QueryCountBtn",this));
1866 abort = abort || !(pQueryHelpBtn = (wxButton *)GetWidgetPtr("QueryHelpBtn",this));
1867 abort = abort || !(pQueryHintMsg = (wxStaticText *)GetWidgetPtr("QueryHintMsg",this));
1871 return(widgetPtrsSet = !abort);
1873 } // CqueryDlg::SetWidgetPtrs
1876 void CqueryDlg::AppendToWhere(char *s
)
1878 wxString whereStr
= pQuerySqlWhereMtxt
->GetValue();
1880 pQuerySqlWhereMtxt
->SetValue(whereStr
);
1882 } // CqueryDlg::AppendToWhere()
1885 void CqueryDlg::ProcessAddBtn()
1887 qryOp oper
= (qryOp
) pQueryOperatorChoice
->GetSelection();
1889 // Verify that eveything is filled in correctly
1890 if (pQueryCol2Choice
->GetSelection() == 0) // "Value" is selected
1892 // Verify that value 1 is filled in
1893 if (strlen(pQueryValue1Txt
->GetValue()) == 0)
1896 pQueryValue1Txt
->SetFocus();
1899 // For the BETWEEN operator, value 2 must be filled in as well
1900 if (oper
== qryOpBETWEEN
&&
1901 strlen(pQueryValue2Txt
->GetValue()) == 0)
1904 pQueryValue2Txt
->SetFocus();
1909 // Build the expression and append it to the where clause window
1910 wxString s
= pQueryCol1Choice
->GetStringSelection();
1912 if (pQueryNotCheck
->GetValue() && (oper
!= qryOpEQ
))
1918 if (pQueryNotCheck
->GetValue()) // NOT box is checked
1947 int col1Idx
= pQueryCol1Choice
->GetSelection();
1950 if (colInf
[col1Idx
].sqlDataType
== SQL_VARCHAR
||
1951 oper
== qryOpBEGINS
||
1952 oper
== qryOpCONTAINS
||
1956 if (pQueryCol2Choice
->GetSelection()) // Column name
1957 s
+= pQueryCol2Choice
->GetStringSelection();
1958 else // Column 2 is a "value"
1962 if (oper
== qryOpCONTAINS
)
1964 s
+= pQueryValue1Txt
->GetValue();
1965 if (oper
== qryOpCONTAINS
|| oper
== qryOpBEGINS
)
1971 if (oper
== qryOpBETWEEN
)
1976 s
+= pQueryValue2Txt
->GetValue();
1981 AppendToWhere((char*) (const char*) s
);
1983 } // CqueryDlg::ProcessAddBtn()
1986 void CqueryDlg::ProcessCountBtn()
1988 if (!ValidateWhereClause())
1991 if (dbTable
== 0) // wxTable object needs to be created and opened
1993 if (!(dbTable
= new wxTable(pDB
, masterTableName
, 0)))
1995 wxMessageBox("Memory allocation failed creating a wxTable object.","Error...",wxOK
| wxICON_EXCLAMATION
);
1998 if (!dbTable
->Open())
2001 tStr
= "ODBC error during Open()\n\n";
2002 tStr
+= GetExtendedDBErrorMsg(__FILE__
,__LINE__
);
2003 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
2008 // Count() with WHERE clause
2009 dbTable
->where
= (char*) (const char*) pQuerySqlWhereMtxt
->GetValue();
2010 ULONG whereCnt
= dbTable
->Count();
2012 // Count() of all records in the table
2014 ULONG totalCnt
= dbTable
->Count();
2016 if (whereCnt
> 0 || totalCnt
== 0)
2019 tStr
.Printf("%lu of %lu records match the query criteria.",whereCnt
,totalCnt
);
2020 wxMessageBox(tStr
,"Notice...",wxOK
| wxICON_INFORMATION
);
2025 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
);
2026 wxMessageBox(tStr
,"Notice...",wxOK
| wxICON_INFORMATION
);
2029 // After a wxMessageBox, the focus does not necessarily return to the
2030 // window which was the focus when the message box popped up, so return
2031 // focus to the Query dialog for certain
2034 } // CqueryDlg::ProcessCountBtn()
2037 bool CqueryDlg::ValidateWhereClause()
2039 wxString where
= pQuerySqlWhereMtxt
->GetValue();
2041 if (where
.Freq('(') != where
.Freq(')'))
2043 wxMessageBox("There are mismatched parenthesis in the constructed where clause","Error...",wxOK
| wxICON_EXCLAMATION
);
2046 // After a wxMessageBox, the focus does not necessarily return to the
2047 // window which was the focus when the message box popped up, so return
2048 // focus to the Query dialog for certain
2053 } // CqueryDlg::ValidateWhereClause()