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
);
153 READONLY_DB
= wxDbGetConnection(DbConnectInf
);
154 if (READONLY_DB
== 0)
156 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
);
157 DemoFrame
->BuildParameterDialog(NULL
);
158 DbConnectInf
->SetDsn("");
159 DbConnectInf
->SetUid("");
160 DbConnectInf
->SetPassword("");
161 wxMessageBox(wxT("Now exiting program.\n\nRestart program to try any new settings."),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
165 DemoFrame
->BuildEditorDialog();
168 DemoFrame
->Refresh();
171 } // DatabaseDemoApp::OnInit()
174 bool DatabaseDemoApp::ReadParamFile(Cparameters
¶ms
)
177 if ((paramFile
= fopen(PARAM_FILENAME
, wxT("r"))) == NULL
)
180 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
);
181 wxMessageBox(tStr
,wxT("File I/O Error..."),wxOK
| wxICON_EXCLAMATION
);
183 DemoFrame
->BuildParameterDialog(NULL
);
184 if ((paramFile
= fopen(PARAM_FILENAME
, wxT("r"))) == NULL
)
188 wxChar buffer
[1000+1];
189 fgets(buffer
, sizeof(params
.ODBCSource
), paramFile
);
190 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
191 wxStrcpy(params
.ODBCSource
,buffer
);
193 fgets(buffer
, sizeof(params
.UserName
), paramFile
);
194 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
195 wxStrcpy(params
.UserName
,buffer
);
197 fgets(buffer
, sizeof(params
.Password
), paramFile
);
198 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
199 wxStrcpy(params
.Password
,buffer
);
201 fgets(buffer
, sizeof(params
.DirPath
), paramFile
);
202 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
203 wxStrcpy(params
.DirPath
,buffer
);
208 } // DatabaseDemoApp::ReadParamFile()
211 bool DatabaseDemoApp::WriteParamFile(Cparameters
¶ms
)
214 if ((paramFile
= fopen(PARAM_FILENAME
, wxT("wt"))) == NULL
)
217 tStr
.Printf(wxT("Unable to write/overwrite '%s'."),PARAM_FILENAME
);
218 wxMessageBox(tStr
,wxT("File I/O Error..."),wxOK
| wxICON_EXCLAMATION
);
222 fputs(wxGetApp().params
.ODBCSource
, paramFile
);
223 fputc(wxT('\n'), paramFile
);
224 fputs(wxGetApp().params
.UserName
, paramFile
);
225 fputc(wxT('\n'), paramFile
);
226 fputs(wxGetApp().params
.Password
, paramFile
);
227 fputc(wxT('\n'), paramFile
);
228 fputs(wxGetApp().params
.DirPath
, paramFile
);
229 fputc(wxT('\n'), paramFile
);
233 } // DatabaseDemoApp::WriteParamFile()
236 void DatabaseDemoApp::CreateDataTable(bool recreate
)
240 Ok
= (wxMessageBox(wxT("Any data currently residing in the table will be erased.\n\nAre you sure?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
249 // Use a temporary instance of a new Ccontact table object
250 // for creating the table within the datasource.
251 Ccontact
*Contact
= new Ccontact();
256 wxMessageBox(wxT("Error allocating memory for 'Ccontact'object.\n\nTable was not created."),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
260 if (!Contact
->CreateTable(recreate
))
264 tStr
= wxT("Error creating CONTACTS table.\nTable was not created.\n\n");
265 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
266 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
271 if (!Contact
->CreateIndexes())
275 tStr
= wxT("Error creating CONTACTS indexes.\nIndexes will be unavailable.\n\n");
276 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
277 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
288 wxMessageBox(wxT("Table and index(es) were successfully created."),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
289 } // DatabaseDemoApp::CreateDataTable()
292 BEGIN_EVENT_TABLE(DatabaseDemoFrame
, wxFrame
)
293 EVT_MENU(FILE_CREATE
, DatabaseDemoFrame::OnCreate
)
294 EVT_MENU(FILE_RECREATE_TABLE
, DatabaseDemoFrame::OnRecreateTable
)
295 EVT_MENU(FILE_RECREATE_INDEXES
, DatabaseDemoFrame::OnRecreateIndexes
)
296 EVT_MENU(FILE_EXIT
, DatabaseDemoFrame::OnExit
)
297 EVT_MENU(EDIT_PARAMETERS
, DatabaseDemoFrame::OnEditParameters
)
298 EVT_MENU(ABOUT_DEMO
, DatabaseDemoFrame::OnAbout
)
299 EVT_CLOSE(DatabaseDemoFrame::OnCloseWindow
)
303 // DatabaseDemoFrame constructor
304 DatabaseDemoFrame::DatabaseDemoFrame(wxFrame
*frame
, const wxString
& title
,
305 const wxPoint
& pos
, const wxSize
& size
):
306 wxFrame(frame
, -1, title
, pos
, size
)
308 // Put any code in necessary for initializing the main frame here
311 } // DatabaseDemoFrame constructor
314 void DatabaseDemoFrame::OnCreate(wxCommandEvent
& event
)
316 wxGetApp().CreateDataTable(FALSE
);
317 } // DatabaseDemoFrame::OnCreate()
320 void DatabaseDemoFrame::OnRecreateTable(wxCommandEvent
& event
)
322 wxGetApp().CreateDataTable(TRUE
);
323 } // DatabaseDemoFrame::OnRecreate()
326 void DatabaseDemoFrame::OnRecreateIndexes(wxCommandEvent
& event
)
328 // Using a new connection to the database so as not to disturb
329 // the current cursors on the table in use in the editor dialog
330 Ccontact
*Contact
= new Ccontact();
335 wxMessageBox(wxT("Error allocating memory for 'Ccontact'object.\n\nTable could not be opened."),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
339 if (!Contact
->CreateIndexes())
343 tStr
= wxT("Error creating CONTACTS indexes.\nNew indexes will be unavailable.\n\n");
344 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
345 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
350 } // DatabaseDemoFrame::OnRecreateIndexes()
352 void DatabaseDemoFrame::OnExit(wxCommandEvent
& event
)
355 } // DatabaseDemoFrame::OnExit()
358 void DatabaseDemoFrame::OnEditParameters(wxCommandEvent
& event
)
360 if ((pEditorDlg
->mode
!= mCreate
) && (pEditorDlg
->mode
!= mEdit
))
361 BuildParameterDialog(this);
363 wxMessageBox(wxT("Cannot change database parameters while creating or editing a record"),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
364 } // DatabaseDemoFrame::OnEditParameters()
367 void DatabaseDemoFrame::OnAbout(wxCommandEvent
& event
)
369 wxMessageBox(wxT("wxWindows sample program for database classes\n\nContributed on 27 July 1998"),wxT("About..."),wxOK
| wxICON_INFORMATION
);
370 } // DatabaseDemoFrame::OnAbout()
373 // Put any additional checking necessary to make certain it is alright
374 // to close the program here that is not done elsewhere
375 void DatabaseDemoFrame::OnCloseWindow(wxCloseEvent
& event
)
378 if (pEditorDlg
&& pEditorDlg
->Close())
389 // This function will close all the connections to the database that have been
390 // previously cached.
391 wxDbCloseConnections();
393 // Deletion of the wxDbConnectInf instance must be the LAST thing done that
394 // has anything to do with the database. Deleting this before disconnecting,
395 // freeing/closing connections, etc will result in a crash!
396 delete wxGetApp().DbConnectInf
;
397 wxGetApp().DbConnectInf
= NULL
;
401 } // DatabaseDemoFrame::OnCloseWindow()
404 void DatabaseDemoFrame::BuildEditorDialog()
407 pEditorDlg
= new CeditorDlg(this);
410 pEditorDlg
->Initialize();
411 if (!pEditorDlg
->initialized
)
415 wxMessageBox(wxT("Unable to initialize the editor dialog for some reason"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
421 wxMessageBox(wxT("Unable to create the editor dialog for some reason"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
424 } // DatabaseDemoFrame::BuildEditorDialog()
427 void DatabaseDemoFrame::BuildParameterDialog(wxWindow
*parent
)
429 pParamDlg
= new CparameterDlg(parent
);
432 wxMessageBox(wxT("Unable to create the parameter dialog for some reason"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
433 } // DatabaseDemoFrame::BuildParameterDialog()
437 * Constructor note: If no wxDb object is passed in, a new connection to the database
438 * is created for this instance of Ccontact. This can be a slow process depending
439 * on the database engine being used, and some database engines have a limit on the
440 * number of connections (either hard limits, or license restricted) so care should
441 * be used to use as few connections as is necessary.
443 * IMPORTANT: Objects which share a wxDb pointer are ALL acted upon whenever a member
444 * function of pDb is called (i.e. CommitTrans() or RollbackTrans(), so if modifying
445 * or creating a table objects which use the same pDb, know that all the objects
446 * will be committed or rolled back when any of the objects has this function call made.
448 Ccontact::Ccontact (wxDb
*pwxDb
) : wxDbTable(pwxDb
? pwxDb
: wxDbGetConnection(wxGetApp().DbConnectInf
),
449 CONTACT_TABLE_NAME
, CONTACT_NO_COLS
, wxT(""),
450 !wxDB_QUERY_ONLY
, wxGetApp().DbConnectInf
->GetDefaultDir())
452 // This is used to represent whether the database connection should be released
453 // when this instance of the object is deleted. If using the same connection
454 // for multiple instance of database objects, then the connection should only be
455 // released when the last database instance using the connection is deleted
460 } // Ccontact Constructor
463 void Ccontact::Initialize()
472 JoinDate
.year
= 1980;
478 JoinDate
.fraction
= 0;
479 NativeLanguage
= langENGLISH
;
483 } // Ccontact::Initialize
486 Ccontact::~Ccontact()
490 if (!wxDbFreeConnection(GetDb()))
493 tStr
= wxT("Unable to Free the Ccontact data table handle\n\n");
494 tStr
+= GetExtendedDBErrorMsg(GetDb(),__FILE__
,__LINE__
);
495 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
498 } // Ccontract destructor
502 * Handles setting up all the connections for the interface from the wxDbTable
503 * functions to interface to the data structure used to store records in
504 * memory, and for all the column definitions that define the table structure
506 void Ccontact::SetupColumns()
508 // NOTE: Columns now are 8 character names, as that is all dBase can support. Longer
509 // names can be used for other database engines
510 SetColDefs ( 0,wxT("NAME"), DB_DATA_TYPE_VARCHAR
, Name
, SQL_C_CHAR
, sizeof(Name
), TRUE
, TRUE
); // Primary index
511 SetColDefs ( 1,wxT("ADDRESS1"), DB_DATA_TYPE_VARCHAR
, Addr1
, SQL_C_CHAR
, sizeof(Addr1
), FALSE
,TRUE
);
512 SetColDefs ( 2,wxT("ADDRESS2"), DB_DATA_TYPE_VARCHAR
, Addr2
, SQL_C_CHAR
, sizeof(Addr2
), FALSE
,TRUE
);
513 SetColDefs ( 3,wxT("CITY"), DB_DATA_TYPE_VARCHAR
, City
, SQL_C_CHAR
, sizeof(City
), FALSE
,TRUE
);
514 SetColDefs ( 4,wxT("STATE"), DB_DATA_TYPE_VARCHAR
, State
, SQL_C_CHAR
, sizeof(State
), FALSE
,TRUE
);
515 SetColDefs ( 5,wxT("POSTCODE"), DB_DATA_TYPE_VARCHAR
, PostalCode
, SQL_C_CHAR
, sizeof(PostalCode
), FALSE
,TRUE
);
516 SetColDefs ( 6,wxT("COUNTRY"), DB_DATA_TYPE_VARCHAR
, Country
, SQL_C_CHAR
, sizeof(Country
), FALSE
,TRUE
);
517 SetColDefs ( 7,wxT("JOINDATE"), DB_DATA_TYPE_DATE
, &JoinDate
, SQL_C_TIMESTAMP
, sizeof(JoinDate
), FALSE
,TRUE
);
518 SetColDefs ( 8,wxT("IS_DEV"), DB_DATA_TYPE_INTEGER
, &IsDeveloper
, SQL_C_BOOLEAN(IsDeveloper
), sizeof(IsDeveloper
), FALSE
,TRUE
);
519 SetColDefs ( 9,wxT("CONTRIBS"), DB_DATA_TYPE_INTEGER
, &Contributions
, SQL_C_USHORT
, sizeof(Contributions
), FALSE
,TRUE
);
520 SetColDefs (10,wxT("LINE_CNT"), DB_DATA_TYPE_INTEGER
, &LinesOfCode
, SQL_C_ULONG
, sizeof(LinesOfCode
), FALSE
,TRUE
);
521 SetColDefs (11,wxT("LANGUAGE"), DB_DATA_TYPE_INTEGER
, &NativeLanguage
, SQL_C_ENUM
, sizeof(NativeLanguage
), FALSE
,TRUE
);
522 } // Ccontact::SetupColumns
525 bool Ccontact::CreateIndexes(void)
527 // This index could easily be accomplished with an "orderBy" clause,
528 // but is done to show how to construct a non-primary index.
530 wxDbIdxDef idxDef
[2];
534 wxStrcpy(idxDef
[0].ColName
, "IS_DEV");
535 idxDef
[0].Ascending
= TRUE
;
537 wxStrcpy(idxDef
[1].ColName
, "NAME");
538 idxDef
[1].Ascending
= TRUE
;
540 indexName
= GetTableName();
541 indexName
+= "_IDX1";
542 Ok
= CreateIndex(indexName
.c_str(), TRUE
, 2, idxDef
);
545 } // Ccontact::CreateIndexes()
549 * Having a function to do a query on the primary key (and possibly others) is
550 * very efficient and tighter coding so that it is available where ever the object
551 * is. Great for use with multiple tables when not using views or outer joins
553 bool Ccontact::FetchByName(const wxString
&name
)
555 whereStr
.Printf(wxT("NAME = '%s'"),name
);
556 SetWhereClause(whereStr
.c_str());
557 SetOrderByClause(wxT(""));
565 } // Ccontact::FetchByName()
570 * ************* DIALOGS ***************
575 /* CeditorDlg constructor
577 * Creates the dialog used for creating/editing/deleting/copying a Ccontact object.
578 * This dialog actually is drawn in the main frame of the program
580 * An instance of Ccontact is created - "Contact" - which is used to hold the Ccontact
581 * object that is currently being worked with.
584 BEGIN_EVENT_TABLE(CeditorDlg
, wxPanel
)
585 EVT_BUTTON(-1, CeditorDlg::OnButton
)
586 EVT_CLOSE(CeditorDlg::OnCloseWindow
)
589 CeditorDlg::CeditorDlg(wxWindow
*parent
) : wxPanel (parent
, 0, 0, 537, 480)
591 // Since the ::OnCommand() function is overridden, this prevents the widget
592 // detection in ::OnCommand() until all widgets have been initialized to prevent
593 // uninitialized pointers from crashing the program
594 widgetPtrsSet
= FALSE
;
601 } // CeditorDlg constructor
604 void CeditorDlg::OnCloseWindow(wxCloseEvent
& event
)
607 if ((mode
!= mCreate
) && (mode
!= mEdit
))
618 wxMessageBox(wxT("Must finish processing the current record being created/modified before exiting"),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
621 } // CeditorDlg::OnCloseWindow()
624 void CeditorDlg::OnButton(wxCommandEvent
&event
)
626 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
627 OnCommand( *win
, event
);
628 } // CeditorDlg::OnButton()
631 void CeditorDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
635 widgetName
= win
.GetName();
640 if (widgetName
== pCreateBtn
->GetName())
642 Contact
->Initialize();
645 pNameTxt
->SetValue(wxT(""));
646 pNameTxt
->SetFocus();
650 if (widgetName
== pEditBtn
->GetName())
652 saveName
= Contact
->Name
;
654 pNameTxt
->SetFocus();
658 if (widgetName
== pCopyBtn
->GetName())
661 pNameTxt
->SetValue(wxT(""));
662 pNameTxt
->SetFocus();
667 if (widgetName
== pDeleteBtn
->GetName())
669 bool Ok
= (wxMessageBox(wxT("Are you sure?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
674 if (Ok
&& Contact
->Delete())
676 // NOTE: Deletions are not finalized until a CommitTrans() is performed.
677 // If the commit were not performed, the program will continue to
678 // show the table contents as if they were deleted until this instance
679 // of Ccontact is deleted. If the Commit wasn't performed, the
680 // database will automatically Rollback the changes when the database
681 // connection is terminated
682 Contact
->GetDb()->CommitTrans();
684 // Try to get the row that followed the just deleted row in the orderBy sequence
687 // There was now row (in sequence) after the just deleted row, so get the
688 // row which preceded the just deleted row
691 // There are now no rows remaining, so clear the dialog widgets
692 Contact
->Initialize();
696 SetMode(mode
); // force reset of button enable/disable
700 Contact
->GetDb()->RollbackTrans();
706 if (widgetName
== pSaveBtn
->GetName())
712 if (widgetName
== pCancelBtn
->GetName())
714 bool Ok
= (wxMessageBox(wxT("Are you sure?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
719 if (saveName
.IsEmpty())
721 Contact
->Initialize();
728 // Requery previous record
729 if (Contact
->FetchByName(saveName
))
737 // Previous record not available, retrieve first record in table
738 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
740 Contact
->whereStr
= wxT("NAME = (SELECT MIN(NAME) FROM ");
741 Contact
->whereStr
+= Contact
->GetTableName();
742 Contact
->whereStr
+= wxT(")");
743 Contact
->SetWhereClause(Contact
->whereStr
.c_str());
746 Contact
->SetWhereClause(wxT(""));
748 if (!Contact
->Query())
751 tStr
= wxT("ODBC error during Query()\n\n");
752 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
753 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
757 if (Contact
->GetNext()) // Successfully read first record
763 // No contacts are available, clear dialog
764 Contact
->Initialize();
770 if (widgetName
== pPrevBtn
->GetName())
777 if (widgetName
== pNextBtn
->GetName())
784 if (widgetName
== pQueryBtn
->GetName())
786 // Display the query dialog box
787 wxChar qryWhere
[DB_MAX_WHERE_CLAUSE_LEN
+1];
788 wxStrcpy(qryWhere
, (const wxChar
*) Contact
->qryWhereStr
);
789 wxChar
*tblName
[] = {(wxChar
*)CONTACT_TABLE_NAME
, 0};
790 new CqueryDlg(GetParent(), Contact
->GetDb(), tblName
, qryWhere
);
792 // Query the first record in the new record set and
793 // display it, if the query string has changed.
794 if (wxStrcmp(qryWhere
, (const wxChar
*) Contact
->qryWhereStr
))
796 Contact
->whereStr
.Empty();
797 Contact
->SetOrderByClause("NAME");
799 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
801 Contact
->whereStr
= wxT("NAME = (SELECT MIN(NAME) FROM ");
802 Contact
->whereStr
+= CONTACT_TABLE_NAME
;
805 // Append the query where string (if there is one)
806 Contact
->qryWhereStr
= qryWhere
;
807 if (wxStrlen(qryWhere
))
809 Contact
->whereStr
+= wxT(" WHERE ");
810 Contact
->whereStr
+= Contact
->qryWhereStr
;
812 // Close the expression with a right paren
813 Contact
->whereStr
+= wxT(")");
815 Contact
->SetWhereClause(Contact
->whereStr
.c_str());
816 if (!Contact
->Query())
819 tStr
= wxT("ODBC error during Query()\n\n");
820 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
821 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
824 // Display the first record from the query set
825 if (!Contact
->GetNext())
826 Contact
->Initialize();
830 // Enable/Disable the reset button
831 pResetBtn
->Enable(!Contact
->qryWhereStr
.IsEmpty());
837 if (widgetName
== pResetBtn
->GetName())
839 // Clear the additional where criteria established by the query feature
840 Contact
->qryWhereStr
= wxT("");
841 Contact
->SetOrderByClause(wxT("NAME"));
843 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
845 Contact
->whereStr
= wxT("NAME = (SELECT MIN(NAME) FROM ");
846 Contact
->whereStr
+= CONTACT_TABLE_NAME
;
847 Contact
->whereStr
+= wxT(")");
850 Contact
->SetWhereClause(Contact
->whereStr
.c_str());
851 if (!Contact
->Query())
854 tStr
= wxT("ODBC error during Query()\n\n");
855 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
856 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
859 if (!Contact
->GetNext())
860 Contact
->Initialize();
862 pResetBtn
->Enable(FALSE
);
868 if (widgetName
== pNameListBtn
->GetName())
870 new ClookUpDlg(/* wxWindow *parent */ this,
871 /* wxChar *windowTitle */ wxT("Select contact name"),
872 /* wxChar *tableName */ (wxChar
*) CONTACT_TABLE_NAME
,
873 /* wxChar *dispCol1 */ wxT("NAME"),
874 /* wxChar *dispCol2 */ wxT("JOINDATE"),
875 /* wxChar *where */ wxT(""),
876 /* wxChar *orderBy */ wxT("NAME"),
877 /* wxDb *pDb */ wxGetApp().READONLY_DB
,
878 /* const wxString &defDir */ wxGetApp().DbConnectInf
->GetDefaultDir(),
879 /* bool distinctValues */ TRUE
);
881 if (ListDB_Selection
&& wxStrlen(ListDB_Selection
))
883 wxString w
= wxT("NAME = '");
884 w
+= ListDB_Selection
;
891 } // CeditorDlg::OnCommand()
894 bool CeditorDlg::Initialize()
896 // Create the data structure and a new database connection.
897 // (As there is not a pDb being passed in the constructor, a new database
898 // connection is created)
899 Contact
= new Ccontact();
903 wxMessageBox(wxT("Unable to instantiate an instance of Ccontact"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
907 // Check if the table exists or not. If it doesn't, ask the user if they want to
908 // create the table. Continue trying to create the table until it exists, or user aborts
909 while (!Contact
->GetDb()->TableExists((wxChar
*)CONTACT_TABLE_NAME
,
910 wxGetApp().DbConnectInf
->GetUserID(),
911 wxGetApp().DbConnectInf
->GetDefaultDir()))
914 tStr
.Printf(wxT("Unable to open the table '%s'.\n\nTable may need to be created...?\n\n"),CONTACT_TABLE_NAME
);
915 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
916 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
918 bool createTable
= (wxMessageBox(wxT("Do you wish to try to create/clear the CONTACTS table?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
926 wxGetApp().CreateDataTable(TRUE
);
929 // Tables must be "opened" before anything other than creating/deleting table can be done
930 if (!Contact
->Open())
932 // Table does exist, or there was some problem opening it. Currently this should
933 // never fail, except in the case of the table not exisiting or the current
934 // user has insufficent privileges to access the table
936 // This code is experimenting with a new function that will hopefully be available
937 // in the 2.4 release. This check will determine whether the open failing was due
938 // to the table not existing, or the users privileges being insufficient to
940 if (!Contact
->GetDb()->TablePrivileges(CONTACT_TABLE_NAME
,wxT("SELECT"),Contact
->GetDb()->GetUsername(),Contact
->GetDb()->GetUsername(),DbConnectInf
->GetDefaultDir()))
943 tStr
.Printf(wxT("Unable to open the table '%s'.\n\n"),CONTACT_TABLE_NAME
);
944 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
945 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
949 if (Contact
->GetDb()->TableExists(CONTACT_TABLE_NAME
, Contact
->GetDb()->GetUsername(),
950 wxGetApp().DbConnectInf
->GetDefaultDir()))
953 tStr
.Printf(wxT("Unable to open the table '%s'.\n\n"),CONTACT_TABLE_NAME
);
954 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
955 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
963 (void)new wxStaticBox(this, EDITOR_DIALOG_FN_GROUP
, wxT(""), wxPoint(15, 1), wxSize(497, 69), 0, wxT("FunctionGrp"));
964 (void)new wxStaticBox(this, EDITOR_DIALOG_SEARCH_GROUP
, wxT(""), wxPoint(417, 1), wxSize(95, 242), 0, wxT("SearchGrp"));
966 pCreateBtn
= new wxButton(this, EDITOR_DIALOG_CREATE
, wxT("&Create"), wxPoint( 25, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("CreateBtn"));
967 pEditBtn
= new wxButton(this, EDITOR_DIALOG_EDIT
, wxT("&Edit"), wxPoint(102, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("EditBtn"));
968 pDeleteBtn
= new wxButton(this, EDITOR_DIALOG_DELETE
, wxT("&Delete"), wxPoint(179, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("DeleteBtn"));
969 pCopyBtn
= new wxButton(this, EDITOR_DIALOG_COPY
, wxT("Cop&y"), wxPoint(256, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("CopyBtn"));
970 pSaveBtn
= new wxButton(this, EDITOR_DIALOG_SAVE
, wxT("&Save"), wxPoint(333, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("SaveBtn"));
971 pCancelBtn
= new wxButton(this, EDITOR_DIALOG_CANCEL
, wxT("C&ancel"), wxPoint(430, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("CancelBtn"));
972 pPrevBtn
= new wxButton(this, EDITOR_DIALOG_PREV
, wxT("<< &Prev"), wxPoint(430, 81), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("PrevBtn"));
973 pNextBtn
= new wxButton(this, EDITOR_DIALOG_NEXT
, wxT("&Next >>"), wxPoint(430, 121), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("NextBtn"));
974 pQueryBtn
= new wxButton(this, EDITOR_DIALOG_QUERY
, wxT("&Query"), wxPoint(430, 161), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("QueryBtn"));
975 pResetBtn
= new wxButton(this, EDITOR_DIALOG_RESET
, wxT("&Reset"), wxPoint(430, 200), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("ResetBtn"));
976 pNameMsg
= new wxStaticText(this, EDITOR_DIALOG_NAME_MSG
, wxT("Name:"), wxPoint( 17, 80), wxSize( -1, -1), 0, wxT("NameMsg"));
977 pNameTxt
= new wxTextCtrl(this, EDITOR_DIALOG_NAME_TEXT
, wxT(""), wxPoint( 17, 97), wxSize(308, 25), 0, wxDefaultValidator
, wxT("NameTxt"));
978 pNameListBtn
= new wxButton(this, EDITOR_DIALOG_LOOKUP
, wxT("&Lookup"), wxPoint(333, 97), wxSize( 70, 24), 0, wxDefaultValidator
, wxT("LookupBtn"));
979 pAddress1Msg
= new wxStaticText(this, EDITOR_DIALOG_ADDRESS1_MSG
, wxT("Address:"), wxPoint( 17, 130), wxSize( -1, -1), 0, wxT("Address1Msg"));
980 pAddress1Txt
= new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT
, wxT(""), wxPoint( 17, 147), wxSize(308, 25), 0, wxDefaultValidator
, wxT("Address1Txt"));
981 pAddress2Msg
= new wxStaticText(this, EDITOR_DIALOG_ADDRESS2_MSG
, wxT("Address:"), wxPoint( 17, 180), wxSize( -1, -1), 0, wxT("Address2Msg"));
982 pAddress2Txt
= new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT
, wxT(""), wxPoint( 17, 197), wxSize(308, 25), 0, wxDefaultValidator
, wxT("Address2Txt"));
983 pCityMsg
= new wxStaticText(this, EDITOR_DIALOG_CITY_MSG
, wxT("City:"), wxPoint( 17, 230), wxSize( -1, -1), 0, wxT("CityMsg"));
984 pCityTxt
= new wxTextCtrl(this, EDITOR_DIALOG_CITY_TEXT
, wxT(""), wxPoint( 17, 247), wxSize(225, 25), 0, wxDefaultValidator
, wxT("CityTxt"));
985 pStateMsg
= new wxStaticText(this, EDITOR_DIALOG_STATE_MSG
, wxT("State:"), wxPoint(250, 230), wxSize( -1, -1), 0, wxT("StateMsg"));
986 pStateTxt
= new wxTextCtrl(this, EDITOR_DIALOG_STATE_TEXT
, wxT(""), wxPoint(250, 247), wxSize(153, 25), 0, wxDefaultValidator
, wxT("StateTxt"));
987 pCountryMsg
= new wxStaticText(this, EDITOR_DIALOG_COUNTRY_MSG
, wxT("Country:"), wxPoint( 17, 280), wxSize( -1, -1), 0, wxT("CountryMsg"));
988 pCountryTxt
= new wxTextCtrl(this, EDITOR_DIALOG_COUNTRY_TEXT
, wxT(""), wxPoint( 17, 297), wxSize(225, 25), 0, wxDefaultValidator
, wxT("CountryTxt"));
989 pPostalCodeMsg
= new wxStaticText(this, EDITOR_DIALOG_POSTAL_MSG
, wxT("Postal Code:"),wxPoint(250, 280), wxSize( -1, -1), 0, wxT("PostalCodeMsg"));
990 pPostalCodeTxt
= new wxTextCtrl(this, EDITOR_DIALOG_POSTAL_TEXT
, wxT(""), wxPoint(250, 297), wxSize(153, 25), 0, wxDefaultValidator
, wxT("PostalCodeTxt"));
992 wxString choice_strings
[5];
993 choice_strings
[0] = wxT("English");
994 choice_strings
[1] = wxT("French");
995 choice_strings
[2] = wxT("German");
996 choice_strings
[3] = wxT("Spanish");
997 choice_strings
[4] = wxT("Other");
999 pNativeLangChoice
= new wxChoice(this, EDITOR_DIALOG_LANG_CHOICE
, wxPoint( 17, 346), wxSize(277, -1), 5, choice_strings
);
1000 pNativeLangMsg
= new wxStaticText(this, EDITOR_DIALOG_LANG_MSG
, wxT("Native language:"), wxPoint( 17, 330), wxSize( -1, -1), 0, wxT("NativeLangMsg"));
1002 wxString radio_strings
[2];
1003 radio_strings
[0] = wxT("No");
1004 radio_strings
[1] = wxT("Yes");
1005 pDeveloperRadio
= new wxRadioBox(this,EDITOR_DIALOG_DEVELOPER
, wxT("Developer:"), wxPoint(303, 330), wxSize( -1, -1), 2, radio_strings
, 2, wxHORIZONTAL
);
1006 pJoinDateMsg
= new wxStaticText(this, EDITOR_DIALOG_JOIN_MSG
, wxT("Date joined:"), wxPoint( 17, 380), wxSize( -1, -1), 0, wxT("JoinDateMsg"));
1007 pJoinDateTxt
= new wxTextCtrl(this, EDITOR_DIALOG_JOIN_TEXT
, wxT(""), wxPoint( 17, 397), wxSize(150, 25), 0, wxDefaultValidator
, wxT("JoinDateTxt"));
1008 pContribMsg
= new wxStaticText(this, EDITOR_DIALOG_CONTRIB_MSG
,wxT("Contributions:"), wxPoint(175, 380), wxSize( -1, -1), 0, wxT("ContribMsg"));
1009 pContribTxt
= new wxTextCtrl(this, EDITOR_DIALOG_CONTRIB_TEXT
, wxT(""), wxPoint(175, 397), wxSize(120, 25), 0, wxDefaultValidator
, wxT("ContribTxt"));
1010 pLinesMsg
= new wxStaticText(this, EDITOR_DIALOG_LINES_MSG
, wxT("Lines of code:"), wxPoint(303, 380), wxSize( -1, -1), 0, wxT("LinesMsg"));
1011 pLinesTxt
= new wxTextCtrl(this, EDITOR_DIALOG_LINES_TEXT
, wxT(""), wxPoint(303, 397), wxSize(100, 25), 0, wxDefaultValidator
, wxT("LinesTxt"));
1013 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
1014 // handle all widget processing
1015 widgetPtrsSet
= TRUE
;
1017 // Setup the orderBy and where clauses to return back a single record as the result set,
1018 // as there will only be one record being shown on the dialog at a time, this optimizes
1019 // network traffic by only returning a one row result
1021 Contact
->SetOrderByClause(wxT("NAME")); // field name to sort by
1023 // The wxString "whereStr" is not a member of the wxDbTable object, it is a member variable
1024 // specifically in the Ccontact class. It is used here for simpler construction of a varying
1025 // length string, and then after the string is built, the wxDbTable member variable "where" is
1026 // assigned the pointer to the constructed string.
1028 // The constructed where clause below has a sub-query within it "SELECT MIN(NAME) FROM %s"
1029 // to achieve a single row (in this case the first name in alphabetical order).
1031 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1033 Contact
->whereStr
.Printf(wxT("NAME = (SELECT MIN(NAME) FROM %s)"),Contact
->GetTableName());
1034 // NOTE: (const wxChar*) returns a pointer which may not be valid later, so this is short term use only
1035 Contact
->SetWhereClause(Contact
->whereStr
);
1038 Contact
->SetWhereClause(wxT(""));
1040 // Perform the Query to get the result set.
1041 // NOTE: If there are no rows returned, that is a valid result, so Query() would return TRUE.
1042 // Only if there is a database error will Query() come back as FALSE
1043 if (!Contact
->Query())
1046 tStr
= wxT("ODBC error during Query()\n\n");
1047 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1048 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1049 // GetParent()->Close();
1053 // Since Query succeeded, now get the row that was returned
1054 if (!Contact
->GetNext())
1055 // If the GetNext() failed at this point, then there are no rows to retrieve,
1056 // so clear the values in the members of "Contact" so that PutData() blanks the
1057 // widgets on the dialog
1058 Contact
->Initialize();
1067 } // CeditorDlg::Initialize()
1070 void CeditorDlg::FieldsEditable()
1072 pNameTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1073 pAddress1Txt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1074 pAddress2Txt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1075 pCityTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1076 pStateTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1077 pPostalCodeTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1078 pCountryTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1080 pJoinDateTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1081 pContribTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1082 pLinesTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1083 pNativeLangChoice
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1084 pDeveloperRadio
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1086 } // CeditorDlg::FieldsEditable()
1089 void CeditorDlg::SetMode(enum DialogModes m
)
1110 pCreateBtn
->Enable( !edit
);
1111 pEditBtn
->Enable( !edit
&& (wxStrcmp(Contact
->Name
,wxT(""))!=0) );
1112 pDeleteBtn
->Enable( !edit
&& (wxStrcmp(Contact
->Name
,wxT(""))!=0) );
1113 pCopyBtn
->Enable( !edit
&& (wxStrcmp(Contact
->Name
,wxT(""))!=0) );
1114 pSaveBtn
->Enable( edit
);
1115 pCancelBtn
->Enable( edit
);
1116 pPrevBtn
->Enable( !edit
);
1117 pNextBtn
->Enable( !edit
);
1118 pQueryBtn
->Enable( !edit
);
1119 pResetBtn
->Enable( !edit
&& !Contact
->qryWhereStr
.IsEmpty() );
1120 pNameListBtn
->Enable( !edit
);
1124 } // CeditorDlg::SetMode()
1127 bool CeditorDlg::PutData()
1131 pNameTxt
->SetValue(Contact
->Name
);
1132 pAddress1Txt
->SetValue(Contact
->Addr1
);
1133 pAddress2Txt
->SetValue(Contact
->Addr2
);
1134 pCityTxt
->SetValue(Contact
->City
);
1135 pStateTxt
->SetValue(Contact
->State
);
1136 pCountryTxt
->SetValue(Contact
->Country
);
1137 pPostalCodeTxt
->SetValue(Contact
->PostalCode
);
1139 tStr
.Printf(wxT("%d/%d/%d"),Contact
->JoinDate
.month
,Contact
->JoinDate
.day
,Contact
->JoinDate
.year
);
1140 pJoinDateTxt
->SetValue(tStr
);
1142 tStr
.Printf(wxT("%d"),Contact
->Contributions
);
1143 pContribTxt
->SetValue(tStr
);
1145 tStr
.Printf(wxT("%lu"),Contact
->LinesOfCode
);
1146 pLinesTxt
->SetValue(tStr
);
1148 pNativeLangChoice
->SetSelection(Contact
->NativeLanguage
);
1150 pDeveloperRadio
->SetSelection(Contact
->IsDeveloper
);
1153 } // Ceditor::PutData()
1157 * Reads the data out of all the widgets on the dialog. Some data evaluation is done
1158 * to ensure that there is a name entered and that the date field is valid.
1160 * A return value of TRUE means that valid data was retrieved from the dialog, otherwise
1161 * invalid data was found (and a message was displayed telling the user what to fix), and
1162 * the data was not placed into the appropraite fields of Ccontact
1164 bool CeditorDlg::GetData()
1166 // Validate that the data currently entered into the widgets is valid data
1169 tStr
= pNameTxt
->GetValue();
1170 if (!wxStrcmp((const wxChar
*) tStr
,wxT("")))
1172 wxMessageBox(wxT("A name is required for entry into the contact table"),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
1176 bool invalid
= FALSE
;
1180 tStr
= pJoinDateTxt
->GetValue();
1181 if (tStr
.Freq(wxT('/')) != 2)
1184 // Find the month, day, and year tokens
1187 first
= tStr
.First(wxT('/'));
1188 second
= tStr
.Last(wxT('/'));
1190 mm
= atoi(tStr
.SubString(0,first
));
1191 dd
= atoi(tStr
.SubString(first
+1,second
));
1192 yyyy
= atoi(tStr
.SubString(second
+1,tStr
.Length()-1));
1194 invalid
= !(mm
&& dd
&& yyyy
);
1197 // Force Year 2000 compliance
1198 if (!invalid
&& (yyyy
< 1000))
1201 // Check the token ranges for validity
1206 else if ((mm
< 1) || (mm
> 12))
1214 int days
[12] = {31,28,31,30,31,30,
1216 if (dd
> days
[mm
-1])
1219 if ((dd
== 29) && (mm
== 2))
1221 if (((yyyy
% 4) == 0) && (((yyyy
% 100) != 0) || ((yyyy
% 400) == 0)))
1231 Contact
->JoinDate
.month
= mm
;
1232 Contact
->JoinDate
.day
= dd
;
1233 Contact
->JoinDate
.year
= yyyy
;
1237 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
);
1241 tStr
= pNameTxt
->GetValue();
1242 wxStrcpy(Contact
->Name
,(const wxChar
*) tStr
);
1243 wxStrcpy(Contact
->Addr1
,pAddress1Txt
->GetValue());
1244 wxStrcpy(Contact
->Addr2
,pAddress2Txt
->GetValue());
1245 wxStrcpy(Contact
->City
,pCityTxt
->GetValue());
1246 wxStrcpy(Contact
->State
,pStateTxt
->GetValue());
1247 wxStrcpy(Contact
->Country
,pCountryTxt
->GetValue());
1248 wxStrcpy(Contact
->PostalCode
,pPostalCodeTxt
->GetValue());
1250 Contact
->Contributions
= atoi(pContribTxt
->GetValue());
1251 Contact
->LinesOfCode
= atol(pLinesTxt
->GetValue());
1253 Contact
->NativeLanguage
= (enum Language
) pNativeLangChoice
->GetSelection();
1254 Contact
->IsDeveloper
= pDeveloperRadio
->GetSelection() > 0;
1257 } // CeditorDlg::GetData()
1261 * Retrieve data from the dialog, verify the validity of the data, and if it is valid,
1262 * try to insert/update the data to the table based on the current 'mode' the dialog
1265 * A return value of TRUE means the insert/update was completed successfully, a return
1266 * value of FALSE means that Save() failed. If returning FALSE, then this function
1267 * has displayed a detailed error message for the user.
1269 bool CeditorDlg::Save()
1271 bool failed
= FALSE
;
1273 // Read the data in the widgets of the dialog to get the user's data
1277 // Perform any other required validations necessary before saving
1280 wxBeginBusyCursor();
1282 if (mode
== mCreate
)
1284 RETCODE result
= Contact
->Insert();
1286 failed
= (result
!= DB_SUCCESS
);
1289 // Some errors may be expected, like a duplicate key, so handle those instances with
1290 // specific error messages.
1291 if (result
== DB_ERR_INTEGRITY_CONSTRAINT_VIOL
)
1294 tStr
= wxT("A duplicate key value already exists in the table.\nUnable to save record\n\n");
1295 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1296 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1300 // Some other unexpexted error occurred
1302 tStr
= wxT("Database insert failed\n\n");
1303 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1304 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1308 else // mode == mEdit
1310 Contact
->whereStr
.Printf("NAME = '%s'",saveName
.c_str());
1311 if (!Contact
->UpdateWhere(Contact
->whereStr
))
1314 tStr
= wxT("Database update failed\n\n");
1315 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1316 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1323 Contact
->GetDb()->CommitTrans();
1324 SetMode(mView
); // Sets the dialog mode back to viewing after save is successful
1327 Contact
->GetDb()->RollbackTrans();
1333 } // CeditorDlg::Save()
1337 * Where this program is only showing a single row at a time in the dialog,
1338 * a special where clause must be built to find just the single row which,
1339 * in sequence, would follow the currently displayed row.
1341 bool CeditorDlg::GetNextRec()
1345 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1347 w
= wxT("NAME = (SELECT MIN(NAME) FROM ");
1348 w
+= Contact
->GetTableName();
1349 w
+= wxT(" WHERE NAME > '");
1352 w
= wxT("(NAME > '");
1357 // If a query where string is currently set, append that criteria
1358 if (!Contact
->qryWhereStr
.IsEmpty())
1361 w
+= Contact
->qryWhereStr
;
1368 } // CeditorDlg::GetNextRec()
1372 * Where this program is only showing a single row at a time in the dialog,
1373 * a special where clause must be built to find just the single row which,
1374 * in sequence, would precede the currently displayed row.
1376 bool CeditorDlg::GetPrevRec()
1380 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1382 w
= wxT("NAME = (SELECT MAX(NAME) FROM ");
1383 w
+= Contact
->GetTableName();
1384 w
+= wxT(" WHERE NAME < '");
1387 w
= wxT("(NAME < '");
1392 // If a query where string is currently set, append that criteria
1393 if (!Contact
->qryWhereStr
.IsEmpty())
1396 w
+= Contact
->qryWhereStr
;
1404 } // CeditorDlg::GetPrevRec()
1408 * This function is here to avoid duplicating this same code in both the
1409 * GetPrevRec() and GetNextRec() functions
1411 bool CeditorDlg::GetRec(const wxString
&whereStr
)
1413 Contact
->SetWhereClause(whereStr
);
1414 Contact
->SetOrderByClause(wxT("NAME"));
1416 if (!Contact
->Query())
1419 tStr
= wxT("ODBC error during Query()\n\n");
1420 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1421 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1426 if (Contact
->GetNext())
1433 } // CeditorDlg::GetRec()
1438 * CparameterDlg constructor
1441 BEGIN_EVENT_TABLE(CparameterDlg
, wxDialog
)
1442 EVT_BUTTON(PARAMETER_DIALOG_SAVE
, CparameterDlg::OnButton
)
1443 EVT_BUTTON(PARAMETER_DIALOG_CANCEL
, CparameterDlg::OnButton
)
1444 EVT_CLOSE(CparameterDlg::OnCloseWindow
)
1447 CparameterDlg::CparameterDlg(wxWindow
*parent
) : wxDialog (parent
, PARAMETER_DIALOG
, wxT("ODBC parameter settings"), wxPoint(-1, -1), wxSize(400, 325))
1449 // Since the ::OnCommand() function is overridden, this prevents the widget
1450 // detection in ::OnCommand() until all widgets have been initialized to prevent
1451 // uninitialized pointers from crashing the program
1452 widgetPtrsSet
= FALSE
;
1454 pParamODBCSourceMsg
= new wxStaticText(this, PARAMETER_DIALOG_SOURCE_MSG
, wxT("ODBC data sources:"), wxPoint( 10, 10), wxSize( -1, -1), 0, wxT("ParamODBCSourceMsg"));
1455 pParamODBCSourceList
= new wxListBox(this, PARAMETER_DIALOG_SOURCE_LISTBOX
, wxPoint( 10, 29), wxSize(285, 150), 0, 0, wxLB_SINGLE
|wxLB_ALWAYS_SB
, wxDefaultValidator
, wxT("ParamODBCSourceList"));
1456 pParamUserNameMsg
= new wxStaticText(this, PARAMETER_DIALOG_NAME_MSG
, wxT("Database user name:"), wxPoint( 10, 193), wxSize( -1, -1), 0, wxT("ParamUserNameMsg"));
1457 pParamUserNameTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_NAME_TEXT
, wxT(""), wxPoint(10, 209), wxSize( 140, 25), 0, wxDefaultValidator
, wxT("ParamUserNameTxt"));
1458 pParamPasswordMsg
= new wxStaticText(this, PARAMETER_DIALOG_PASSWORD_MSG
, wxT("Password:"), wxPoint(156, 193), wxSize( -1, -1), 0, wxT("ParamPasswordMsg"));
1459 pParamPasswordTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_PASSWORD_TEXT
, wxT(""), wxPoint(156, 209), wxSize( 140, 25), 0, wxDefaultValidator
, wxT("ParamPasswordTxt"));
1460 pParamDirPathMsg
= new wxStaticText(this, PARAMETER_DIALOG_DIRPATH_MSG
, wxT("Directory:"), wxPoint( 10, 243), wxSize( -1, -1), 0, wxT("ParamDirPathMsg"));
1461 pParamDirPathTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_DIRPATH_TEXT
, wxT(""), wxPoint( 10, 259), wxSize(140, 25), 0, wxDefaultValidator
, wxT("ParamDirPathTxt"));
1462 pParamSaveBtn
= new wxButton(this, PARAMETER_DIALOG_SAVE
, wxT("&Save"), wxPoint(310, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("ParamSaveBtn"));
1463 pParamCancelBtn
= new wxButton(this, PARAMETER_DIALOG_CANCEL
, wxT("C&ancel"), wxPoint(310, 66), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("ParamCancelBtn"));
1465 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
1466 // handle all widget processing
1467 widgetPtrsSet
= TRUE
;
1470 savedParamSettings
= wxGetApp().params
;
1475 } // CparameterDlg constructor
1478 void CparameterDlg::OnCloseWindow(wxCloseEvent
& event
)
1480 // Put any additional checking necessary to make certain it is alright
1481 // to close the program here that is not done elsewhere
1484 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
);
1492 wxGetApp().params
= savedParamSettings
;
1495 if (GetParent() != NULL
)
1496 GetParent()->SetFocus();
1502 SetReturnCode(0); // added so BoundsChecker would not report use of uninitialized variable
1505 } // CparameterDlg::OnCloseWindow()
1508 void CparameterDlg::OnButton( wxCommandEvent
&event
)
1510 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
1511 OnCommand( *win
, event
);
1515 void CparameterDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
1517 wxString widgetName
;
1519 widgetName
= win
.GetName();
1524 if (widgetName
== pParamSaveBtn
->GetName())
1529 tStr
= wxT("Database parameters have been saved.");
1530 if (GetParent() != NULL
) // The parameter dialog was not called during startup due to a missing cfg file
1531 tStr
+= wxT("\nNew parameters will take effect the next time the program is started.");
1532 wxMessageBox(tStr
,wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
1539 if (widgetName
== pParamCancelBtn
->GetName())
1544 } // CparameterDlg::OnCommand()
1547 bool CparameterDlg::PutData()
1549 // Fill the data source list box
1550 FillDataSourceList();
1552 // Fill in the fields from the params object
1553 if (wxGetApp().params
.ODBCSource
&& wxStrlen(wxGetApp().params
.ODBCSource
))
1554 pParamODBCSourceList
->SetStringSelection(wxGetApp().params
.ODBCSource
);
1555 pParamUserNameTxt
->SetValue(wxGetApp().params
.UserName
);
1556 pParamPasswordTxt
->SetValue(wxGetApp().params
.Password
);
1557 pParamDirPathTxt
->SetValue(wxGetApp().params
.DirPath
);
1559 } // CparameterDlg::PutData()
1562 bool CparameterDlg::GetData()
1565 if (pParamODBCSourceList
->GetStringSelection() != wxT(""))
1567 tStr
= pParamODBCSourceList
->GetStringSelection();
1568 if (tStr
.Length() > (sizeof(wxGetApp().params
.ODBCSource
)-1))
1571 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());
1572 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1575 wxStrcpy(wxGetApp().params
.ODBCSource
, tStr
);
1580 tStr
= pParamUserNameTxt
->GetValue();
1581 if (tStr
.Length() > (sizeof(wxGetApp().params
.UserName
)-1))
1584 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());
1585 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1588 wxStrcpy(wxGetApp().params
.UserName
, tStr
);
1590 tStr
= pParamPasswordTxt
->GetValue();
1591 if (tStr
.Length() > (sizeof(wxGetApp().params
.Password
)-1))
1594 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());
1595 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1598 wxStrcpy(wxGetApp().params
.Password
,tStr
);
1600 tStr
= pParamDirPathTxt
->GetValue();
1601 tStr
.Replace(wxT("\\"),wxT("/"));
1602 if (tStr
.Length() > (sizeof(wxGetApp().params
.DirPath
)-1))
1605 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());
1606 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1609 wxStrcpy(wxGetApp().params
.DirPath
,tStr
);
1611 } // CparameterDlg::GetData()
1614 bool CparameterDlg::Save()
1616 // Copy the current params in case user cancels changing
1617 // the params, so that we can reset them.
1620 wxGetApp().params
= savedParamSettings
;
1624 wxGetApp().WriteParamFile(wxGetApp().params
);
1627 } // CparameterDlg::Save()
1630 void CparameterDlg::FillDataSourceList()
1632 wxChar Dsn
[SQL_MAX_DSN_LENGTH
+ 1];
1634 wxStringList strList
;
1636 while (wxDbGetDataSource(wxGetApp().DbConnectInf
->GetHenv(), Dsn
,
1637 SQL_MAX_DSN_LENGTH
+1, DsDesc
, 255))
1641 strList
.Add(wxT(""));
1642 wxChar
**p
= strList
.ListToArray();
1645 for (i
= 0; wxStrlen(p
[i
]); i
++)
1646 pParamODBCSourceList
->Append(p
[i
]);
1649 } // CparameterDlg::CparameterDlg::FillDataSourceList()
1652 BEGIN_EVENT_TABLE(CqueryDlg
, wxDialog
)
1653 EVT_BUTTON(-1, CqueryDlg::OnButton
)
1654 EVT_CLOSE(CqueryDlg::OnCloseWindow
)
1658 // CqueryDlg() constructor
1659 CqueryDlg::CqueryDlg(wxWindow
*parent
, wxDb
*pDb
, wxChar
*tblName
[], wxChar
*pWhereArg
) : wxDialog (parent
, QUERY_DIALOG
, wxT("Query"), wxPoint(-1, -1), wxSize(480, 360))
1661 wxBeginBusyCursor();
1665 masterTableName
= tblName
[0];
1666 widgetPtrsSet
= FALSE
;
1669 // Initialize the WHERE clause from the string passed in
1670 pWhere
= pWhereArg
; // Save a pointer to the output buffer
1671 if (wxStrlen(pWhere
) > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN
) // Check the length of the buffer passed in
1674 s
.Printf(wxT("Maximum where clause length exceeded.\nLength must be less than %d"), DB_MAX_WHERE_CLAUSE_LEN
+1);
1675 wxMessageBox(s
,wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
1680 pQueryCol1Msg
= new wxStaticText(this, QUERY_DIALOG_COL_MSG
, wxT("Column 1:"), wxPoint( 10, 10), wxSize( 69, 16), 0, wxT("QueryCol1Msg"));
1681 pQueryCol1Choice
= new wxChoice(this, QUERY_DIALOG_COL_CHOICE
, wxPoint( 10, 27), wxSize(250, 27), 0, 0, 0, wxDefaultValidator
, wxT("QueryCol1Choice"));
1682 pQueryNotMsg
= new wxStaticText(this, QUERY_DIALOG_NOT_MSG
, wxT("NOT"), wxPoint(268, 10), wxSize( -1, -1), 0, wxT("QueryNotMsg"));
1683 pQueryNotCheck
= new wxCheckBox(this, QUERY_DIALOG_NOT_CHECKBOX
, wxT(""), wxPoint(275, 37), wxSize( 20, 20), 0, wxDefaultValidator
, wxT("QueryNotCheck"));
1685 wxString choice_strings
[9];
1686 choice_strings
[0] = wxT("=");
1687 choice_strings
[1] = wxT("<");
1688 choice_strings
[2] = wxT(">");
1689 choice_strings
[3] = wxT("<=");
1690 choice_strings
[4] = wxT(">=");
1691 choice_strings
[5] = wxT("Begins");
1692 choice_strings
[6] = wxT("Contains");
1693 choice_strings
[7] = wxT("Like");
1694 choice_strings
[8] = wxT("Between");
1696 pQueryOperatorMsg
= new wxStaticText(this, QUERY_DIALOG_OP_MSG
, wxT("Operator:"), wxPoint(305, 10), wxSize( -1, -1), 0, wxT("QueryOperatorMsg"));
1697 pQueryOperatorChoice
= new wxChoice(this, QUERY_DIALOG_OP_CHOICE
, wxPoint(305, 27), wxSize( 80, 27), 9, choice_strings
, 0, wxDefaultValidator
, wxT("QueryOperatorChoice"));
1698 pQueryCol2Msg
= new wxStaticText(this, QUERY_DIALOG_COL2_MSG
, wxT("Column 2:"), wxPoint( 10, 65), wxSize( 69, 16), 0, wxT("QueryCol2Msg"));
1699 pQueryCol2Choice
= new wxChoice(this, QUERY_DIALOG_COL2_CHOICE
, wxPoint( 10, 82), wxSize(250, 27), 0, 0, 0, wxDefaultValidator
, wxT("QueryCol2Choice"));
1700 pQuerySqlWhereMsg
= new wxStaticText(this, QUERY_DIALOG_WHERE_MSG
, wxT("SQL where clause:"), wxPoint( 10, 141), wxSize( -1, -1), 0, wxT("QuerySqlWhereMsg"));
1701 pQuerySqlWhereMtxt
= new wxTextCtrl(this, QUERY_DIALOG_WHERE_TEXT
, wxT(""), wxPoint( 10, 159), wxSize(377, 134), wxTE_MULTILINE
, wxDefaultValidator
, wxT("QuerySqlWhereMtxt"));
1702 pQueryAddBtn
= new wxButton(this, QUERY_DIALOG_ADD
, wxT("&Add"), wxPoint(406, 24), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryAddBtn"));
1703 pQueryAndBtn
= new wxButton(this, QUERY_DIALOG_AND
, wxT("A&nd"), wxPoint(406, 58), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryAndBtn"));
1704 pQueryOrBtn
= new wxButton(this, QUERY_DIALOG_OR
, wxT("&Or"), wxPoint(406, 92), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryOrBtn"));
1705 pQueryLParenBtn
= new wxButton(this, QUERY_DIALOG_LPAREN
, wxT("("), wxPoint(406, 126), wxSize( 26, 26), 0, wxDefaultValidator
, wxT("QueryLParenBtn"));
1706 pQueryRParenBtn
= new wxButton(this, QUERY_DIALOG_RPAREN
, wxT(")"), wxPoint(436, 126), wxSize( 26, 26), 0, wxDefaultValidator
, wxT("QueryRParenBtn"));
1707 pQueryDoneBtn
= new wxButton(this, QUERY_DIALOG_DONE
, wxT("&Done"), wxPoint(406, 185), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryDoneBtn"));
1708 pQueryClearBtn
= new wxButton(this, QUERY_DIALOG_CLEAR
, wxT("C&lear"), wxPoint(406, 218), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryClearBtn"));
1709 pQueryCountBtn
= new wxButton(this, QUERY_DIALOG_COUNT
, wxT("&Count"), wxPoint(406, 252), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryCountBtn"));
1710 pQueryValue1Msg
= new wxStaticText(this, QUERY_DIALOG_VALUE1_MSG
, wxT("Value:"), wxPoint(277, 66), wxSize( -1, -1), 0, wxT("QueryValue1Msg"));
1711 pQueryValue1Txt
= new wxTextCtrl(this, QUERY_DIALOG_VALUE1_TEXT
, wxT(""), wxPoint(277, 83), wxSize(108, 25), 0, wxDefaultValidator
, wxT("QueryValue1Txt"));
1712 pQueryValue2Msg
= new wxStaticText(this, QUERY_DIALOG_VALUE2_MSG
, wxT("AND"), wxPoint(238, 126), wxSize( -1, -1), 0, wxT("QueryValue2Msg"));
1713 pQueryValue2Txt
= new wxTextCtrl(this, QUERY_DIALOG_VALUE2_TEXT
, wxT(""), wxPoint(277, 120), wxSize(108, 25), 0, wxDefaultValidator
, wxT("QueryValue2Txt"));
1714 pQueryHintGrp
= new wxStaticBox(this, QUERY_DIALOG_HINT_GROUP
, wxT(""), wxPoint( 10, 291), wxSize(377, 40), 0, wxT("QueryHintGrp"));
1715 pQueryHintMsg
= new wxStaticText(this, QUERY_DIALOG_HINT_MSG
, wxT(""), wxPoint( 16, 306), wxSize( -1, -1), 0, wxT("QueryHintMsg"));
1717 widgetPtrsSet
= TRUE
;
1718 // Initialize the dialog
1720 pQueryCol2Choice
->Append(wxT("VALUE -->"));
1721 colInf
= pDB
->GetColumns(tblName
);
1727 tStr
= wxT("ODBC error during GetColumns()\n\n");
1728 tStr
+= GetExtendedDBErrorMsg(pDb
,__FILE__
,__LINE__
);
1729 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1734 for (i
= 0; colInf
[i
].colName
&& wxStrlen(colInf
[i
].colName
); i
++)
1736 // If there is more than one table being queried, qualify
1737 // the column names with the table name prefix.
1738 if (tblName
[1] && wxStrlen(tblName
[1]))
1740 qualName
.Printf(wxT("%s.%s"), colInf
[i
].tableName
, colInf
[i
].colName
);
1741 pQueryCol1Choice
->Append(qualName
);
1742 pQueryCol2Choice
->Append(qualName
);
1744 else // Single table query, append just the column names
1746 pQueryCol1Choice
->Append(colInf
[i
].colName
);
1747 pQueryCol2Choice
->Append(colInf
[i
].colName
);
1751 pQueryCol1Choice
->SetSelection(0);
1752 pQueryCol2Choice
->SetSelection(0);
1753 pQueryOperatorChoice
->SetSelection(0);
1755 pQueryValue2Msg
->Show(FALSE
);
1756 pQueryValue2Txt
->Show(FALSE
);
1758 pQueryHintMsg
->SetLabel(langQRY_EQ
);
1760 pQuerySqlWhereMtxt
->SetValue(pWhere
);
1764 // Display the dialog window
1767 } // CqueryDlg() constructor
1770 CqueryDlg::~CqueryDlg()
1772 } // CqueryDlg::~CqueryDlg() destructor
1775 void CqueryDlg::OnButton(wxCommandEvent
&event
)
1777 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
1778 OnCommand( *win
, event
);
1779 } // CqueryDlg::OnButton()
1782 void CqueryDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
1784 // Widget pointers won't be set when the dialog is constructed.
1785 // Control is passed through this function once for each widget on
1786 // a dialog as the dialog is constructed.
1790 wxString widgetName
= win
.GetName();
1792 // Operator choice box
1793 if (widgetName
== pQueryOperatorChoice
->GetName())
1795 // Set the help text
1796 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
1799 pQueryHintMsg
->SetLabel(langQRY_EQ
);
1802 pQueryHintMsg
->SetLabel(langQRY_LT
);
1805 pQueryHintMsg
->SetLabel(langQRY_GT
);
1808 pQueryHintMsg
->SetLabel(langQRY_LE
);
1811 pQueryHintMsg
->SetLabel(langQRY_GE
);
1814 pQueryHintMsg
->SetLabel(langQRY_BEGINS
);
1817 pQueryHintMsg
->SetLabel(langQRY_CONTAINS
);
1820 pQueryHintMsg
->SetLabel(langQRY_LIKE
);
1823 pQueryHintMsg
->SetLabel(langQRY_BETWEEN
);
1827 // Hide the value2 widget
1828 pQueryValue2Msg
->Show(FALSE
); // BETWEEN will show this widget
1829 pQueryValue2Txt
->Show(FALSE
); // BETWEEN will show this widget
1831 // Disable the NOT operator for <, <=, >, >=
1832 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
1838 pQueryNotCheck
->SetValue(0);
1839 pQueryNotCheck
->Enable(FALSE
);
1842 pQueryNotCheck
->Enable(TRUE
);
1846 // Manipulate the dialog to handle the selected operator
1847 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
1854 pQueryCol2Choice
->Enable(TRUE
);
1855 if (pQueryCol2Choice
->GetSelection()) // Column name is highlighted
1857 pQueryValue1Msg
->Show(FALSE
);
1858 pQueryValue1Txt
->Show(FALSE
);
1860 else // "Value" is highlighted
1862 pQueryValue1Msg
->Show(TRUE
);
1863 pQueryValue1Txt
->Show(TRUE
);
1864 pQueryValue1Txt
->SetFocus();
1870 pQueryCol2Choice
->SetSelection(0);
1871 pQueryCol2Choice
->Enable(FALSE
);
1872 pQueryValue1Msg
->Show(TRUE
);
1873 pQueryValue1Txt
->Show(TRUE
);
1874 pQueryValue1Txt
->SetFocus();
1877 pQueryCol2Choice
->SetSelection(0);
1878 pQueryCol2Choice
->Enable(FALSE
);
1879 pQueryValue2Msg
->Show(TRUE
);
1880 pQueryValue2Txt
->Show(TRUE
);
1881 pQueryValue1Msg
->Show(TRUE
);
1882 pQueryValue1Txt
->Show(TRUE
);
1883 pQueryValue1Txt
->SetFocus();
1889 } // Operator choice box
1892 if (widgetName
== pQueryCol2Choice
->GetName())
1894 if (pQueryCol2Choice
->GetSelection()) // Column name is highlighted
1896 pQueryValue1Msg
->Show(FALSE
);
1897 pQueryValue1Txt
->Show(FALSE
);
1899 else // "Value" is highlighted
1901 pQueryValue1Msg
->Show(TRUE
);
1902 pQueryValue1Txt
->Show(TRUE
);
1903 pQueryValue1Txt
->SetFocus();
1906 } // Column 2 choice
1909 if (widgetName
== pQueryAddBtn
->GetName())
1916 if (widgetName
== pQueryAndBtn
->GetName())
1918 AppendToWhere(wxT(" AND\n"));
1923 if (widgetName
== pQueryOrBtn
->GetName())
1925 AppendToWhere(wxT(" OR\n"));
1929 // Left Paren button
1930 if (widgetName
== pQueryLParenBtn
->GetName())
1932 AppendToWhere(wxT("("));
1934 } // Left Paren button
1936 // Right paren button
1937 if (widgetName
== pQueryRParenBtn
->GetName())
1939 AppendToWhere(wxT(")"));
1941 } // Right Paren button
1944 if (widgetName
== pQueryDoneBtn
->GetName())
1946 // Be sure the where clause will not overflow the output buffer
1947 if (wxStrlen(pQuerySqlWhereMtxt
->GetValue()) > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN
)
1950 s
.Printf(wxT("Maximum where clause length exceeded.\nLength must be less than %d"), DB_MAX_WHERE_CLAUSE_LEN
+1);
1951 wxMessageBox(s
,wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
1954 // Validate the where clause for things such as matching parens
1955 if (!ValidateWhereClause())
1957 // Copy the where clause to the output buffer and exit
1958 wxStrcpy(pWhere
, pQuerySqlWhereMtxt
->GetValue());
1964 if (widgetName
== pQueryClearBtn
->GetName())
1966 bool Ok
= (wxMessageBox(wxT("Are you sure you wish to clear the Query?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
1969 pQuerySqlWhereMtxt
->SetValue(wxT(""));
1974 if (widgetName
== pQueryCountBtn
->GetName())
1976 wxBeginBusyCursor();
1982 } // CqueryDlg::OnCommand
1985 void CqueryDlg::OnCloseWindow(wxCloseEvent
& event
)
2000 GetParent()->SetFocus();
2005 SetReturnCode(1); // added so BoundsChecker would not report use of uninitialized variable
2008 } // CqueryDlg::OnCloseWindow()
2011 void CqueryDlg::AppendToWhere(wxChar
*s
)
2013 wxString whereStr
= pQuerySqlWhereMtxt
->GetValue();
2015 pQuerySqlWhereMtxt
->SetValue(whereStr
);
2016 } // CqueryDlg::AppendToWhere()
2019 void CqueryDlg::ProcessAddBtn()
2021 qryOp oper
= (qryOp
) pQueryOperatorChoice
->GetSelection();
2023 // Verify that eveything is filled in correctly
2024 if (pQueryCol2Choice
->GetSelection() == 0) // "Value" is selected
2026 // Verify that value 1 is filled in
2027 if (wxStrlen(pQueryValue1Txt
->GetValue()) == 0)
2030 pQueryValue1Txt
->SetFocus();
2033 // For the BETWEEN operator, value 2 must be filled in as well
2034 if (oper
== qryOpBETWEEN
&&
2035 wxStrlen(pQueryValue2Txt
->GetValue()) == 0)
2038 pQueryValue2Txt
->SetFocus();
2043 // Build the expression and append it to the where clause window
2044 wxString s
= pQueryCol1Choice
->GetStringSelection();
2046 if (pQueryNotCheck
->GetValue() && (oper
!= qryOpEQ
))
2052 if (pQueryNotCheck
->GetValue()) // NOT box is checked
2075 s
+= wxT(" BETWEEN");
2081 int col1Idx
= pQueryCol1Choice
->GetSelection();
2084 if (colInf
[col1Idx
].sqlDataType
== SQL_VARCHAR
||
2085 oper
== qryOpBEGINS
||
2086 oper
== qryOpCONTAINS
||
2090 if (pQueryCol2Choice
->GetSelection()) // Column name
2091 s
+= pQueryCol2Choice
->GetStringSelection();
2092 else // Column 2 is a "value"
2096 if (oper
== qryOpCONTAINS
)
2098 s
+= pQueryValue1Txt
->GetValue();
2099 if (oper
== qryOpCONTAINS
|| oper
== qryOpBEGINS
)
2105 if (oper
== qryOpBETWEEN
)
2110 s
+= pQueryValue2Txt
->GetValue();
2115 AppendToWhere((wxChar
*) (const wxChar
*) s
);
2117 } // CqueryDlg::ProcessAddBtn()
2120 void CqueryDlg::ProcessCountBtn()
2122 if (!ValidateWhereClause())
2125 if (dbTable
== 0) // wxDbTable object needs to be created and opened
2127 if (!(dbTable
= new wxDbTable(pDB
, masterTableName
, 0, wxT(""),
2129 wxGetApp().DbConnectInf
->GetDefaultDir())))
2131 wxMessageBox(wxT("Memory allocation failed creating a wxDbTable object."),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
2134 if (!dbTable
->Open())
2137 tStr
= wxT("ODBC error during Open()\n\n");
2138 tStr
+= GetExtendedDBErrorMsg(dbTable
->GetDb(),__FILE__
,__LINE__
);
2139 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
2144 // Count() with WHERE clause
2147 whereStr
= pQuerySqlWhereMtxt
->GetValue();
2148 dbTable
->SetWhereClause(whereStr
.c_str());
2150 ULONG whereCnt
= dbTable
->Count();
2152 // Count() of all records in the table
2153 dbTable
->SetWhereClause(wxT(""));
2154 ULONG totalCnt
= dbTable
->Count();
2156 if (whereCnt
> 0 || totalCnt
== 0)
2159 tStr
.Printf(wxT("%lu of %lu records match the query criteria."),whereCnt
,totalCnt
);
2160 wxMessageBox(tStr
,wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
2165 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
);
2166 wxMessageBox(tStr
,wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
2169 // After a wxMessageBox, the focus does not necessarily return to the
2170 // window which was the focus when the message box popped up, so return
2171 // focus to the Query dialog for certain
2174 } // CqueryDlg::ProcessCountBtn()
2177 bool CqueryDlg::ValidateWhereClause()
2179 wxString where
= pQuerySqlWhereMtxt
->GetValue();
2181 if (where
.Freq(wxT('(')) != where
.Freq(wxT(')')))
2183 wxMessageBox(wxT("There are mismatched parenthesis in the constructed where clause"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
2186 // After a wxMessageBox, the focus does not necessarily return to the
2187 // window which was the focus when the message box popped up, so return
2188 // focus to the Query dialog for certain
2193 } // CqueryDlg::ValidateWhereClause()
2199 TEST CODE FOR TESTING THE wxDbCreateDataSource() FUNCTION
2202 result = wxDbCreateDataSource(wxT("Microsoft Access Driver (*.mdb)"),wxT("GLT-TEST2"),wxT("GLT-Descrip"),FALSE,wxT(""),this);
2205 // check for errors caused by ConfigDSN based functions
2208 wxChar errMsg[500+1];
2209 errMsg[0] = wxT('\0');
2211 SQLInstallerError(1,&retcode,errMsg,500,&cb);
2213 wxMessageBox(wxT("FAILED creating data source"),wxT("FAILED"));
2216 wxMessageBox(wxT("SUCCEEDED creating data source"),wxT("SUCCESS"));