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 wxDbTable.
25 #pragma implementation "dbtest.h"
28 #include "wx/wxprec.h"
42 #include <stdio.h> /* Included strictly for reading the text file with the database parameters */
44 #include <wx/db.h> /* Required in the file which will get the data source connection */
45 #include <wx/dbtable.h> /* Has the wxDbTable object from which all data objects will inherit their data table functionality */
47 extern wxDbList WXDLLEXPORT
*PtrBegDbList
; /* from db.cpp, used in getting back error results from db connections */
49 #include "dbtest.h" /* Header file for this demonstration program */
50 #include "listdb.h" /* Code to support the "Lookup" button on the editor dialog */
52 IMPLEMENT_APP(DatabaseDemoApp
)
54 extern wxChar ListDB_Selection
[]; /* Used to return the first column value for the selected line from the listDB routines */
55 extern wxChar ListDB_Selection2
[]; /* Used to return the second column value for the selected line from the listDB routines */
57 DatabaseDemoFrame
*DemoFrame
; /* Pointer to the main frame */
59 /* Pointer to the main database connection used in the program. This
60 * pointer would normally be used for doing things as database lookups
61 * for user login names and passwords, getting workstation settings, etc.
64 * For each database object created which uses this wxDb pointer
65 * connection to the database, when a CommitTrans() or RollBackTrans()
66 * will commit or rollback EVERY object which uses this wxDb pointer.
68 * To allow each table object (those derived from wxDbTable) to be
69 * individually committed or rolled back, you MUST use a different
70 * instance of wxDb in the constructor of the table. Doing so creates
71 * more overhead, and will use more database connections (some DBs have
72 * connection limits...), so use connections sparringly.
74 * It is recommended that one "main" database connection be created for
75 * the entire program to use for READ-ONLY database accesses, but for each
76 * table object which will do a CommitTrans() or RollbackTrans() that a
77 * new wxDb object be created and used for it.
82 const char *GetExtendedDBErrorMsg(wxDb
*pDb
, char *ErrFile
, int ErrLine
)
89 if (ErrFile
|| ErrLine
)
93 msg
+= wxT(" Line: ");
94 tStr
.Printf(wxT("%d"),ErrLine
);
99 msg
.Append (wxT("\nODBC errors:\n"));
102 // Display errors for this connection
104 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
106 if (pDb
->errorList
[i
])
108 msg
.Append(pDb
->errorList
[i
]);
109 if (wxStrcmp(pDb
->errorList
[i
],wxT("")) != 0)
110 msg
.Append(wxT("\n"));
111 // Clear the errmsg buffer so the next error will not
112 // end up showing the previous error that have occurred
113 wxStrcpy(pDb
->errorList
[i
],wxT(""));
119 } // GetExtendedDBErrorMsg
122 bool DatabaseDemoApp::OnInit()
124 // Create the main frame window
125 DemoFrame
= new DatabaseDemoFrame(NULL
, wxT("wxWindows Database Demo"), wxPoint(50, 50), wxSize(537, 480));
128 DemoFrame
->SetIcon(wxICON(db
));
131 wxMenu
*file_menu
= new wxMenu
;
132 file_menu
->Append(FILE_CREATE
, wxT("&Create CONTACT table"));
133 file_menu
->Append(FILE_RECREATE_TABLE
, wxT("&Recreate CONTACT table"));
134 file_menu
->Append(FILE_RECREATE_INDEXES
, wxT("&Recreate CONTACT indexes"));
135 file_menu
->Append(FILE_EXIT
, wxT("E&xit"));
137 wxMenu
*edit_menu
= new wxMenu
;
138 edit_menu
->Append(EDIT_PARAMETERS
, wxT("&Parameters..."));
140 wxMenu
*about_menu
= new wxMenu
;
141 about_menu
->Append(ABOUT_DEMO
, wxT("&About"));
143 wxMenuBar
*menu_bar
= new wxMenuBar
;
144 menu_bar
->Append(file_menu
, wxT("&File"));
145 menu_bar
->Append(edit_menu
, wxT("&Edit"));
146 menu_bar
->Append(about_menu
, wxT("&About"));
147 DemoFrame
->SetMenuBar(menu_bar
);
149 // Initialize the ODBC Environment for Database Operations
150 if (SQLAllocEnv(&DbConnectInf
.Henv
) != SQL_SUCCESS
)
152 wxMessageBox(wxT("A problem occured while trying to get a connection to the data source"),wxT("DB CONNECTION ERROR"),wxOK
| wxICON_EXCLAMATION
);
156 params
.ODBCSource
[0] = 0;
157 params
.UserName
[0] = 0;
158 params
.Password
[0] = 0;
159 params
.DirPath
[0] = 0;
162 DemoFrame
->Show(TRUE
);
165 if ((paramFile
= fopen(paramFilename
, wxT("r"))) == NULL
)
168 tStr
.Printf(wxT("Unable to open the parameter file '%s' for reading.\n\nYou must specify the data source, user name, and\npassword that will be used and save those settings."),paramFilename
);
169 wxMessageBox(tStr
,wxT("File I/O Error..."),wxOK
| wxICON_EXCLAMATION
);
171 DemoFrame
->BuildParameterDialog(NULL
);
172 if ((paramFile
= fopen(paramFilename
, wxT("r"))) == NULL
)
176 wxChar buffer
[1000+1];
177 fgets(buffer
, sizeof(params
.ODBCSource
), paramFile
);
178 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
179 wxStrcpy(params
.ODBCSource
,buffer
);
181 fgets(buffer
, sizeof(params
.UserName
), paramFile
);
182 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
183 wxStrcpy(params
.UserName
,buffer
);
185 fgets(buffer
, sizeof(params
.Password
), paramFile
);
186 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
187 wxStrcpy(params
.Password
,buffer
);
189 fgets(buffer
, sizeof(params
.DirPath
), paramFile
);
190 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
191 wxStrcpy(params
.DirPath
,buffer
);
195 // Connect to datasource
196 DbConnectInf
.Dsn
= params
.ODBCSource
; // ODBC data source name (created with ODBC Administrator under Win95/NT)
197 DbConnectInf
.Uid
= params
.UserName
; // database username - must already exist in the data source
198 DbConnectInf
.AuthStr
= params
.Password
; // password database username
199 DbConnectInf
.defaultDir
= params
.DirPath
; // path where the table exists (needed for dBase)
201 READONLY_DB
= wxDbGetConnection(&DbConnectInf
);
202 if (READONLY_DB
== 0)
204 wxMessageBox(wxT("Unable to connect to the data source.\n\nCheck the name of your data source to verify it has been correctly entered/spelled.\n\nWith some databases, the user name and password must\nbe created with full rights to the CONTACT table prior to making a connection\n(using tools provided by the database manufacturer)"), wxT("DB CONNECTION ERROR..."),wxOK
| wxICON_EXCLAMATION
);
205 DemoFrame
->BuildParameterDialog(NULL
);
206 DbConnectInf
.Dsn
.Empty();
207 DbConnectInf
.Uid
.Empty();
208 DbConnectInf
.AuthStr
.Empty();
209 wxMessageBox(wxT("Now exiting program.\n\nRestart program to try any new settings."),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
213 DemoFrame
->BuildEditorDialog();
216 DemoFrame
->Refresh();
219 } // DatabaseDemoApp::OnInit()
222 BEGIN_EVENT_TABLE(DatabaseDemoFrame
, wxFrame
)
223 EVT_MENU(FILE_CREATE
, DatabaseDemoFrame::OnCreate
)
224 EVT_MENU(FILE_RECREATE_TABLE
, DatabaseDemoFrame::OnRecreateTable
)
225 EVT_MENU(FILE_RECREATE_INDEXES
, DatabaseDemoFrame::OnRecreateIndexes
)
226 EVT_MENU(FILE_EXIT
, DatabaseDemoFrame::OnExit
)
227 EVT_MENU(EDIT_PARAMETERS
, DatabaseDemoFrame::OnEditParameters
)
228 EVT_MENU(ABOUT_DEMO
, DatabaseDemoFrame::OnAbout
)
229 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 } // DatabaseDemoFrame constructor
244 void DatabaseDemoFrame::OnCreate(wxCommandEvent
& event
)
246 CreateDataTable(FALSE
);
247 } // DatabaseDemoFrame::OnCreate()
250 void DatabaseDemoFrame::OnRecreateTable(wxCommandEvent
& event
)
252 CreateDataTable(TRUE
);
253 } // DatabaseDemoFrame::OnRecreate()
256 void DatabaseDemoFrame::OnRecreateIndexes(wxCommandEvent
& event
)
258 // Using a new connection to the database so as not to disturb
259 // the current cursors on the table in use in the editor dialog
260 Ccontact
*Contact
= new Ccontact();
265 wxMessageBox(wxT("Error allocating memory for 'Ccontact'object.\n\nTable could not be opened."),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
269 if (!Contact
->CreateIndexes())
273 tStr
= wxT("Error creating CONTACTS indexes.\nNew indexes will be unavailable.\n\n");
274 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
275 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
280 } // DatabaseDemoFrame::OnRecreateIndexes()
282 void DatabaseDemoFrame::OnExit(wxCommandEvent
& event
)
285 } // DatabaseDemoFrame::OnExit()
288 void DatabaseDemoFrame::OnEditParameters(wxCommandEvent
& event
)
290 if ((pEditorDlg
->mode
!= mCreate
) && (pEditorDlg
->mode
!= mEdit
))
291 BuildParameterDialog(this);
293 wxMessageBox(wxT("Cannot change database parameters while creating or editing a record"),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
294 } // DatabaseDemoFrame::OnEditParameters()
297 void DatabaseDemoFrame::OnAbout(wxCommandEvent
& event
)
299 wxMessageBox(wxT("wxWindows sample program for database classes\n\nContributed on 27 July 1998"),wxT("About..."),wxOK
| wxICON_INFORMATION
);
300 } // DatabaseDemoFrame::OnAbout()
303 void DatabaseDemoFrame::OnCloseWindow(wxCloseEvent
& event
)
305 // Put any additional checking necessary to make certain it is alright
306 // to close the program here that is not done elsewhere
309 if (pEditorDlg
&& pEditorDlg
->Close())
320 // This function will close all the connections to the database that have been
321 // previously cached.
322 wxDbCloseConnections();
324 // Cleans up the environment space allocated for the SQL/ODBC connection handle
325 SQLFreeEnv(DbConnectInf
.Henv
);
329 } // DatabaseDemoFrame::OnCloseWindow()
332 void DatabaseDemoFrame::CreateDataTable(bool recreate
)
336 Ok
= (wxMessageBox(wxT("Any data currently residing in the table will be erased.\n\nAre you sure?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
345 Ccontact
*Contact
= new Ccontact();
349 wxMessageBox(wxT("Error allocating memory for 'Ccontact'object.\n\nTable was not created."),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
353 if (!Contact
->CreateTable(recreate
))
357 tStr
= wxT("Error creating CONTACTS table.\nTable was not created.\n\n");
358 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
359 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
364 if (!Contact
->CreateIndexes())
368 tStr
= wxT("Error creating CONTACTS indexes.\nIndexes will be unavailable.\n\n");
369 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
370 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
381 wxMessageBox(wxT("Table and index(es) were successfully created."),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
382 } // DatabaseDemoFrame::CreateDataTable()
385 void DatabaseDemoFrame::BuildEditorDialog()
388 pEditorDlg
= new CeditorDlg(this);
391 pEditorDlg
->Initialize();
392 if (!pEditorDlg
->initialized
)
396 wxMessageBox(wxT("Unable to initialize the editor dialog for some reason"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
402 wxMessageBox(wxT("Unable to create the editor dialog for some reason"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
405 } // DatabaseDemoFrame::BuildEditorDialog()
408 void DatabaseDemoFrame::BuildParameterDialog(wxWindow
*parent
)
410 pParamDlg
= new CparameterDlg(parent
);
413 wxMessageBox(wxT("Unable to create the parameter dialog for some reason"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
414 } // DatabaseDemoFrame::BuildParameterDialog()
418 * Constructor note: If no wxDb object is passed in, a new connection to the database
419 * is created for this instance of Ccontact. This can be a slow process depending
420 * on the database engine being used, and some database engines have a limit on the
421 * number of connections (either hard limits, or license restricted) so care should
422 * be used to use as few connections as is necessary.
424 * IMPORTANT: Objects which share a wxDb pointer are ALL acted upon whenever a member
425 * function of pDb is called (i.e. CommitTrans() or RollbackTrans(), so if modifying
426 * or creating a table objects which use the same pDb, know that all the objects
427 * will be committed or rolled back when any of the objects has this function call made.
429 Ccontact::Ccontact (wxDb
*pwxDb
) : wxDbTable(pwxDb
? pwxDb
: wxDbGetConnection(&DbConnectInf
), CONTACT_TABLE_NAME
,CONTACT_NO_COLS
, wxT(""), !wxDB_QUERY_ONLY
, DbConnectInf
.defaultDir
)
431 // This is used to represent whether the database connection should be released
432 // when this instance of the object is deleted. If using the same connection
433 // for multiple instance of database objects, then the connection should only be
434 // released when the last database instance using the connection is deleted
439 } // Ccontact Constructor
442 void Ccontact::Initialize()
451 JoinDate
.year
= 1980;
457 JoinDate
.fraction
= 0;
458 NativeLanguage
= langENGLISH
;
462 } // Ccontact::Initialize
465 Ccontact::~Ccontact()
469 if (!wxDbFreeConnection(GetDb()))
472 tStr
= wxT("Unable to Free the Ccontact data table handle\n\n");
473 tStr
+= GetExtendedDBErrorMsg(GetDb(),__FILE__
,__LINE__
);
474 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
477 } // Ccontract destructor
481 * Handles setting up all the connections for the interface from the wxDbTable
482 * functions to interface to the data structure used to store records in
483 * memory, and for all the column definitions that define the table structure
485 void Ccontact::SetupColumns()
487 // NOTE: Columns now are 8 character names, as that is all dBase can support. Longer
488 // names can be used for other database engines
489 SetColDefs ( 0,wxT("NAME"), DB_DATA_TYPE_VARCHAR
, Name
, SQL_C_CHAR
, sizeof(Name
), TRUE
, TRUE
); // Primary index
490 SetColDefs ( 1,wxT("ADDRESS1"), DB_DATA_TYPE_VARCHAR
, Addr1
, SQL_C_CHAR
, sizeof(Addr1
), FALSE
,TRUE
);
491 SetColDefs ( 2,wxT("ADDRESS2"), DB_DATA_TYPE_VARCHAR
, Addr2
, SQL_C_CHAR
, sizeof(Addr2
), FALSE
,TRUE
);
492 SetColDefs ( 3,wxT("CITY"), DB_DATA_TYPE_VARCHAR
, City
, SQL_C_CHAR
, sizeof(City
), FALSE
,TRUE
);
493 SetColDefs ( 4,wxT("STATE"), DB_DATA_TYPE_VARCHAR
, State
, SQL_C_CHAR
, sizeof(State
), FALSE
,TRUE
);
494 SetColDefs ( 5,wxT("POSTCODE"), DB_DATA_TYPE_VARCHAR
, PostalCode
, SQL_C_CHAR
, sizeof(PostalCode
), FALSE
,TRUE
);
495 SetColDefs ( 6,wxT("COUNTRY"), DB_DATA_TYPE_VARCHAR
, Country
, SQL_C_CHAR
, sizeof(Country
), FALSE
,TRUE
);
496 SetColDefs ( 7,wxT("JOINDATE"), DB_DATA_TYPE_DATE
, &JoinDate
, SQL_C_TIMESTAMP
, sizeof(JoinDate
), FALSE
,TRUE
);
497 SetColDefs ( 8,wxT("IS_DEV"), DB_DATA_TYPE_INTEGER
, &IsDeveloper
, SQL_C_BOOLEAN(IsDeveloper
), sizeof(IsDeveloper
), FALSE
,TRUE
);
498 SetColDefs ( 9,wxT("CONTRIBS"), DB_DATA_TYPE_INTEGER
, &Contributions
, SQL_C_USHORT
, sizeof(Contributions
), FALSE
,TRUE
);
499 SetColDefs (10,wxT("LINE_CNT"), DB_DATA_TYPE_INTEGER
, &LinesOfCode
, SQL_C_ULONG
, sizeof(LinesOfCode
), FALSE
,TRUE
);
500 SetColDefs (11,wxT("LANGUAGE"), DB_DATA_TYPE_INTEGER
, &NativeLanguage
, SQL_C_ENUM
, sizeof(NativeLanguage
), FALSE
,TRUE
);
501 } // Ccontact::SetupColumns
504 bool Ccontact::CreateIndexes(void)
506 // This index could easily be accomplished with an "orderBy" clause,
507 // but is done to show how to construct a non-primary index.
509 wxDbIdxDef idxDef
[2];
513 wxStrcpy(idxDef
[0].ColName
, "IS_DEV");
514 idxDef
[0].Ascending
= TRUE
;
516 wxStrcpy(idxDef
[1].ColName
, "NAME");
517 idxDef
[1].Ascending
= TRUE
;
519 indexName
= GetTableName();
520 indexName
+= "_IDX1";
521 Ok
= CreateIndex(indexName
.c_str(), TRUE
, 2, idxDef
);
524 } // Ccontact::CreateIndexes()
528 * Having a function to do a query on the primary key (and possibly others) is
529 * very efficient and tighter coding so that it is available where ever the object
530 * is. Great for use with multiple tables when not using views or outer joins
532 bool Ccontact::FetchByName(wxChar
*name
)
534 whereStr
.Printf(wxT("NAME = '%s'"),name
);
535 SetWhereClause(whereStr
.c_str());
536 SetOrderByClause(wxT(""));
544 } // Ccontact::FetchByName()
549 * ************* DIALOGS ***************
554 /* CeditorDlg constructor
556 * Creates the dialog used for creating/editing/deleting/copying a Ccontact object.
557 * This dialog actually is drawn in the main frame of the program
559 * An instance of Ccontact is created - "Contact" - which is used to hold the Ccontact
560 * object that is currently being worked with.
563 BEGIN_EVENT_TABLE(CeditorDlg
, wxPanel
)
564 EVT_BUTTON(-1, CeditorDlg::OnButton
)
565 EVT_CLOSE(CeditorDlg::OnCloseWindow
)
568 CeditorDlg::CeditorDlg(wxWindow
*parent
) : wxPanel (parent
, 0, 0, 537, 480)
570 // Since the ::OnCommand() function is overridden, this prevents the widget
571 // detection in ::OnCommand() until all widgets have been initialized to prevent
572 // uninitialized pointers from crashing the program
573 widgetPtrsSet
= FALSE
;
580 } // CeditorDlg constructor
583 void CeditorDlg::OnCloseWindow(wxCloseEvent
& event
)
586 if ((mode
!= mCreate
) && (mode
!= mEdit
))
597 wxMessageBox(wxT("Must finish processing the current record being created/modified before exiting"),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
600 } // CeditorDlg::OnCloseWindow()
603 void CeditorDlg::OnButton(wxCommandEvent
&event
)
605 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
606 OnCommand( *win
, event
);
607 } // CeditorDlg::OnButton()
610 void CeditorDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
614 widgetName
= win
.GetName();
619 if (widgetName
== pCreateBtn
->GetName())
621 Contact
->Initialize();
624 pNameTxt
->SetValue(wxT(""));
625 pNameTxt
->SetFocus();
629 if (widgetName
== pEditBtn
->GetName())
631 saveName
= Contact
->Name
;
633 pNameTxt
->SetFocus();
637 if (widgetName
== pCopyBtn
->GetName())
640 pNameTxt
->SetValue(wxT(""));
641 pNameTxt
->SetFocus();
646 if (widgetName
== pDeleteBtn
->GetName())
648 bool Ok
= (wxMessageBox(wxT("Are you sure?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
653 if (Ok
&& Contact
->Delete())
655 // NOTE: Deletions are not finalized until a CommitTrans() is performed.
656 // If the commit were not performed, the program will continue to
657 // show the table contents as if they were deleted until this instance
658 // of Ccontact is deleted. If the Commit wasn't performed, the
659 // database will automatically Rollback the changes when the database
660 // connection is terminated
661 Contact
->GetDb()->CommitTrans();
663 // Try to get the row that followed the just deleted row in the orderBy sequence
666 // There was now row (in sequence) after the just deleted row, so get the
667 // row which preceded the just deleted row
670 // There are now no rows remaining, so clear the dialog widgets
671 Contact
->Initialize();
675 SetMode(mode
); // force reset of button enable/disable
679 Contact
->GetDb()->RollbackTrans();
685 if (widgetName
== pSaveBtn
->GetName())
691 if (widgetName
== pCancelBtn
->GetName())
693 bool Ok
= (wxMessageBox(wxT("Are you sure?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
698 if (saveName
.IsEmpty())
700 Contact
->Initialize();
707 // Requery previous record
708 if (Contact
->FetchByName((wxChar
*) (const wxChar
*) saveName
))
716 // Previous record not available, retrieve first record in table
717 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
719 Contact
->whereStr
= wxT("NAME = (SELECT MIN(NAME) FROM ");
720 Contact
->whereStr
+= Contact
->GetTableName();
721 Contact
->whereStr
+= wxT(")");
722 Contact
->SetWhereClause(Contact
->whereStr
.c_str());
725 Contact
->SetWhereClause(wxT(""));
727 if (!Contact
->Query())
730 tStr
= wxT("ODBC error during Query()\n\n");
731 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
732 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
736 if (Contact
->GetNext()) // Successfully read first record
742 // No contacts are available, clear dialog
743 Contact
->Initialize();
749 if (widgetName
== pPrevBtn
->GetName())
756 if (widgetName
== pNextBtn
->GetName())
763 if (widgetName
== pQueryBtn
->GetName())
765 // Display the query dialog box
766 wxChar qryWhere
[DB_MAX_WHERE_CLAUSE_LEN
+1];
767 wxStrcpy(qryWhere
, (const wxChar
*) Contact
->qryWhereStr
);
768 wxChar
*tblName
[] = {(wxChar
*)CONTACT_TABLE_NAME
, 0};
769 new CqueryDlg(GetParent(), Contact
->GetDb(), tblName
, qryWhere
);
771 // Query the first record in the new record set and
772 // display it, if the query string has changed.
773 if (wxStrcmp(qryWhere
, (const wxChar
*) Contact
->qryWhereStr
))
775 Contact
->whereStr
.Empty();
776 Contact
->SetOrderByClause("NAME");
778 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
780 Contact
->whereStr
= wxT("NAME = (SELECT MIN(NAME) FROM ");
781 Contact
->whereStr
+= CONTACT_TABLE_NAME
;
784 // Append the query where string (if there is one)
785 Contact
->qryWhereStr
= qryWhere
;
786 if (wxStrlen(qryWhere
))
788 Contact
->whereStr
+= wxT(" WHERE ");
789 Contact
->whereStr
+= Contact
->qryWhereStr
;
791 // Close the expression with a right paren
792 Contact
->whereStr
+= wxT(")");
794 Contact
->SetWhereClause(Contact
->whereStr
.c_str());
795 if (!Contact
->Query())
798 tStr
= wxT("ODBC error during Query()\n\n");
799 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
800 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
803 // Display the first record from the query set
804 if (!Contact
->GetNext())
805 Contact
->Initialize();
809 // Enable/Disable the reset button
810 pResetBtn
->Enable(!Contact
->qryWhereStr
.IsEmpty());
816 if (widgetName
== pResetBtn
->GetName())
818 // Clear the additional where criteria established by the query feature
819 Contact
->qryWhereStr
= wxT("");
820 Contact
->SetOrderByClause(wxT("NAME"));
822 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
824 Contact
->whereStr
= wxT("NAME = (SELECT MIN(NAME) FROM ");
825 Contact
->whereStr
+= CONTACT_TABLE_NAME
;
826 Contact
->whereStr
+= wxT(")");
829 Contact
->SetWhereClause(Contact
->whereStr
.c_str());
830 if (!Contact
->Query())
833 tStr
= wxT("ODBC error during Query()\n\n");
834 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
835 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
838 if (!Contact
->GetNext())
839 Contact
->Initialize();
841 pResetBtn
->Enable(FALSE
);
847 if (widgetName
== pNameListBtn
->GetName())
849 new ClookUpDlg(/* wxWindow *parent */ this,
850 /* wxChar *windowTitle */ wxT("Select contact name"),
851 /* wxChar *tableName */ (wxChar
*) CONTACT_TABLE_NAME
,
852 /* wxChar *dispCol1 */ wxT("NAME"),
853 /* wxChar *dispCol2 */ wxT("JOINDATE"),
854 /* wxChar *where */ wxT(""),
855 /* wxChar *orderBy */ wxT("NAME"),
856 /* bool distinctValues */ TRUE
);
858 if (ListDB_Selection
&& wxStrlen(ListDB_Selection
))
860 wxString w
= wxT("NAME = '");
861 w
+= ListDB_Selection
;
863 GetRec((wxChar
*) (const wxChar
*) w
);
868 } // CeditorDlg::OnCommand()
871 bool CeditorDlg::Initialize()
873 // Create the data structure and a new database connection.
874 // (As there is not a pDb being passed in the constructor, a new database
875 // connection is created)
876 Contact
= new Ccontact();
880 wxMessageBox(wxT("Unable to instantiate an instance of Ccontact"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
884 // Check if the table exists or not. If it doesn't, ask the user if they want to
885 // create the table. Continue trying to create the table until it exists, or user aborts
886 while (!Contact
->GetDb()->TableExists((wxChar
*)CONTACT_TABLE_NAME
,DbConnectInf
.Uid
,DbConnectInf
.defaultDir
))
889 tStr
.Printf(wxT("Unable to open the table '%s'.\n\nTable may need to be created...?\n\n"),CONTACT_TABLE_NAME
);
890 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
891 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
893 bool createTable
= (wxMessageBox(wxT("Do you wish to try to create/clear the CONTACTS table?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
901 DemoFrame
->CreateDataTable(TRUE
);
904 // Tables must be "opened" before anything other than creating/deleting table can be done
905 if (!Contact
->Open())
907 // Table does exist, or there was some problem opening it. Currently this should
908 // never fail, except in the case of the table not exisiting or the current
909 // user has insufficent privileges to access the table
911 // This code is experimenting with a new function that will hopefully be available
912 // in the 2.4 release. This check will determine whether the open failing was due
913 // to the table not existing, or the users privileges being insufficient to
915 if (!Contact
->GetDb()->TablePrivileges(CONTACT_TABLE_NAME
,wxT("SELECT"),Contact
->GetDb()->GetUsername(),Contact
->GetDb()->GetUsername(),DbConnectInf
.defaultDir
))
918 tStr
.Printf(wxT("Unable to open the table '%s'.\n\n"),CONTACT_TABLE_NAME
);
919 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
920 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
924 if (Contact
->GetDb()->TableExists(CONTACT_TABLE_NAME
,Contact
->GetDb()->GetUsername(),DbConnectInf
.defaultDir
))
927 tStr
.Printf(wxT("Unable to open the table '%s'.\n\n"),CONTACT_TABLE_NAME
);
928 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
929 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
937 (void)new wxStaticBox(this, EDITOR_DIALOG_FN_GROUP
, wxT(""), wxPoint(15, 1), wxSize(497, 69), 0, wxT("FunctionGrp"));
938 (void)new wxStaticBox(this, EDITOR_DIALOG_SEARCH_GROUP
, wxT(""), wxPoint(417, 1), wxSize(95, 242), 0, wxT("SearchGrp"));
940 pCreateBtn
= new wxButton(this, EDITOR_DIALOG_CREATE
, wxT("&Create"), wxPoint( 25, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("CreateBtn"));
941 pEditBtn
= new wxButton(this, EDITOR_DIALOG_EDIT
, wxT("&Edit"), wxPoint(102, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("EditBtn"));
942 pDeleteBtn
= new wxButton(this, EDITOR_DIALOG_DELETE
, wxT("&Delete"), wxPoint(179, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("DeleteBtn"));
943 pCopyBtn
= new wxButton(this, EDITOR_DIALOG_COPY
, wxT("Cop&y"), wxPoint(256, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("CopyBtn"));
944 pSaveBtn
= new wxButton(this, EDITOR_DIALOG_SAVE
, wxT("&Save"), wxPoint(333, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("SaveBtn"));
945 pCancelBtn
= new wxButton(this, EDITOR_DIALOG_CANCEL
, wxT("C&ancel"), wxPoint(430, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("CancelBtn"));
946 pPrevBtn
= new wxButton(this, EDITOR_DIALOG_PREV
, wxT("<< &Prev"), wxPoint(430, 81), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("PrevBtn"));
947 pNextBtn
= new wxButton(this, EDITOR_DIALOG_NEXT
, wxT("&Next >>"), wxPoint(430, 121), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("NextBtn"));
948 pQueryBtn
= new wxButton(this, EDITOR_DIALOG_QUERY
, wxT("&Query"), wxPoint(430, 161), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("QueryBtn"));
949 pResetBtn
= new wxButton(this, EDITOR_DIALOG_RESET
, wxT("&Reset"), wxPoint(430, 200), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("ResetBtn"));
950 pNameMsg
= new wxStaticText(this, EDITOR_DIALOG_NAME_MSG
, wxT("Name:"), wxPoint( 17, 80), wxSize( -1, -1), 0, wxT("NameMsg"));
951 pNameTxt
= new wxTextCtrl(this, EDITOR_DIALOG_NAME_TEXT
, wxT(""), wxPoint( 17, 97), wxSize(308, 25), 0, wxDefaultValidator
, wxT("NameTxt"));
952 pNameListBtn
= new wxButton(this, EDITOR_DIALOG_LOOKUP
, wxT("&Lookup"), wxPoint(333, 97), wxSize( 70, 24), 0, wxDefaultValidator
, wxT("LookupBtn"));
953 pAddress1Msg
= new wxStaticText(this, EDITOR_DIALOG_ADDRESS1_MSG
, wxT("Address:"), wxPoint( 17, 130), wxSize( -1, -1), 0, wxT("Address1Msg"));
954 pAddress1Txt
= new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT
, wxT(""), wxPoint( 17, 147), wxSize(308, 25), 0, wxDefaultValidator
, wxT("Address1Txt"));
955 pAddress2Msg
= new wxStaticText(this, EDITOR_DIALOG_ADDRESS2_MSG
, wxT("Address:"), wxPoint( 17, 180), wxSize( -1, -1), 0, wxT("Address2Msg"));
956 pAddress2Txt
= new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT
, wxT(""), wxPoint( 17, 197), wxSize(308, 25), 0, wxDefaultValidator
, wxT("Address2Txt"));
957 pCityMsg
= new wxStaticText(this, EDITOR_DIALOG_CITY_MSG
, wxT("City:"), wxPoint( 17, 230), wxSize( -1, -1), 0, wxT("CityMsg"));
958 pCityTxt
= new wxTextCtrl(this, EDITOR_DIALOG_CITY_TEXT
, wxT(""), wxPoint( 17, 247), wxSize(225, 25), 0, wxDefaultValidator
, wxT("CityTxt"));
959 pStateMsg
= new wxStaticText(this, EDITOR_DIALOG_STATE_MSG
, wxT("State:"), wxPoint(250, 230), wxSize( -1, -1), 0, wxT("StateMsg"));
960 pStateTxt
= new wxTextCtrl(this, EDITOR_DIALOG_STATE_TEXT
, wxT(""), wxPoint(250, 247), wxSize(153, 25), 0, wxDefaultValidator
, wxT("StateTxt"));
961 pCountryMsg
= new wxStaticText(this, EDITOR_DIALOG_COUNTRY_MSG
, wxT("Country:"), wxPoint( 17, 280), wxSize( -1, -1), 0, wxT("CountryMsg"));
962 pCountryTxt
= new wxTextCtrl(this, EDITOR_DIALOG_COUNTRY_TEXT
, wxT(""), wxPoint( 17, 297), wxSize(225, 25), 0, wxDefaultValidator
, wxT("CountryTxt"));
963 pPostalCodeMsg
= new wxStaticText(this, EDITOR_DIALOG_POSTAL_MSG
, wxT("Postal Code:"),wxPoint(250, 280), wxSize( -1, -1), 0, wxT("PostalCodeMsg"));
964 pPostalCodeTxt
= new wxTextCtrl(this, EDITOR_DIALOG_POSTAL_TEXT
, wxT(""), wxPoint(250, 297), wxSize(153, 25), 0, wxDefaultValidator
, wxT("PostalCodeTxt"));
966 wxString choice_strings
[5];
967 choice_strings
[0] = wxT("English");
968 choice_strings
[1] = wxT("French");
969 choice_strings
[2] = wxT("German");
970 choice_strings
[3] = wxT("Spanish");
971 choice_strings
[4] = wxT("Other");
973 pNativeLangChoice
= new wxChoice(this, EDITOR_DIALOG_LANG_CHOICE
, wxPoint( 17, 346), wxSize(277, -1), 5, choice_strings
);
974 pNativeLangMsg
= new wxStaticText(this, EDITOR_DIALOG_LANG_MSG
, wxT("Native language:"), wxPoint( 17, 330), wxSize( -1, -1), 0, wxT("NativeLangMsg"));
976 wxString radio_strings
[2];
977 radio_strings
[0] = wxT("No");
978 radio_strings
[1] = wxT("Yes");
979 pDeveloperRadio
= new wxRadioBox(this,EDITOR_DIALOG_DEVELOPER
, wxT("Developer:"), wxPoint(303, 330), wxSize( -1, -1), 2, radio_strings
, 2, wxHORIZONTAL
);
980 pJoinDateMsg
= new wxStaticText(this, EDITOR_DIALOG_JOIN_MSG
, wxT("Date joined:"), wxPoint( 17, 380), wxSize( -1, -1), 0, wxT("JoinDateMsg"));
981 pJoinDateTxt
= new wxTextCtrl(this, EDITOR_DIALOG_JOIN_TEXT
, wxT(""), wxPoint( 17, 397), wxSize(150, 25), 0, wxDefaultValidator
, wxT("JoinDateTxt"));
982 pContribMsg
= new wxStaticText(this, EDITOR_DIALOG_CONTRIB_MSG
,wxT("Contributions:"), wxPoint(175, 380), wxSize( -1, -1), 0, wxT("ContribMsg"));
983 pContribTxt
= new wxTextCtrl(this, EDITOR_DIALOG_CONTRIB_TEXT
, wxT(""), wxPoint(175, 397), wxSize(120, 25), 0, wxDefaultValidator
, wxT("ContribTxt"));
984 pLinesMsg
= new wxStaticText(this, EDITOR_DIALOG_LINES_MSG
, wxT("Lines of code:"), wxPoint(303, 380), wxSize( -1, -1), 0, wxT("LinesMsg"));
985 pLinesTxt
= new wxTextCtrl(this, EDITOR_DIALOG_LINES_TEXT
, wxT(""), wxPoint(303, 397), wxSize(100, 25), 0, wxDefaultValidator
, wxT("LinesTxt"));
987 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
988 // handle all widget processing
989 widgetPtrsSet
= TRUE
;
991 // Setup the orderBy and where clauses to return back a single record as the result set,
992 // as there will only be one record being shown on the dialog at a time, this optimizes
993 // network traffic by only returning a one row result
995 Contact
->SetOrderByClause(wxT("NAME")); // field name to sort by
997 // The wxString "whereStr" is not a member of the wxDbTable object, it is a member variable
998 // specifically in the Ccontact class. It is used here for simpler construction of a varying
999 // length string, and then after the string is built, the wxDbTable member variable "where" is
1000 // assigned the pointer to the constructed string.
1002 // The constructed where clause below has a sub-query within it "SELECT MIN(NAME) FROM %s"
1003 // to achieve a single row (in this case the first name in alphabetical order).
1005 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1007 Contact
->whereStr
.sprintf(wxT("NAME = (SELECT MIN(NAME) FROM %s)"),Contact
->GetTableName());
1008 // NOTE: (const wxChar*) returns a pointer which may not be valid later, so this is short term use only
1009 Contact
->SetWhereClause(Contact
->whereStr
.c_str());
1012 Contact
->SetWhereClause(wxT(""));
1014 // Perform the Query to get the result set.
1015 // NOTE: If there are no rows returned, that is a valid result, so Query() would return TRUE.
1016 // Only if there is a database error will Query() come back as FALSE
1017 if (!Contact
->Query())
1020 tStr
= wxT("ODBC error during Query()\n\n");
1021 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1022 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1023 // GetParent()->Close();
1027 // Since Query succeeded, now get the row that was returned
1028 if (!Contact
->GetNext())
1029 // If the GetNext() failed at this point, then there are no rows to retrieve,
1030 // so clear the values in the members of "Contact" so that PutData() blanks the
1031 // widgets on the dialog
1032 Contact
->Initialize();
1041 } // CeditorDlg::Initialize()
1044 void CeditorDlg::FieldsEditable()
1046 pNameTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1047 pAddress1Txt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1048 pAddress2Txt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1049 pCityTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1050 pStateTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1051 pPostalCodeTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1052 pCountryTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1054 pJoinDateTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1055 pContribTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1056 pLinesTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1057 pNativeLangChoice
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1058 pDeveloperRadio
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1060 } // CeditorDlg::FieldsEditable()
1063 void CeditorDlg::SetMode(enum DialogModes m
)
1084 pCreateBtn
->Enable( !edit
);
1085 pEditBtn
->Enable( !edit
&& (wxStrcmp(Contact
->Name
,wxT(""))!=0) );
1086 pDeleteBtn
->Enable( !edit
&& (wxStrcmp(Contact
->Name
,wxT(""))!=0) );
1087 pCopyBtn
->Enable( !edit
&& (wxStrcmp(Contact
->Name
,wxT(""))!=0) );
1088 pSaveBtn
->Enable( edit
);
1089 pCancelBtn
->Enable( edit
);
1090 pPrevBtn
->Enable( !edit
);
1091 pNextBtn
->Enable( !edit
);
1092 pQueryBtn
->Enable( !edit
);
1093 pResetBtn
->Enable( !edit
&& !Contact
->qryWhereStr
.IsEmpty() );
1094 pNameListBtn
->Enable( !edit
);
1098 } // CeditorDlg::SetMode()
1101 bool CeditorDlg::PutData()
1105 pNameTxt
->SetValue(Contact
->Name
);
1106 pAddress1Txt
->SetValue(Contact
->Addr1
);
1107 pAddress2Txt
->SetValue(Contact
->Addr2
);
1108 pCityTxt
->SetValue(Contact
->City
);
1109 pStateTxt
->SetValue(Contact
->State
);
1110 pCountryTxt
->SetValue(Contact
->Country
);
1111 pPostalCodeTxt
->SetValue(Contact
->PostalCode
);
1113 tStr
.Printf(wxT("%d/%d/%d"),Contact
->JoinDate
.month
,Contact
->JoinDate
.day
,Contact
->JoinDate
.year
);
1114 pJoinDateTxt
->SetValue(tStr
);
1116 tStr
.Printf(wxT("%d"),Contact
->Contributions
);
1117 pContribTxt
->SetValue(tStr
);
1119 tStr
.Printf(wxT("%lu"),Contact
->LinesOfCode
);
1120 pLinesTxt
->SetValue(tStr
);
1122 pNativeLangChoice
->SetSelection(Contact
->NativeLanguage
);
1124 pDeveloperRadio
->SetSelection(Contact
->IsDeveloper
);
1127 } // Ceditor::PutData()
1131 * Reads the data out of all the widgets on the dialog. Some data evaluation is done
1132 * to ensure that there is a name entered and that the date field is valid.
1134 * A return value of TRUE means that valid data was retrieved from the dialog, otherwise
1135 * invalid data was found (and a message was displayed telling the user what to fix), and
1136 * the data was not placed into the appropraite fields of Ccontact
1138 bool CeditorDlg::GetData()
1140 // Validate that the data currently entered into the widgets is valid data
1143 tStr
= pNameTxt
->GetValue();
1144 if (!wxStrcmp((const wxChar
*) tStr
,wxT("")))
1146 wxMessageBox(wxT("A name is required for entry into the contact table"),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
1150 bool invalid
= FALSE
;
1154 tStr
= pJoinDateTxt
->GetValue();
1155 if (tStr
.Freq(wxT('/')) != 2)
1158 // Find the month, day, and year tokens
1161 first
= tStr
.First(wxT('/'));
1162 second
= tStr
.Last(wxT('/'));
1164 mm
= atoi(tStr
.SubString(0,first
));
1165 dd
= atoi(tStr
.SubString(first
+1,second
));
1166 yyyy
= atoi(tStr
.SubString(second
+1,tStr
.Length()-1));
1168 invalid
= !(mm
&& dd
&& yyyy
);
1171 // Force Year 2000 compliance
1172 if (!invalid
&& (yyyy
< 1000))
1175 // Check the token ranges for validity
1180 else if ((mm
< 1) || (mm
> 12))
1188 int days
[12] = {31,28,31,30,31,30,
1190 if (dd
> days
[mm
-1])
1193 if ((dd
== 29) && (mm
== 2))
1195 if (((yyyy
% 4) == 0) && (((yyyy
% 100) != 0) || ((yyyy
% 400) == 0)))
1205 Contact
->JoinDate
.month
= mm
;
1206 Contact
->JoinDate
.day
= dd
;
1207 Contact
->JoinDate
.year
= yyyy
;
1211 wxMessageBox(wxT("Improper date format. Please check the date\nspecified and try again.\n\nNOTE: Dates are in american format (MM/DD/YYYY)"),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
1215 tStr
= pNameTxt
->GetValue();
1216 wxStrcpy(Contact
->Name
,(const wxChar
*) tStr
);
1217 wxStrcpy(Contact
->Addr1
,pAddress1Txt
->GetValue());
1218 wxStrcpy(Contact
->Addr2
,pAddress2Txt
->GetValue());
1219 wxStrcpy(Contact
->City
,pCityTxt
->GetValue());
1220 wxStrcpy(Contact
->State
,pStateTxt
->GetValue());
1221 wxStrcpy(Contact
->Country
,pCountryTxt
->GetValue());
1222 wxStrcpy(Contact
->PostalCode
,pPostalCodeTxt
->GetValue());
1224 Contact
->Contributions
= atoi(pContribTxt
->GetValue());
1225 Contact
->LinesOfCode
= atol(pLinesTxt
->GetValue());
1227 Contact
->NativeLanguage
= (enum Language
) pNativeLangChoice
->GetSelection();
1228 Contact
->IsDeveloper
= pDeveloperRadio
->GetSelection() > 0;
1231 } // CeditorDlg::GetData()
1235 * Retrieve data from the dialog, verify the validity of the data, and if it is valid,
1236 * try to insert/update the data to the table based on the current 'mode' the dialog
1239 * A return value of TRUE means the insert/update was completed successfully, a return
1240 * value of FALSE means that Save() failed. If returning FALSE, then this function
1241 * has displayed a detailed error message for the user.
1243 bool CeditorDlg::Save()
1245 bool failed
= FALSE
;
1247 // Read the data in the widgets of the dialog to get the user's data
1251 // Perform any other required validations necessary before saving
1254 wxBeginBusyCursor();
1256 if (mode
== mCreate
)
1258 RETCODE result
= Contact
->Insert();
1260 failed
= (result
!= DB_SUCCESS
);
1263 // Some errors may be expected, like a duplicate key, so handle those instances with
1264 // specific error messages.
1265 if (result
== DB_ERR_INTEGRITY_CONSTRAINT_VIOL
)
1268 tStr
= wxT("A duplicate key value already exists in the table.\nUnable to save record\n\n");
1269 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1270 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1274 // Some other unexpexted error occurred
1276 tStr
= wxT("Database insert failed\n\n");
1277 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1278 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1282 else // mode == mEdit
1284 if (!Contact
->Update())
1287 tStr
= wxT("Database update failed\n\n");
1288 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1289 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1296 Contact
->GetDb()->CommitTrans();
1297 SetMode(mView
); // Sets the dialog mode back to viewing after save is successful
1300 Contact
->GetDb()->RollbackTrans();
1306 } // CeditorDlg::Save()
1310 * Where this program is only showing a single row at a time in the dialog,
1311 * a special where clause must be built to find just the single row which,
1312 * in sequence, would follow the currently displayed row.
1314 bool CeditorDlg::GetNextRec()
1318 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1320 w
= wxT("NAME = (SELECT MIN(NAME) FROM ");
1321 w
+= Contact
->GetTableName();
1322 w
+= wxT(" WHERE NAME > '");
1325 w
= wxT("(NAME > '");
1330 // If a query where string is currently set, append that criteria
1331 if (!Contact
->qryWhereStr
.IsEmpty())
1334 w
+= Contact
->qryWhereStr
;
1339 return(GetRec((wxChar
*) (const wxChar
*) w
));
1341 } // CeditorDlg::GetNextRec()
1345 * Where this program is only showing a single row at a time in the dialog,
1346 * a special where clause must be built to find just the single row which,
1347 * in sequence, would precede the currently displayed row.
1349 bool CeditorDlg::GetPrevRec()
1353 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1355 w
= wxT("NAME = (SELECT MAX(NAME) FROM ");
1356 w
+= Contact
->GetTableName();
1357 w
+= wxT(" WHERE NAME < '");
1360 w
= wxT("(NAME < '");
1365 // If a query where string is currently set, append that criteria
1366 if (!Contact
->qryWhereStr
.IsEmpty())
1369 w
+= Contact
->qryWhereStr
;
1375 return(GetRec((wxChar
*) (const wxChar
*)w
));
1377 } // CeditorDlg::GetPrevRec()
1381 * This function is here to avoid duplicating this same code in both the
1382 * GetPrevRec() and GetNextRec() functions
1384 bool CeditorDlg::GetRec(wxChar
*whereStr
)
1386 Contact
->SetWhereClause(whereStr
);
1387 Contact
->SetOrderByClause(wxT("NAME"));
1389 if (!Contact
->Query())
1392 tStr
= wxT("ODBC error during Query()\n\n");
1393 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1394 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1399 if (Contact
->GetNext())
1406 } // CeditorDlg::GetRec()
1411 * CparameterDlg constructor
1414 BEGIN_EVENT_TABLE(CparameterDlg
, wxDialog
)
1415 EVT_BUTTON(PARAMETER_DIALOG_SAVE
, CparameterDlg::OnButton
)
1416 EVT_BUTTON(PARAMETER_DIALOG_CANCEL
, CparameterDlg::OnButton
)
1417 EVT_CLOSE(CparameterDlg::OnCloseWindow
)
1420 CparameterDlg::CparameterDlg(wxWindow
*parent
) : wxDialog (parent
, PARAMETER_DIALOG
, wxT("ODBC parameter settings"), wxPoint(-1, -1), wxSize(400, 325))
1422 // Since the ::OnCommand() function is overridden, this prevents the widget
1423 // detection in ::OnCommand() until all widgets have been initialized to prevent
1424 // uninitialized pointers from crashing the program
1425 widgetPtrsSet
= FALSE
;
1427 pParamODBCSourceMsg
= new wxStaticText(this, PARAMETER_DIALOG_SOURCE_MSG
, wxT("ODBC data sources:"), wxPoint( 10, 10), wxSize( -1, -1), 0, wxT("ParamODBCSourceMsg"));
1428 pParamODBCSourceList
= new wxListBox(this, PARAMETER_DIALOG_SOURCE_LISTBOX
, wxPoint( 10, 29), wxSize(285, 150), 0, 0, wxLB_SINGLE
|wxLB_ALWAYS_SB
, wxDefaultValidator
, wxT("ParamODBCSourceList"));
1429 pParamUserNameMsg
= new wxStaticText(this, PARAMETER_DIALOG_NAME_MSG
, wxT("Database user name:"), wxPoint( 10, 193), wxSize( -1, -1), 0, wxT("ParamUserNameMsg"));
1430 pParamUserNameTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_NAME_TEXT
, wxT(""), wxPoint(10, 209), wxSize( 140, 25), 0, wxDefaultValidator
, wxT("ParamUserNameTxt"));
1431 pParamPasswordMsg
= new wxStaticText(this, PARAMETER_DIALOG_PASSWORD_MSG
, wxT("Password:"), wxPoint(156, 193), wxSize( -1, -1), 0, wxT("ParamPasswordMsg"));
1432 pParamPasswordTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_PASSWORD_TEXT
, wxT(""), wxPoint(156, 209), wxSize( 140, 25), 0, wxDefaultValidator
, wxT("ParamPasswordTxt"));
1433 pParamDirPathMsg
= new wxStaticText(this, PARAMETER_DIALOG_DIRPATH_MSG
, wxT("Directory:"), wxPoint( 10, 243), wxSize( -1, -1), 0, wxT("ParamDirPathMsg"));
1434 pParamDirPathTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_DIRPATH_TEXT
, wxT(""), wxPoint( 10, 259), wxSize(140, 25), 0, wxDefaultValidator
, wxT("ParamDirPathTxt"));
1435 pParamSaveBtn
= new wxButton(this, PARAMETER_DIALOG_SAVE
, wxT("&Save"), wxPoint(310, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("ParamSaveBtn"));
1436 pParamCancelBtn
= new wxButton(this, PARAMETER_DIALOG_CANCEL
, wxT("C&ancel"), wxPoint(310, 66), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("ParamCancelBtn"));
1438 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
1439 // handle all widget processing
1440 widgetPtrsSet
= TRUE
;
1443 savedParamSettings
= wxGetApp().params
;
1448 } // CparameterDlg constructor
1451 void CparameterDlg::OnCloseWindow(wxCloseEvent
& event
)
1453 // Put any additional checking necessary to make certain it is alright
1454 // to close the program here that is not done elsewhere
1457 bool Ok
= (wxMessageBox(wxT("No changes have been saved.\n\nAre you sure you wish exit the parameter screen?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
1465 wxGetApp().params
= savedParamSettings
;
1468 if (GetParent() != NULL
)
1469 GetParent()->SetFocus();
1475 SetReturnCode(0); // added so BoundsChecker would not report use of uninitialized variable
1478 } // CparameterDlg::OnCloseWindow()
1481 void CparameterDlg::OnButton( wxCommandEvent
&event
)
1483 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
1484 OnCommand( *win
, event
);
1488 void CparameterDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
1490 wxString widgetName
;
1492 widgetName
= win
.GetName();
1497 if (widgetName
== pParamSaveBtn
->GetName())
1502 tStr
= wxT("Database parameters have been saved.");
1503 if (GetParent() != NULL
) // The parameter dialog was not called during startup due to a missing cfg file
1504 tStr
+= wxT("\nNew parameters will take effect the next time the program is started.");
1505 wxMessageBox(tStr
,wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
1512 if (widgetName
== pParamCancelBtn
->GetName())
1517 } // CparameterDlg::OnCommand()
1520 bool CparameterDlg::PutData()
1522 // Fill the data source list box
1523 FillDataSourceList();
1525 // Fill in the fields from the params object
1526 if (wxGetApp().params
.ODBCSource
&& wxStrlen(wxGetApp().params
.ODBCSource
))
1527 pParamODBCSourceList
->SetStringSelection(wxGetApp().params
.ODBCSource
);
1528 pParamUserNameTxt
->SetValue(wxGetApp().params
.UserName
);
1529 pParamPasswordTxt
->SetValue(wxGetApp().params
.Password
);
1530 pParamDirPathTxt
->SetValue(wxGetApp().params
.DirPath
);
1532 } // CparameterDlg::PutData()
1535 bool CparameterDlg::GetData()
1538 if (pParamODBCSourceList
->GetStringSelection() != wxT(""))
1540 tStr
= pParamODBCSourceList
->GetStringSelection();
1541 if (tStr
.Length() > (sizeof(wxGetApp().params
.ODBCSource
)-1))
1544 errmsg
.Printf(wxT("ODBC Data source name is longer than the data structure to hold it.\n'Cparameter.ODBCSource' must have a larger character array\nto handle a data source with this long of a name\n\nThe data source currently selected is %d characters long."),tStr
.Length());
1545 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1548 wxStrcpy(wxGetApp().params
.ODBCSource
, tStr
);
1553 tStr
= pParamUserNameTxt
->GetValue();
1554 if (tStr
.Length() > (sizeof(wxGetApp().params
.UserName
)-1))
1557 errmsg
.Printf(wxT("User name is longer than the data structure to hold it.\n'Cparameter.UserName' must have a larger character array\nto handle a data source with this long of a name\n\nThe user name currently specified is %d characters long."),tStr
.Length());
1558 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1561 wxStrcpy(wxGetApp().params
.UserName
, tStr
);
1563 tStr
= pParamPasswordTxt
->GetValue();
1564 if (tStr
.Length() > (sizeof(wxGetApp().params
.Password
)-1))
1567 errmsg
.Printf(wxT("Password is longer than the data structure to hold it.\n'Cparameter.Password' must have a larger character array\nto handle a data source with this long of a name\n\nThe password currently specified is %d characters long."),tStr
.Length());
1568 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1571 wxStrcpy(wxGetApp().params
.Password
,tStr
);
1573 tStr
= pParamDirPathTxt
->GetValue();
1574 tStr
.Replace(wxT("\\"),wxT("/"));
1575 if (tStr
.Length() > (sizeof(wxGetApp().params
.DirPath
)-1))
1578 errmsg
.Printf(wxT("DirPath is longer than the data structure to hold it.\n'Cparameter.DirPath' must have a larger character array\nto handle a data source with this long of a name\n\nThe password currently specified is %d characters long."),tStr
.Length());
1579 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1582 wxStrcpy(wxGetApp().params
.DirPath
,tStr
);
1584 } // CparameterDlg::GetData()
1587 bool CparameterDlg::Save()
1589 Cparameters saveParams
= wxGetApp().params
;
1592 wxGetApp().params
= saveParams
;
1597 if ((paramFile
= fopen(paramFilename
, wxT("wt"))) == NULL
)
1600 tStr
.Printf(wxT("Unable to write/overwrite '%s'."),paramFilename
);
1601 wxMessageBox(tStr
,wxT("File I/O Error..."),wxOK
| wxICON_EXCLAMATION
);
1605 fputs(wxGetApp().params
.ODBCSource
, paramFile
);
1606 fputc(wxT('\n'), paramFile
);
1607 fputs(wxGetApp().params
.UserName
, paramFile
);
1608 fputc(wxT('\n'), paramFile
);
1609 fputs(wxGetApp().params
.Password
, paramFile
);
1610 fputc(wxT('\n'), paramFile
);
1611 fputs(wxGetApp().params
.DirPath
, paramFile
);
1612 fputc(wxT('\n'), paramFile
);
1616 } // CparameterDlg::Save()
1619 void CparameterDlg::FillDataSourceList()
1621 wxChar Dsn
[SQL_MAX_DSN_LENGTH
+ 1];
1623 wxStringList strList
;
1625 while (wxDbGetDataSource(DbConnectInf
.Henv
, Dsn
, SQL_MAX_DSN_LENGTH
+1, DsDesc
, 255))
1629 strList
.Add(wxT(""));
1630 wxChar
**p
= strList
.ListToArray();
1633 for (i
= 0; wxStrlen(p
[i
]); i
++)
1634 pParamODBCSourceList
->Append(p
[i
]);
1637 } // CparameterDlg::CparameterDlg::FillDataSourceList()
1640 BEGIN_EVENT_TABLE(CqueryDlg
, wxDialog
)
1641 EVT_BUTTON(-1, CqueryDlg::OnButton
)
1642 EVT_CLOSE(CqueryDlg::OnCloseWindow
)
1646 // CqueryDlg() constructor
1647 CqueryDlg::CqueryDlg(wxWindow
*parent
, wxDb
*pDb
, wxChar
*tblName
[], wxChar
*pWhereArg
) : wxDialog (parent
, QUERY_DIALOG
, wxT("Query"), wxPoint(-1, -1), wxSize(480, 360))
1649 wxBeginBusyCursor();
1653 masterTableName
= tblName
[0];
1654 widgetPtrsSet
= FALSE
;
1657 // Initialize the WHERE clause from the string passed in
1658 pWhere
= pWhereArg
; // Save a pointer to the output buffer
1659 if (wxStrlen(pWhere
) > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN
) // Check the length of the buffer passed in
1662 s
.Printf(wxT("Maximum where clause length exceeded.\nLength must be less than %d"), DB_MAX_WHERE_CLAUSE_LEN
+1);
1663 wxMessageBox(s
,wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
1668 pQueryCol1Msg
= new wxStaticText(this, QUERY_DIALOG_COL_MSG
, wxT("Column 1:"), wxPoint( 10, 10), wxSize( 69, 16), 0, wxT("QueryCol1Msg"));
1669 pQueryCol1Choice
= new wxChoice(this, QUERY_DIALOG_COL_CHOICE
, wxPoint( 10, 27), wxSize(250, 27), 0, 0, 0, wxDefaultValidator
, wxT("QueryCol1Choice"));
1670 pQueryNotMsg
= new wxStaticText(this, QUERY_DIALOG_NOT_MSG
, wxT("NOT"), wxPoint(268, 10), wxSize( -1, -1), 0, wxT("QueryNotMsg"));
1671 pQueryNotCheck
= new wxCheckBox(this, QUERY_DIALOG_NOT_CHECKBOX
, wxT(""), wxPoint(275, 37), wxSize( 20, 20), 0, wxDefaultValidator
, wxT("QueryNotCheck"));
1673 wxString choice_strings
[9];
1674 choice_strings
[0] = wxT("=");
1675 choice_strings
[1] = wxT("<");
1676 choice_strings
[2] = wxT(">");
1677 choice_strings
[3] = wxT("<=");
1678 choice_strings
[4] = wxT(">=");
1679 choice_strings
[5] = wxT("Begins");
1680 choice_strings
[6] = wxT("Contains");
1681 choice_strings
[7] = wxT("Like");
1682 choice_strings
[8] = wxT("Between");
1684 pQueryOperatorMsg
= new wxStaticText(this, QUERY_DIALOG_OP_MSG
, wxT("Operator:"), wxPoint(305, 10), wxSize( -1, -1), 0, wxT("QueryOperatorMsg"));
1685 pQueryOperatorChoice
= new wxChoice(this, QUERY_DIALOG_OP_CHOICE
, wxPoint(305, 27), wxSize( 80, 27), 9, choice_strings
, 0, wxDefaultValidator
, wxT("QueryOperatorChoice"));
1686 pQueryCol2Msg
= new wxStaticText(this, QUERY_DIALOG_COL2_MSG
, wxT("Column 2:"), wxPoint( 10, 65), wxSize( 69, 16), 0, wxT("QueryCol2Msg"));
1687 pQueryCol2Choice
= new wxChoice(this, QUERY_DIALOG_COL2_CHOICE
, wxPoint( 10, 82), wxSize(250, 27), 0, 0, 0, wxDefaultValidator
, wxT("QueryCol2Choice"));
1688 pQuerySqlWhereMsg
= new wxStaticText(this, QUERY_DIALOG_WHERE_MSG
, wxT("SQL where clause:"), wxPoint( 10, 141), wxSize( -1, -1), 0, wxT("QuerySqlWhereMsg"));
1689 pQuerySqlWhereMtxt
= new wxTextCtrl(this, QUERY_DIALOG_WHERE_TEXT
, wxT(""), wxPoint( 10, 159), wxSize(377, 134), wxTE_MULTILINE
, wxDefaultValidator
, wxT("QuerySqlWhereMtxt"));
1690 pQueryAddBtn
= new wxButton(this, QUERY_DIALOG_ADD
, wxT("&Add"), wxPoint(406, 24), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryAddBtn"));
1691 pQueryAndBtn
= new wxButton(this, QUERY_DIALOG_AND
, wxT("A&nd"), wxPoint(406, 58), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryAndBtn"));
1692 pQueryOrBtn
= new wxButton(this, QUERY_DIALOG_OR
, wxT("&Or"), wxPoint(406, 92), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryOrBtn"));
1693 pQueryLParenBtn
= new wxButton(this, QUERY_DIALOG_LPAREN
, wxT("("), wxPoint(406, 126), wxSize( 26, 26), 0, wxDefaultValidator
, wxT("QueryLParenBtn"));
1694 pQueryRParenBtn
= new wxButton(this, QUERY_DIALOG_RPAREN
, wxT(")"), wxPoint(436, 126), wxSize( 26, 26), 0, wxDefaultValidator
, wxT("QueryRParenBtn"));
1695 pQueryDoneBtn
= new wxButton(this, QUERY_DIALOG_DONE
, wxT("&Done"), wxPoint(406, 185), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryDoneBtn"));
1696 pQueryClearBtn
= new wxButton(this, QUERY_DIALOG_CLEAR
, wxT("C&lear"), wxPoint(406, 218), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryClearBtn"));
1697 pQueryCountBtn
= new wxButton(this, QUERY_DIALOG_COUNT
, wxT("&Count"), wxPoint(406, 252), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryCountBtn"));
1698 pQueryValue1Msg
= new wxStaticText(this, QUERY_DIALOG_VALUE1_MSG
, wxT("Value:"), wxPoint(277, 66), wxSize( -1, -1), 0, wxT("QueryValue1Msg"));
1699 pQueryValue1Txt
= new wxTextCtrl(this, QUERY_DIALOG_VALUE1_TEXT
, wxT(""), wxPoint(277, 83), wxSize(108, 25), 0, wxDefaultValidator
, wxT("QueryValue1Txt"));
1700 pQueryValue2Msg
= new wxStaticText(this, QUERY_DIALOG_VALUE2_MSG
, wxT("AND"), wxPoint(238, 126), wxSize( -1, -1), 0, wxT("QueryValue2Msg"));
1701 pQueryValue2Txt
= new wxTextCtrl(this, QUERY_DIALOG_VALUE2_TEXT
, wxT(""), wxPoint(277, 120), wxSize(108, 25), 0, wxDefaultValidator
, wxT("QueryValue2Txt"));
1702 pQueryHintGrp
= new wxStaticBox(this, QUERY_DIALOG_HINT_GROUP
, wxT(""), wxPoint( 10, 291), wxSize(377, 40), 0, wxT("QueryHintGrp"));
1703 pQueryHintMsg
= new wxStaticText(this, QUERY_DIALOG_HINT_MSG
, wxT(""), wxPoint( 16, 306), wxSize( -1, -1), 0, wxT("QueryHintMsg"));
1705 widgetPtrsSet
= TRUE
;
1706 // Initialize the dialog
1708 pQueryCol2Choice
->Append(wxT("VALUE -->"));
1709 colInf
= pDB
->GetColumns(tblName
);
1715 tStr
= wxT("ODBC error during GetColumns()\n\n");
1716 tStr
+= GetExtendedDBErrorMsg(pDb
,__FILE__
,__LINE__
);
1717 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1722 for (i
= 0; colInf
[i
].colName
&& wxStrlen(colInf
[i
].colName
); i
++)
1724 // If there is more than one table being queried, qualify
1725 // the column names with the table name prefix.
1726 if (tblName
[1] && wxStrlen(tblName
[1]))
1728 qualName
.Printf(wxT("%s.%s"), colInf
[i
].tableName
, colInf
[i
].colName
);
1729 pQueryCol1Choice
->Append(qualName
);
1730 pQueryCol2Choice
->Append(qualName
);
1732 else // Single table query, append just the column names
1734 pQueryCol1Choice
->Append(colInf
[i
].colName
);
1735 pQueryCol2Choice
->Append(colInf
[i
].colName
);
1739 pQueryCol1Choice
->SetSelection(0);
1740 pQueryCol2Choice
->SetSelection(0);
1741 pQueryOperatorChoice
->SetSelection(0);
1743 pQueryValue2Msg
->Show(FALSE
);
1744 pQueryValue2Txt
->Show(FALSE
);
1746 pQueryHintMsg
->SetLabel(langQRY_EQ
);
1748 pQuerySqlWhereMtxt
->SetValue(pWhere
);
1752 // Display the dialog window
1755 } // CqueryDlg() constructor
1758 CqueryDlg::~CqueryDlg()
1760 } // CqueryDlg::~CqueryDlg() destructor
1763 void CqueryDlg::OnButton(wxCommandEvent
&event
)
1765 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
1766 OnCommand( *win
, event
);
1767 } // CqueryDlg::OnButton()
1770 void CqueryDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
1772 // Widget pointers won't be set when the dialog is constructed.
1773 // Control is passed through this function once for each widget on
1774 // a dialog as the dialog is constructed.
1778 wxString widgetName
= win
.GetName();
1780 // Operator choice box
1781 if (widgetName
== pQueryOperatorChoice
->GetName())
1783 // Set the help text
1784 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
1787 pQueryHintMsg
->SetLabel(langQRY_EQ
);
1790 pQueryHintMsg
->SetLabel(langQRY_LT
);
1793 pQueryHintMsg
->SetLabel(langQRY_GT
);
1796 pQueryHintMsg
->SetLabel(langQRY_LE
);
1799 pQueryHintMsg
->SetLabel(langQRY_GE
);
1802 pQueryHintMsg
->SetLabel(langQRY_BEGINS
);
1805 pQueryHintMsg
->SetLabel(langQRY_CONTAINS
);
1808 pQueryHintMsg
->SetLabel(langQRY_LIKE
);
1811 pQueryHintMsg
->SetLabel(langQRY_BETWEEN
);
1815 // Hide the value2 widget
1816 pQueryValue2Msg
->Show(FALSE
); // BETWEEN will show this widget
1817 pQueryValue2Txt
->Show(FALSE
); // BETWEEN will show this widget
1819 // Disable the NOT operator for <, <=, >, >=
1820 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
1826 pQueryNotCheck
->SetValue(0);
1827 pQueryNotCheck
->Enable(FALSE
);
1830 pQueryNotCheck
->Enable(TRUE
);
1834 // Manipulate the dialog to handle the selected operator
1835 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
1842 pQueryCol2Choice
->Enable(TRUE
);
1843 if (pQueryCol2Choice
->GetSelection()) // Column name is highlighted
1845 pQueryValue1Msg
->Show(FALSE
);
1846 pQueryValue1Txt
->Show(FALSE
);
1848 else // "Value" is highlighted
1850 pQueryValue1Msg
->Show(TRUE
);
1851 pQueryValue1Txt
->Show(TRUE
);
1852 pQueryValue1Txt
->SetFocus();
1858 pQueryCol2Choice
->SetSelection(0);
1859 pQueryCol2Choice
->Enable(FALSE
);
1860 pQueryValue1Msg
->Show(TRUE
);
1861 pQueryValue1Txt
->Show(TRUE
);
1862 pQueryValue1Txt
->SetFocus();
1865 pQueryCol2Choice
->SetSelection(0);
1866 pQueryCol2Choice
->Enable(FALSE
);
1867 pQueryValue2Msg
->Show(TRUE
);
1868 pQueryValue2Txt
->Show(TRUE
);
1869 pQueryValue1Msg
->Show(TRUE
);
1870 pQueryValue1Txt
->Show(TRUE
);
1871 pQueryValue1Txt
->SetFocus();
1877 } // Operator choice box
1880 if (widgetName
== pQueryCol2Choice
->GetName())
1882 if (pQueryCol2Choice
->GetSelection()) // Column name is highlighted
1884 pQueryValue1Msg
->Show(FALSE
);
1885 pQueryValue1Txt
->Show(FALSE
);
1887 else // "Value" is highlighted
1889 pQueryValue1Msg
->Show(TRUE
);
1890 pQueryValue1Txt
->Show(TRUE
);
1891 pQueryValue1Txt
->SetFocus();
1894 } // Column 2 choice
1897 if (widgetName
== pQueryAddBtn
->GetName())
1904 if (widgetName
== pQueryAndBtn
->GetName())
1906 AppendToWhere(wxT(" AND\n"));
1911 if (widgetName
== pQueryOrBtn
->GetName())
1913 AppendToWhere(wxT(" OR\n"));
1917 // Left Paren button
1918 if (widgetName
== pQueryLParenBtn
->GetName())
1920 AppendToWhere(wxT("("));
1922 } // Left Paren button
1924 // Right paren button
1925 if (widgetName
== pQueryRParenBtn
->GetName())
1927 AppendToWhere(wxT(")"));
1929 } // Right Paren button
1932 if (widgetName
== pQueryDoneBtn
->GetName())
1934 // Be sure the where clause will not overflow the output buffer
1935 if (wxStrlen(pQuerySqlWhereMtxt
->GetValue()) > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN
)
1938 s
.Printf(wxT("Maximum where clause length exceeded.\nLength must be less than %d"), DB_MAX_WHERE_CLAUSE_LEN
+1);
1939 wxMessageBox(s
,wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
1942 // Validate the where clause for things such as matching parens
1943 if (!ValidateWhereClause())
1945 // Copy the where clause to the output buffer and exit
1946 wxStrcpy(pWhere
, pQuerySqlWhereMtxt
->GetValue());
1952 if (widgetName
== pQueryClearBtn
->GetName())
1954 bool Ok
= (wxMessageBox(wxT("Are you sure you wish to clear the Query?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
1957 pQuerySqlWhereMtxt
->SetValue(wxT(""));
1962 if (widgetName
== pQueryCountBtn
->GetName())
1964 wxBeginBusyCursor();
1970 } // CqueryDlg::OnCommand
1973 void CqueryDlg::OnCloseWindow(wxCloseEvent
& event
)
1988 GetParent()->SetFocus();
1993 SetReturnCode(1); // added so BoundsChecker would not report use of uninitialized variable
1996 } // CqueryDlg::OnCloseWindow()
1999 void CqueryDlg::AppendToWhere(wxChar
*s
)
2001 wxString whereStr
= pQuerySqlWhereMtxt
->GetValue();
2003 pQuerySqlWhereMtxt
->SetValue(whereStr
);
2004 } // CqueryDlg::AppendToWhere()
2007 void CqueryDlg::ProcessAddBtn()
2009 qryOp oper
= (qryOp
) pQueryOperatorChoice
->GetSelection();
2011 // Verify that eveything is filled in correctly
2012 if (pQueryCol2Choice
->GetSelection() == 0) // "Value" is selected
2014 // Verify that value 1 is filled in
2015 if (wxStrlen(pQueryValue1Txt
->GetValue()) == 0)
2018 pQueryValue1Txt
->SetFocus();
2021 // For the BETWEEN operator, value 2 must be filled in as well
2022 if (oper
== qryOpBETWEEN
&&
2023 wxStrlen(pQueryValue2Txt
->GetValue()) == 0)
2026 pQueryValue2Txt
->SetFocus();
2031 // Build the expression and append it to the where clause window
2032 wxString s
= pQueryCol1Choice
->GetStringSelection();
2034 if (pQueryNotCheck
->GetValue() && (oper
!= qryOpEQ
))
2040 if (pQueryNotCheck
->GetValue()) // NOT box is checked
2063 s
+= wxT(" BETWEEN");
2069 int col1Idx
= pQueryCol1Choice
->GetSelection();
2072 if (colInf
[col1Idx
].sqlDataType
== SQL_VARCHAR
||
2073 oper
== qryOpBEGINS
||
2074 oper
== qryOpCONTAINS
||
2078 if (pQueryCol2Choice
->GetSelection()) // Column name
2079 s
+= pQueryCol2Choice
->GetStringSelection();
2080 else // Column 2 is a "value"
2084 if (oper
== qryOpCONTAINS
)
2086 s
+= pQueryValue1Txt
->GetValue();
2087 if (oper
== qryOpCONTAINS
|| oper
== qryOpBEGINS
)
2093 if (oper
== qryOpBETWEEN
)
2098 s
+= pQueryValue2Txt
->GetValue();
2103 AppendToWhere((wxChar
*) (const wxChar
*) s
);
2105 } // CqueryDlg::ProcessAddBtn()
2108 void CqueryDlg::ProcessCountBtn()
2110 if (!ValidateWhereClause())
2113 if (dbTable
== 0) // wxDbTable object needs to be created and opened
2115 if (!(dbTable
= new wxDbTable(pDB
, masterTableName
, 0, wxT(""), !wxDB_QUERY_ONLY
, DbConnectInf
.defaultDir
)))
2117 wxMessageBox(wxT("Memory allocation failed creating a wxDbTable object."),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
2120 if (!dbTable
->Open())
2123 tStr
= wxT("ODBC error during Open()\n\n");
2124 tStr
+= GetExtendedDBErrorMsg(dbTable
->GetDb(),__FILE__
,__LINE__
);
2125 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
2130 // Count() with WHERE clause
2133 whereStr
= pQuerySqlWhereMtxt
->GetValue();
2134 dbTable
->SetWhereClause(whereStr
.c_str());
2136 ULONG whereCnt
= dbTable
->Count();
2138 // Count() of all records in the table
2139 dbTable
->SetWhereClause(wxT(""));
2140 ULONG totalCnt
= dbTable
->Count();
2142 if (whereCnt
> 0 || totalCnt
== 0)
2145 tStr
.Printf(wxT("%lu of %lu records match the query criteria."),whereCnt
,totalCnt
);
2146 wxMessageBox(tStr
,wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
2151 tStr
.Printf(wxT("%lu of %lu records match the query criteria.\n\nEither the criteria entered produced a result set\nwith no records, or there was a syntactical error\nin the clause you entered.\n\nPress the details button to see if any database errors were reported."),whereCnt
,totalCnt
);
2152 wxMessageBox(tStr
,wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
2155 // After a wxMessageBox, the focus does not necessarily return to the
2156 // window which was the focus when the message box popped up, so return
2157 // focus to the Query dialog for certain
2160 } // CqueryDlg::ProcessCountBtn()
2163 bool CqueryDlg::ValidateWhereClause()
2165 wxString where
= pQuerySqlWhereMtxt
->GetValue();
2167 if (where
.Freq(wxT('(')) != where
.Freq(wxT(')')))
2169 wxMessageBox(wxT("There are mismatched parenthesis in the constructed where clause"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
2172 // After a wxMessageBox, the focus does not necessarily return to the
2173 // window which was the focus when the message box popped up, so return
2174 // focus to the Query dialog for certain
2179 } // CqueryDlg::ValidateWhereClause()
2185 TEST CODE FOR TESTING THE wxDbCreateDataSource() FUNCTION
2188 result = wxDbCreateDataSource(wxT("Microsoft Access Driver (*.mdb)"),wxT("GLT-TEST2"),wxT("GLT-Descrip"),FALSE,wxT(""),this);
2191 // check for errors caused by ConfigDSN based functions
2194 wxChar errMsg[500+1];
2195 errMsg[0] = wxT('\0');
2197 SQLInstallerError(1,&retcode,errMsg,500,&cb);
2199 wxMessageBox(wxT("FAILED creating data source"),wxT("FAILED"));
2202 wxMessageBox(wxT("SUCCEEDED creating data source"),wxT("SUCCESS"));