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 const char *GetExtendedDBErrorMsg(wxDb
*pDb
, char *ErrFile
, int ErrLine
)
64 if (ErrFile
|| ErrLine
)
68 msg
+= wxT(" Line: ");
69 tStr
.Printf(wxT("%d"),ErrLine
);
74 msg
.Append (wxT("\nODBC errors:\n"));
77 // Display errors for this connection
79 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
81 if (pDb
->errorList
[i
])
83 msg
.Append(pDb
->errorList
[i
]);
84 if (wxStrcmp(pDb
->errorList
[i
],wxT("")) != 0)
85 msg
.Append(wxT("\n"));
86 // Clear the errmsg buffer so the next error will not
87 // end up showing the previous error that have occurred
88 wxStrcpy(pDb
->errorList
[i
],wxT(""));
94 } // GetExtendedDBErrorMsg
97 bool DatabaseDemoApp::OnInit()
101 // Create the main frame window
102 DemoFrame
= new DatabaseDemoFrame(NULL
, wxT("wxWindows Database Demo"), wxPoint(50, 50), wxSize(537, 480));
105 DemoFrame
->SetIcon(wxICON(db
));
108 wxMenu
*file_menu
= new wxMenu
;
109 file_menu
->Append(FILE_CREATE
, wxT("&Create CONTACT table"));
110 file_menu
->Append(FILE_RECREATE_TABLE
, wxT("&Recreate CONTACT table"));
111 file_menu
->Append(FILE_RECREATE_INDEXES
, wxT("&Recreate CONTACT indexes"));
112 file_menu
->Append(FILE_EXIT
, wxT("E&xit"));
114 wxMenu
*edit_menu
= new wxMenu
;
115 edit_menu
->Append(EDIT_PARAMETERS
, wxT("&Parameters..."));
117 wxMenu
*about_menu
= new wxMenu
;
118 about_menu
->Append(ABOUT_DEMO
, wxT("&About"));
120 wxMenuBar
*menu_bar
= new wxMenuBar
;
121 menu_bar
->Append(file_menu
, wxT("&File"));
122 menu_bar
->Append(edit_menu
, wxT("&Edit"));
123 menu_bar
->Append(about_menu
, wxT("&About"));
124 DemoFrame
->SetMenuBar(menu_bar
);
126 params
.ODBCSource
[0] = 0;
127 params
.UserName
[0] = 0;
128 params
.Password
[0] = 0;
129 params
.DirPath
[0] = 0;
132 DemoFrame
->Show(TRUE
);
134 ReadParamFile(params
);
136 // Passing NULL for the SQL environment handle causes
137 // the wxDbConnectInf constructor to obtain a handle
140 // WARNING: Be certain that you do not free this handle
141 // directly with SQLFreeEnv(). Use either the
142 // method ::FreeHenv() or delete the DbConnectInf.
143 DbConnectInf
= new wxDbConnectInf(NULL
, params
.ODBCSource
, params
.UserName
,
144 params
.Password
, params
.DirPath
);
146 if (!DbConnectInf
|| !DbConnectInf
->GetHenv())
148 wxMessageBox(wxT("Unable to define data source connection info."), wxT("DB CONNECTION ERROR..."),wxOK
| wxICON_EXCLAMATION
);
152 READONLY_DB
= wxDbGetConnection(DbConnectInf
);
153 if (READONLY_DB
== 0)
155 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
);
156 DemoFrame
->BuildParameterDialog(NULL
);
158 wxMessageBox(wxT("Now exiting program.\n\nRestart program to try any new settings."),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
162 DemoFrame
->BuildEditorDialog();
165 DemoFrame
->Refresh();
168 } // DatabaseDemoApp::OnInit()
171 bool DatabaseDemoApp::ReadParamFile(Cparameters
¶ms
)
174 if ((paramFile
= fopen(PARAM_FILENAME
, wxT("r"))) == NULL
)
177 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."),PARAM_FILENAME
);
178 wxMessageBox(tStr
,wxT("File I/O Error..."),wxOK
| wxICON_EXCLAMATION
);
180 DemoFrame
->BuildParameterDialog(NULL
);
181 if ((paramFile
= fopen(PARAM_FILENAME
, wxT("r"))) == NULL
)
185 wxChar buffer
[1000+1];
186 fgets(buffer
, sizeof(params
.ODBCSource
), paramFile
);
187 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
188 wxStrcpy(params
.ODBCSource
,buffer
);
190 fgets(buffer
, sizeof(params
.UserName
), paramFile
);
191 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
192 wxStrcpy(params
.UserName
,buffer
);
194 fgets(buffer
, sizeof(params
.Password
), paramFile
);
195 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
196 wxStrcpy(params
.Password
,buffer
);
198 fgets(buffer
, sizeof(params
.DirPath
), paramFile
);
199 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
200 wxStrcpy(params
.DirPath
,buffer
);
205 } // DatabaseDemoApp::ReadParamFile()
208 bool DatabaseDemoApp::WriteParamFile(Cparameters
¶ms
)
211 if ((paramFile
= fopen(PARAM_FILENAME
, wxT("wt"))) == NULL
)
214 tStr
.Printf(wxT("Unable to write/overwrite '%s'."),PARAM_FILENAME
);
215 wxMessageBox(tStr
,wxT("File I/O Error..."),wxOK
| wxICON_EXCLAMATION
);
219 fputs(wxGetApp().params
.ODBCSource
, paramFile
);
220 fputc(wxT('\n'), paramFile
);
221 fputs(wxGetApp().params
.UserName
, paramFile
);
222 fputc(wxT('\n'), paramFile
);
223 fputs(wxGetApp().params
.Password
, paramFile
);
224 fputc(wxT('\n'), paramFile
);
225 fputs(wxGetApp().params
.DirPath
, paramFile
);
226 fputc(wxT('\n'), paramFile
);
230 } // DatabaseDemoApp::WriteParamFile()
233 void DatabaseDemoApp::CreateDataTable(bool recreate
)
237 Ok
= (wxMessageBox(wxT("Any data currently residing in the table will be erased.\n\nAre you sure?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
246 // Use a temporary instance of a new Ccontact table object
247 // for creating the table within the datasource.
248 Ccontact
*Contact
= new Ccontact();
253 wxMessageBox(wxT("Error allocating memory for 'Ccontact'object.\n\nTable was not created."),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
257 if (!Contact
->CreateTable(recreate
))
261 tStr
= wxT("Error creating CONTACTS table.\nTable was not created.\n\n");
262 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
263 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
268 if (!Contact
->CreateIndexes())
272 tStr
= wxT("Error creating CONTACTS indexes.\nIndexes will be unavailable.\n\n");
273 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
274 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
285 wxMessageBox(wxT("Table and index(es) were successfully created."),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
286 } // DatabaseDemoApp::CreateDataTable()
289 BEGIN_EVENT_TABLE(DatabaseDemoFrame
, wxFrame
)
290 EVT_MENU(FILE_CREATE
, DatabaseDemoFrame::OnCreate
)
291 EVT_MENU(FILE_RECREATE_TABLE
, DatabaseDemoFrame::OnRecreateTable
)
292 EVT_MENU(FILE_RECREATE_INDEXES
, DatabaseDemoFrame::OnRecreateIndexes
)
293 EVT_MENU(FILE_EXIT
, DatabaseDemoFrame::OnExit
)
294 EVT_MENU(EDIT_PARAMETERS
, DatabaseDemoFrame::OnEditParameters
)
295 EVT_MENU(ABOUT_DEMO
, DatabaseDemoFrame::OnAbout
)
296 EVT_CLOSE(DatabaseDemoFrame::OnCloseWindow
)
300 // DatabaseDemoFrame constructor
301 DatabaseDemoFrame::DatabaseDemoFrame(wxFrame
*frame
, const wxString
& title
,
302 const wxPoint
& pos
, const wxSize
& size
):
303 wxFrame(frame
, -1, title
, pos
, size
)
305 // Put any code in necessary for initializing the main frame here
308 } // DatabaseDemoFrame constructor
311 void DatabaseDemoFrame::OnCreate(wxCommandEvent
& event
)
313 wxGetApp().CreateDataTable(FALSE
);
314 } // DatabaseDemoFrame::OnCreate()
317 void DatabaseDemoFrame::OnRecreateTable(wxCommandEvent
& event
)
319 wxGetApp().CreateDataTable(TRUE
);
320 } // DatabaseDemoFrame::OnRecreate()
323 void DatabaseDemoFrame::OnRecreateIndexes(wxCommandEvent
& event
)
325 // Using a new connection to the database so as not to disturb
326 // the current cursors on the table in use in the editor dialog
327 Ccontact
*Contact
= new Ccontact();
332 wxMessageBox(wxT("Error allocating memory for 'Ccontact'object.\n\nTable could not be opened."),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
336 if (!Contact
->CreateIndexes())
340 tStr
= wxT("Error creating CONTACTS indexes.\nNew indexes will be unavailable.\n\n");
341 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
342 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
347 } // DatabaseDemoFrame::OnRecreateIndexes()
349 void DatabaseDemoFrame::OnExit(wxCommandEvent
& event
)
352 } // DatabaseDemoFrame::OnExit()
355 void DatabaseDemoFrame::OnEditParameters(wxCommandEvent
& event
)
357 if ((pEditorDlg
->mode
!= mCreate
) && (pEditorDlg
->mode
!= mEdit
))
358 BuildParameterDialog(this);
360 wxMessageBox(wxT("Cannot change database parameters while creating or editing a record"),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
361 } // DatabaseDemoFrame::OnEditParameters()
364 void DatabaseDemoFrame::OnAbout(wxCommandEvent
& event
)
366 wxMessageBox(wxT("wxWindows sample program for database classes\n\nContributed on 27 July 1998"),wxT("About..."),wxOK
| wxICON_INFORMATION
);
367 } // DatabaseDemoFrame::OnAbout()
370 // Put any additional checking necessary to make certain it is alright
371 // to close the program here that is not done elsewhere
372 void DatabaseDemoFrame::OnCloseWindow(wxCloseEvent
& event
)
375 if (pEditorDlg
&& pEditorDlg
->Close())
386 // This function will close all the connections to the database that have been
387 // previously cached.
388 wxDbCloseConnections();
390 // Deletion of the wxDbConnectInf instance must be the LAST thing done that
391 // has anything to do with the database. Deleting this before disconnecting,
392 // freeing/closing connections, etc will result in a crash!
393 delete wxGetApp().DbConnectInf
;
394 wxGetApp().DbConnectInf
= NULL
;
398 } // DatabaseDemoFrame::OnCloseWindow()
401 void DatabaseDemoFrame::BuildEditorDialog()
404 pEditorDlg
= new CeditorDlg(this);
407 pEditorDlg
->Initialize();
408 if (!pEditorDlg
->initialized
)
412 wxMessageBox(wxT("Unable to initialize the editor dialog for some reason"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
418 wxMessageBox(wxT("Unable to create the editor dialog for some reason"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
421 } // DatabaseDemoFrame::BuildEditorDialog()
424 void DatabaseDemoFrame::BuildParameterDialog(wxWindow
*parent
)
426 pParamDlg
= new CparameterDlg(parent
);
429 wxMessageBox(wxT("Unable to create the parameter dialog for some reason"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
430 } // DatabaseDemoFrame::BuildParameterDialog()
434 * Constructor note: If no wxDb object is passed in, a new connection to the database
435 * is created for this instance of Ccontact. This can be a slow process depending
436 * on the database engine being used, and some database engines have a limit on the
437 * number of connections (either hard limits, or license restricted) so care should
438 * be used to use as few connections as is necessary.
440 * IMPORTANT: Objects which share a wxDb pointer are ALL acted upon whenever a member
441 * function of pDb is called (i.e. CommitTrans() or RollbackTrans(), so if modifying
442 * or creating a table objects which use the same pDb, know that all the objects
443 * will be committed or rolled back when any of the objects has this function call made.
445 Ccontact::Ccontact (wxDb
*pwxDb
) : wxDbTable(pwxDb
? pwxDb
: wxDbGetConnection(wxGetApp().DbConnectInf
),
446 CONTACT_TABLE_NAME
, CONTACT_NO_COLS
, wxT(""),
447 !wxDB_QUERY_ONLY
, wxGetApp().DbConnectInf
->GetDefaultDir())
449 // This is used to represent whether the database connection should be released
450 // when this instance of the object is deleted. If using the same connection
451 // for multiple instance of database objects, then the connection should only be
452 // released when the last database instance using the connection is deleted
457 } // Ccontact Constructor
460 void Ccontact::Initialize()
469 JoinDate
.year
= 1980;
475 JoinDate
.fraction
= 0;
476 NativeLanguage
= langENGLISH
;
480 } // Ccontact::Initialize
483 Ccontact::~Ccontact()
487 if (!wxDbFreeConnection(GetDb()))
490 tStr
= wxT("Unable to Free the Ccontact data table handle\n\n");
491 tStr
+= GetExtendedDBErrorMsg(GetDb(),__FILE__
,__LINE__
);
492 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
495 } // Ccontract destructor
499 * Handles setting up all the connections for the interface from the wxDbTable
500 * functions to interface to the data structure used to store records in
501 * memory, and for all the column definitions that define the table structure
503 void Ccontact::SetupColumns()
505 // NOTE: Columns now are 8 character names, as that is all dBase can support. Longer
506 // names can be used for other database engines
507 SetColDefs ( 0,wxT("NAME"), DB_DATA_TYPE_VARCHAR
, Name
, SQL_C_CHAR
, sizeof(Name
), TRUE
, TRUE
); // Primary index
508 SetColDefs ( 1,wxT("ADDRESS1"), DB_DATA_TYPE_VARCHAR
, Addr1
, SQL_C_CHAR
, sizeof(Addr1
), FALSE
,TRUE
);
509 SetColDefs ( 2,wxT("ADDRESS2"), DB_DATA_TYPE_VARCHAR
, Addr2
, SQL_C_CHAR
, sizeof(Addr2
), FALSE
,TRUE
);
510 SetColDefs ( 3,wxT("CITY"), DB_DATA_TYPE_VARCHAR
, City
, SQL_C_CHAR
, sizeof(City
), FALSE
,TRUE
);
511 SetColDefs ( 4,wxT("STATE"), DB_DATA_TYPE_VARCHAR
, State
, SQL_C_CHAR
, sizeof(State
), FALSE
,TRUE
);
512 SetColDefs ( 5,wxT("POSTCODE"), DB_DATA_TYPE_VARCHAR
, PostalCode
, SQL_C_CHAR
, sizeof(PostalCode
), FALSE
,TRUE
);
513 SetColDefs ( 6,wxT("COUNTRY"), DB_DATA_TYPE_VARCHAR
, Country
, SQL_C_CHAR
, sizeof(Country
), FALSE
,TRUE
);
514 SetColDefs ( 7,wxT("JOINDATE"), DB_DATA_TYPE_DATE
, &JoinDate
, SQL_C_TIMESTAMP
, sizeof(JoinDate
), FALSE
,TRUE
);
515 SetColDefs ( 8,wxT("IS_DEV"), DB_DATA_TYPE_INTEGER
, &IsDeveloper
, SQL_C_BOOLEAN(IsDeveloper
), sizeof(IsDeveloper
), FALSE
,TRUE
);
516 SetColDefs ( 9,wxT("CONTRIBS"), DB_DATA_TYPE_INTEGER
, &Contributions
, SQL_C_USHORT
, sizeof(Contributions
), FALSE
,TRUE
);
517 SetColDefs (10,wxT("LINE_CNT"), DB_DATA_TYPE_INTEGER
, &LinesOfCode
, SQL_C_ULONG
, sizeof(LinesOfCode
), FALSE
,TRUE
);
518 SetColDefs (11,wxT("LANGUAGE"), DB_DATA_TYPE_INTEGER
, &NativeLanguage
, SQL_C_ENUM
, sizeof(NativeLanguage
), FALSE
,TRUE
);
519 } // Ccontact::SetupColumns
522 bool Ccontact::CreateIndexes(void)
524 // This index could easily be accomplished with an "orderBy" clause,
525 // but is done to show how to construct a non-primary index.
527 wxDbIdxDef idxDef
[2];
531 wxStrcpy(idxDef
[0].ColName
, "IS_DEV");
532 idxDef
[0].Ascending
= TRUE
;
534 wxStrcpy(idxDef
[1].ColName
, "NAME");
535 idxDef
[1].Ascending
= TRUE
;
537 indexName
= GetTableName();
538 indexName
+= "_IDX1";
539 Ok
= CreateIndex(indexName
.c_str(), TRUE
, 2, idxDef
);
542 } // Ccontact::CreateIndexes()
546 * Having a function to do a query on the primary key (and possibly others) is
547 * very efficient and tighter coding so that it is available where ever the object
548 * is. Great for use with multiple tables when not using views or outer joins
550 bool Ccontact::FetchByName(const wxString
&name
)
552 whereStr
.Printf(wxT("NAME = '%s'"),name
.c_str());
553 SetWhereClause(whereStr
.c_str());
554 SetOrderByClause(wxT(""));
562 } // Ccontact::FetchByName()
567 * ************* DIALOGS ***************
572 /* CeditorDlg constructor
574 * Creates the dialog used for creating/editing/deleting/copying a Ccontact object.
575 * This dialog actually is drawn in the main frame of the program
577 * An instance of Ccontact is created - "Contact" - which is used to hold the Ccontact
578 * object that is currently being worked with.
581 BEGIN_EVENT_TABLE(CeditorDlg
, wxPanel
)
582 EVT_BUTTON(-1, CeditorDlg::OnButton
)
583 EVT_CLOSE(CeditorDlg::OnCloseWindow
)
586 CeditorDlg::CeditorDlg(wxWindow
*parent
) : wxPanel (parent
, 0, 0, 537, 480)
588 // Since the ::OnCommand() function is overridden, this prevents the widget
589 // detection in ::OnCommand() until all widgets have been initialized to prevent
590 // uninitialized pointers from crashing the program
591 widgetPtrsSet
= FALSE
;
598 } // CeditorDlg constructor
601 void CeditorDlg::OnCloseWindow(wxCloseEvent
& event
)
604 if ((mode
!= mCreate
) && (mode
!= mEdit
))
615 wxMessageBox(wxT("Must finish processing the current record being created/modified before exiting"),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
618 } // CeditorDlg::OnCloseWindow()
621 void CeditorDlg::OnButton(wxCommandEvent
&event
)
623 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
624 OnCommand( *win
, event
);
625 } // CeditorDlg::OnButton()
628 void CeditorDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
632 widgetName
= win
.GetName();
637 if (widgetName
== pCreateBtn
->GetName())
639 Contact
->Initialize();
642 pNameTxt
->SetValue(wxT(""));
643 pNameTxt
->SetFocus();
647 if (widgetName
== pEditBtn
->GetName())
649 saveName
= Contact
->Name
;
651 pNameTxt
->SetFocus();
655 if (widgetName
== pCopyBtn
->GetName())
658 pNameTxt
->SetValue(wxT(""));
659 pNameTxt
->SetFocus();
664 if (widgetName
== pDeleteBtn
->GetName())
666 bool Ok
= (wxMessageBox(wxT("Are you sure?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
671 if (Ok
&& Contact
->Delete())
673 // NOTE: Deletions are not finalized until a CommitTrans() is performed.
674 // If the commit were not performed, the program will continue to
675 // show the table contents as if they were deleted until this instance
676 // of Ccontact is deleted. If the Commit wasn't performed, the
677 // database will automatically Rollback the changes when the database
678 // connection is terminated
679 Contact
->GetDb()->CommitTrans();
681 // Try to get the row that followed the just deleted row in the orderBy sequence
684 // There was now row (in sequence) after the just deleted row, so get the
685 // row which preceded the just deleted row
688 // There are now no rows remaining, so clear the dialog widgets
689 Contact
->Initialize();
693 SetMode(mode
); // force reset of button enable/disable
697 Contact
->GetDb()->RollbackTrans();
703 if (widgetName
== pSaveBtn
->GetName())
709 if (widgetName
== pCancelBtn
->GetName())
711 bool Ok
= (wxMessageBox(wxT("Are you sure?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
716 if (saveName
.IsEmpty())
718 Contact
->Initialize();
725 // Requery previous record
726 if (Contact
->FetchByName(saveName
))
734 // Previous record not available, retrieve first record in table
735 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
737 Contact
->whereStr
= wxT("NAME = (SELECT MIN(NAME) FROM ");
738 Contact
->whereStr
+= Contact
->GetTableName();
739 Contact
->whereStr
+= wxT(")");
740 Contact
->SetWhereClause(Contact
->whereStr
.c_str());
743 Contact
->SetWhereClause(wxT(""));
745 if (!Contact
->Query())
748 tStr
= wxT("ODBC error during Query()\n\n");
749 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
750 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
754 if (Contact
->GetNext()) // Successfully read first record
760 // No contacts are available, clear dialog
761 Contact
->Initialize();
767 if (widgetName
== pPrevBtn
->GetName())
774 if (widgetName
== pNextBtn
->GetName())
781 if (widgetName
== pQueryBtn
->GetName())
783 // Display the query dialog box
784 wxChar qryWhere
[DB_MAX_WHERE_CLAUSE_LEN
+1];
785 wxStrcpy(qryWhere
, (const wxChar
*) Contact
->qryWhereStr
);
786 wxChar
*tblName
[] = {(wxChar
*)CONTACT_TABLE_NAME
, 0};
787 new CqueryDlg(GetParent(), Contact
->GetDb(), tblName
, qryWhere
);
789 // Query the first record in the new record set and
790 // display it, if the query string has changed.
791 if (wxStrcmp(qryWhere
, (const wxChar
*) Contact
->qryWhereStr
))
793 Contact
->whereStr
.Empty();
794 Contact
->SetOrderByClause("NAME");
796 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
798 Contact
->whereStr
= wxT("NAME = (SELECT MIN(NAME) FROM ");
799 Contact
->whereStr
+= CONTACT_TABLE_NAME
;
802 // Append the query where string (if there is one)
803 Contact
->qryWhereStr
= qryWhere
;
804 if (wxStrlen(qryWhere
))
806 Contact
->whereStr
+= wxT(" WHERE ");
807 Contact
->whereStr
+= Contact
->qryWhereStr
;
809 // Close the expression with a right paren
810 Contact
->whereStr
+= wxT(")");
812 Contact
->SetWhereClause(Contact
->whereStr
.c_str());
813 if (!Contact
->Query())
816 tStr
= wxT("ODBC error during Query()\n\n");
817 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
818 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
821 // Display the first record from the query set
822 if (!Contact
->GetNext())
823 Contact
->Initialize();
827 // Enable/Disable the reset button
828 pResetBtn
->Enable(!Contact
->qryWhereStr
.IsEmpty());
834 if (widgetName
== pResetBtn
->GetName())
836 // Clear the additional where criteria established by the query feature
837 Contact
->qryWhereStr
= wxT("");
838 Contact
->SetOrderByClause(wxT("NAME"));
840 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
842 Contact
->whereStr
= wxT("NAME = (SELECT MIN(NAME) FROM ");
843 Contact
->whereStr
+= CONTACT_TABLE_NAME
;
844 Contact
->whereStr
+= wxT(")");
847 Contact
->SetWhereClause(Contact
->whereStr
.c_str());
848 if (!Contact
->Query())
851 tStr
= wxT("ODBC error during Query()\n\n");
852 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
853 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
856 if (!Contact
->GetNext())
857 Contact
->Initialize();
859 pResetBtn
->Enable(FALSE
);
865 if (widgetName
== pNameListBtn
->GetName())
867 new ClookUpDlg(/* wxWindow *parent */ this,
868 /* wxChar *windowTitle */ wxT("Select contact name"),
869 /* wxChar *tableName */ (wxChar
*) CONTACT_TABLE_NAME
,
870 /* wxChar *dispCol1 */ wxT("NAME"),
871 /* wxChar *dispCol2 */ wxT("JOINDATE"),
872 /* wxChar *where */ wxT(""),
873 /* wxChar *orderBy */ wxT("NAME"),
874 /* wxDb *pDb */ wxGetApp().READONLY_DB
,
875 /* const wxString &defDir */ wxGetApp().DbConnectInf
->GetDefaultDir(),
876 /* bool distinctValues */ TRUE
);
878 if (ListDB_Selection
&& wxStrlen(ListDB_Selection
))
880 wxString w
= wxT("NAME = '");
881 w
+= ListDB_Selection
;
888 } // CeditorDlg::OnCommand()
891 bool CeditorDlg::Initialize()
893 // Create the data structure and a new database connection.
894 // (As there is not a pDb being passed in the constructor, a new database
895 // connection is created)
896 Contact
= new Ccontact();
900 wxMessageBox(wxT("Unable to instantiate an instance of Ccontact"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
904 // Check if the table exists or not. If it doesn't, ask the user if they want to
905 // create the table. Continue trying to create the table until it exists, or user aborts
906 while (!Contact
->GetDb()->TableExists((wxChar
*)CONTACT_TABLE_NAME
,
907 wxGetApp().DbConnectInf
->GetUserID(),
908 wxGetApp().DbConnectInf
->GetDefaultDir()))
911 tStr
.Printf(wxT("Unable to open the table '%s'.\n\nTable may need to be created...?\n\n"),CONTACT_TABLE_NAME
);
912 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
913 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
915 bool createTable
= (wxMessageBox(wxT("Do you wish to try to create/clear the CONTACTS table?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
923 wxGetApp().CreateDataTable(TRUE
);
926 // Tables must be "opened" before anything other than creating/deleting table can be done
927 if (!Contact
->Open())
929 // Table does exist, or there was some problem opening it. Currently this should
930 // never fail, except in the case of the table not exisiting or the current
931 // user has insufficent privileges to access the table
933 // This code is experimenting with a new function that will hopefully be available
934 // in the 2.4 release. This check will determine whether the open failing was due
935 // to the table not existing, or the users privileges being insufficient to
937 if (!Contact
->GetDb()->TablePrivileges(CONTACT_TABLE_NAME
,wxT("SELECT"),Contact
->GetDb()->GetUsername(),Contact
->GetDb()->GetUsername(),DbConnectInf
->GetDefaultDir()))
940 tStr
.Printf(wxT("Unable to open the table '%s'.\n\n"),CONTACT_TABLE_NAME
);
941 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
942 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
946 if (Contact
->GetDb()->TableExists(CONTACT_TABLE_NAME
, Contact
->GetDb()->GetUsername(),
947 wxGetApp().DbConnectInf
->GetDefaultDir()))
950 tStr
.Printf(wxT("Unable to open the table '%s'.\n\n"),CONTACT_TABLE_NAME
);
951 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
952 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
960 (void)new wxStaticBox(this, EDITOR_DIALOG_FN_GROUP
, wxT(""), wxPoint(15, 1), wxSize(497, 69), 0, wxT("FunctionGrp"));
961 (void)new wxStaticBox(this, EDITOR_DIALOG_SEARCH_GROUP
, wxT(""), wxPoint(417, 1), wxSize(95, 242), 0, wxT("SearchGrp"));
963 pCreateBtn
= new wxButton(this, EDITOR_DIALOG_CREATE
, wxT("&Create"), wxPoint( 25, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("CreateBtn"));
964 pEditBtn
= new wxButton(this, EDITOR_DIALOG_EDIT
, wxT("&Edit"), wxPoint(102, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("EditBtn"));
965 pDeleteBtn
= new wxButton(this, EDITOR_DIALOG_DELETE
, wxT("&Delete"), wxPoint(179, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("DeleteBtn"));
966 pCopyBtn
= new wxButton(this, EDITOR_DIALOG_COPY
, wxT("Cop&y"), wxPoint(256, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("CopyBtn"));
967 pSaveBtn
= new wxButton(this, EDITOR_DIALOG_SAVE
, wxT("&Save"), wxPoint(333, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("SaveBtn"));
968 pCancelBtn
= new wxButton(this, EDITOR_DIALOG_CANCEL
, wxT("C&ancel"), wxPoint(430, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("CancelBtn"));
969 pPrevBtn
= new wxButton(this, EDITOR_DIALOG_PREV
, wxT("<< &Prev"), wxPoint(430, 81), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("PrevBtn"));
970 pNextBtn
= new wxButton(this, EDITOR_DIALOG_NEXT
, wxT("&Next >>"), wxPoint(430, 121), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("NextBtn"));
971 pQueryBtn
= new wxButton(this, EDITOR_DIALOG_QUERY
, wxT("&Query"), wxPoint(430, 161), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("QueryBtn"));
972 pResetBtn
= new wxButton(this, EDITOR_DIALOG_RESET
, wxT("&Reset"), wxPoint(430, 200), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("ResetBtn"));
973 pNameMsg
= new wxStaticText(this, EDITOR_DIALOG_NAME_MSG
, wxT("Name:"), wxPoint( 17, 80), wxSize( -1, -1), 0, wxT("NameMsg"));
974 pNameTxt
= new wxTextCtrl(this, EDITOR_DIALOG_NAME_TEXT
, wxT(""), wxPoint( 17, 97), wxSize(308, 25), 0, wxDefaultValidator
, wxT("NameTxt"));
975 pNameListBtn
= new wxButton(this, EDITOR_DIALOG_LOOKUP
, wxT("&Lookup"), wxPoint(333, 97), wxSize( 70, 24), 0, wxDefaultValidator
, wxT("LookupBtn"));
976 pAddress1Msg
= new wxStaticText(this, EDITOR_DIALOG_ADDRESS1_MSG
, wxT("Address:"), wxPoint( 17, 130), wxSize( -1, -1), 0, wxT("Address1Msg"));
977 pAddress1Txt
= new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT
, wxT(""), wxPoint( 17, 147), wxSize(308, 25), 0, wxDefaultValidator
, wxT("Address1Txt"));
978 pAddress2Msg
= new wxStaticText(this, EDITOR_DIALOG_ADDRESS2_MSG
, wxT("Address:"), wxPoint( 17, 180), wxSize( -1, -1), 0, wxT("Address2Msg"));
979 pAddress2Txt
= new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT
, wxT(""), wxPoint( 17, 197), wxSize(308, 25), 0, wxDefaultValidator
, wxT("Address2Txt"));
980 pCityMsg
= new wxStaticText(this, EDITOR_DIALOG_CITY_MSG
, wxT("City:"), wxPoint( 17, 230), wxSize( -1, -1), 0, wxT("CityMsg"));
981 pCityTxt
= new wxTextCtrl(this, EDITOR_DIALOG_CITY_TEXT
, wxT(""), wxPoint( 17, 247), wxSize(225, 25), 0, wxDefaultValidator
, wxT("CityTxt"));
982 pStateMsg
= new wxStaticText(this, EDITOR_DIALOG_STATE_MSG
, wxT("State:"), wxPoint(250, 230), wxSize( -1, -1), 0, wxT("StateMsg"));
983 pStateTxt
= new wxTextCtrl(this, EDITOR_DIALOG_STATE_TEXT
, wxT(""), wxPoint(250, 247), wxSize(153, 25), 0, wxDefaultValidator
, wxT("StateTxt"));
984 pCountryMsg
= new wxStaticText(this, EDITOR_DIALOG_COUNTRY_MSG
, wxT("Country:"), wxPoint( 17, 280), wxSize( -1, -1), 0, wxT("CountryMsg"));
985 pCountryTxt
= new wxTextCtrl(this, EDITOR_DIALOG_COUNTRY_TEXT
, wxT(""), wxPoint( 17, 297), wxSize(225, 25), 0, wxDefaultValidator
, wxT("CountryTxt"));
986 pPostalCodeMsg
= new wxStaticText(this, EDITOR_DIALOG_POSTAL_MSG
, wxT("Postal Code:"),wxPoint(250, 280), wxSize( -1, -1), 0, wxT("PostalCodeMsg"));
987 pPostalCodeTxt
= new wxTextCtrl(this, EDITOR_DIALOG_POSTAL_TEXT
, wxT(""), wxPoint(250, 297), wxSize(153, 25), 0, wxDefaultValidator
, wxT("PostalCodeTxt"));
989 wxString choice_strings
[5];
990 choice_strings
[0] = wxT("English");
991 choice_strings
[1] = wxT("French");
992 choice_strings
[2] = wxT("German");
993 choice_strings
[3] = wxT("Spanish");
994 choice_strings
[4] = wxT("Other");
996 pNativeLangChoice
= new wxChoice(this, EDITOR_DIALOG_LANG_CHOICE
, wxPoint( 17, 346), wxSize(277, -1), 5, choice_strings
);
997 pNativeLangMsg
= new wxStaticText(this, EDITOR_DIALOG_LANG_MSG
, wxT("Native language:"), wxPoint( 17, 330), wxSize( -1, -1), 0, wxT("NativeLangMsg"));
999 wxString radio_strings
[2];
1000 radio_strings
[0] = wxT("No");
1001 radio_strings
[1] = wxT("Yes");
1002 pDeveloperRadio
= new wxRadioBox(this,EDITOR_DIALOG_DEVELOPER
, wxT("Developer:"), wxPoint(303, 330), wxSize( -1, -1), 2, radio_strings
, 2, wxHORIZONTAL
);
1003 pJoinDateMsg
= new wxStaticText(this, EDITOR_DIALOG_JOIN_MSG
, wxT("Date joined:"), wxPoint( 17, 380), wxSize( -1, -1), 0, wxT("JoinDateMsg"));
1004 pJoinDateTxt
= new wxTextCtrl(this, EDITOR_DIALOG_JOIN_TEXT
, wxT(""), wxPoint( 17, 397), wxSize(150, 25), 0, wxDefaultValidator
, wxT("JoinDateTxt"));
1005 pContribMsg
= new wxStaticText(this, EDITOR_DIALOG_CONTRIB_MSG
,wxT("Contributions:"), wxPoint(175, 380), wxSize( -1, -1), 0, wxT("ContribMsg"));
1006 pContribTxt
= new wxTextCtrl(this, EDITOR_DIALOG_CONTRIB_TEXT
, wxT(""), wxPoint(175, 397), wxSize(120, 25), 0, wxDefaultValidator
, wxT("ContribTxt"));
1007 pLinesMsg
= new wxStaticText(this, EDITOR_DIALOG_LINES_MSG
, wxT("Lines of code:"), wxPoint(303, 380), wxSize( -1, -1), 0, wxT("LinesMsg"));
1008 pLinesTxt
= new wxTextCtrl(this, EDITOR_DIALOG_LINES_TEXT
, wxT(""), wxPoint(303, 397), wxSize(100, 25), 0, wxDefaultValidator
, wxT("LinesTxt"));
1010 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
1011 // handle all widget processing
1012 widgetPtrsSet
= TRUE
;
1014 // Setup the orderBy and where clauses to return back a single record as the result set,
1015 // as there will only be one record being shown on the dialog at a time, this optimizes
1016 // network traffic by only returning a one row result
1018 Contact
->SetOrderByClause(wxT("NAME")); // field name to sort by
1020 // The wxString "whereStr" is not a member of the wxDbTable object, it is a member variable
1021 // specifically in the Ccontact class. It is used here for simpler construction of a varying
1022 // length string, and then after the string is built, the wxDbTable member variable "where" is
1023 // assigned the pointer to the constructed string.
1025 // The constructed where clause below has a sub-query within it "SELECT MIN(NAME) FROM %s"
1026 // to achieve a single row (in this case the first name in alphabetical order).
1028 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1030 Contact
->whereStr
.Printf(wxT("NAME = (SELECT MIN(NAME) FROM %s)"),Contact
->GetTableName().c_str());
1031 // NOTE: (const wxChar*) returns a pointer which may not be valid later, so this is short term use only
1032 Contact
->SetWhereClause(Contact
->whereStr
);
1035 Contact
->SetWhereClause(wxT(""));
1037 // Perform the Query to get the result set.
1038 // NOTE: If there are no rows returned, that is a valid result, so Query() would return TRUE.
1039 // Only if there is a database error will Query() come back as FALSE
1040 if (!Contact
->Query())
1043 tStr
= wxT("ODBC error during Query()\n\n");
1044 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1045 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1046 // GetParent()->Close();
1050 // Since Query succeeded, now get the row that was returned
1051 if (!Contact
->GetNext())
1052 // If the GetNext() failed at this point, then there are no rows to retrieve,
1053 // so clear the values in the members of "Contact" so that PutData() blanks the
1054 // widgets on the dialog
1055 Contact
->Initialize();
1064 } // CeditorDlg::Initialize()
1067 void CeditorDlg::FieldsEditable()
1069 pNameTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1070 pAddress1Txt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1071 pAddress2Txt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1072 pCityTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1073 pStateTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1074 pPostalCodeTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1075 pCountryTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1077 pJoinDateTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1078 pContribTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1079 pLinesTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1080 pNativeLangChoice
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1081 pDeveloperRadio
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1083 } // CeditorDlg::FieldsEditable()
1086 void CeditorDlg::SetMode(enum DialogModes m
)
1107 pCreateBtn
->Enable( !edit
);
1108 pEditBtn
->Enable( !edit
&& (wxStrcmp(Contact
->Name
,wxT(""))!=0) );
1109 pDeleteBtn
->Enable( !edit
&& (wxStrcmp(Contact
->Name
,wxT(""))!=0) );
1110 pCopyBtn
->Enable( !edit
&& (wxStrcmp(Contact
->Name
,wxT(""))!=0) );
1111 pSaveBtn
->Enable( edit
);
1112 pCancelBtn
->Enable( edit
);
1113 pPrevBtn
->Enable( !edit
);
1114 pNextBtn
->Enable( !edit
);
1115 pQueryBtn
->Enable( !edit
);
1116 pResetBtn
->Enable( !edit
&& !Contact
->qryWhereStr
.IsEmpty() );
1117 pNameListBtn
->Enable( !edit
);
1121 } // CeditorDlg::SetMode()
1124 bool CeditorDlg::PutData()
1128 pNameTxt
->SetValue(Contact
->Name
);
1129 pAddress1Txt
->SetValue(Contact
->Addr1
);
1130 pAddress2Txt
->SetValue(Contact
->Addr2
);
1131 pCityTxt
->SetValue(Contact
->City
);
1132 pStateTxt
->SetValue(Contact
->State
);
1133 pCountryTxt
->SetValue(Contact
->Country
);
1134 pPostalCodeTxt
->SetValue(Contact
->PostalCode
);
1136 tStr
.Printf(wxT("%d/%d/%d"),Contact
->JoinDate
.month
,Contact
->JoinDate
.day
,Contact
->JoinDate
.year
);
1137 pJoinDateTxt
->SetValue(tStr
);
1139 tStr
.Printf(wxT("%d"),Contact
->Contributions
);
1140 pContribTxt
->SetValue(tStr
);
1142 tStr
.Printf(wxT("%lu"),Contact
->LinesOfCode
);
1143 pLinesTxt
->SetValue(tStr
);
1145 pNativeLangChoice
->SetSelection(Contact
->NativeLanguage
);
1147 pDeveloperRadio
->SetSelection(Contact
->IsDeveloper
);
1150 } // Ceditor::PutData()
1154 * Reads the data out of all the widgets on the dialog. Some data evaluation is done
1155 * to ensure that there is a name entered and that the date field is valid.
1157 * A return value of TRUE means that valid data was retrieved from the dialog, otherwise
1158 * invalid data was found (and a message was displayed telling the user what to fix), and
1159 * the data was not placed into the appropraite fields of Ccontact
1161 bool CeditorDlg::GetData()
1163 // Validate that the data currently entered into the widgets is valid data
1166 tStr
= pNameTxt
->GetValue();
1167 if (!wxStrcmp((const wxChar
*) tStr
,wxT("")))
1169 wxMessageBox(wxT("A name is required for entry into the contact table"),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
1173 bool invalid
= FALSE
;
1177 tStr
= pJoinDateTxt
->GetValue();
1178 if (tStr
.Freq(wxT('/')) != 2)
1181 // Find the month, day, and year tokens
1184 first
= tStr
.First(wxT('/'));
1185 second
= tStr
.Last(wxT('/'));
1187 mm
= atoi(tStr
.SubString(0,first
));
1188 dd
= atoi(tStr
.SubString(first
+1,second
));
1189 yyyy
= atoi(tStr
.SubString(second
+1,tStr
.Length()-1));
1191 invalid
= !(mm
&& dd
&& yyyy
);
1194 // Force Year 2000 compliance
1195 if (!invalid
&& (yyyy
< 1000))
1198 // Check the token ranges for validity
1203 else if ((mm
< 1) || (mm
> 12))
1211 int days
[12] = {31,28,31,30,31,30,
1213 if (dd
> days
[mm
-1])
1216 if ((dd
== 29) && (mm
== 2))
1218 if (((yyyy
% 4) == 0) && (((yyyy
% 100) != 0) || ((yyyy
% 400) == 0)))
1228 Contact
->JoinDate
.month
= mm
;
1229 Contact
->JoinDate
.day
= dd
;
1230 Contact
->JoinDate
.year
= yyyy
;
1234 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
);
1238 tStr
= pNameTxt
->GetValue();
1239 wxStrcpy(Contact
->Name
,(const wxChar
*) tStr
);
1240 wxStrcpy(Contact
->Addr1
,pAddress1Txt
->GetValue());
1241 wxStrcpy(Contact
->Addr2
,pAddress2Txt
->GetValue());
1242 wxStrcpy(Contact
->City
,pCityTxt
->GetValue());
1243 wxStrcpy(Contact
->State
,pStateTxt
->GetValue());
1244 wxStrcpy(Contact
->Country
,pCountryTxt
->GetValue());
1245 wxStrcpy(Contact
->PostalCode
,pPostalCodeTxt
->GetValue());
1247 Contact
->Contributions
= atoi(pContribTxt
->GetValue());
1248 Contact
->LinesOfCode
= atol(pLinesTxt
->GetValue());
1250 Contact
->NativeLanguage
= (enum Language
) pNativeLangChoice
->GetSelection();
1251 Contact
->IsDeveloper
= pDeveloperRadio
->GetSelection() > 0;
1254 } // CeditorDlg::GetData()
1258 * Retrieve data from the dialog, verify the validity of the data, and if it is valid,
1259 * try to insert/update the data to the table based on the current 'mode' the dialog
1262 * A return value of TRUE means the insert/update was completed successfully, a return
1263 * value of FALSE means that Save() failed. If returning FALSE, then this function
1264 * has displayed a detailed error message for the user.
1266 bool CeditorDlg::Save()
1268 bool failed
= FALSE
;
1270 // Read the data in the widgets of the dialog to get the user's data
1274 // Perform any other required validations necessary before saving
1277 wxBeginBusyCursor();
1279 if (mode
== mCreate
)
1281 RETCODE result
= Contact
->Insert();
1283 failed
= (result
!= DB_SUCCESS
);
1286 // Some errors may be expected, like a duplicate key, so handle those instances with
1287 // specific error messages.
1288 if (result
== DB_ERR_INTEGRITY_CONSTRAINT_VIOL
)
1291 tStr
= wxT("A duplicate key value already exists in the table.\nUnable to save record\n\n");
1292 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1293 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1297 // Some other unexpexted error occurred
1299 tStr
= wxT("Database insert failed\n\n");
1300 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1301 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1305 else // mode == mEdit
1307 Contact
->whereStr
.Printf("NAME = '%s'",saveName
.c_str());
1308 if (!Contact
->UpdateWhere(Contact
->whereStr
))
1311 tStr
= wxT("Database update failed\n\n");
1312 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1313 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1320 Contact
->GetDb()->CommitTrans();
1321 SetMode(mView
); // Sets the dialog mode back to viewing after save is successful
1324 Contact
->GetDb()->RollbackTrans();
1330 } // CeditorDlg::Save()
1334 * Where this program is only showing a single row at a time in the dialog,
1335 * a special where clause must be built to find just the single row which,
1336 * in sequence, would follow the currently displayed row.
1338 bool CeditorDlg::GetNextRec()
1342 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1344 w
= wxT("NAME = (SELECT MIN(NAME) FROM ");
1345 w
+= Contact
->GetTableName();
1346 w
+= wxT(" WHERE NAME > '");
1349 w
= wxT("(NAME > '");
1354 // If a query where string is currently set, append that criteria
1355 if (!Contact
->qryWhereStr
.IsEmpty())
1358 w
+= Contact
->qryWhereStr
;
1365 } // CeditorDlg::GetNextRec()
1369 * Where this program is only showing a single row at a time in the dialog,
1370 * a special where clause must be built to find just the single row which,
1371 * in sequence, would precede the currently displayed row.
1373 bool CeditorDlg::GetPrevRec()
1377 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1379 w
= wxT("NAME = (SELECT MAX(NAME) FROM ");
1380 w
+= Contact
->GetTableName();
1381 w
+= wxT(" WHERE NAME < '");
1384 w
= wxT("(NAME < '");
1389 // If a query where string is currently set, append that criteria
1390 if (!Contact
->qryWhereStr
.IsEmpty())
1393 w
+= Contact
->qryWhereStr
;
1401 } // CeditorDlg::GetPrevRec()
1405 * This function is here to avoid duplicating this same code in both the
1406 * GetPrevRec() and GetNextRec() functions
1408 bool CeditorDlg::GetRec(const wxString
&whereStr
)
1410 Contact
->SetWhereClause(whereStr
);
1411 Contact
->SetOrderByClause(wxT("NAME"));
1413 if (!Contact
->Query())
1416 tStr
= wxT("ODBC error during Query()\n\n");
1417 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1418 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1423 if (Contact
->GetNext())
1430 } // CeditorDlg::GetRec()
1435 * CparameterDlg constructor
1438 BEGIN_EVENT_TABLE(CparameterDlg
, wxDialog
)
1439 EVT_BUTTON(PARAMETER_DIALOG_SAVE
, CparameterDlg::OnButton
)
1440 EVT_BUTTON(PARAMETER_DIALOG_CANCEL
, CparameterDlg::OnButton
)
1441 EVT_CLOSE(CparameterDlg::OnCloseWindow
)
1444 CparameterDlg::CparameterDlg(wxWindow
*parent
) : wxDialog (parent
, PARAMETER_DIALOG
, wxT("ODBC parameter settings"), wxPoint(-1, -1), wxSize(400, 325))
1446 // Since the ::OnCommand() function is overridden, this prevents the widget
1447 // detection in ::OnCommand() until all widgets have been initialized to prevent
1448 // uninitialized pointers from crashing the program
1449 widgetPtrsSet
= FALSE
;
1451 pParamODBCSourceMsg
= new wxStaticText(this, PARAMETER_DIALOG_SOURCE_MSG
, wxT("ODBC data sources:"), wxPoint( 10, 10), wxSize( -1, -1), 0, wxT("ParamODBCSourceMsg"));
1452 pParamODBCSourceList
= new wxListBox(this, PARAMETER_DIALOG_SOURCE_LISTBOX
, wxPoint( 10, 29), wxSize(285, 150), 0, 0, wxLB_SINGLE
|wxLB_ALWAYS_SB
, wxDefaultValidator
, wxT("ParamODBCSourceList"));
1453 pParamUserNameMsg
= new wxStaticText(this, PARAMETER_DIALOG_NAME_MSG
, wxT("Database user name:"), wxPoint( 10, 193), wxSize( -1, -1), 0, wxT("ParamUserNameMsg"));
1454 pParamUserNameTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_NAME_TEXT
, wxT(""), wxPoint(10, 209), wxSize( 140, 25), 0, wxDefaultValidator
, wxT("ParamUserNameTxt"));
1455 pParamPasswordMsg
= new wxStaticText(this, PARAMETER_DIALOG_PASSWORD_MSG
, wxT("Password:"), wxPoint(156, 193), wxSize( -1, -1), 0, wxT("ParamPasswordMsg"));
1456 pParamPasswordTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_PASSWORD_TEXT
, wxT(""), wxPoint(156, 209), wxSize( 140, 25), 0, wxDefaultValidator
, wxT("ParamPasswordTxt"));
1457 pParamDirPathMsg
= new wxStaticText(this, PARAMETER_DIALOG_DIRPATH_MSG
, wxT("Directory:"), wxPoint( 10, 243), wxSize( -1, -1), 0, wxT("ParamDirPathMsg"));
1458 pParamDirPathTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_DIRPATH_TEXT
, wxT(""), wxPoint( 10, 259), wxSize(140, 25), 0, wxDefaultValidator
, wxT("ParamDirPathTxt"));
1459 pParamSaveBtn
= new wxButton(this, PARAMETER_DIALOG_SAVE
, wxT("&Save"), wxPoint(310, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("ParamSaveBtn"));
1460 pParamCancelBtn
= new wxButton(this, PARAMETER_DIALOG_CANCEL
, wxT("C&ancel"), wxPoint(310, 66), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("ParamCancelBtn"));
1462 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
1463 // handle all widget processing
1464 widgetPtrsSet
= TRUE
;
1467 savedParamSettings
= wxGetApp().params
;
1472 } // CparameterDlg constructor
1475 void CparameterDlg::OnCloseWindow(wxCloseEvent
& event
)
1477 // Put any additional checking necessary to make certain it is alright
1478 // to close the program here that is not done elsewhere
1481 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
);
1489 wxGetApp().params
= savedParamSettings
;
1492 if (GetParent() != NULL
)
1493 GetParent()->SetFocus();
1499 SetReturnCode(0); // added so BoundsChecker would not report use of uninitialized variable
1502 } // CparameterDlg::OnCloseWindow()
1505 void CparameterDlg::OnButton( wxCommandEvent
&event
)
1507 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
1508 OnCommand( *win
, event
);
1512 void CparameterDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
1514 wxString widgetName
;
1516 widgetName
= win
.GetName();
1521 if (widgetName
== pParamSaveBtn
->GetName())
1526 tStr
= wxT("Database parameters have been saved.");
1527 if (GetParent() != NULL
) // The parameter dialog was not called during startup due to a missing cfg file
1528 tStr
+= wxT("\nNew parameters will take effect the next time the program is started.");
1529 wxMessageBox(tStr
,wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
1536 if (widgetName
== pParamCancelBtn
->GetName())
1541 } // CparameterDlg::OnCommand()
1544 bool CparameterDlg::PutData()
1546 // Fill the data source list box
1547 FillDataSourceList();
1549 // Fill in the fields from the params object
1550 if (wxGetApp().params
.ODBCSource
&& wxStrlen(wxGetApp().params
.ODBCSource
))
1551 pParamODBCSourceList
->SetStringSelection(wxGetApp().params
.ODBCSource
);
1552 pParamUserNameTxt
->SetValue(wxGetApp().params
.UserName
);
1553 pParamPasswordTxt
->SetValue(wxGetApp().params
.Password
);
1554 pParamDirPathTxt
->SetValue(wxGetApp().params
.DirPath
);
1556 } // CparameterDlg::PutData()
1559 bool CparameterDlg::GetData()
1562 if (pParamODBCSourceList
->GetStringSelection() != wxT(""))
1564 tStr
= pParamODBCSourceList
->GetStringSelection();
1565 if (tStr
.Length() > (sizeof(wxGetApp().params
.ODBCSource
)-1))
1568 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());
1569 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1572 wxStrcpy(wxGetApp().params
.ODBCSource
, tStr
);
1577 tStr
= pParamUserNameTxt
->GetValue();
1578 if (tStr
.Length() > (sizeof(wxGetApp().params
.UserName
)-1))
1581 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());
1582 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1585 wxStrcpy(wxGetApp().params
.UserName
, tStr
);
1587 tStr
= pParamPasswordTxt
->GetValue();
1588 if (tStr
.Length() > (sizeof(wxGetApp().params
.Password
)-1))
1591 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());
1592 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1595 wxStrcpy(wxGetApp().params
.Password
,tStr
);
1597 tStr
= pParamDirPathTxt
->GetValue();
1598 tStr
.Replace(wxT("\\"),wxT("/"));
1599 if (tStr
.Length() > (sizeof(wxGetApp().params
.DirPath
)-1))
1602 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());
1603 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1606 wxStrcpy(wxGetApp().params
.DirPath
,tStr
);
1608 } // CparameterDlg::GetData()
1611 bool CparameterDlg::Save()
1613 // Copy the current params in case user cancels changing
1614 // the params, so that we can reset them.
1617 wxGetApp().params
= savedParamSettings
;
1621 wxGetApp().WriteParamFile(wxGetApp().params
);
1624 } // CparameterDlg::Save()
1627 void CparameterDlg::FillDataSourceList()
1629 wxChar Dsn
[SQL_MAX_DSN_LENGTH
+ 1];
1631 wxStringList strList
;
1633 while (wxDbGetDataSource(wxGetApp().DbConnectInf
->GetHenv(), Dsn
,
1634 SQL_MAX_DSN_LENGTH
+1, DsDesc
, 255))
1638 strList
.Add(wxT(""));
1639 wxChar
**p
= strList
.ListToArray();
1642 for (i
= 0; wxStrlen(p
[i
]); i
++)
1643 pParamODBCSourceList
->Append(p
[i
]);
1646 } // CparameterDlg::CparameterDlg::FillDataSourceList()
1649 BEGIN_EVENT_TABLE(CqueryDlg
, wxDialog
)
1650 EVT_BUTTON(-1, CqueryDlg::OnButton
)
1651 EVT_CLOSE(CqueryDlg::OnCloseWindow
)
1655 // CqueryDlg() constructor
1656 CqueryDlg::CqueryDlg(wxWindow
*parent
, wxDb
*pDb
, wxChar
*tblName
[],
1657 const wxString
&pWhereArg
) :
1658 wxDialog (parent
, QUERY_DIALOG
, wxT("Query"), wxPoint(-1, -1), wxSize(480, 360))
1660 wxBeginBusyCursor();
1664 masterTableName
= tblName
[0];
1665 widgetPtrsSet
= FALSE
;
1668 // Initialize the WHERE clause from the string passed in
1669 pWhere
= pWhereArg
; // Save a pointer to the output buffer
1670 if (pWhere
.Length() > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN
) // Check the length of the buffer passed in
1673 s
.Printf(wxT("Maximum where clause length exceeded.\nLength must be less than %d"), DB_MAX_WHERE_CLAUSE_LEN
+1);
1674 wxMessageBox(s
,wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
1679 pQueryCol1Msg
= new wxStaticText(this, QUERY_DIALOG_COL_MSG
, wxT("Column 1:"), wxPoint( 10, 10), wxSize( 69, 16), 0, wxT("QueryCol1Msg"));
1680 pQueryCol1Choice
= new wxChoice(this, QUERY_DIALOG_COL_CHOICE
, wxPoint( 10, 27), wxSize(250, 27), 0, 0, 0, wxDefaultValidator
, wxT("QueryCol1Choice"));
1681 pQueryNotMsg
= new wxStaticText(this, QUERY_DIALOG_NOT_MSG
, wxT("NOT"), wxPoint(268, 10), wxSize( -1, -1), 0, wxT("QueryNotMsg"));
1682 pQueryNotCheck
= new wxCheckBox(this, QUERY_DIALOG_NOT_CHECKBOX
, wxT(""), wxPoint(275, 37), wxSize( 20, 20), 0, wxDefaultValidator
, wxT("QueryNotCheck"));
1684 wxString choice_strings
[9];
1685 choice_strings
[0] = wxT("=");
1686 choice_strings
[1] = wxT("<");
1687 choice_strings
[2] = wxT(">");
1688 choice_strings
[3] = wxT("<=");
1689 choice_strings
[4] = wxT(">=");
1690 choice_strings
[5] = wxT("Begins");
1691 choice_strings
[6] = wxT("Contains");
1692 choice_strings
[7] = wxT("Like");
1693 choice_strings
[8] = wxT("Between");
1695 pQueryOperatorMsg
= new wxStaticText(this, QUERY_DIALOG_OP_MSG
, wxT("Operator:"), wxPoint(305, 10), wxSize( -1, -1), 0, wxT("QueryOperatorMsg"));
1696 pQueryOperatorChoice
= new wxChoice(this, QUERY_DIALOG_OP_CHOICE
, wxPoint(305, 27), wxSize( 80, 27), 9, choice_strings
, 0, wxDefaultValidator
, wxT("QueryOperatorChoice"));
1697 pQueryCol2Msg
= new wxStaticText(this, QUERY_DIALOG_COL2_MSG
, wxT("Column 2:"), wxPoint( 10, 65), wxSize( 69, 16), 0, wxT("QueryCol2Msg"));
1698 pQueryCol2Choice
= new wxChoice(this, QUERY_DIALOG_COL2_CHOICE
, wxPoint( 10, 82), wxSize(250, 27), 0, 0, 0, wxDefaultValidator
, wxT("QueryCol2Choice"));
1699 pQuerySqlWhereMsg
= new wxStaticText(this, QUERY_DIALOG_WHERE_MSG
, wxT("SQL where clause:"), wxPoint( 10, 141), wxSize( -1, -1), 0, wxT("QuerySqlWhereMsg"));
1700 pQuerySqlWhereMtxt
= new wxTextCtrl(this, QUERY_DIALOG_WHERE_TEXT
, wxT(""), wxPoint( 10, 159), wxSize(377, 134), wxTE_MULTILINE
, wxDefaultValidator
, wxT("QuerySqlWhereMtxt"));
1701 pQueryAddBtn
= new wxButton(this, QUERY_DIALOG_ADD
, wxT("&Add"), wxPoint(406, 24), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryAddBtn"));
1702 pQueryAndBtn
= new wxButton(this, QUERY_DIALOG_AND
, wxT("A&nd"), wxPoint(406, 58), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryAndBtn"));
1703 pQueryOrBtn
= new wxButton(this, QUERY_DIALOG_OR
, wxT("&Or"), wxPoint(406, 92), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryOrBtn"));
1704 pQueryLParenBtn
= new wxButton(this, QUERY_DIALOG_LPAREN
, wxT("("), wxPoint(406, 126), wxSize( 26, 26), 0, wxDefaultValidator
, wxT("QueryLParenBtn"));
1705 pQueryRParenBtn
= new wxButton(this, QUERY_DIALOG_RPAREN
, wxT(")"), wxPoint(436, 126), wxSize( 26, 26), 0, wxDefaultValidator
, wxT("QueryRParenBtn"));
1706 pQueryDoneBtn
= new wxButton(this, QUERY_DIALOG_DONE
, wxT("&Done"), wxPoint(406, 185), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryDoneBtn"));
1707 pQueryClearBtn
= new wxButton(this, QUERY_DIALOG_CLEAR
, wxT("C&lear"), wxPoint(406, 218), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryClearBtn"));
1708 pQueryCountBtn
= new wxButton(this, QUERY_DIALOG_COUNT
, wxT("&Count"), wxPoint(406, 252), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryCountBtn"));
1709 pQueryValue1Msg
= new wxStaticText(this, QUERY_DIALOG_VALUE1_MSG
, wxT("Value:"), wxPoint(277, 66), wxSize( -1, -1), 0, wxT("QueryValue1Msg"));
1710 pQueryValue1Txt
= new wxTextCtrl(this, QUERY_DIALOG_VALUE1_TEXT
, wxT(""), wxPoint(277, 83), wxSize(108, 25), 0, wxDefaultValidator
, wxT("QueryValue1Txt"));
1711 pQueryValue2Msg
= new wxStaticText(this, QUERY_DIALOG_VALUE2_MSG
, wxT("AND"), wxPoint(238, 126), wxSize( -1, -1), 0, wxT("QueryValue2Msg"));
1712 pQueryValue2Txt
= new wxTextCtrl(this, QUERY_DIALOG_VALUE2_TEXT
, wxT(""), wxPoint(277, 120), wxSize(108, 25), 0, wxDefaultValidator
, wxT("QueryValue2Txt"));
1713 pQueryHintGrp
= new wxStaticBox(this, QUERY_DIALOG_HINT_GROUP
, wxT(""), wxPoint( 10, 291), wxSize(377, 40), 0, wxT("QueryHintGrp"));
1714 pQueryHintMsg
= new wxStaticText(this, QUERY_DIALOG_HINT_MSG
, wxT(""), wxPoint( 16, 306), wxSize( -1, -1), 0, wxT("QueryHintMsg"));
1716 widgetPtrsSet
= TRUE
;
1717 // Initialize the dialog
1719 pQueryCol2Choice
->Append(wxT("VALUE -->"));
1720 colInf
= pDB
->GetColumns(tblName
);
1726 tStr
= wxT("ODBC error during GetColumns()\n\n");
1727 tStr
+= GetExtendedDBErrorMsg(pDb
,__FILE__
,__LINE__
);
1728 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1733 for (i
= 0; colInf
[i
].colName
&& wxStrlen(colInf
[i
].colName
); i
++)
1735 // If there is more than one table being queried, qualify
1736 // the column names with the table name prefix.
1737 if (tblName
[1] && wxStrlen(tblName
[1]))
1739 qualName
.Printf(wxT("%s.%s"), colInf
[i
].tableName
, colInf
[i
].colName
);
1740 pQueryCol1Choice
->Append(qualName
);
1741 pQueryCol2Choice
->Append(qualName
);
1743 else // Single table query, append just the column names
1745 pQueryCol1Choice
->Append(colInf
[i
].colName
);
1746 pQueryCol2Choice
->Append(colInf
[i
].colName
);
1750 pQueryCol1Choice
->SetSelection(0);
1751 pQueryCol2Choice
->SetSelection(0);
1752 pQueryOperatorChoice
->SetSelection(0);
1754 pQueryValue2Msg
->Show(FALSE
);
1755 pQueryValue2Txt
->Show(FALSE
);
1757 pQueryHintMsg
->SetLabel(langQRY_EQ
);
1759 pQuerySqlWhereMtxt
->SetValue(pWhere
.c_str());
1763 // Display the dialog window
1766 } // CqueryDlg() constructor
1769 CqueryDlg::~CqueryDlg()
1771 } // CqueryDlg::~CqueryDlg() destructor
1774 void CqueryDlg::OnButton(wxCommandEvent
&event
)
1776 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
1777 OnCommand( *win
, event
);
1778 } // CqueryDlg::OnButton()
1781 void CqueryDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
1783 // Widget pointers won't be set when the dialog is constructed.
1784 // Control is passed through this function once for each widget on
1785 // a dialog as the dialog is constructed.
1789 wxString widgetName
= win
.GetName();
1791 // Operator choice box
1792 if (widgetName
== pQueryOperatorChoice
->GetName())
1794 // Set the help text
1795 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
1798 pQueryHintMsg
->SetLabel(langQRY_EQ
);
1801 pQueryHintMsg
->SetLabel(langQRY_LT
);
1804 pQueryHintMsg
->SetLabel(langQRY_GT
);
1807 pQueryHintMsg
->SetLabel(langQRY_LE
);
1810 pQueryHintMsg
->SetLabel(langQRY_GE
);
1813 pQueryHintMsg
->SetLabel(langQRY_BEGINS
);
1816 pQueryHintMsg
->SetLabel(langQRY_CONTAINS
);
1819 pQueryHintMsg
->SetLabel(langQRY_LIKE
);
1822 pQueryHintMsg
->SetLabel(langQRY_BETWEEN
);
1826 // Hide the value2 widget
1827 pQueryValue2Msg
->Show(FALSE
); // BETWEEN will show this widget
1828 pQueryValue2Txt
->Show(FALSE
); // BETWEEN will show this widget
1830 // Disable the NOT operator for <, <=, >, >=
1831 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
1837 pQueryNotCheck
->SetValue(0);
1838 pQueryNotCheck
->Enable(FALSE
);
1841 pQueryNotCheck
->Enable(TRUE
);
1845 // Manipulate the dialog to handle the selected operator
1846 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
1853 pQueryCol2Choice
->Enable(TRUE
);
1854 if (pQueryCol2Choice
->GetSelection()) // Column name is highlighted
1856 pQueryValue1Msg
->Show(FALSE
);
1857 pQueryValue1Txt
->Show(FALSE
);
1859 else // "Value" is highlighted
1861 pQueryValue1Msg
->Show(TRUE
);
1862 pQueryValue1Txt
->Show(TRUE
);
1863 pQueryValue1Txt
->SetFocus();
1869 pQueryCol2Choice
->SetSelection(0);
1870 pQueryCol2Choice
->Enable(FALSE
);
1871 pQueryValue1Msg
->Show(TRUE
);
1872 pQueryValue1Txt
->Show(TRUE
);
1873 pQueryValue1Txt
->SetFocus();
1876 pQueryCol2Choice
->SetSelection(0);
1877 pQueryCol2Choice
->Enable(FALSE
);
1878 pQueryValue2Msg
->Show(TRUE
);
1879 pQueryValue2Txt
->Show(TRUE
);
1880 pQueryValue1Msg
->Show(TRUE
);
1881 pQueryValue1Txt
->Show(TRUE
);
1882 pQueryValue1Txt
->SetFocus();
1888 } // Operator choice box
1891 if (widgetName
== pQueryCol2Choice
->GetName())
1893 if (pQueryCol2Choice
->GetSelection()) // Column name is highlighted
1895 pQueryValue1Msg
->Show(FALSE
);
1896 pQueryValue1Txt
->Show(FALSE
);
1898 else // "Value" is highlighted
1900 pQueryValue1Msg
->Show(TRUE
);
1901 pQueryValue1Txt
->Show(TRUE
);
1902 pQueryValue1Txt
->SetFocus();
1905 } // Column 2 choice
1908 if (widgetName
== pQueryAddBtn
->GetName())
1915 if (widgetName
== pQueryAndBtn
->GetName())
1917 AppendToWhere(wxT(" AND\n"));
1922 if (widgetName
== pQueryOrBtn
->GetName())
1924 AppendToWhere(wxT(" OR\n"));
1928 // Left Paren button
1929 if (widgetName
== pQueryLParenBtn
->GetName())
1931 AppendToWhere(wxT("("));
1933 } // Left Paren button
1935 // Right paren button
1936 if (widgetName
== pQueryRParenBtn
->GetName())
1938 AppendToWhere(wxT(")"));
1940 } // Right Paren button
1943 if (widgetName
== pQueryDoneBtn
->GetName())
1945 // Be sure the where clause will not overflow the output buffer
1946 if (wxStrlen(pQuerySqlWhereMtxt
->GetValue()) > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN
)
1949 s
.Printf(wxT("Maximum where clause length exceeded.\nLength must be less than %d"), DB_MAX_WHERE_CLAUSE_LEN
+1);
1950 wxMessageBox(s
,wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
1953 // Validate the where clause for things such as matching parens
1954 if (!ValidateWhereClause())
1956 // Copy the where clause to the output buffer and exit
1957 pWhere
= pQuerySqlWhereMtxt
->GetValue();
1963 if (widgetName
== pQueryClearBtn
->GetName())
1965 bool Ok
= (wxMessageBox(wxT("Are you sure you wish to clear the Query?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
1968 pQuerySqlWhereMtxt
->SetValue(wxT(""));
1973 if (widgetName
== pQueryCountBtn
->GetName())
1975 wxBeginBusyCursor();
1981 } // CqueryDlg::OnCommand
1984 void CqueryDlg::OnCloseWindow(wxCloseEvent
& event
)
1999 GetParent()->SetFocus();
2004 SetReturnCode(1); // added so BoundsChecker would not report use of uninitialized variable
2007 } // CqueryDlg::OnCloseWindow()
2010 void CqueryDlg::AppendToWhere(wxChar
*s
)
2012 wxString whereStr
= pQuerySqlWhereMtxt
->GetValue();
2014 pQuerySqlWhereMtxt
->SetValue(whereStr
);
2015 } // CqueryDlg::AppendToWhere()
2018 void CqueryDlg::ProcessAddBtn()
2020 qryOp oper
= (qryOp
) pQueryOperatorChoice
->GetSelection();
2022 // Verify that eveything is filled in correctly
2023 if (pQueryCol2Choice
->GetSelection() == 0) // "Value" is selected
2025 // Verify that value 1 is filled in
2026 if (wxStrlen(pQueryValue1Txt
->GetValue()) == 0)
2029 pQueryValue1Txt
->SetFocus();
2032 // For the BETWEEN operator, value 2 must be filled in as well
2033 if (oper
== qryOpBETWEEN
&&
2034 wxStrlen(pQueryValue2Txt
->GetValue()) == 0)
2037 pQueryValue2Txt
->SetFocus();
2042 // Build the expression and append it to the where clause window
2043 wxString s
= pQueryCol1Choice
->GetStringSelection();
2045 if (pQueryNotCheck
->GetValue() && (oper
!= qryOpEQ
))
2051 if (pQueryNotCheck
->GetValue()) // NOT box is checked
2074 s
+= wxT(" BETWEEN");
2080 int col1Idx
= pQueryCol1Choice
->GetSelection();
2083 if (colInf
[col1Idx
].sqlDataType
== SQL_VARCHAR
||
2084 oper
== qryOpBEGINS
||
2085 oper
== qryOpCONTAINS
||
2089 if (pQueryCol2Choice
->GetSelection()) // Column name
2090 s
+= pQueryCol2Choice
->GetStringSelection();
2091 else // Column 2 is a "value"
2095 if (oper
== qryOpCONTAINS
)
2097 s
+= pQueryValue1Txt
->GetValue();
2098 if (oper
== qryOpCONTAINS
|| oper
== qryOpBEGINS
)
2104 if (oper
== qryOpBETWEEN
)
2109 s
+= pQueryValue2Txt
->GetValue();
2114 AppendToWhere((wxChar
*) (const wxChar
*) s
);
2116 } // CqueryDlg::ProcessAddBtn()
2119 void CqueryDlg::ProcessCountBtn()
2121 if (!ValidateWhereClause())
2124 if (dbTable
== 0) // wxDbTable object needs to be created and opened
2126 if (!(dbTable
= new wxDbTable(pDB
, masterTableName
, 0, wxT(""),
2128 wxGetApp().DbConnectInf
->GetDefaultDir())))
2130 wxMessageBox(wxT("Memory allocation failed creating a wxDbTable object."),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
2133 if (!dbTable
->Open())
2136 tStr
= wxT("ODBC error during Open()\n\n");
2137 tStr
+= GetExtendedDBErrorMsg(dbTable
->GetDb(),__FILE__
,__LINE__
);
2138 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
2143 // Count() with WHERE clause
2146 whereStr
= pQuerySqlWhereMtxt
->GetValue();
2147 dbTable
->SetWhereClause(whereStr
.c_str());
2149 ULONG whereCnt
= dbTable
->Count();
2151 // Count() of all records in the table
2152 dbTable
->SetWhereClause(wxT(""));
2153 ULONG totalCnt
= dbTable
->Count();
2155 if (whereCnt
> 0 || totalCnt
== 0)
2158 tStr
.Printf(wxT("%lu of %lu records match the query criteria."),whereCnt
,totalCnt
);
2159 wxMessageBox(tStr
,wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
2164 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
);
2165 wxMessageBox(tStr
,wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
2168 // After a wxMessageBox, the focus does not necessarily return to the
2169 // window which was the focus when the message box popped up, so return
2170 // focus to the Query dialog for certain
2173 } // CqueryDlg::ProcessCountBtn()
2176 bool CqueryDlg::ValidateWhereClause()
2178 wxString where
= pQuerySqlWhereMtxt
->GetValue();
2180 if (where
.Freq(wxT('(')) != where
.Freq(wxT(')')))
2182 wxMessageBox(wxT("There are mismatched parenthesis in the constructed where clause"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
2185 // After a wxMessageBox, the focus does not necessarily return to the
2186 // window which was the focus when the message box popped up, so return
2187 // focus to the Query dialog for certain
2192 } // CqueryDlg::ValidateWhereClause()
2198 TEST CODE FOR TESTING THE wxDbCreateDataSource() FUNCTION
2201 result = wxDbCreateDataSource(wxT("Microsoft Access Driver (*.mdb)"),wxT("GLT-TEST2"),wxT("GLT-Descrip"),FALSE,wxT(""),this);
2204 // check for errors caused by ConfigDSN based functions
2207 wxChar errMsg[500+1];
2208 errMsg[0] = wxT('\0');
2210 SQLInstallerError(1,&retcode,errMsg,500,&cb);
2212 wxMessageBox(wxT("FAILED creating data source"),wxT("FAILED"));
2215 wxMessageBox(wxT("SUCCEEDED creating data source"),wxT("SUCCESS"));