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 DataTypeSupported(wxDb
*pDb
, SWORD datatype
)
99 wxDbSqlTypeInfo sqlTypeInfo
;
101 bool breakpoint
= FALSE
;
103 if (pDb
->GetDataTypeInfo(datatype
, sqlTypeInfo
))
108 } // GetDataTypesSupported();
112 void CheckSupportForAllDataTypes(wxDb
*pDb
)
116 supported
= DataTypeSupported(pDb
,SQL_C_BINARY
);
119 supported
= DataTypeSupported(pDb
,SQL_C_BIT
);
121 #ifdef SQL_C_BOOKMARK
122 supported
= DataTypeSupported(pDb
,SQL_C_BOOKMARK
);
125 supported
= DataTypeSupported(pDb
,SQL_C_CHAR
);
128 supported
= DataTypeSupported(pDb
,SQL_C_DATE
);
131 supported
= DataTypeSupported(pDb
,SQL_C_DEFAULT
);
134 supported
= DataTypeSupported(pDb
,SQL_C_DOUBLE
);
137 supported
= DataTypeSupported(pDb
,SQL_C_FLOAT
);
140 supported
= DataTypeSupported(pDb
,SQL_C_GUID
);
142 #ifdef SQL_C_INTERVAL_DAY
143 supported
= DataTypeSupported(pDb
,SQL_C_INTERVAL_DAY
);
145 #ifdef SQL_C_INTERVAL_DAY_TO_HOUR
146 supported
= DataTypeSupported(pDb
,SQL_C_INTERVAL_DAY_TO_HOUR
);
148 #ifdef SQL_C_INTERVAL_DAY_TO_MINUTE
149 supported
= DataTypeSupported(pDb
,SQL_C_INTERVAL_DAY_TO_MINUTE
);
151 #ifdef SQL_C_INTERVAL_DAY_TO_SECOND
152 supported
= DataTypeSupported(pDb
,SQL_C_INTERVAL_DAY_TO_SECOND
);
154 #ifdef SQL_C_INTERVAL_HOUR
155 supported
= DataTypeSupported(pDb
,SQL_C_INTERVAL_HOUR
);
157 #ifdef SQL_C_INTERVAL_HOUR_TO_MINUTE
158 supported
= DataTypeSupported(pDb
,SQL_C_INTERVAL_HOUR_TO_MINUTE
);
160 #ifdef SQL_C_INTERVAL_HOUR_TO_SECOND
161 supported
= DataTypeSupported(pDb
,SQL_C_INTERVAL_HOUR_TO_SECOND
);
163 #ifdef SQL_C_INTERVAL_MINUTE
164 supported
= DataTypeSupported(pDb
,SQL_C_INTERVAL_MINUTE
);
166 #ifdef SQL_C_INTERVAL_MINUTE_TO_SECOND
167 supported
= DataTypeSupported(pDb
,SQL_C_INTERVAL_MINUTE_TO_SECOND
);
169 #ifdef SQL_C_INTERVAL_MONTH
170 supported
= DataTypeSupported(pDb
,SQL_C_INTERVAL_MONTH
);
172 #ifdef SQL_C_INTERVAL_SECOND
173 supported
= DataTypeSupported(pDb
,SQL_C_INTERVAL_SECOND
);
175 #ifdef SQL_C_INTERVAL_YEAR
176 supported
= DataTypeSupported(pDb
,SQL_C_INTERVAL_YEAR
);
178 #ifdef SQL_C_INTERVAL_YEAR_TO_MONTH
179 supported
= DataTypeSupported(pDb
,SQL_C_INTERVAL_YEAR_TO_MONTH
);
182 supported
= DataTypeSupported(pDb
,SQL_C_LONG
);
185 supported
= DataTypeSupported(pDb
,SQL_C_NUMERIC
);
188 supported
= DataTypeSupported(pDb
,SQL_C_SBIGINT
);
191 supported
= DataTypeSupported(pDb
,SQL_C_SHORT
);
194 supported
= DataTypeSupported(pDb
,SQL_C_SLONG
);
197 supported
= DataTypeSupported(pDb
,SQL_C_SSHORT
);
199 #ifdef SQL_C_STINYINT
200 supported
= DataTypeSupported(pDb
,SQL_C_STINYINT
);
203 supported
= DataTypeSupported(pDb
,SQL_C_TIME
);
205 #ifdef SQL_C_TIMESTAMP
206 supported
= DataTypeSupported(pDb
,SQL_C_TIMESTAMP
);
209 supported
= DataTypeSupported(pDb
,SQL_C_TINYINT
);
211 #ifdef SQL_C_TYPE_DATE
212 supported
= DataTypeSupported(pDb
,SQL_C_TYPE_DATE
);
214 #ifdef SQL_C_TYPE_TIME
215 supported
= DataTypeSupported(pDb
,SQL_C_TYPE_TIME
);
217 #ifdef SQL_C_TYPE_TIMESTAMP
218 supported
= DataTypeSupported(pDb
,SQL_C_TYPE_TIMESTAMP
);
221 supported
= DataTypeSupported(pDb
,SQL_C_UBIGINT
);
224 supported
= DataTypeSupported(pDb
,SQL_C_ULONG
);
227 supported
= DataTypeSupported(pDb
,SQL_C_USHORT
);
229 #ifdef SQL_C_UTINYINT
230 supported
= DataTypeSupported(pDb
,SQL_C_UTINYINT
);
232 #ifdef SQL_C_VARBOOKMARK
233 supported
= DataTypeSupported(pDb
,SQL_C_VARBOOKMARK
);
236 // Extended SQL types
238 supported
= DataTypeSupported(pDb
,SQL_DATE
);
241 supported
= DataTypeSupported(pDb
,SQL_INTERVAL
);
244 supported
= DataTypeSupported(pDb
,SQL_TIME
);
247 supported
= DataTypeSupported(pDb
,SQL_TIMESTAMP
);
249 #ifdef SQL_LONGVARCHAR
250 supported
= DataTypeSupported(pDb
,SQL_LONGVARCHAR
);
253 supported
= DataTypeSupported(pDb
,SQL_BINARY
);
256 supported
= DataTypeSupported(pDb
,SQL_VARBINARY
);
258 #ifdef SQL_LONGVARBINARY
259 supported
= DataTypeSupported(pDb
,SQL_LONGVARBINARY
);
262 supported
= DataTypeSupported(pDb
,SQL_BIGINT
);
265 supported
= DataTypeSupported(pDb
,SQL_TINYINT
);
268 supported
= DataTypeSupported(pDb
,SQL_BIT
);
271 supported
= DataTypeSupported(pDb
,SQL_GUID
);
275 supported
= DataTypeSupported(pDb
,SQL_CHAR
);
278 supported
= DataTypeSupported(pDb
,SQL_INTEGER
);
281 supported
= DataTypeSupported(pDb
,SQL_SMALLINT
);
284 supported
= DataTypeSupported(pDb
,SQL_REAL
);
287 supported
= DataTypeSupported(pDb
,SQL_DOUBLE
);
290 supported
= DataTypeSupported(pDb
,SQL_NUMERIC
);
293 supported
= DataTypeSupported(pDb
,SQL_DATE
);
296 supported
= DataTypeSupported(pDb
,SQL_TIME
);
299 supported
= DataTypeSupported(pDb
,SQL_TIMESTAMP
);
302 supported
= DataTypeSupported(pDb
,SQL_VARCHAR
);
308 supported
= DataTypeSupported(pDb
,SQL_C_TCHAR
);
310 } // CheckSupportForAllDataTypes()
313 bool DatabaseDemoApp::OnInit()
318 // Create the main frame window
319 DemoFrame
= new DatabaseDemoFrame(NULL
, wxT("wxWindows Database Demo"), wxPoint(50, 50), wxSize(537, 480));
322 DemoFrame
->SetIcon(wxICON(db
));
325 wxMenu
*file_menu
= new wxMenu
;
326 file_menu
->Append(FILE_CREATE
, wxT("&Create CONTACT table"));
327 file_menu
->Append(FILE_RECREATE_TABLE
, wxT("&Recreate CONTACT table"));
328 file_menu
->Append(FILE_RECREATE_INDEXES
, wxT("&Recreate CONTACT indexes"));
329 file_menu
->Append(FILE_EXIT
, wxT("E&xit"));
331 wxMenu
*edit_menu
= new wxMenu
;
332 edit_menu
->Append(EDIT_PARAMETERS
, wxT("&Parameters..."));
334 wxMenu
*help_menu
= new wxMenu
;
335 help_menu
->Append(HELP_ABOUT
, wxT("&About"));
337 wxMenuBar
*menu_bar
= new wxMenuBar
;
338 menu_bar
->Append(file_menu
, wxT("&File"));
339 menu_bar
->Append(edit_menu
, wxT("&Edit"));
340 menu_bar
->Append(help_menu
, wxT("&Help"));
341 DemoFrame
->SetMenuBar(menu_bar
);
343 params
.ODBCSource
[0] = 0;
344 params
.UserName
[0] = 0;
345 params
.Password
[0] = 0;
346 params
.DirPath
[0] = 0;
349 DemoFrame
->Show(TRUE
);
351 // Passing NULL for the SQL environment handle causes
352 // the wxDbConnectInf constructor to obtain a handle
355 // WARNING: Be certain that you do not free this handle
356 // directly with SQLFreeEnv(). Use either the
357 // method ::FreeHenv() or delete the DbConnectInf.
358 DbConnectInf
= new wxDbConnectInf(NULL
, params
.ODBCSource
, params
.UserName
,
359 params
.Password
, params
.DirPath
);
361 if (!DbConnectInf
|| !DbConnectInf
->GetHenv())
363 wxMessageBox(wxT("Unable to define data source connection info."), wxT("DB CONNECTION ERROR..."),wxOK
| wxICON_EXCLAMATION
);
364 wxDELETE(DbConnectInf
);
367 if (!ReadParamFile(params
))
368 DemoFrame
->BuildParameterDialog(NULL
);
370 if (!wxStrlen(params
.ODBCSource
))
372 wxDELETE(DbConnectInf
);
376 DbConnectInf
->SetDsn(params
.ODBCSource
);
377 DbConnectInf
->SetUserID(params
.UserName
);
378 DbConnectInf
->SetPassword(params
.Password
);
379 DbConnectInf
->SetDefaultDir(params
.DirPath
);
381 READONLY_DB
= wxDbGetConnection(DbConnectInf
);
382 if (READONLY_DB
== 0)
384 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
);
385 DemoFrame
->BuildParameterDialog(NULL
);
386 wxDELETE(DbConnectInf
);
387 wxMessageBox(wxT("Now exiting program.\n\nRestart program to try any new settings."),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
391 DemoFrame
->BuildEditorDialog();
394 DemoFrame
->Refresh();
397 } // DatabaseDemoApp::OnInit()
400 bool DatabaseDemoApp::ReadParamFile(Cparameters
¶ms
)
403 if ((paramFile
= fopen(PARAM_FILENAME
, wxT("r"))) == NULL
)
406 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
);
407 wxMessageBox(tStr
,wxT("File I/O Error..."),wxOK
| wxICON_EXCLAMATION
);
412 wxChar buffer
[1000+1];
413 fgets(buffer
, sizeof(params
.ODBCSource
), paramFile
);
414 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
415 wxStrcpy(params
.ODBCSource
,buffer
);
417 fgets(buffer
, sizeof(params
.UserName
), paramFile
);
418 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
419 wxStrcpy(params
.UserName
,buffer
);
421 fgets(buffer
, sizeof(params
.Password
), paramFile
);
422 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
423 wxStrcpy(params
.Password
,buffer
);
425 fgets(buffer
, sizeof(params
.DirPath
), paramFile
);
426 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
427 wxStrcpy(params
.DirPath
,buffer
);
432 } // DatabaseDemoApp::ReadParamFile()
435 bool DatabaseDemoApp::WriteParamFile(Cparameters
¶ms
)
438 if ((paramFile
= fopen(PARAM_FILENAME
, wxT("wt"))) == NULL
)
441 tStr
.Printf(wxT("Unable to write/overwrite '%s'."),PARAM_FILENAME
);
442 wxMessageBox(tStr
,wxT("File I/O Error..."),wxOK
| wxICON_EXCLAMATION
);
446 fputs(wxGetApp().params
.ODBCSource
, paramFile
);
447 fputc(wxT('\n'), paramFile
);
448 fputs(wxGetApp().params
.UserName
, paramFile
);
449 fputc(wxT('\n'), paramFile
);
450 fputs(wxGetApp().params
.Password
, paramFile
);
451 fputc(wxT('\n'), paramFile
);
452 fputs(wxGetApp().params
.DirPath
, paramFile
);
453 fputc(wxT('\n'), paramFile
);
457 } // DatabaseDemoApp::WriteParamFile()
460 void DatabaseDemoApp::CreateDataTable(bool recreate
)
464 Ok
= (wxMessageBox(wxT("Any data currently residing in the table will be erased.\n\nAre you sure?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
473 Contact
->GetDb()->RollbackTrans(); // Make sure the current cursor is in a known/stable state
475 if (!Contact
->CreateTable(recreate
))
479 tStr
= wxT("Error creating CONTACTS table.\nTable was not created.\n\n");
480 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
481 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
486 if (!Contact
->CreateIndexes())
490 tStr
= wxT("Error creating CONTACTS indexes.\nIndexes will be unavailable.\n\n");
491 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
492 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
500 wxMessageBox(wxT("Table and index(es) were successfully created."),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
501 } // DatabaseDemoApp::CreateDataTable()
504 BEGIN_EVENT_TABLE(DatabaseDemoFrame
, wxFrame
)
505 EVT_MENU(FILE_CREATE
, DatabaseDemoFrame::OnCreate
)
506 EVT_MENU(FILE_RECREATE_TABLE
, DatabaseDemoFrame::OnRecreateTable
)
507 EVT_MENU(FILE_RECREATE_INDEXES
, DatabaseDemoFrame::OnRecreateIndexes
)
508 EVT_MENU(FILE_EXIT
, DatabaseDemoFrame::OnExit
)
509 EVT_MENU(EDIT_PARAMETERS
, DatabaseDemoFrame::OnEditParameters
)
510 EVT_MENU(HELP_ABOUT
, DatabaseDemoFrame::OnAbout
)
511 EVT_CLOSE(DatabaseDemoFrame::OnCloseWindow
)
515 // DatabaseDemoFrame constructor
516 DatabaseDemoFrame::DatabaseDemoFrame(wxFrame
*frame
, const wxString
& title
,
517 const wxPoint
& pos
, const wxSize
& size
):
518 wxFrame(frame
, -1, title
, pos
, size
)
520 // Put any code in necessary for initializing the main frame here
523 } // DatabaseDemoFrame constructor
526 void DatabaseDemoFrame::OnCreate(wxCommandEvent
& event
)
528 wxGetApp().CreateDataTable(FALSE
);
529 } // DatabaseDemoFrame::OnCreate()
532 void DatabaseDemoFrame::OnRecreateTable(wxCommandEvent
& event
)
534 wxGetApp().CreateDataTable(TRUE
);
535 } // DatabaseDemoFrame::OnRecreate()
538 void DatabaseDemoFrame::OnRecreateIndexes(wxCommandEvent
& event
)
540 if (!wxGetApp().Contact
->CreateIndexes())
545 tStr
= wxT("Error creating CONTACTS indexes.\nNew indexes will be unavailable.\n\n");
546 tStr
+= GetExtendedDBErrorMsg(wxGetApp().Contact
->GetDb(),__FILE__
,__LINE__
);
547 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
550 wxMessageBox(wxT("Index(es) were successfully recreated."),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
552 } // DatabaseDemoFrame::OnRecreateIndexes()
555 void DatabaseDemoFrame::OnExit(wxCommandEvent
& event
)
558 } // DatabaseDemoFrame::OnExit()
561 void DatabaseDemoFrame::OnEditParameters(wxCommandEvent
& event
)
563 if ((pEditorDlg
->mode
!= mCreate
) && (pEditorDlg
->mode
!= mEdit
))
564 BuildParameterDialog(this);
566 wxMessageBox(wxT("Cannot change database parameters while creating or editing a record"),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
567 } // DatabaseDemoFrame::OnEditParameters()
570 void DatabaseDemoFrame::OnAbout(wxCommandEvent
& event
)
572 wxMessageBox(wxT("wxWindows sample program for database classes\n\nContributed on 27 July 1998"),wxT("About..."),wxOK
| wxICON_INFORMATION
);
573 } // DatabaseDemoFrame::OnAbout()
576 // Put any additional checking necessary to make certain it is alright
577 // to close the program here that is not done elsewhere
578 void DatabaseDemoFrame::OnCloseWindow(wxCloseEvent
& event
)
581 if (pEditorDlg
&& pEditorDlg
->Close())
592 wxDELETE(wxGetApp().Contact
);
594 // This function will close all the connections to the database that have been
595 // previously cached.
596 wxDbCloseConnections();
598 // Deletion of the wxDbConnectInf instance must be the LAST thing done that
599 // has anything to do with the database. Deleting this before disconnecting,
600 // freeing/closing connections, etc will result in a crash!
601 wxDELETE(wxGetApp().DbConnectInf
);
605 } // DatabaseDemoFrame::OnCloseWindow()
608 void DatabaseDemoFrame::BuildEditorDialog()
611 pEditorDlg
= new CeditorDlg(this);
614 pEditorDlg
->Initialize();
615 if (!pEditorDlg
->initialized
)
619 wxMessageBox(wxT("Unable to initialize the editor dialog for some reason"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
625 wxMessageBox(wxT("Unable to create the editor dialog for some reason"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
628 } // DatabaseDemoFrame::BuildEditorDialog()
631 void DatabaseDemoFrame::BuildParameterDialog(wxWindow
*parent
)
633 pParamDlg
= new CparameterDlg(parent
);
636 wxMessageBox(wxT("Unable to create the parameter dialog for some reason"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
637 } // DatabaseDemoFrame::BuildParameterDialog()
641 * Constructor note: If no wxDb object is passed in, a new connection to the database
642 * is created for this instance of Ccontact. This can be a slow process depending
643 * on the database engine being used, and some database engines have a limit on the
644 * number of connections (either hard limits, or license restricted) so care should
645 * be used to use as few connections as is necessary.
647 * IMPORTANT: Objects which share a wxDb pointer are ALL acted upon whenever a member
648 * function of pDb is called (i.e. CommitTrans() or RollbackTrans(), so if modifying
649 * or creating a table objects which use the same pDb, know that all the objects
650 * will be committed or rolled back when any of the objects has this function call made.
652 Ccontact::Ccontact (wxDb
*pwxDb
) : wxDbTable(pwxDb
? pwxDb
: wxDbGetConnection(wxGetApp().DbConnectInf
),
653 CONTACT_TABLE_NAME
, CONTACT_NO_COLS
, wxT(""),
654 !wxDB_QUERY_ONLY
, wxGetApp().DbConnectInf
->GetDefaultDir())
656 // This is used to represent whether the database connection should be released
657 // when this instance of the object is deleted. If using the same connection
658 // for multiple instance of database objects, then the connection should only be
659 // released when the last database instance using the connection is deleted
663 GetDb()->SetSqlLogging(sqlLogON
);
667 } // Ccontact Constructor
670 void Ccontact::Initialize()
679 JoinDate
.year
= 1980;
685 JoinDate
.fraction
= 0;
686 NativeLanguage
= langENGLISH
;
690 } // Ccontact::Initialize
693 Ccontact::~Ccontact()
697 if (!wxDbFreeConnection(GetDb()))
700 tStr
= wxT("Unable to Free the Ccontact data table handle\n\n");
701 tStr
+= GetExtendedDBErrorMsg(GetDb(),__FILE__
,__LINE__
);
702 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
705 } // Ccontract destructor
709 * Handles setting up all the connections for the interface from the wxDbTable
710 * functions to interface to the data structure used to store records in
711 * memory, and for all the column definitions that define the table structure
713 void Ccontact::SetupColumns()
715 // NOTE: Columns now are 8 character names, as that is all dBase can support. Longer
716 // names can be used for other database engines
717 SetColDefs ( 0,wxT("NAME"), DB_DATA_TYPE_VARCHAR
, Name
, SQL_C_CHAR
, sizeof(Name
), TRUE
, TRUE
); // Primary index
718 SetColDefs ( 1,wxT("ADDRESS1"), DB_DATA_TYPE_VARCHAR
, Addr1
, SQL_C_CHAR
, sizeof(Addr1
), FALSE
,TRUE
);
719 SetColDefs ( 2,wxT("ADDRESS2"), DB_DATA_TYPE_VARCHAR
, Addr2
, SQL_C_CHAR
, sizeof(Addr2
), FALSE
,TRUE
);
720 SetColDefs ( 3,wxT("CITY"), DB_DATA_TYPE_VARCHAR
, City
, SQL_C_CHAR
, sizeof(City
), FALSE
,TRUE
);
721 SetColDefs ( 4,wxT("STATE"), DB_DATA_TYPE_VARCHAR
, State
, SQL_C_CHAR
, sizeof(State
), FALSE
,TRUE
);
722 SetColDefs ( 5,wxT("POSTCODE"), DB_DATA_TYPE_VARCHAR
, PostalCode
, SQL_C_CHAR
, sizeof(PostalCode
), FALSE
,TRUE
);
723 SetColDefs ( 6,wxT("COUNTRY"), DB_DATA_TYPE_VARCHAR
, Country
, SQL_C_CHAR
, sizeof(Country
), FALSE
,TRUE
);
724 SetColDefs ( 7,wxT("JOINDATE"), DB_DATA_TYPE_DATE
, &JoinDate
, SQL_C_TIMESTAMP
, sizeof(JoinDate
), FALSE
,TRUE
);
725 SetColDefs ( 8,wxT("IS_DEV"), DB_DATA_TYPE_INTEGER
, &IsDeveloper
, SQL_C_BOOLEAN(IsDeveloper
), sizeof(IsDeveloper
), FALSE
,TRUE
);
726 SetColDefs ( 9,wxT("CONTRIBS"), DB_DATA_TYPE_INTEGER
, &Contributions
, SQL_C_USHORT
, sizeof(Contributions
), FALSE
,TRUE
);
727 SetColDefs (10,wxT("LINE_CNT"), DB_DATA_TYPE_INTEGER
, &LinesOfCode
, SQL_C_ULONG
, sizeof(LinesOfCode
), FALSE
,TRUE
);
728 SetColDefs (11,wxT("LANGUAGE"), DB_DATA_TYPE_INTEGER
, &NativeLanguage
, SQL_C_ENUM
, sizeof(NativeLanguage
), FALSE
,TRUE
);
729 #if wxODBC_BLOB_EXPERIMENT > 0
730 SetColDefs (12,wxT("PICTURE"), DB_DATA_TYPE_BLOB
, Picture
, SQL_LONGVARBINARY
, sizeof(Picture
), FALSE
,TRUE
);
732 } // Ccontact::SetupColumns
735 bool Ccontact::CreateIndexes(void)
737 // This index could easily be accomplished with an "orderBy" clause,
738 // but is done to show how to construct a non-primary index.
740 wxDbIdxDef idxDef
[2];
744 wxStrcpy(idxDef
[0].ColName
, "IS_DEV");
745 idxDef
[0].Ascending
= TRUE
;
747 wxStrcpy(idxDef
[1].ColName
, "NAME");
748 idxDef
[1].Ascending
= TRUE
;
750 indexName
= GetTableName();
751 indexName
+= "_IDX1";
752 Ok
= CreateIndex(indexName
.c_str(), TRUE
, 2, idxDef
);
755 } // Ccontact::CreateIndexes()
759 * Having a function to do a query on the primary key (and possibly others) is
760 * very efficient and tighter coding so that it is available where ever the object
761 * is. Great for use with multiple tables when not using views or outer joins
763 bool Ccontact::FetchByName(const wxString
&name
)
765 whereStr
.Printf(wxT("NAME = '%s'"),name
.c_str());
766 SetWhereClause(whereStr
.c_str());
767 SetOrderByClause(wxT(""));
775 } // Ccontact::FetchByName()
780 * ************* DIALOGS ***************
785 /* CeditorDlg constructor
787 * Creates the dialog used for creating/editing/deleting/copying a Ccontact object.
788 * This dialog actually is drawn in the main frame of the program
790 * An instance of Ccontact is created - "Contact" - which is used to hold the Ccontact
791 * object that is currently being worked with.
794 BEGIN_EVENT_TABLE(CeditorDlg
, wxPanel
)
795 EVT_BUTTON(-1, CeditorDlg::OnButton
)
796 EVT_CLOSE(CeditorDlg::OnCloseWindow
)
799 CeditorDlg::CeditorDlg(wxWindow
*parent
) : wxPanel (parent
, 0, 0, 537, 480)
801 // Since the ::OnCommand() function is overridden, this prevents the widget
802 // detection in ::OnCommand() until all widgets have been initialized to prevent
803 // uninitialized pointers from crashing the program
804 widgetPtrsSet
= FALSE
;
811 } // CeditorDlg constructor
814 void CeditorDlg::OnCloseWindow(wxCloseEvent
& event
)
817 if ((mode
!= mCreate
) && (mode
!= mEdit
))
823 wxMessageBox(wxT("Must finish processing the current record being created/modified before exiting"),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
826 } // CeditorDlg::OnCloseWindow()
829 void CeditorDlg::OnButton(wxCommandEvent
&event
)
831 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
832 OnCommand( *win
, event
);
833 } // CeditorDlg::OnButton()
836 void CeditorDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
840 widgetName
= win
.GetName();
845 if (widgetName
== pCreateBtn
->GetName())
847 wxGetApp().Contact
->Initialize();
850 pNameTxt
->SetValue(wxT(""));
851 pNameTxt
->SetFocus();
855 if (widgetName
== pEditBtn
->GetName())
857 saveName
= wxGetApp().Contact
->Name
;
859 pNameTxt
->SetFocus();
863 if (widgetName
== pCopyBtn
->GetName())
866 CheckSupportForAllDataTypes(wxGetApp().READONLY_DB
);
869 pNameTxt->SetValue(wxT(""));
870 pNameTxt->SetFocus();
875 if (widgetName
== pDeleteBtn
->GetName())
877 bool Ok
= (wxMessageBox(wxT("Are you sure?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
882 if (Ok
&& wxGetApp().Contact
->Delete())
884 // NOTE: Deletions are not finalized until a CommitTrans() is performed.
885 // If the commit were not performed, the program will continue to
886 // show the table contents as if they were deleted until this instance
887 // of Ccontact is deleted. If the Commit wasn't performed, the
888 // database will automatically Rollback the changes when the database
889 // connection is terminated
890 wxGetApp().Contact
->GetDb()->CommitTrans();
892 // Try to get the row that followed the just deleted row in the orderBy sequence
895 // There was now row (in sequence) after the just deleted row, so get the
896 // row which preceded the just deleted row
899 // There are now no rows remaining, so clear the dialog widgets
900 wxGetApp().Contact
->Initialize();
904 SetMode(mode
); // force reset of button enable/disable
908 wxGetApp().Contact
->GetDb()->RollbackTrans();
914 if (widgetName
== pSaveBtn
->GetName())
920 if (widgetName
== pCancelBtn
->GetName())
922 bool Ok
= (wxMessageBox(wxT("Are you sure?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
927 if (saveName
.IsEmpty())
929 wxGetApp().Contact
->Initialize();
936 // Requery previous record
937 if (wxGetApp().Contact
->FetchByName(saveName
))
945 // Previous record not available, retrieve first record in table
946 if (wxGetApp().Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&&
947 wxGetApp().Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
949 wxGetApp().Contact
->whereStr
= wxT("NAME = (SELECT MIN(NAME) FROM ");
950 wxGetApp().Contact
->whereStr
+= wxGetApp().Contact
->GetTableName();
951 wxGetApp().Contact
->whereStr
+= wxT(")");
952 wxGetApp().Contact
->SetWhereClause(wxGetApp().Contact
->whereStr
.c_str());
955 wxGetApp().Contact
->SetWhereClause(wxT(""));
957 if (!wxGetApp().Contact
->Query())
960 tStr
= wxT("ODBC error during Query()\n\n");
961 tStr
+= GetExtendedDBErrorMsg(wxGetApp().Contact
->GetDb(),__FILE__
,__LINE__
);
962 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
966 if (wxGetApp().Contact
->GetNext()) // Successfully read first record
972 // No contacts are available, clear dialog
973 wxGetApp().Contact
->Initialize();
979 if (widgetName
== pPrevBtn
->GetName())
986 if (widgetName
== pNextBtn
->GetName())
993 if (widgetName
== pQueryBtn
->GetName())
995 // Display the query dialog box
996 wxChar qryWhere
[DB_MAX_WHERE_CLAUSE_LEN
+1];
997 wxStrcpy(qryWhere
, (const wxChar
*) wxGetApp().Contact
->qryWhereStr
);
998 wxChar
*tblName
[] = {(wxChar
*)CONTACT_TABLE_NAME
, 0};
999 new CqueryDlg(GetParent(), wxGetApp().Contact
->GetDb(), tblName
, qryWhere
);
1001 // Query the first record in the new record set and
1002 // display it, if the query string has changed.
1003 if (wxStrcmp(qryWhere
, (const wxChar
*) wxGetApp().Contact
->qryWhereStr
))
1005 wxGetApp().Contact
->whereStr
.Empty();
1006 wxGetApp().Contact
->SetOrderByClause("NAME");
1008 if (wxGetApp().Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&&
1009 wxGetApp().Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1011 wxGetApp().Contact
->whereStr
= wxT("NAME = (SELECT MIN(NAME) FROM ");
1012 wxGetApp().Contact
->whereStr
+= CONTACT_TABLE_NAME
;
1015 // Append the query where string (if there is one)
1016 wxGetApp().Contact
->qryWhereStr
= qryWhere
;
1017 if (wxStrlen(qryWhere
))
1019 wxGetApp().Contact
->whereStr
+= wxT(" WHERE ");
1020 wxGetApp().Contact
->whereStr
+= wxGetApp().Contact
->qryWhereStr
;
1022 // Close the expression with a right paren
1023 wxGetApp().Contact
->whereStr
+= wxT(")");
1024 // Requery the table
1025 wxGetApp().Contact
->SetWhereClause(wxGetApp().Contact
->whereStr
.c_str());
1026 if (!wxGetApp().Contact
->Query())
1029 tStr
= wxT("ODBC error during Query()\n\n");
1030 tStr
+= GetExtendedDBErrorMsg(wxGetApp().Contact
->GetDb(),__FILE__
,__LINE__
);
1031 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1034 // Display the first record from the query set
1035 if (!wxGetApp().Contact
->GetNext())
1036 wxGetApp().Contact
->Initialize();
1040 // Enable/Disable the reset button
1041 pResetBtn
->Enable(!wxGetApp().Contact
->qryWhereStr
.IsEmpty());
1047 if (widgetName
== pResetBtn
->GetName())
1049 // Clear the additional where criteria established by the query feature
1050 wxGetApp().Contact
->qryWhereStr
= wxT("");
1051 wxGetApp().Contact
->SetOrderByClause(wxT("NAME"));
1053 if (wxGetApp().Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&&
1054 wxGetApp().Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1056 wxGetApp().Contact
->whereStr
= wxT("NAME = (SELECT MIN(NAME) FROM ");
1057 wxGetApp().Contact
->whereStr
+= CONTACT_TABLE_NAME
;
1058 wxGetApp().Contact
->whereStr
+= wxT(")");
1061 wxGetApp().Contact
->SetWhereClause(wxGetApp().Contact
->whereStr
.c_str());
1062 if (!wxGetApp().Contact
->Query())
1065 tStr
= wxT("ODBC error during Query()\n\n");
1066 tStr
+= GetExtendedDBErrorMsg(wxGetApp().Contact
->GetDb(),__FILE__
,__LINE__
);
1067 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1070 if (!wxGetApp().Contact
->GetNext())
1071 wxGetApp().Contact
->Initialize();
1073 pResetBtn
->Enable(FALSE
);
1079 if (widgetName
== pNameListBtn
->GetName())
1081 new ClookUpDlg(/* wxWindow *parent */ this,
1082 /* wxChar *windowTitle */ wxT("Select contact name"),
1083 /* wxChar *tableName */ (wxChar
*) CONTACT_TABLE_NAME
,
1084 /* wxChar *dispCol1 */ wxT("NAME"),
1085 /* wxChar *dispCol2 */ wxT("JOINDATE"),
1086 /* wxChar *where */ wxT(""),
1087 /* wxChar *orderBy */ wxT("NAME"),
1088 /* wxDb *pDb */ wxGetApp().READONLY_DB
,
1089 /* const wxString &defDir */ wxGetApp().DbConnectInf
->GetDefaultDir(),
1090 /* bool distinctValues */ TRUE
);
1092 if (ListDB_Selection
&& wxStrlen(ListDB_Selection
))
1094 wxString w
= wxT("NAME = '");
1095 w
+= ListDB_Selection
;
1102 } // CeditorDlg::OnCommand()
1105 bool CeditorDlg::Initialize()
1107 // Create the data structure and a new database connection.
1108 // (As there is not a pDb being passed in the constructor, a new database
1109 // connection is created)
1110 wxGetApp().Contact
= new Ccontact();
1112 if (!wxGetApp().Contact
)
1114 wxMessageBox(wxT("Unable to instantiate an instance of Ccontact"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
1118 // Check if the table exists or not. If it doesn't, ask the user if they want to
1119 // create the table. Continue trying to create the table until it exists, or user aborts
1120 while (!wxGetApp().Contact
->GetDb()->TableExists((wxChar
*)CONTACT_TABLE_NAME
,
1121 wxGetApp().DbConnectInf
->GetUserID(),
1122 wxGetApp().DbConnectInf
->GetDefaultDir()))
1125 tStr
.Printf(wxT("Unable to open the table '%s'.\n\nTable may need to be created...?\n\n"),CONTACT_TABLE_NAME
);
1126 tStr
+= GetExtendedDBErrorMsg(wxGetApp().Contact
->GetDb(),__FILE__
,__LINE__
);
1127 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1129 bool createTable
= (wxMessageBox(wxT("Do you wish to try to create/clear the CONTACTS table?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
1137 wxGetApp().CreateDataTable(FALSE
);
1140 // Tables must be "opened" before anything other than creating/deleting table can be done
1141 if (!wxGetApp().Contact
->Open())
1143 // Table does exist, or there was some problem opening it. Currently this should
1144 // never fail, except in the case of the table not exisiting or the current
1145 // user has insufficent privileges to access the table
1147 // This code is experimenting with a new function that will hopefully be available
1148 // in the 2.4 release. This check will determine whether the open failing was due
1149 // to the table not existing, or the users privileges being insufficient to
1151 if (!wxGetApp().Contact
->GetDb()->TablePrivileges(CONTACT_TABLE_NAME
, wxT("SELECT"),
1152 wxGetApp().Contact
->GetDb()->GetUsername(),
1153 wxGetApp().Contact
->GetDb()->GetUsername(),
1154 wxGetApp().DbConnectInf
->GetDefaultDir()))
1157 tStr
.Printf(wxT("Unable to open the table '%s' (likely due to\ninsufficient privileges of the logged in user).\n\n"),CONTACT_TABLE_NAME
);
1158 tStr
+= GetExtendedDBErrorMsg(wxGetApp().Contact
->GetDb(),__FILE__
,__LINE__
);
1159 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1163 if (!wxGetApp().Contact
->GetDb()->TableExists(CONTACT_TABLE_NAME
,
1164 wxGetApp().Contact
->GetDb()->GetUsername(),
1165 wxGetApp().DbConnectInf
->GetDefaultDir()))
1168 tStr
.Printf(wxT("Unable to open the table '%s' as the table\ndoes not appear to exist in the tablespace available\nto the currently logged in user.\n\n"),CONTACT_TABLE_NAME
);
1169 tStr
+= GetExtendedDBErrorMsg(wxGetApp().Contact
->GetDb(),__FILE__
,__LINE__
);
1170 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1178 (void)new wxStaticBox(this, EDITOR_DIALOG_FN_GROUP
, wxT(""), wxPoint(15, 1), wxSize(497, 69), 0, wxT("FunctionGrp"));
1179 (void)new wxStaticBox(this, EDITOR_DIALOG_SEARCH_GROUP
, wxT(""), wxPoint(417, 1), wxSize(95, 242), 0, wxT("SearchGrp"));
1181 pCreateBtn
= new wxButton(this, EDITOR_DIALOG_CREATE
, wxT("&Create"), wxPoint( 25, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("CreateBtn"));
1182 pEditBtn
= new wxButton(this, EDITOR_DIALOG_EDIT
, wxT("&Edit"), wxPoint(102, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("EditBtn"));
1183 pDeleteBtn
= new wxButton(this, EDITOR_DIALOG_DELETE
, wxT("&Delete"), wxPoint(179, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("DeleteBtn"));
1184 pCopyBtn
= new wxButton(this, EDITOR_DIALOG_COPY
, wxT("Cop&y"), wxPoint(256, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("CopyBtn"));
1185 pSaveBtn
= new wxButton(this, EDITOR_DIALOG_SAVE
, wxT("&Save"), wxPoint(333, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("SaveBtn"));
1186 pCancelBtn
= new wxButton(this, EDITOR_DIALOG_CANCEL
, wxT("C&ancel"), wxPoint(430, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("CancelBtn"));
1187 pPrevBtn
= new wxButton(this, EDITOR_DIALOG_PREV
, wxT("<< &Prev"), wxPoint(430, 81), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("PrevBtn"));
1188 pNextBtn
= new wxButton(this, EDITOR_DIALOG_NEXT
, wxT("&Next >>"), wxPoint(430, 121), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("NextBtn"));
1189 pQueryBtn
= new wxButton(this, EDITOR_DIALOG_QUERY
, wxT("&Query"), wxPoint(430, 161), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("QueryBtn"));
1190 pResetBtn
= new wxButton(this, EDITOR_DIALOG_RESET
, wxT("&Reset"), wxPoint(430, 200), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("ResetBtn"));
1191 pNameMsg
= new wxStaticText(this, EDITOR_DIALOG_NAME_MSG
, wxT("Name:"), wxPoint( 17, 80), wxSize( -1, -1), 0, wxT("NameMsg"));
1192 pNameTxt
= new wxTextCtrl(this, EDITOR_DIALOG_NAME_TEXT
, wxT(""), wxPoint( 17, 97), wxSize(308, 25), 0, wxDefaultValidator
, wxT("NameTxt"));
1193 pNameListBtn
= new wxButton(this, EDITOR_DIALOG_LOOKUP
, wxT("&Lookup"), wxPoint(333, 97), wxSize( 70, 24), 0, wxDefaultValidator
, wxT("LookupBtn"));
1194 pAddress1Msg
= new wxStaticText(this, EDITOR_DIALOG_ADDRESS1_MSG
, wxT("Address:"), wxPoint( 17, 130), wxSize( -1, -1), 0, wxT("Address1Msg"));
1195 pAddress1Txt
= new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT
, wxT(""), wxPoint( 17, 147), wxSize(308, 25), 0, wxDefaultValidator
, wxT("Address1Txt"));
1196 pAddress2Msg
= new wxStaticText(this, EDITOR_DIALOG_ADDRESS2_MSG
, wxT("Address:"), wxPoint( 17, 180), wxSize( -1, -1), 0, wxT("Address2Msg"));
1197 pAddress2Txt
= new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT
, wxT(""), wxPoint( 17, 197), wxSize(308, 25), 0, wxDefaultValidator
, wxT("Address2Txt"));
1198 pCityMsg
= new wxStaticText(this, EDITOR_DIALOG_CITY_MSG
, wxT("City:"), wxPoint( 17, 230), wxSize( -1, -1), 0, wxT("CityMsg"));
1199 pCityTxt
= new wxTextCtrl(this, EDITOR_DIALOG_CITY_TEXT
, wxT(""), wxPoint( 17, 247), wxSize(225, 25), 0, wxDefaultValidator
, wxT("CityTxt"));
1200 pStateMsg
= new wxStaticText(this, EDITOR_DIALOG_STATE_MSG
, wxT("State:"), wxPoint(250, 230), wxSize( -1, -1), 0, wxT("StateMsg"));
1201 pStateTxt
= new wxTextCtrl(this, EDITOR_DIALOG_STATE_TEXT
, wxT(""), wxPoint(250, 247), wxSize(153, 25), 0, wxDefaultValidator
, wxT("StateTxt"));
1202 pCountryMsg
= new wxStaticText(this, EDITOR_DIALOG_COUNTRY_MSG
, wxT("Country:"), wxPoint( 17, 280), wxSize( -1, -1), 0, wxT("CountryMsg"));
1203 pCountryTxt
= new wxTextCtrl(this, EDITOR_DIALOG_COUNTRY_TEXT
, wxT(""), wxPoint( 17, 297), wxSize(225, 25), 0, wxDefaultValidator
, wxT("CountryTxt"));
1204 pPostalCodeMsg
= new wxStaticText(this, EDITOR_DIALOG_POSTAL_MSG
, wxT("Postal Code:"),wxPoint(250, 280), wxSize( -1, -1), 0, wxT("PostalCodeMsg"));
1205 pPostalCodeTxt
= new wxTextCtrl(this, EDITOR_DIALOG_POSTAL_TEXT
, wxT(""), wxPoint(250, 297), wxSize(153, 25), 0, wxDefaultValidator
, wxT("PostalCodeTxt"));
1207 wxString choice_strings
[5];
1208 choice_strings
[0] = wxT("English");
1209 choice_strings
[1] = wxT("French");
1210 choice_strings
[2] = wxT("German");
1211 choice_strings
[3] = wxT("Spanish");
1212 choice_strings
[4] = wxT("Other");
1214 pNativeLangChoice
= new wxChoice(this, EDITOR_DIALOG_LANG_CHOICE
, wxPoint( 17, 346), wxSize(277, -1), 5, choice_strings
);
1215 pNativeLangMsg
= new wxStaticText(this, EDITOR_DIALOG_LANG_MSG
, wxT("Native language:"), wxPoint( 17, 330), wxSize( -1, -1), 0, wxT("NativeLangMsg"));
1217 wxString radio_strings
[2];
1218 radio_strings
[0] = wxT("No");
1219 radio_strings
[1] = wxT("Yes");
1220 pDeveloperRadio
= new wxRadioBox(this,EDITOR_DIALOG_DEVELOPER
, wxT("Developer:"), wxPoint(303, 330), wxSize( -1, -1), 2, radio_strings
, 2, wxHORIZONTAL
);
1221 pJoinDateMsg
= new wxStaticText(this, EDITOR_DIALOG_JOIN_MSG
, wxT("Date joined:"), wxPoint( 17, 380), wxSize( -1, -1), 0, wxT("JoinDateMsg"));
1222 pJoinDateTxt
= new wxTextCtrl(this, EDITOR_DIALOG_JOIN_TEXT
, wxT(""), wxPoint( 17, 397), wxSize(150, 25), 0, wxDefaultValidator
, wxT("JoinDateTxt"));
1223 pContribMsg
= new wxStaticText(this, EDITOR_DIALOG_CONTRIB_MSG
,wxT("Contributions:"), wxPoint(175, 380), wxSize( -1, -1), 0, wxT("ContribMsg"));
1224 pContribTxt
= new wxTextCtrl(this, EDITOR_DIALOG_CONTRIB_TEXT
, wxT(""), wxPoint(175, 397), wxSize(120, 25), 0, wxDefaultValidator
, wxT("ContribTxt"));
1225 pLinesMsg
= new wxStaticText(this, EDITOR_DIALOG_LINES_MSG
, wxT("Lines of code:"), wxPoint(303, 380), wxSize( -1, -1), 0, wxT("LinesMsg"));
1226 pLinesTxt
= new wxTextCtrl(this, EDITOR_DIALOG_LINES_TEXT
, wxT(""), wxPoint(303, 397), wxSize(100, 25), 0, wxDefaultValidator
, wxT("LinesTxt"));
1228 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
1229 // handle all widget processing
1230 widgetPtrsSet
= TRUE
;
1232 // Setup the orderBy and where clauses to return back a single record as the result set,
1233 // as there will only be one record being shown on the dialog at a time, this optimizes
1234 // network traffic by only returning a one row result
1236 wxGetApp().Contact
->SetOrderByClause(wxT("NAME")); // field name to sort by
1238 // The wxString "whereStr" is not a member of the wxDbTable object, it is a member variable
1239 // specifically in the Ccontact class. It is used here for simpler construction of a varying
1240 // length string, and then after the string is built, the wxDbTable member variable "where" is
1241 // assigned the pointer to the constructed string.
1243 // The constructed where clause below has a sub-query within it "SELECT MIN(NAME) FROM %s"
1244 // to achieve a single row (in this case the first name in alphabetical order).
1246 if (wxGetApp().Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&&
1247 wxGetApp().Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1249 wxGetApp().Contact
->whereStr
.Printf(wxT("NAME = (SELECT MIN(NAME) FROM %s)"),
1250 wxGetApp().Contact
->GetTableName().c_str());
1251 // NOTE: (const wxChar*) returns a pointer which may not be valid later, so this is short term use only
1252 wxGetApp().Contact
->SetWhereClause(wxGetApp().Contact
->whereStr
);
1255 wxGetApp().Contact
->SetWhereClause(wxT(""));
1257 // Perform the Query to get the result set.
1258 // NOTE: If there are no rows returned, that is a valid result, so Query() would return TRUE.
1259 // Only if there is a database error will Query() come back as FALSE
1260 if (!wxGetApp().Contact
->Query())
1263 tStr
= wxT("ODBC error during Query()\n\n");
1264 tStr
+= GetExtendedDBErrorMsg(wxGetApp().Contact
->GetDb(),__FILE__
,__LINE__
);
1265 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1269 // Since Query succeeded, now get the row that was returned
1270 if (!wxGetApp().Contact
->GetNext())
1271 // If the GetNext() failed at this point, then there are no rows to retrieve,
1272 // so clear the values in the members of "Contact" so that PutData() blanks the
1273 // widgets on the dialog
1274 wxGetApp().Contact
->Initialize();
1276 wxGetApp().Contact->GetDb()->RollbackTrans();
1285 } // CeditorDlg::Initialize()
1288 void CeditorDlg::FieldsEditable()
1293 pNameTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1294 pAddress1Txt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1295 pAddress2Txt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1296 pCityTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1297 pStateTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1298 pPostalCodeTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1299 pCountryTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1301 pJoinDateTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1302 pContribTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1303 pLinesTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1304 pNativeLangChoice
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1305 pDeveloperRadio
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1307 } // CeditorDlg::FieldsEditable()
1310 void CeditorDlg::SetMode(enum DialogModes m
)
1331 pCreateBtn
->Enable( !edit
);
1332 pEditBtn
->Enable( !edit
&& (wxStrcmp(wxGetApp().Contact
->Name
,wxT(""))!=0) );
1333 pDeleteBtn
->Enable( !edit
&& (wxStrcmp(wxGetApp().Contact
->Name
,wxT(""))!=0) );
1334 pCopyBtn
->Enable( !edit
&& (wxStrcmp(wxGetApp().Contact
->Name
,wxT(""))!=0) );
1335 pSaveBtn
->Enable( edit
);
1336 pCancelBtn
->Enable( edit
);
1337 pPrevBtn
->Enable( !edit
);
1338 pNextBtn
->Enable( !edit
);
1339 pQueryBtn
->Enable( !edit
);
1340 pResetBtn
->Enable( !edit
&& !wxGetApp().Contact
->qryWhereStr
.IsEmpty() );
1341 pNameListBtn
->Enable( !edit
);
1345 } // CeditorDlg::SetMode()
1348 bool CeditorDlg::PutData()
1352 pNameTxt
->SetValue(wxGetApp().Contact
->Name
);
1353 pAddress1Txt
->SetValue(wxGetApp().Contact
->Addr1
);
1354 pAddress2Txt
->SetValue(wxGetApp().Contact
->Addr2
);
1355 pCityTxt
->SetValue(wxGetApp().Contact
->City
);
1356 pStateTxt
->SetValue(wxGetApp().Contact
->State
);
1357 pCountryTxt
->SetValue(wxGetApp().Contact
->Country
);
1358 pPostalCodeTxt
->SetValue(wxGetApp().Contact
->PostalCode
);
1360 tStr
.Printf(wxT("%d/%d/%d"),wxGetApp().Contact
->JoinDate
.month
,wxGetApp().Contact
->JoinDate
.day
,wxGetApp().Contact
->JoinDate
.year
);
1361 pJoinDateTxt
->SetValue(tStr
);
1363 tStr
.Printf(wxT("%d"),wxGetApp().Contact
->Contributions
);
1364 pContribTxt
->SetValue(tStr
);
1366 tStr
.Printf(wxT("%lu"),wxGetApp().Contact
->LinesOfCode
);
1367 pLinesTxt
->SetValue(tStr
);
1369 pNativeLangChoice
->SetSelection(wxGetApp().Contact
->NativeLanguage
);
1371 pDeveloperRadio
->SetSelection(wxGetApp().Contact
->IsDeveloper
);
1374 } // Ceditor::PutData()
1378 * Reads the data out of all the widgets on the dialog. Some data evaluation is done
1379 * to ensure that there is a name entered and that the date field is valid.
1381 * A return value of TRUE means that valid data was retrieved from the dialog, otherwise
1382 * invalid data was found (and a message was displayed telling the user what to fix), and
1383 * the data was not placed into the appropraite fields of Ccontact
1385 bool CeditorDlg::GetData()
1387 // Validate that the data currently entered into the widgets is valid data
1390 tStr
= pNameTxt
->GetValue();
1391 if (!wxStrcmp((const wxChar
*) tStr
,wxT("")))
1393 wxMessageBox(wxT("A name is required for entry into the contact table"),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
1397 bool invalid
= FALSE
;
1401 tStr
= pJoinDateTxt
->GetValue();
1402 if (tStr
.Freq(wxT('/')) != 2)
1405 // Find the month, day, and year tokens
1408 first
= tStr
.First(wxT('/'));
1409 second
= tStr
.Last(wxT('/'));
1411 mm
= atoi(tStr
.SubString(0,first
));
1412 dd
= atoi(tStr
.SubString(first
+1,second
));
1413 yyyy
= atoi(tStr
.SubString(second
+1,tStr
.Length()-1));
1415 invalid
= !(mm
&& dd
&& yyyy
);
1418 // Force Year 2000 compliance
1419 if (!invalid
&& (yyyy
< 1000))
1422 // Check the token ranges for validity
1427 else if ((mm
< 1) || (mm
> 12))
1435 int days
[12] = {31,28,31,30,31,30,
1437 if (dd
> days
[mm
-1])
1440 if ((dd
== 29) && (mm
== 2))
1442 if (((yyyy
% 4) == 0) && (((yyyy
% 100) != 0) || ((yyyy
% 400) == 0)))
1452 wxGetApp().Contact
->JoinDate
.month
= mm
;
1453 wxGetApp().Contact
->JoinDate
.day
= dd
;
1454 wxGetApp().Contact
->JoinDate
.year
= yyyy
;
1458 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
);
1462 tStr
= pNameTxt
->GetValue();
1463 wxStrcpy(wxGetApp().Contact
->Name
,(const wxChar
*) tStr
);
1464 wxStrcpy(wxGetApp().Contact
->Addr1
,pAddress1Txt
->GetValue());
1465 wxStrcpy(wxGetApp().Contact
->Addr2
,pAddress2Txt
->GetValue());
1466 wxStrcpy(wxGetApp().Contact
->City
,pCityTxt
->GetValue());
1467 wxStrcpy(wxGetApp().Contact
->State
,pStateTxt
->GetValue());
1468 wxStrcpy(wxGetApp().Contact
->Country
,pCountryTxt
->GetValue());
1469 wxStrcpy(wxGetApp().Contact
->PostalCode
,pPostalCodeTxt
->GetValue());
1471 wxGetApp().Contact
->Contributions
= atoi(pContribTxt
->GetValue());
1472 wxGetApp().Contact
->LinesOfCode
= atol(pLinesTxt
->GetValue());
1474 wxGetApp().Contact
->NativeLanguage
= (enum Language
) pNativeLangChoice
->GetSelection();
1475 wxGetApp().Contact
->IsDeveloper
= pDeveloperRadio
->GetSelection() > 0;
1478 } // CeditorDlg::GetData()
1482 * Retrieve data from the dialog, verify the validity of the data, and if it is valid,
1483 * try to insert/update the data to the table based on the current 'mode' the dialog
1486 * A return value of TRUE means the insert/update was completed successfully, a return
1487 * value of FALSE means that Save() failed. If returning FALSE, then this function
1488 * has displayed a detailed error message for the user.
1490 bool CeditorDlg::Save()
1492 bool failed
= FALSE
;
1494 // Read the data in the widgets of the dialog to get the user's data
1498 // Perform any other required validations necessary before saving
1501 wxBeginBusyCursor();
1503 if (mode
== mCreate
)
1505 RETCODE result
= wxGetApp().Contact
->Insert();
1507 failed
= (result
!= DB_SUCCESS
);
1510 // Some errors may be expected, like a duplicate key, so handle those instances with
1511 // specific error messages.
1512 if (result
== DB_ERR_INTEGRITY_CONSTRAINT_VIOL
)
1515 tStr
= wxT("A duplicate key value already exists in the table.\nUnable to save record\n\n");
1516 tStr
+= GetExtendedDBErrorMsg(wxGetApp().Contact
->GetDb(),__FILE__
,__LINE__
);
1517 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1521 // Some other unexpexted error occurred
1523 tStr
= wxT("Database insert failed\n\n");
1524 tStr
+= GetExtendedDBErrorMsg(wxGetApp().Contact
->GetDb(),__FILE__
,__LINE__
);
1525 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1529 else // mode == mEdit
1531 wxGetApp().Contact
->whereStr
.Printf("NAME = '%s'",saveName
.c_str());
1532 if (!wxGetApp().Contact
->UpdateWhere(wxGetApp().Contact
->whereStr
))
1535 tStr
= wxT("Database update failed\n\n");
1536 tStr
+= GetExtendedDBErrorMsg(wxGetApp().Contact
->GetDb(),__FILE__
,__LINE__
);
1537 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1544 wxGetApp().Contact
->GetDb()->CommitTrans();
1545 SetMode(mView
); // Sets the dialog mode back to viewing after save is successful
1548 wxGetApp().Contact
->GetDb()->RollbackTrans();
1554 } // CeditorDlg::Save()
1558 * Where this program is only showing a single row at a time in the dialog,
1559 * a special where clause must be built to find just the single row which,
1560 * in sequence, would follow the currently displayed row.
1562 bool CeditorDlg::GetNextRec()
1566 if (wxGetApp().Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&&
1567 wxGetApp().Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1569 w
= wxT("NAME = (SELECT MIN(NAME) FROM ");
1570 w
+= wxGetApp().Contact
->GetTableName();
1571 w
+= wxT(" WHERE NAME > '");
1574 w
= wxT("(NAME > '");
1576 w
+= wxGetApp().Contact
->Name
;
1579 // If a query where string is currently set, append that criteria
1580 if (!wxGetApp().Contact
->qryWhereStr
.IsEmpty())
1583 w
+= wxGetApp().Contact
->qryWhereStr
;
1590 } // CeditorDlg::GetNextRec()
1594 * Where this program is only showing a single row at a time in the dialog,
1595 * a special where clause must be built to find just the single row which,
1596 * in sequence, would precede the currently displayed row.
1598 bool CeditorDlg::GetPrevRec()
1602 if (wxGetApp().Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&&
1603 wxGetApp().Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1605 w
= wxT("NAME = (SELECT MAX(NAME) FROM ");
1606 w
+= wxGetApp().Contact
->GetTableName();
1607 w
+= wxT(" WHERE NAME < '");
1610 w
= wxT("(NAME < '");
1612 w
+= wxGetApp().Contact
->Name
;
1615 // If a query where string is currently set, append that criteria
1616 if (!wxGetApp().Contact
->qryWhereStr
.IsEmpty())
1619 w
+= wxGetApp().Contact
->qryWhereStr
;
1627 } // CeditorDlg::GetPrevRec()
1631 * This function is here to avoid duplicating this same code in both the
1632 * GetPrevRec() and GetNextRec() functions
1634 bool CeditorDlg::GetRec(const wxString
&whereStr
)
1636 wxGetApp().Contact
->SetWhereClause(whereStr
);
1637 wxGetApp().Contact
->SetOrderByClause(wxT("NAME"));
1639 if (!wxGetApp().Contact
->Query())
1642 tStr
= wxT("ODBC error during Query()\n\n");
1643 tStr
+= GetExtendedDBErrorMsg(wxGetApp().Contact
->GetDb(),__FILE__
,__LINE__
);
1644 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1649 if (wxGetApp().Contact
->GetNext())
1656 } // CeditorDlg::GetRec()
1661 * CparameterDlg constructor
1664 BEGIN_EVENT_TABLE(CparameterDlg
, wxDialog
)
1665 EVT_BUTTON(PARAMETER_DIALOG_SAVE
, CparameterDlg::OnButton
)
1666 EVT_BUTTON(PARAMETER_DIALOG_CANCEL
, CparameterDlg::OnButton
)
1667 EVT_CLOSE(CparameterDlg::OnCloseWindow
)
1670 CparameterDlg::CparameterDlg(wxWindow
*parent
) : wxDialog (parent
, PARAMETER_DIALOG
, wxT("ODBC parameter settings"), wxPoint(-1, -1), wxSize(400, 325))
1672 // Since the ::OnCommand() function is overridden, this prevents the widget
1673 // detection in ::OnCommand() until all widgets have been initialized to prevent
1674 // uninitialized pointers from crashing the program
1675 widgetPtrsSet
= FALSE
;
1677 pParamODBCSourceMsg
= new wxStaticText(this, PARAMETER_DIALOG_SOURCE_MSG
, wxT("ODBC data sources:"), wxPoint( 10, 10), wxSize( -1, -1), 0, wxT("ParamODBCSourceMsg"));
1678 pParamODBCSourceList
= new wxListBox(this, PARAMETER_DIALOG_SOURCE_LISTBOX
, wxPoint( 10, 29), wxSize(285, 150), 0, 0, wxLB_SINGLE
|wxLB_ALWAYS_SB
, wxDefaultValidator
, wxT("ParamODBCSourceList"));
1679 pParamUserNameMsg
= new wxStaticText(this, PARAMETER_DIALOG_NAME_MSG
, wxT("Database user name:"), wxPoint( 10, 193), wxSize( -1, -1), 0, wxT("ParamUserNameMsg"));
1680 pParamUserNameTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_NAME_TEXT
, wxT(""), wxPoint(10, 209), wxSize( 140, 25), 0, wxDefaultValidator
, wxT("ParamUserNameTxt"));
1681 pParamPasswordMsg
= new wxStaticText(this, PARAMETER_DIALOG_PASSWORD_MSG
, wxT("Password:"), wxPoint(156, 193), wxSize( -1, -1), 0, wxT("ParamPasswordMsg"));
1682 pParamPasswordTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_PASSWORD_TEXT
, wxT(""), wxPoint(156, 209), wxSize( 140, 25), 0, wxDefaultValidator
, wxT("ParamPasswordTxt"));
1683 pParamDirPathMsg
= new wxStaticText(this, PARAMETER_DIALOG_DIRPATH_MSG
, wxT("Directory:"), wxPoint( 10, 243), wxSize( -1, -1), 0, wxT("ParamDirPathMsg"));
1684 pParamDirPathTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_DIRPATH_TEXT
, wxT(""), wxPoint( 10, 259), wxSize(140, 25), 0, wxDefaultValidator
, wxT("ParamDirPathTxt"));
1685 pParamSaveBtn
= new wxButton(this, PARAMETER_DIALOG_SAVE
, wxT("&Save"), wxPoint(310, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("ParamSaveBtn"));
1686 pParamCancelBtn
= new wxButton(this, PARAMETER_DIALOG_CANCEL
, wxT("C&ancel"), wxPoint(310, 66), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("ParamCancelBtn"));
1688 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
1689 // handle all widget processing
1690 widgetPtrsSet
= TRUE
;
1693 savedParamSettings
= wxGetApp().params
;
1698 } // CparameterDlg constructor
1701 void CparameterDlg::OnCloseWindow(wxCloseEvent
& event
)
1703 // Put any additional checking necessary to make certain it is alright
1704 // to close the program here that is not done elsewhere
1707 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
);
1715 wxGetApp().params
= savedParamSettings
;
1718 if (GetParent() != NULL
)
1719 GetParent()->SetFocus();
1725 SetReturnCode(0); // added so BoundsChecker would not report use of uninitialized variable
1728 } // CparameterDlg::OnCloseWindow()
1731 void CparameterDlg::OnButton( wxCommandEvent
&event
)
1733 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
1734 OnCommand( *win
, event
);
1738 void CparameterDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
1740 wxString widgetName
;
1742 widgetName
= win
.GetName();
1747 if (widgetName
== pParamSaveBtn
->GetName())
1752 tStr
= wxT("Database parameters have been saved.");
1753 if (GetParent() != NULL
) // The parameter dialog was not called during startup due to a missing cfg file
1754 tStr
+= wxT("\nNew parameters will take effect the next time the program is started.");
1755 wxMessageBox(tStr
,wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
1762 if (widgetName
== pParamCancelBtn
->GetName())
1767 } // CparameterDlg::OnCommand()
1770 bool CparameterDlg::PutData()
1772 // Fill the data source list box
1773 FillDataSourceList();
1775 // Fill in the fields from the params object
1776 if (wxGetApp().params
.ODBCSource
&& wxStrlen(wxGetApp().params
.ODBCSource
))
1777 pParamODBCSourceList
->SetStringSelection(wxGetApp().params
.ODBCSource
);
1778 pParamUserNameTxt
->SetValue(wxGetApp().params
.UserName
);
1779 pParamPasswordTxt
->SetValue(wxGetApp().params
.Password
);
1780 pParamDirPathTxt
->SetValue(wxGetApp().params
.DirPath
);
1782 } // CparameterDlg::PutData()
1785 bool CparameterDlg::GetData()
1788 if (pParamODBCSourceList
->GetStringSelection() != wxT(""))
1790 tStr
= pParamODBCSourceList
->GetStringSelection();
1791 if (tStr
.Length() > (sizeof(wxGetApp().params
.ODBCSource
)-1))
1794 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());
1795 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1798 wxStrcpy(wxGetApp().params
.ODBCSource
, tStr
);
1803 tStr
= pParamUserNameTxt
->GetValue();
1804 if (tStr
.Length() > (sizeof(wxGetApp().params
.UserName
)-1))
1807 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());
1808 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1811 wxStrcpy(wxGetApp().params
.UserName
, tStr
);
1813 tStr
= pParamPasswordTxt
->GetValue();
1814 if (tStr
.Length() > (sizeof(wxGetApp().params
.Password
)-1))
1817 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());
1818 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1821 wxStrcpy(wxGetApp().params
.Password
,tStr
);
1823 tStr
= pParamDirPathTxt
->GetValue();
1824 tStr
.Replace(wxT("\\"),wxT("/"));
1825 if (tStr
.Length() > (sizeof(wxGetApp().params
.DirPath
)-1))
1828 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());
1829 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1832 wxStrcpy(wxGetApp().params
.DirPath
,tStr
);
1834 } // CparameterDlg::GetData()
1837 bool CparameterDlg::Save()
1839 // Copy the current params in case user cancels changing
1840 // the params, so that we can reset them.
1843 wxGetApp().params
= savedParamSettings
;
1847 wxGetApp().WriteParamFile(wxGetApp().params
);
1850 } // CparameterDlg::Save()
1853 void CparameterDlg::FillDataSourceList()
1855 wxChar Dsn
[SQL_MAX_DSN_LENGTH
+ 1];
1857 wxStringList strList
;
1859 while (wxDbGetDataSource(wxGetApp().DbConnectInf
->GetHenv(), Dsn
,
1860 SQL_MAX_DSN_LENGTH
+1, DsDesc
, 255))
1864 strList
.Add(wxT(""));
1865 wxChar
**p
= strList
.ListToArray();
1868 for (i
= 0; wxStrlen(p
[i
]); i
++)
1869 pParamODBCSourceList
->Append(p
[i
]);
1872 } // CparameterDlg::FillDataSourceList()
1875 BEGIN_EVENT_TABLE(CqueryDlg
, wxDialog
)
1876 EVT_BUTTON(-1, CqueryDlg::OnButton
)
1877 EVT_CLOSE(CqueryDlg::OnCloseWindow
)
1881 // CqueryDlg() constructor
1882 CqueryDlg::CqueryDlg(wxWindow
*parent
, wxDb
*pDb
, wxChar
*tblName
[],
1883 const wxString
&pWhereArg
) :
1884 wxDialog (parent
, QUERY_DIALOG
, wxT("Query"), wxPoint(-1, -1), wxSize(480, 360))
1886 wxBeginBusyCursor();
1890 masterTableName
= tblName
[0];
1891 widgetPtrsSet
= FALSE
;
1894 // Initialize the WHERE clause from the string passed in
1895 pWhere
= pWhereArg
; // Save a pointer to the output buffer
1896 if (pWhere
.Length() > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN
) // Check the length of the buffer passed in
1899 s
.Printf(wxT("Maximum where clause length exceeded.\nLength must be less than %d"), DB_MAX_WHERE_CLAUSE_LEN
+1);
1900 wxMessageBox(s
,wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
1905 pQueryCol1Msg
= new wxStaticText(this, QUERY_DIALOG_COL_MSG
, wxT("Column 1:"), wxPoint( 10, 10), wxSize( 69, 16), 0, wxT("QueryCol1Msg"));
1906 pQueryCol1Choice
= new wxChoice(this, QUERY_DIALOG_COL_CHOICE
, wxPoint( 10, 27), wxSize(250, 27), 0, 0, 0, wxDefaultValidator
, wxT("QueryCol1Choice"));
1907 pQueryNotMsg
= new wxStaticText(this, QUERY_DIALOG_NOT_MSG
, wxT("NOT"), wxPoint(268, 10), wxSize( -1, -1), 0, wxT("QueryNotMsg"));
1908 pQueryNotCheck
= new wxCheckBox(this, QUERY_DIALOG_NOT_CHECKBOX
, wxT(""), wxPoint(275, 37), wxSize( 20, 20), 0, wxDefaultValidator
, wxT("QueryNotCheck"));
1910 wxString choice_strings
[9];
1911 choice_strings
[0] = wxT("=");
1912 choice_strings
[1] = wxT("<");
1913 choice_strings
[2] = wxT(">");
1914 choice_strings
[3] = wxT("<=");
1915 choice_strings
[4] = wxT(">=");
1916 choice_strings
[5] = wxT("Begins");
1917 choice_strings
[6] = wxT("Contains");
1918 choice_strings
[7] = wxT("Like");
1919 choice_strings
[8] = wxT("Between");
1921 pQueryOperatorMsg
= new wxStaticText(this, QUERY_DIALOG_OP_MSG
, wxT("Operator:"), wxPoint(305, 10), wxSize( -1, -1), 0, wxT("QueryOperatorMsg"));
1922 pQueryOperatorChoice
= new wxChoice(this, QUERY_DIALOG_OP_CHOICE
, wxPoint(305, 27), wxSize( 80, 27), 9, choice_strings
, 0, wxDefaultValidator
, wxT("QueryOperatorChoice"));
1923 pQueryCol2Msg
= new wxStaticText(this, QUERY_DIALOG_COL2_MSG
, wxT("Column 2:"), wxPoint( 10, 65), wxSize( 69, 16), 0, wxT("QueryCol2Msg"));
1924 pQueryCol2Choice
= new wxChoice(this, QUERY_DIALOG_COL2_CHOICE
, wxPoint( 10, 82), wxSize(250, 27), 0, 0, 0, wxDefaultValidator
, wxT("QueryCol2Choice"));
1925 pQuerySqlWhereMsg
= new wxStaticText(this, QUERY_DIALOG_WHERE_MSG
, wxT("SQL where clause:"), wxPoint( 10, 141), wxSize( -1, -1), 0, wxT("QuerySqlWhereMsg"));
1926 pQuerySqlWhereMtxt
= new wxTextCtrl(this, QUERY_DIALOG_WHERE_TEXT
, wxT(""), wxPoint( 10, 159), wxSize(377, 134), wxTE_MULTILINE
, wxDefaultValidator
, wxT("QuerySqlWhereMtxt"));
1927 pQueryAddBtn
= new wxButton(this, QUERY_DIALOG_ADD
, wxT("&Add"), wxPoint(406, 24), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryAddBtn"));
1928 pQueryAndBtn
= new wxButton(this, QUERY_DIALOG_AND
, wxT("A&nd"), wxPoint(406, 58), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryAndBtn"));
1929 pQueryOrBtn
= new wxButton(this, QUERY_DIALOG_OR
, wxT("&Or"), wxPoint(406, 92), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryOrBtn"));
1930 pQueryLParenBtn
= new wxButton(this, QUERY_DIALOG_LPAREN
, wxT("("), wxPoint(406, 126), wxSize( 26, 26), 0, wxDefaultValidator
, wxT("QueryLParenBtn"));
1931 pQueryRParenBtn
= new wxButton(this, QUERY_DIALOG_RPAREN
, wxT(")"), wxPoint(436, 126), wxSize( 26, 26), 0, wxDefaultValidator
, wxT("QueryRParenBtn"));
1932 pQueryDoneBtn
= new wxButton(this, QUERY_DIALOG_DONE
, wxT("&Done"), wxPoint(406, 185), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryDoneBtn"));
1933 pQueryClearBtn
= new wxButton(this, QUERY_DIALOG_CLEAR
, wxT("C&lear"), wxPoint(406, 218), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryClearBtn"));
1934 pQueryCountBtn
= new wxButton(this, QUERY_DIALOG_COUNT
, wxT("&Count"), wxPoint(406, 252), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryCountBtn"));
1935 pQueryValue1Msg
= new wxStaticText(this, QUERY_DIALOG_VALUE1_MSG
, wxT("Value:"), wxPoint(277, 66), wxSize( -1, -1), 0, wxT("QueryValue1Msg"));
1936 pQueryValue1Txt
= new wxTextCtrl(this, QUERY_DIALOG_VALUE1_TEXT
, wxT(""), wxPoint(277, 83), wxSize(108, 25), 0, wxDefaultValidator
, wxT("QueryValue1Txt"));
1937 pQueryValue2Msg
= new wxStaticText(this, QUERY_DIALOG_VALUE2_MSG
, wxT("AND"), wxPoint(238, 126), wxSize( -1, -1), 0, wxT("QueryValue2Msg"));
1938 pQueryValue2Txt
= new wxTextCtrl(this, QUERY_DIALOG_VALUE2_TEXT
, wxT(""), wxPoint(277, 120), wxSize(108, 25), 0, wxDefaultValidator
, wxT("QueryValue2Txt"));
1939 pQueryHintGrp
= new wxStaticBox(this, QUERY_DIALOG_HINT_GROUP
, wxT(""), wxPoint( 10, 291), wxSize(377, 40), 0, wxT("QueryHintGrp"));
1940 pQueryHintMsg
= new wxStaticText(this, QUERY_DIALOG_HINT_MSG
, wxT(""), wxPoint( 16, 306), wxSize( -1, -1), 0, wxT("QueryHintMsg"));
1942 widgetPtrsSet
= TRUE
;
1943 // Initialize the dialog
1945 pQueryCol2Choice
->Append(wxT("VALUE -->"));
1946 colInf
= pDB
->GetColumns(tblName
);
1952 tStr
= wxT("ODBC error during GetColumns()\n\n");
1953 tStr
+= GetExtendedDBErrorMsg(pDb
,__FILE__
,__LINE__
);
1954 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1959 for (i
= 0; colInf
[i
].colName
&& wxStrlen(colInf
[i
].colName
); i
++)
1961 // If there is more than one table being queried, qualify
1962 // the column names with the table name prefix.
1963 if (tblName
[1] && wxStrlen(tblName
[1]))
1965 qualName
.Printf(wxT("%s.%s"), colInf
[i
].tableName
, colInf
[i
].colName
);
1966 pQueryCol1Choice
->Append(qualName
);
1967 pQueryCol2Choice
->Append(qualName
);
1969 else // Single table query, append just the column names
1971 pQueryCol1Choice
->Append(colInf
[i
].colName
);
1972 pQueryCol2Choice
->Append(colInf
[i
].colName
);
1976 pQueryCol1Choice
->SetSelection(0);
1977 pQueryCol2Choice
->SetSelection(0);
1978 pQueryOperatorChoice
->SetSelection(0);
1980 pQueryValue2Msg
->Show(FALSE
);
1981 pQueryValue2Txt
->Show(FALSE
);
1983 pQueryHintMsg
->SetLabel(langQRY_EQ
);
1985 pQuerySqlWhereMtxt
->SetValue(pWhere
.c_str());
1989 // Display the dialog window
1992 } // CqueryDlg() constructor
1995 CqueryDlg::~CqueryDlg()
1997 } // CqueryDlg::~CqueryDlg() destructor
2000 void CqueryDlg::OnButton(wxCommandEvent
&event
)
2002 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
2003 OnCommand( *win
, event
);
2004 } // CqueryDlg::OnButton()
2007 void CqueryDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
2009 // Widget pointers won't be set when the dialog is constructed.
2010 // Control is passed through this function once for each widget on
2011 // a dialog as the dialog is constructed.
2015 wxString widgetName
= win
.GetName();
2017 // Operator choice box
2018 if (widgetName
== pQueryOperatorChoice
->GetName())
2020 // Set the help text
2021 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
2024 pQueryHintMsg
->SetLabel(langQRY_EQ
);
2027 pQueryHintMsg
->SetLabel(langQRY_LT
);
2030 pQueryHintMsg
->SetLabel(langQRY_GT
);
2033 pQueryHintMsg
->SetLabel(langQRY_LE
);
2036 pQueryHintMsg
->SetLabel(langQRY_GE
);
2039 pQueryHintMsg
->SetLabel(langQRY_BEGINS
);
2042 pQueryHintMsg
->SetLabel(langQRY_CONTAINS
);
2045 pQueryHintMsg
->SetLabel(langQRY_LIKE
);
2048 pQueryHintMsg
->SetLabel(langQRY_BETWEEN
);
2052 // Hide the value2 widget
2053 pQueryValue2Msg
->Show(FALSE
); // BETWEEN will show this widget
2054 pQueryValue2Txt
->Show(FALSE
); // BETWEEN will show this widget
2056 // Disable the NOT operator for <, <=, >, >=
2057 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
2063 pQueryNotCheck
->SetValue(0);
2064 pQueryNotCheck
->Enable(FALSE
);
2067 pQueryNotCheck
->Enable(TRUE
);
2071 // Manipulate the dialog to handle the selected operator
2072 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
2079 pQueryCol2Choice
->Enable(TRUE
);
2080 if (pQueryCol2Choice
->GetSelection()) // Column name is highlighted
2082 pQueryValue1Msg
->Show(FALSE
);
2083 pQueryValue1Txt
->Show(FALSE
);
2085 else // "Value" is highlighted
2087 pQueryValue1Msg
->Show(TRUE
);
2088 pQueryValue1Txt
->Show(TRUE
);
2089 pQueryValue1Txt
->SetFocus();
2095 pQueryCol2Choice
->SetSelection(0);
2096 pQueryCol2Choice
->Enable(FALSE
);
2097 pQueryValue1Msg
->Show(TRUE
);
2098 pQueryValue1Txt
->Show(TRUE
);
2099 pQueryValue1Txt
->SetFocus();
2102 pQueryCol2Choice
->SetSelection(0);
2103 pQueryCol2Choice
->Enable(FALSE
);
2104 pQueryValue2Msg
->Show(TRUE
);
2105 pQueryValue2Txt
->Show(TRUE
);
2106 pQueryValue1Msg
->Show(TRUE
);
2107 pQueryValue1Txt
->Show(TRUE
);
2108 pQueryValue1Txt
->SetFocus();
2114 } // Operator choice box
2117 if (widgetName
== pQueryCol2Choice
->GetName())
2119 if (pQueryCol2Choice
->GetSelection()) // Column name is highlighted
2121 pQueryValue1Msg
->Show(FALSE
);
2122 pQueryValue1Txt
->Show(FALSE
);
2124 else // "Value" is highlighted
2126 pQueryValue1Msg
->Show(TRUE
);
2127 pQueryValue1Txt
->Show(TRUE
);
2128 pQueryValue1Txt
->SetFocus();
2131 } // Column 2 choice
2134 if (widgetName
== pQueryAddBtn
->GetName())
2141 if (widgetName
== pQueryAndBtn
->GetName())
2143 AppendToWhere(wxT(" AND\n"));
2148 if (widgetName
== pQueryOrBtn
->GetName())
2150 AppendToWhere(wxT(" OR\n"));
2154 // Left Paren button
2155 if (widgetName
== pQueryLParenBtn
->GetName())
2157 AppendToWhere(wxT("("));
2159 } // Left Paren button
2161 // Right paren button
2162 if (widgetName
== pQueryRParenBtn
->GetName())
2164 AppendToWhere(wxT(")"));
2166 } // Right Paren button
2169 if (widgetName
== pQueryDoneBtn
->GetName())
2171 // Be sure the where clause will not overflow the output buffer
2172 if (wxStrlen(pQuerySqlWhereMtxt
->GetValue()) > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN
)
2175 s
.Printf(wxT("Maximum where clause length exceeded.\nLength must be less than %d"), DB_MAX_WHERE_CLAUSE_LEN
+1);
2176 wxMessageBox(s
,wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
2179 // Validate the where clause for things such as matching parens
2180 if (!ValidateWhereClause())
2182 // Copy the where clause to the output buffer and exit
2183 pWhere
= pQuerySqlWhereMtxt
->GetValue();
2189 if (widgetName
== pQueryClearBtn
->GetName())
2191 bool Ok
= (wxMessageBox(wxT("Are you sure you wish to clear the Query?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
2194 pQuerySqlWhereMtxt
->SetValue(wxT(""));
2199 if (widgetName
== pQueryCountBtn
->GetName())
2201 wxBeginBusyCursor();
2207 } // CqueryDlg::OnCommand
2210 void CqueryDlg::OnCloseWindow(wxCloseEvent
& event
)
2217 GetParent()->SetFocus();
2222 SetReturnCode(1); // added so BoundsChecker would not report use of uninitialized variable
2225 } // CqueryDlg::OnCloseWindow()
2228 void CqueryDlg::AppendToWhere(wxChar
*s
)
2230 wxString whereStr
= pQuerySqlWhereMtxt
->GetValue();
2232 pQuerySqlWhereMtxt
->SetValue(whereStr
);
2233 } // CqueryDlg::AppendToWhere()
2236 void CqueryDlg::ProcessAddBtn()
2238 qryOp oper
= (qryOp
) pQueryOperatorChoice
->GetSelection();
2240 // Verify that eveything is filled in correctly
2241 if (pQueryCol2Choice
->GetSelection() == 0) // "Value" is selected
2243 // Verify that value 1 is filled in
2244 if (wxStrlen(pQueryValue1Txt
->GetValue()) == 0)
2247 pQueryValue1Txt
->SetFocus();
2250 // For the BETWEEN operator, value 2 must be filled in as well
2251 if (oper
== qryOpBETWEEN
&&
2252 wxStrlen(pQueryValue2Txt
->GetValue()) == 0)
2255 pQueryValue2Txt
->SetFocus();
2260 // Build the expression and append it to the where clause window
2261 wxString s
= pQueryCol1Choice
->GetStringSelection();
2263 if (pQueryNotCheck
->GetValue() && (oper
!= qryOpEQ
))
2269 if (pQueryNotCheck
->GetValue()) // NOT box is checked
2292 s
+= wxT(" BETWEEN");
2298 int col1Idx
= pQueryCol1Choice
->GetSelection();
2301 if (colInf
[col1Idx
].sqlDataType
== SQL_VARCHAR
||
2302 oper
== qryOpBEGINS
||
2303 oper
== qryOpCONTAINS
||
2307 if (pQueryCol2Choice
->GetSelection()) // Column name
2308 s
+= pQueryCol2Choice
->GetStringSelection();
2309 else // Column 2 is a "value"
2313 if (oper
== qryOpCONTAINS
)
2315 s
+= pQueryValue1Txt
->GetValue();
2316 if (oper
== qryOpCONTAINS
|| oper
== qryOpBEGINS
)
2322 if (oper
== qryOpBETWEEN
)
2327 s
+= pQueryValue2Txt
->GetValue();
2332 AppendToWhere((wxChar
*) (const wxChar
*) s
);
2334 } // CqueryDlg::ProcessAddBtn()
2337 void CqueryDlg::ProcessCountBtn()
2339 if (!ValidateWhereClause())
2342 if (!dbTable
) // wxDbTable object needs to be created and opened
2344 dbTable
= new wxDbTable(pDB
, masterTableName
, 0, wxT(""),
2346 wxGetApp().DbConnectInf
->GetDefaultDir());
2349 wxMessageBox(wxT("Memory allocation failed creating a wxDbTable object."),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
2352 if (!dbTable
->Open())
2355 tStr
= wxT("ODBC error during Open()\n\n");
2356 tStr
+= GetExtendedDBErrorMsg(dbTable
->GetDb(),__FILE__
,__LINE__
);
2357 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
2362 // Count() with WHERE clause
2365 whereStr
= pQuerySqlWhereMtxt
->GetValue();
2366 dbTable
->SetWhereClause(whereStr
.c_str());
2368 ULONG whereCnt
= dbTable
->Count();
2370 // Count() of all records in the table
2371 dbTable
->SetWhereClause(wxT(""));
2372 ULONG totalCnt
= dbTable
->Count();
2374 if (whereCnt
> 0 || totalCnt
== 0)
2377 tStr
.Printf(wxT("%lu of %lu records match the query criteria."),whereCnt
,totalCnt
);
2378 wxMessageBox(tStr
,wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
2383 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
);
2384 wxMessageBox(tStr
,wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
2387 // After a wxMessageBox, the focus does not necessarily return to the
2388 // window which was the focus when the message box popped up, so return
2389 // focus to the Query dialog for certain
2392 } // CqueryDlg::ProcessCountBtn()
2395 bool CqueryDlg::ValidateWhereClause()
2397 wxString where
= pQuerySqlWhereMtxt
->GetValue();
2399 if (where
.Freq(wxT('(')) != where
.Freq(wxT(')')))
2401 wxMessageBox(wxT("There are mismatched parenthesis in the constructed where clause"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
2404 // After a wxMessageBox, the focus does not necessarily return to the
2405 // window which was the focus when the message box popped up, so return
2406 // focus to the Query dialog for certain
2411 } // CqueryDlg::ValidateWhereClause()
2417 TEST CODE FOR TESTING THE wxDbCreateDataSource() FUNCTION
2420 result = wxDbCreateDataSource(wxT("Microsoft Access Driver (*.mdb)"),wxT("GLT-TEST2"),wxT("GLT-Descrip"),FALSE,wxT(""),this);
2423 // check for errors caused by ConfigDSN based functions
2426 wxChar errMsg[500+1];
2427 errMsg[0] = wxT('\0');
2429 SQLInstallerError(1,&retcode,errMsg,500,&cb);
2431 wxMessageBox(wxT("FAILED creating data source"),wxT("FAILED"));
2434 wxMessageBox(wxT("SUCCEEDED creating data source"),wxT("SUCCESS"));