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()
317 // Create the main frame window
318 DemoFrame
= new DatabaseDemoFrame(NULL
, wxT("wxWindows Database Demo"), wxPoint(50, 50), wxSize(537, 480));
321 DemoFrame
->SetIcon(wxICON(db
));
324 wxMenu
*file_menu
= new wxMenu
;
325 file_menu
->Append(FILE_CREATE
, wxT("&Create CONTACT table"));
326 file_menu
->Append(FILE_RECREATE_TABLE
, wxT("&Recreate CONTACT table"));
327 file_menu
->Append(FILE_RECREATE_INDEXES
, wxT("&Recreate CONTACT indexes"));
328 file_menu
->Append(FILE_EXIT
, wxT("E&xit"));
330 wxMenu
*edit_menu
= new wxMenu
;
331 edit_menu
->Append(EDIT_PARAMETERS
, wxT("&Parameters..."));
333 wxMenu
*about_menu
= new wxMenu
;
334 about_menu
->Append(ABOUT_DEMO
, wxT("&About"));
336 wxMenuBar
*menu_bar
= new wxMenuBar
;
337 menu_bar
->Append(file_menu
, wxT("&File"));
338 menu_bar
->Append(edit_menu
, wxT("&Edit"));
339 menu_bar
->Append(about_menu
, wxT("&About"));
340 DemoFrame
->SetMenuBar(menu_bar
);
342 params
.ODBCSource
[0] = 0;
343 params
.UserName
[0] = 0;
344 params
.Password
[0] = 0;
345 params
.DirPath
[0] = 0;
348 DemoFrame
->Show(TRUE
);
350 // Passing NULL for the SQL environment handle causes
351 // the wxDbConnectInf constructor to obtain a handle
354 // WARNING: Be certain that you do not free this handle
355 // directly with SQLFreeEnv(). Use either the
356 // method ::FreeHenv() or delete the DbConnectInf.
357 DbConnectInf
= new wxDbConnectInf(NULL
, params
.ODBCSource
, params
.UserName
,
358 params
.Password
, params
.DirPath
);
360 if (!DbConnectInf
|| !DbConnectInf
->GetHenv())
362 wxMessageBox(wxT("Unable to define data source connection info."), wxT("DB CONNECTION ERROR..."),wxOK
| wxICON_EXCLAMATION
);
366 if (!ReadParamFile(params
))
367 DemoFrame
->BuildParameterDialog(NULL
);
369 if (!wxStrlen(params
.ODBCSource
))
375 DbConnectInf
->SetDsn(params
.ODBCSource
);
376 DbConnectInf
->SetUserID(params
.UserName
);
377 DbConnectInf
->SetPassword(params
.Password
);
378 DbConnectInf
->SetDefaultDir(params
.DirPath
);
380 READONLY_DB
= wxDbGetConnection(DbConnectInf
);
381 if (READONLY_DB
== 0)
383 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
);
384 DemoFrame
->BuildParameterDialog(NULL
);
386 wxMessageBox(wxT("Now exiting program.\n\nRestart program to try any new settings."),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
390 DemoFrame
->BuildEditorDialog();
393 DemoFrame
->Refresh();
396 } // DatabaseDemoApp::OnInit()
399 bool DatabaseDemoApp::ReadParamFile(Cparameters
¶ms
)
402 if ((paramFile
= fopen(PARAM_FILENAME
, wxT("r"))) == NULL
)
405 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
);
406 wxMessageBox(tStr
,wxT("File I/O Error..."),wxOK
| wxICON_EXCLAMATION
);
411 wxChar buffer
[1000+1];
412 fgets(buffer
, sizeof(params
.ODBCSource
), paramFile
);
413 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
414 wxStrcpy(params
.ODBCSource
,buffer
);
416 fgets(buffer
, sizeof(params
.UserName
), paramFile
);
417 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
418 wxStrcpy(params
.UserName
,buffer
);
420 fgets(buffer
, sizeof(params
.Password
), paramFile
);
421 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
422 wxStrcpy(params
.Password
,buffer
);
424 fgets(buffer
, sizeof(params
.DirPath
), paramFile
);
425 buffer
[wxStrlen(buffer
)-1] = wxT('\0');
426 wxStrcpy(params
.DirPath
,buffer
);
431 } // DatabaseDemoApp::ReadParamFile()
434 bool DatabaseDemoApp::WriteParamFile(Cparameters
¶ms
)
437 if ((paramFile
= fopen(PARAM_FILENAME
, wxT("wt"))) == NULL
)
440 tStr
.Printf(wxT("Unable to write/overwrite '%s'."),PARAM_FILENAME
);
441 wxMessageBox(tStr
,wxT("File I/O Error..."),wxOK
| wxICON_EXCLAMATION
);
445 fputs(wxGetApp().params
.ODBCSource
, paramFile
);
446 fputc(wxT('\n'), paramFile
);
447 fputs(wxGetApp().params
.UserName
, paramFile
);
448 fputc(wxT('\n'), paramFile
);
449 fputs(wxGetApp().params
.Password
, paramFile
);
450 fputc(wxT('\n'), paramFile
);
451 fputs(wxGetApp().params
.DirPath
, paramFile
);
452 fputc(wxT('\n'), paramFile
);
456 } // DatabaseDemoApp::WriteParamFile()
459 void DatabaseDemoApp::CreateDataTable(bool recreate
)
463 Ok
= (wxMessageBox(wxT("Any data currently residing in the table will be erased.\n\nAre you sure?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
472 // Use a temporary instance of a new Ccontact table object
473 // for creating the table within the datasource.
474 Ccontact
*Contact
= new Ccontact();
479 wxMessageBox(wxT("Error allocating memory for 'Ccontact'object.\n\nTable was not created."),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
483 if (!Contact
->CreateTable(recreate
))
487 tStr
= wxT("Error creating CONTACTS table.\nTable was not created.\n\n");
488 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
489 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
494 if (!Contact
->CreateIndexes())
498 tStr
= wxT("Error creating CONTACTS indexes.\nIndexes will be unavailable.\n\n");
499 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
500 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
511 wxMessageBox(wxT("Table and index(es) were successfully created."),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
512 } // DatabaseDemoApp::CreateDataTable()
515 BEGIN_EVENT_TABLE(DatabaseDemoFrame
, wxFrame
)
516 EVT_MENU(FILE_CREATE
, DatabaseDemoFrame::OnCreate
)
517 EVT_MENU(FILE_RECREATE_TABLE
, DatabaseDemoFrame::OnRecreateTable
)
518 EVT_MENU(FILE_RECREATE_INDEXES
, DatabaseDemoFrame::OnRecreateIndexes
)
519 EVT_MENU(FILE_EXIT
, DatabaseDemoFrame::OnExit
)
520 EVT_MENU(EDIT_PARAMETERS
, DatabaseDemoFrame::OnEditParameters
)
521 EVT_MENU(ABOUT_DEMO
, DatabaseDemoFrame::OnAbout
)
522 EVT_CLOSE(DatabaseDemoFrame::OnCloseWindow
)
526 // DatabaseDemoFrame constructor
527 DatabaseDemoFrame::DatabaseDemoFrame(wxFrame
*frame
, const wxString
& title
,
528 const wxPoint
& pos
, const wxSize
& size
):
529 wxFrame(frame
, -1, title
, pos
, size
)
531 // Put any code in necessary for initializing the main frame here
534 } // DatabaseDemoFrame constructor
537 void DatabaseDemoFrame::OnCreate(wxCommandEvent
& event
)
539 wxGetApp().CreateDataTable(FALSE
);
540 } // DatabaseDemoFrame::OnCreate()
543 void DatabaseDemoFrame::OnRecreateTable(wxCommandEvent
& event
)
545 wxGetApp().CreateDataTable(TRUE
);
546 } // DatabaseDemoFrame::OnRecreate()
549 void DatabaseDemoFrame::OnRecreateIndexes(wxCommandEvent
& event
)
551 // Using a new connection to the database so as not to disturb
552 // the current cursors on the table in use in the editor dialog
553 Ccontact
*Contact
= new Ccontact();
558 wxMessageBox(wxT("Error allocating memory for 'Ccontact'object.\n\nTable could not be opened."),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
562 if (!Contact
->CreateIndexes())
566 tStr
= wxT("Error creating CONTACTS indexes.\nNew indexes will be unavailable.\n\n");
567 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
568 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
573 } // DatabaseDemoFrame::OnRecreateIndexes()
575 void DatabaseDemoFrame::OnExit(wxCommandEvent
& event
)
578 } // DatabaseDemoFrame::OnExit()
581 void DatabaseDemoFrame::OnEditParameters(wxCommandEvent
& event
)
583 if ((pEditorDlg
->mode
!= mCreate
) && (pEditorDlg
->mode
!= mEdit
))
584 BuildParameterDialog(this);
586 wxMessageBox(wxT("Cannot change database parameters while creating or editing a record"),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
587 } // DatabaseDemoFrame::OnEditParameters()
590 void DatabaseDemoFrame::OnAbout(wxCommandEvent
& event
)
592 wxMessageBox(wxT("wxWindows sample program for database classes\n\nContributed on 27 July 1998"),wxT("About..."),wxOK
| wxICON_INFORMATION
);
593 } // DatabaseDemoFrame::OnAbout()
596 // Put any additional checking necessary to make certain it is alright
597 // to close the program here that is not done elsewhere
598 void DatabaseDemoFrame::OnCloseWindow(wxCloseEvent
& event
)
601 if (pEditorDlg
&& pEditorDlg
->Close())
612 // This function will close all the connections to the database that have been
613 // previously cached.
614 wxDbCloseConnections();
616 // Deletion of the wxDbConnectInf instance must be the LAST thing done that
617 // has anything to do with the database. Deleting this before disconnecting,
618 // freeing/closing connections, etc will result in a crash!
619 delete wxGetApp().DbConnectInf
;
620 wxGetApp().DbConnectInf
= NULL
;
624 } // DatabaseDemoFrame::OnCloseWindow()
627 void DatabaseDemoFrame::BuildEditorDialog()
630 pEditorDlg
= new CeditorDlg(this);
633 pEditorDlg
->Initialize();
634 if (!pEditorDlg
->initialized
)
638 wxMessageBox(wxT("Unable to initialize the editor dialog for some reason"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
644 wxMessageBox(wxT("Unable to create the editor dialog for some reason"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
647 } // DatabaseDemoFrame::BuildEditorDialog()
650 void DatabaseDemoFrame::BuildParameterDialog(wxWindow
*parent
)
652 pParamDlg
= new CparameterDlg(parent
);
655 wxMessageBox(wxT("Unable to create the parameter dialog for some reason"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
656 } // DatabaseDemoFrame::BuildParameterDialog()
660 * Constructor note: If no wxDb object is passed in, a new connection to the database
661 * is created for this instance of Ccontact. This can be a slow process depending
662 * on the database engine being used, and some database engines have a limit on the
663 * number of connections (either hard limits, or license restricted) so care should
664 * be used to use as few connections as is necessary.
666 * IMPORTANT: Objects which share a wxDb pointer are ALL acted upon whenever a member
667 * function of pDb is called (i.e. CommitTrans() or RollbackTrans(), so if modifying
668 * or creating a table objects which use the same pDb, know that all the objects
669 * will be committed or rolled back when any of the objects has this function call made.
671 Ccontact::Ccontact (wxDb
*pwxDb
) : wxDbTable(pwxDb
? pwxDb
: wxDbGetConnection(wxGetApp().DbConnectInf
),
672 CONTACT_TABLE_NAME
, CONTACT_NO_COLS
, wxT(""),
673 !wxDB_QUERY_ONLY
, wxGetApp().DbConnectInf
->GetDefaultDir())
675 // This is used to represent whether the database connection should be released
676 // when this instance of the object is deleted. If using the same connection
677 // for multiple instance of database objects, then the connection should only be
678 // released when the last database instance using the connection is deleted
682 GetDb()->SetSqlLogging(sqlLogON
);
686 } // Ccontact Constructor
689 void Ccontact::Initialize()
698 JoinDate
.year
= 1980;
704 JoinDate
.fraction
= 0;
705 NativeLanguage
= langENGLISH
;
709 } // Ccontact::Initialize
712 Ccontact::~Ccontact()
716 if (!wxDbFreeConnection(GetDb()))
719 tStr
= wxT("Unable to Free the Ccontact data table handle\n\n");
720 tStr
+= GetExtendedDBErrorMsg(GetDb(),__FILE__
,__LINE__
);
721 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
724 } // Ccontract destructor
728 * Handles setting up all the connections for the interface from the wxDbTable
729 * functions to interface to the data structure used to store records in
730 * memory, and for all the column definitions that define the table structure
732 void Ccontact::SetupColumns()
734 // NOTE: Columns now are 8 character names, as that is all dBase can support. Longer
735 // names can be used for other database engines
736 SetColDefs ( 0,wxT("NAME"), DB_DATA_TYPE_VARCHAR
, Name
, SQL_C_CHAR
, sizeof(Name
), TRUE
, TRUE
); // Primary index
737 SetColDefs ( 1,wxT("ADDRESS1"), DB_DATA_TYPE_VARCHAR
, Addr1
, SQL_C_CHAR
, sizeof(Addr1
), FALSE
,TRUE
);
738 SetColDefs ( 2,wxT("ADDRESS2"), DB_DATA_TYPE_VARCHAR
, Addr2
, SQL_C_CHAR
, sizeof(Addr2
), FALSE
,TRUE
);
739 SetColDefs ( 3,wxT("CITY"), DB_DATA_TYPE_VARCHAR
, City
, SQL_C_CHAR
, sizeof(City
), FALSE
,TRUE
);
740 SetColDefs ( 4,wxT("STATE"), DB_DATA_TYPE_VARCHAR
, State
, SQL_C_CHAR
, sizeof(State
), FALSE
,TRUE
);
741 SetColDefs ( 5,wxT("POSTCODE"), DB_DATA_TYPE_VARCHAR
, PostalCode
, SQL_C_CHAR
, sizeof(PostalCode
), FALSE
,TRUE
);
742 SetColDefs ( 6,wxT("COUNTRY"), DB_DATA_TYPE_VARCHAR
, Country
, SQL_C_CHAR
, sizeof(Country
), FALSE
,TRUE
);
743 SetColDefs ( 7,wxT("JOINDATE"), DB_DATA_TYPE_DATE
, &JoinDate
, SQL_C_TIMESTAMP
, sizeof(JoinDate
), FALSE
,TRUE
);
744 SetColDefs ( 8,wxT("IS_DEV"), DB_DATA_TYPE_INTEGER
, &IsDeveloper
, SQL_C_BOOLEAN(IsDeveloper
), sizeof(IsDeveloper
), FALSE
,TRUE
);
745 SetColDefs ( 9,wxT("CONTRIBS"), DB_DATA_TYPE_INTEGER
, &Contributions
, SQL_C_USHORT
, sizeof(Contributions
), FALSE
,TRUE
);
746 SetColDefs (10,wxT("LINE_CNT"), DB_DATA_TYPE_INTEGER
, &LinesOfCode
, SQL_C_ULONG
, sizeof(LinesOfCode
), FALSE
,TRUE
);
747 SetColDefs (11,wxT("LANGUAGE"), DB_DATA_TYPE_INTEGER
, &NativeLanguage
, SQL_C_ENUM
, sizeof(NativeLanguage
), FALSE
,TRUE
);
748 #if wxODBC_BLOB_EXPERIMENT > 0
749 SetColDefs (12,wxT("PICTURE"), DB_DATA_TYPE_BLOB
, Picture
, SQL_LONGVARBINARY
, sizeof(Picture
), FALSE
,TRUE
);
751 } // Ccontact::SetupColumns
754 bool Ccontact::CreateIndexes(void)
756 // This index could easily be accomplished with an "orderBy" clause,
757 // but is done to show how to construct a non-primary index.
759 wxDbIdxDef idxDef
[2];
763 wxStrcpy(idxDef
[0].ColName
, "IS_DEV");
764 idxDef
[0].Ascending
= TRUE
;
766 wxStrcpy(idxDef
[1].ColName
, "NAME");
767 idxDef
[1].Ascending
= TRUE
;
769 indexName
= GetTableName();
770 indexName
+= "_IDX1";
771 Ok
= CreateIndex(indexName
.c_str(), TRUE
, 2, idxDef
);
774 } // Ccontact::CreateIndexes()
778 * Having a function to do a query on the primary key (and possibly others) is
779 * very efficient and tighter coding so that it is available where ever the object
780 * is. Great for use with multiple tables when not using views or outer joins
782 bool Ccontact::FetchByName(const wxString
&name
)
784 whereStr
.Printf(wxT("NAME = '%s'"),name
.c_str());
785 SetWhereClause(whereStr
.c_str());
786 SetOrderByClause(wxT(""));
794 } // Ccontact::FetchByName()
799 * ************* DIALOGS ***************
804 /* CeditorDlg constructor
806 * Creates the dialog used for creating/editing/deleting/copying a Ccontact object.
807 * This dialog actually is drawn in the main frame of the program
809 * An instance of Ccontact is created - "Contact" - which is used to hold the Ccontact
810 * object that is currently being worked with.
813 BEGIN_EVENT_TABLE(CeditorDlg
, wxPanel
)
814 EVT_BUTTON(-1, CeditorDlg::OnButton
)
815 EVT_CLOSE(CeditorDlg::OnCloseWindow
)
818 CeditorDlg::CeditorDlg(wxWindow
*parent
) : wxPanel (parent
, 0, 0, 537, 480)
820 // Since the ::OnCommand() function is overridden, this prevents the widget
821 // detection in ::OnCommand() until all widgets have been initialized to prevent
822 // uninitialized pointers from crashing the program
823 widgetPtrsSet
= FALSE
;
832 } // CeditorDlg constructor
835 void CeditorDlg::OnCloseWindow(wxCloseEvent
& event
)
838 if ((mode
!= mCreate
) && (mode
!= mEdit
))
849 wxMessageBox(wxT("Must finish processing the current record being created/modified before exiting"),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
852 } // CeditorDlg::OnCloseWindow()
855 void CeditorDlg::OnButton(wxCommandEvent
&event
)
857 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
858 OnCommand( *win
, event
);
859 } // CeditorDlg::OnButton()
862 void CeditorDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
866 widgetName
= win
.GetName();
871 if (widgetName
== pCreateBtn
->GetName())
873 Contact
->Initialize();
876 pNameTxt
->SetValue(wxT(""));
877 pNameTxt
->SetFocus();
881 if (widgetName
== pEditBtn
->GetName())
883 saveName
= Contact
->Name
;
885 pNameTxt
->SetFocus();
889 if (widgetName
== pCopyBtn
->GetName())
892 CheckSupportForAllDataTypes(wxGetApp().READONLY_DB
);
895 pNameTxt->SetValue(wxT(""));
896 pNameTxt->SetFocus();
901 if (widgetName
== pDeleteBtn
->GetName())
903 bool Ok
= (wxMessageBox(wxT("Are you sure?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
908 if (Ok
&& Contact
->Delete())
910 // NOTE: Deletions are not finalized until a CommitTrans() is performed.
911 // If the commit were not performed, the program will continue to
912 // show the table contents as if they were deleted until this instance
913 // of Ccontact is deleted. If the Commit wasn't performed, the
914 // database will automatically Rollback the changes when the database
915 // connection is terminated
916 Contact
->GetDb()->CommitTrans();
918 // Try to get the row that followed the just deleted row in the orderBy sequence
921 // There was now row (in sequence) after the just deleted row, so get the
922 // row which preceded the just deleted row
925 // There are now no rows remaining, so clear the dialog widgets
926 Contact
->Initialize();
930 SetMode(mode
); // force reset of button enable/disable
934 Contact
->GetDb()->RollbackTrans();
940 if (widgetName
== pSaveBtn
->GetName())
946 if (widgetName
== pCancelBtn
->GetName())
948 bool Ok
= (wxMessageBox(wxT("Are you sure?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
953 if (saveName
.IsEmpty())
955 Contact
->Initialize();
962 // Requery previous record
963 if (Contact
->FetchByName(saveName
))
971 // Previous record not available, retrieve first record in table
972 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
974 Contact
->whereStr
= wxT("NAME = (SELECT MIN(NAME) FROM ");
975 Contact
->whereStr
+= Contact
->GetTableName();
976 Contact
->whereStr
+= wxT(")");
977 Contact
->SetWhereClause(Contact
->whereStr
.c_str());
980 Contact
->SetWhereClause(wxT(""));
982 if (!Contact
->Query())
985 tStr
= wxT("ODBC error during Query()\n\n");
986 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
987 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
991 if (Contact
->GetNext()) // Successfully read first record
997 // No contacts are available, clear dialog
998 Contact
->Initialize();
1004 if (widgetName
== pPrevBtn
->GetName())
1011 if (widgetName
== pNextBtn
->GetName())
1018 if (widgetName
== pQueryBtn
->GetName())
1020 // Display the query dialog box
1021 wxChar qryWhere
[DB_MAX_WHERE_CLAUSE_LEN
+1];
1022 wxStrcpy(qryWhere
, (const wxChar
*) Contact
->qryWhereStr
);
1023 wxChar
*tblName
[] = {(wxChar
*)CONTACT_TABLE_NAME
, 0};
1024 new CqueryDlg(GetParent(), Contact
->GetDb(), tblName
, qryWhere
);
1026 // Query the first record in the new record set and
1027 // display it, if the query string has changed.
1028 if (wxStrcmp(qryWhere
, (const wxChar
*) Contact
->qryWhereStr
))
1030 Contact
->whereStr
.Empty();
1031 Contact
->SetOrderByClause("NAME");
1033 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1035 Contact
->whereStr
= wxT("NAME = (SELECT MIN(NAME) FROM ");
1036 Contact
->whereStr
+= CONTACT_TABLE_NAME
;
1039 // Append the query where string (if there is one)
1040 Contact
->qryWhereStr
= qryWhere
;
1041 if (wxStrlen(qryWhere
))
1043 Contact
->whereStr
+= wxT(" WHERE ");
1044 Contact
->whereStr
+= Contact
->qryWhereStr
;
1046 // Close the expression with a right paren
1047 Contact
->whereStr
+= wxT(")");
1048 // Requery the table
1049 Contact
->SetWhereClause(Contact
->whereStr
.c_str());
1050 if (!Contact
->Query())
1053 tStr
= wxT("ODBC error during Query()\n\n");
1054 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1055 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1058 // Display the first record from the query set
1059 if (!Contact
->GetNext())
1060 Contact
->Initialize();
1064 // Enable/Disable the reset button
1065 pResetBtn
->Enable(!Contact
->qryWhereStr
.IsEmpty());
1071 if (widgetName
== pResetBtn
->GetName())
1073 // Clear the additional where criteria established by the query feature
1074 Contact
->qryWhereStr
= wxT("");
1075 Contact
->SetOrderByClause(wxT("NAME"));
1077 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1079 Contact
->whereStr
= wxT("NAME = (SELECT MIN(NAME) FROM ");
1080 Contact
->whereStr
+= CONTACT_TABLE_NAME
;
1081 Contact
->whereStr
+= wxT(")");
1084 Contact
->SetWhereClause(Contact
->whereStr
.c_str());
1085 if (!Contact
->Query())
1088 tStr
= wxT("ODBC error during Query()\n\n");
1089 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1090 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1093 if (!Contact
->GetNext())
1094 Contact
->Initialize();
1096 pResetBtn
->Enable(FALSE
);
1102 if (widgetName
== pNameListBtn
->GetName())
1104 new ClookUpDlg(/* wxWindow *parent */ this,
1105 /* wxChar *windowTitle */ wxT("Select contact name"),
1106 /* wxChar *tableName */ (wxChar
*) CONTACT_TABLE_NAME
,
1107 /* wxChar *dispCol1 */ wxT("NAME"),
1108 /* wxChar *dispCol2 */ wxT("JOINDATE"),
1109 /* wxChar *where */ wxT(""),
1110 /* wxChar *orderBy */ wxT("NAME"),
1111 /* wxDb *pDb */ wxGetApp().READONLY_DB
,
1112 /* const wxString &defDir */ wxGetApp().DbConnectInf
->GetDefaultDir(),
1113 /* bool distinctValues */ TRUE
);
1115 if (ListDB_Selection
&& wxStrlen(ListDB_Selection
))
1117 wxString w
= wxT("NAME = '");
1118 w
+= ListDB_Selection
;
1125 } // CeditorDlg::OnCommand()
1128 bool CeditorDlg::Initialize()
1130 // Create the data structure and a new database connection.
1131 // (As there is not a pDb being passed in the constructor, a new database
1132 // connection is created)
1133 Contact
= new Ccontact();
1137 wxMessageBox(wxT("Unable to instantiate an instance of Ccontact"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
1141 // Check if the table exists or not. If it doesn't, ask the user if they want to
1142 // create the table. Continue trying to create the table until it exists, or user aborts
1143 while (!Contact
->GetDb()->TableExists((wxChar
*)CONTACT_TABLE_NAME
,
1144 wxGetApp().DbConnectInf
->GetUserID(),
1145 wxGetApp().DbConnectInf
->GetDefaultDir()))
1148 tStr
.Printf(wxT("Unable to open the table '%s'.\n\nTable may need to be created...?\n\n"),CONTACT_TABLE_NAME
);
1149 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1150 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1152 bool createTable
= (wxMessageBox(wxT("Do you wish to try to create/clear the CONTACTS table?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
1160 wxGetApp().CreateDataTable(TRUE
);
1163 // Tables must be "opened" before anything other than creating/deleting table can be done
1164 if (!Contact
->Open())
1166 // Table does exist, or there was some problem opening it. Currently this should
1167 // never fail, except in the case of the table not exisiting or the current
1168 // user has insufficent privileges to access the table
1170 // This code is experimenting with a new function that will hopefully be available
1171 // in the 2.4 release. This check will determine whether the open failing was due
1172 // to the table not existing, or the users privileges being insufficient to
1174 if (!Contact
->GetDb()->TablePrivileges(CONTACT_TABLE_NAME
, wxT("SELECT"),
1175 Contact
->GetDb()->GetUsername(),
1176 Contact
->GetDb()->GetUsername(),
1177 wxGetApp().DbConnectInf
->GetDefaultDir()))
1180 tStr
.Printf(wxT("Unable to open the table '%s' (likely due to\ninsufficient privileges of the logged in user).\n\n"),CONTACT_TABLE_NAME
);
1181 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1182 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1186 if (!Contact
->GetDb()->TableExists(CONTACT_TABLE_NAME
,
1187 Contact
->GetDb()->GetUsername(),
1188 wxGetApp().DbConnectInf
->GetDefaultDir()))
1191 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
);
1192 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1193 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1201 (void)new wxStaticBox(this, EDITOR_DIALOG_FN_GROUP
, wxT(""), wxPoint(15, 1), wxSize(497, 69), 0, wxT("FunctionGrp"));
1202 (void)new wxStaticBox(this, EDITOR_DIALOG_SEARCH_GROUP
, wxT(""), wxPoint(417, 1), wxSize(95, 242), 0, wxT("SearchGrp"));
1204 pCreateBtn
= new wxButton(this, EDITOR_DIALOG_CREATE
, wxT("&Create"), wxPoint( 25, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("CreateBtn"));
1205 pEditBtn
= new wxButton(this, EDITOR_DIALOG_EDIT
, wxT("&Edit"), wxPoint(102, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("EditBtn"));
1206 pDeleteBtn
= new wxButton(this, EDITOR_DIALOG_DELETE
, wxT("&Delete"), wxPoint(179, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("DeleteBtn"));
1207 pCopyBtn
= new wxButton(this, EDITOR_DIALOG_COPY
, wxT("Cop&y"), wxPoint(256, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("CopyBtn"));
1208 pSaveBtn
= new wxButton(this, EDITOR_DIALOG_SAVE
, wxT("&Save"), wxPoint(333, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("SaveBtn"));
1209 pCancelBtn
= new wxButton(this, EDITOR_DIALOG_CANCEL
, wxT("C&ancel"), wxPoint(430, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("CancelBtn"));
1210 pPrevBtn
= new wxButton(this, EDITOR_DIALOG_PREV
, wxT("<< &Prev"), wxPoint(430, 81), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("PrevBtn"));
1211 pNextBtn
= new wxButton(this, EDITOR_DIALOG_NEXT
, wxT("&Next >>"), wxPoint(430, 121), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("NextBtn"));
1212 pQueryBtn
= new wxButton(this, EDITOR_DIALOG_QUERY
, wxT("&Query"), wxPoint(430, 161), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("QueryBtn"));
1213 pResetBtn
= new wxButton(this, EDITOR_DIALOG_RESET
, wxT("&Reset"), wxPoint(430, 200), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("ResetBtn"));
1214 pNameMsg
= new wxStaticText(this, EDITOR_DIALOG_NAME_MSG
, wxT("Name:"), wxPoint( 17, 80), wxSize( -1, -1), 0, wxT("NameMsg"));
1215 pNameTxt
= new wxTextCtrl(this, EDITOR_DIALOG_NAME_TEXT
, wxT(""), wxPoint( 17, 97), wxSize(308, 25), 0, wxDefaultValidator
, wxT("NameTxt"));
1216 pNameListBtn
= new wxButton(this, EDITOR_DIALOG_LOOKUP
, wxT("&Lookup"), wxPoint(333, 97), wxSize( 70, 24), 0, wxDefaultValidator
, wxT("LookupBtn"));
1217 pAddress1Msg
= new wxStaticText(this, EDITOR_DIALOG_ADDRESS1_MSG
, wxT("Address:"), wxPoint( 17, 130), wxSize( -1, -1), 0, wxT("Address1Msg"));
1218 pAddress1Txt
= new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT
, wxT(""), wxPoint( 17, 147), wxSize(308, 25), 0, wxDefaultValidator
, wxT("Address1Txt"));
1219 pAddress2Msg
= new wxStaticText(this, EDITOR_DIALOG_ADDRESS2_MSG
, wxT("Address:"), wxPoint( 17, 180), wxSize( -1, -1), 0, wxT("Address2Msg"));
1220 pAddress2Txt
= new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT
, wxT(""), wxPoint( 17, 197), wxSize(308, 25), 0, wxDefaultValidator
, wxT("Address2Txt"));
1221 pCityMsg
= new wxStaticText(this, EDITOR_DIALOG_CITY_MSG
, wxT("City:"), wxPoint( 17, 230), wxSize( -1, -1), 0, wxT("CityMsg"));
1222 pCityTxt
= new wxTextCtrl(this, EDITOR_DIALOG_CITY_TEXT
, wxT(""), wxPoint( 17, 247), wxSize(225, 25), 0, wxDefaultValidator
, wxT("CityTxt"));
1223 pStateMsg
= new wxStaticText(this, EDITOR_DIALOG_STATE_MSG
, wxT("State:"), wxPoint(250, 230), wxSize( -1, -1), 0, wxT("StateMsg"));
1224 pStateTxt
= new wxTextCtrl(this, EDITOR_DIALOG_STATE_TEXT
, wxT(""), wxPoint(250, 247), wxSize(153, 25), 0, wxDefaultValidator
, wxT("StateTxt"));
1225 pCountryMsg
= new wxStaticText(this, EDITOR_DIALOG_COUNTRY_MSG
, wxT("Country:"), wxPoint( 17, 280), wxSize( -1, -1), 0, wxT("CountryMsg"));
1226 pCountryTxt
= new wxTextCtrl(this, EDITOR_DIALOG_COUNTRY_TEXT
, wxT(""), wxPoint( 17, 297), wxSize(225, 25), 0, wxDefaultValidator
, wxT("CountryTxt"));
1227 pPostalCodeMsg
= new wxStaticText(this, EDITOR_DIALOG_POSTAL_MSG
, wxT("Postal Code:"),wxPoint(250, 280), wxSize( -1, -1), 0, wxT("PostalCodeMsg"));
1228 pPostalCodeTxt
= new wxTextCtrl(this, EDITOR_DIALOG_POSTAL_TEXT
, wxT(""), wxPoint(250, 297), wxSize(153, 25), 0, wxDefaultValidator
, wxT("PostalCodeTxt"));
1230 wxString choice_strings
[5];
1231 choice_strings
[0] = wxT("English");
1232 choice_strings
[1] = wxT("French");
1233 choice_strings
[2] = wxT("German");
1234 choice_strings
[3] = wxT("Spanish");
1235 choice_strings
[4] = wxT("Other");
1237 pNativeLangChoice
= new wxChoice(this, EDITOR_DIALOG_LANG_CHOICE
, wxPoint( 17, 346), wxSize(277, -1), 5, choice_strings
);
1238 pNativeLangMsg
= new wxStaticText(this, EDITOR_DIALOG_LANG_MSG
, wxT("Native language:"), wxPoint( 17, 330), wxSize( -1, -1), 0, wxT("NativeLangMsg"));
1240 wxString radio_strings
[2];
1241 radio_strings
[0] = wxT("No");
1242 radio_strings
[1] = wxT("Yes");
1243 pDeveloperRadio
= new wxRadioBox(this,EDITOR_DIALOG_DEVELOPER
, wxT("Developer:"), wxPoint(303, 330), wxSize( -1, -1), 2, radio_strings
, 2, wxHORIZONTAL
);
1244 pJoinDateMsg
= new wxStaticText(this, EDITOR_DIALOG_JOIN_MSG
, wxT("Date joined:"), wxPoint( 17, 380), wxSize( -1, -1), 0, wxT("JoinDateMsg"));
1245 pJoinDateTxt
= new wxTextCtrl(this, EDITOR_DIALOG_JOIN_TEXT
, wxT(""), wxPoint( 17, 397), wxSize(150, 25), 0, wxDefaultValidator
, wxT("JoinDateTxt"));
1246 pContribMsg
= new wxStaticText(this, EDITOR_DIALOG_CONTRIB_MSG
,wxT("Contributions:"), wxPoint(175, 380), wxSize( -1, -1), 0, wxT("ContribMsg"));
1247 pContribTxt
= new wxTextCtrl(this, EDITOR_DIALOG_CONTRIB_TEXT
, wxT(""), wxPoint(175, 397), wxSize(120, 25), 0, wxDefaultValidator
, wxT("ContribTxt"));
1248 pLinesMsg
= new wxStaticText(this, EDITOR_DIALOG_LINES_MSG
, wxT("Lines of code:"), wxPoint(303, 380), wxSize( -1, -1), 0, wxT("LinesMsg"));
1249 pLinesTxt
= new wxTextCtrl(this, EDITOR_DIALOG_LINES_TEXT
, wxT(""), wxPoint(303, 397), wxSize(100, 25), 0, wxDefaultValidator
, wxT("LinesTxt"));
1251 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
1252 // handle all widget processing
1253 widgetPtrsSet
= TRUE
;
1255 // Setup the orderBy and where clauses to return back a single record as the result set,
1256 // as there will only be one record being shown on the dialog at a time, this optimizes
1257 // network traffic by only returning a one row result
1259 Contact
->SetOrderByClause(wxT("NAME")); // field name to sort by
1261 // The wxString "whereStr" is not a member of the wxDbTable object, it is a member variable
1262 // specifically in the Ccontact class. It is used here for simpler construction of a varying
1263 // length string, and then after the string is built, the wxDbTable member variable "where" is
1264 // assigned the pointer to the constructed string.
1266 // The constructed where clause below has a sub-query within it "SELECT MIN(NAME) FROM %s"
1267 // to achieve a single row (in this case the first name in alphabetical order).
1269 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1271 Contact
->whereStr
.Printf(wxT("NAME = (SELECT MIN(NAME) FROM %s)"),Contact
->GetTableName().c_str());
1272 // NOTE: (const wxChar*) returns a pointer which may not be valid later, so this is short term use only
1273 Contact
->SetWhereClause(Contact
->whereStr
);
1276 Contact
->SetWhereClause(wxT(""));
1278 // Perform the Query to get the result set.
1279 // NOTE: If there are no rows returned, that is a valid result, so Query() would return TRUE.
1280 // Only if there is a database error will Query() come back as FALSE
1281 if (!Contact
->Query())
1284 tStr
= wxT("ODBC error during Query()\n\n");
1285 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1286 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1287 // GetParent()->Close();
1291 // Since Query succeeded, now get the row that was returned
1292 if (!Contact
->GetNext())
1293 // If the GetNext() failed at this point, then there are no rows to retrieve,
1294 // so clear the values in the members of "Contact" so that PutData() blanks the
1295 // widgets on the dialog
1296 Contact
->Initialize();
1305 } // CeditorDlg::Initialize()
1308 void CeditorDlg::FieldsEditable()
1313 pNameTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1314 pAddress1Txt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1315 pAddress2Txt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1316 pCityTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1317 pStateTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1318 pPostalCodeTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1319 pCountryTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1321 pJoinDateTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1322 pContribTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1323 pLinesTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1324 pNativeLangChoice
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1325 pDeveloperRadio
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1327 } // CeditorDlg::FieldsEditable()
1330 void CeditorDlg::SetMode(enum DialogModes m
)
1351 pCreateBtn
->Enable( !edit
);
1352 pEditBtn
->Enable( !edit
&& (wxStrcmp(Contact
->Name
,wxT(""))!=0) );
1353 pDeleteBtn
->Enable( !edit
&& (wxStrcmp(Contact
->Name
,wxT(""))!=0) );
1354 pCopyBtn
->Enable( !edit
&& (wxStrcmp(Contact
->Name
,wxT(""))!=0) );
1355 pSaveBtn
->Enable( edit
);
1356 pCancelBtn
->Enable( edit
);
1357 pPrevBtn
->Enable( !edit
);
1358 pNextBtn
->Enable( !edit
);
1359 pQueryBtn
->Enable( !edit
);
1360 pResetBtn
->Enable( !edit
&& !Contact
->qryWhereStr
.IsEmpty() );
1361 pNameListBtn
->Enable( !edit
);
1365 } // CeditorDlg::SetMode()
1368 bool CeditorDlg::PutData()
1372 pNameTxt
->SetValue(Contact
->Name
);
1373 pAddress1Txt
->SetValue(Contact
->Addr1
);
1374 pAddress2Txt
->SetValue(Contact
->Addr2
);
1375 pCityTxt
->SetValue(Contact
->City
);
1376 pStateTxt
->SetValue(Contact
->State
);
1377 pCountryTxt
->SetValue(Contact
->Country
);
1378 pPostalCodeTxt
->SetValue(Contact
->PostalCode
);
1380 tStr
.Printf(wxT("%d/%d/%d"),Contact
->JoinDate
.month
,Contact
->JoinDate
.day
,Contact
->JoinDate
.year
);
1381 pJoinDateTxt
->SetValue(tStr
);
1383 tStr
.Printf(wxT("%d"),Contact
->Contributions
);
1384 pContribTxt
->SetValue(tStr
);
1386 tStr
.Printf(wxT("%lu"),Contact
->LinesOfCode
);
1387 pLinesTxt
->SetValue(tStr
);
1389 pNativeLangChoice
->SetSelection(Contact
->NativeLanguage
);
1391 pDeveloperRadio
->SetSelection(Contact
->IsDeveloper
);
1394 } // Ceditor::PutData()
1398 * Reads the data out of all the widgets on the dialog. Some data evaluation is done
1399 * to ensure that there is a name entered and that the date field is valid.
1401 * A return value of TRUE means that valid data was retrieved from the dialog, otherwise
1402 * invalid data was found (and a message was displayed telling the user what to fix), and
1403 * the data was not placed into the appropraite fields of Ccontact
1405 bool CeditorDlg::GetData()
1407 // Validate that the data currently entered into the widgets is valid data
1410 tStr
= pNameTxt
->GetValue();
1411 if (!wxStrcmp((const wxChar
*) tStr
,wxT("")))
1413 wxMessageBox(wxT("A name is required for entry into the contact table"),wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
1417 bool invalid
= FALSE
;
1421 tStr
= pJoinDateTxt
->GetValue();
1422 if (tStr
.Freq(wxT('/')) != 2)
1425 // Find the month, day, and year tokens
1428 first
= tStr
.First(wxT('/'));
1429 second
= tStr
.Last(wxT('/'));
1431 mm
= atoi(tStr
.SubString(0,first
));
1432 dd
= atoi(tStr
.SubString(first
+1,second
));
1433 yyyy
= atoi(tStr
.SubString(second
+1,tStr
.Length()-1));
1435 invalid
= !(mm
&& dd
&& yyyy
);
1438 // Force Year 2000 compliance
1439 if (!invalid
&& (yyyy
< 1000))
1442 // Check the token ranges for validity
1447 else if ((mm
< 1) || (mm
> 12))
1455 int days
[12] = {31,28,31,30,31,30,
1457 if (dd
> days
[mm
-1])
1460 if ((dd
== 29) && (mm
== 2))
1462 if (((yyyy
% 4) == 0) && (((yyyy
% 100) != 0) || ((yyyy
% 400) == 0)))
1472 Contact
->JoinDate
.month
= mm
;
1473 Contact
->JoinDate
.day
= dd
;
1474 Contact
->JoinDate
.year
= yyyy
;
1478 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
);
1482 tStr
= pNameTxt
->GetValue();
1483 wxStrcpy(Contact
->Name
,(const wxChar
*) tStr
);
1484 wxStrcpy(Contact
->Addr1
,pAddress1Txt
->GetValue());
1485 wxStrcpy(Contact
->Addr2
,pAddress2Txt
->GetValue());
1486 wxStrcpy(Contact
->City
,pCityTxt
->GetValue());
1487 wxStrcpy(Contact
->State
,pStateTxt
->GetValue());
1488 wxStrcpy(Contact
->Country
,pCountryTxt
->GetValue());
1489 wxStrcpy(Contact
->PostalCode
,pPostalCodeTxt
->GetValue());
1491 Contact
->Contributions
= atoi(pContribTxt
->GetValue());
1492 Contact
->LinesOfCode
= atol(pLinesTxt
->GetValue());
1494 Contact
->NativeLanguage
= (enum Language
) pNativeLangChoice
->GetSelection();
1495 Contact
->IsDeveloper
= pDeveloperRadio
->GetSelection() > 0;
1498 } // CeditorDlg::GetData()
1502 * Retrieve data from the dialog, verify the validity of the data, and if it is valid,
1503 * try to insert/update the data to the table based on the current 'mode' the dialog
1506 * A return value of TRUE means the insert/update was completed successfully, a return
1507 * value of FALSE means that Save() failed. If returning FALSE, then this function
1508 * has displayed a detailed error message for the user.
1510 bool CeditorDlg::Save()
1512 bool failed
= FALSE
;
1514 // Read the data in the widgets of the dialog to get the user's data
1518 // Perform any other required validations necessary before saving
1521 wxBeginBusyCursor();
1523 if (mode
== mCreate
)
1525 RETCODE result
= Contact
->Insert();
1527 failed
= (result
!= DB_SUCCESS
);
1530 // Some errors may be expected, like a duplicate key, so handle those instances with
1531 // specific error messages.
1532 if (result
== DB_ERR_INTEGRITY_CONSTRAINT_VIOL
)
1535 tStr
= wxT("A duplicate key value already exists in the table.\nUnable to save record\n\n");
1536 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1537 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1541 // Some other unexpexted error occurred
1543 tStr
= wxT("Database insert failed\n\n");
1544 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1545 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1549 else // mode == mEdit
1551 Contact
->whereStr
.Printf("NAME = '%s'",saveName
.c_str());
1552 if (!Contact
->UpdateWhere(Contact
->whereStr
))
1555 tStr
= wxT("Database update failed\n\n");
1556 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1557 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1564 Contact
->GetDb()->CommitTrans();
1565 SetMode(mView
); // Sets the dialog mode back to viewing after save is successful
1568 Contact
->GetDb()->RollbackTrans();
1574 } // CeditorDlg::Save()
1578 * Where this program is only showing a single row at a time in the dialog,
1579 * a special where clause must be built to find just the single row which,
1580 * in sequence, would follow the currently displayed row.
1582 bool CeditorDlg::GetNextRec()
1586 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1588 w
= wxT("NAME = (SELECT MIN(NAME) FROM ");
1589 w
+= Contact
->GetTableName();
1590 w
+= wxT(" WHERE NAME > '");
1593 w
= wxT("(NAME > '");
1598 // If a query where string is currently set, append that criteria
1599 if (!Contact
->qryWhereStr
.IsEmpty())
1602 w
+= Contact
->qryWhereStr
;
1609 } // CeditorDlg::GetNextRec()
1613 * Where this program is only showing a single row at a time in the dialog,
1614 * a special where clause must be built to find just the single row which,
1615 * in sequence, would precede the currently displayed row.
1617 bool CeditorDlg::GetPrevRec()
1621 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1623 w
= wxT("NAME = (SELECT MAX(NAME) FROM ");
1624 w
+= Contact
->GetTableName();
1625 w
+= wxT(" WHERE NAME < '");
1628 w
= wxT("(NAME < '");
1633 // If a query where string is currently set, append that criteria
1634 if (!Contact
->qryWhereStr
.IsEmpty())
1637 w
+= Contact
->qryWhereStr
;
1645 } // CeditorDlg::GetPrevRec()
1649 * This function is here to avoid duplicating this same code in both the
1650 * GetPrevRec() and GetNextRec() functions
1652 bool CeditorDlg::GetRec(const wxString
&whereStr
)
1654 Contact
->SetWhereClause(whereStr
);
1655 Contact
->SetOrderByClause(wxT("NAME"));
1657 if (!Contact
->Query())
1660 tStr
= wxT("ODBC error during Query()\n\n");
1661 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1662 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1667 if (Contact
->GetNext())
1674 } // CeditorDlg::GetRec()
1679 * CparameterDlg constructor
1682 BEGIN_EVENT_TABLE(CparameterDlg
, wxDialog
)
1683 EVT_BUTTON(PARAMETER_DIALOG_SAVE
, CparameterDlg::OnButton
)
1684 EVT_BUTTON(PARAMETER_DIALOG_CANCEL
, CparameterDlg::OnButton
)
1685 EVT_CLOSE(CparameterDlg::OnCloseWindow
)
1688 CparameterDlg::CparameterDlg(wxWindow
*parent
) : wxDialog (parent
, PARAMETER_DIALOG
, wxT("ODBC parameter settings"), wxPoint(-1, -1), wxSize(400, 325))
1690 // Since the ::OnCommand() function is overridden, this prevents the widget
1691 // detection in ::OnCommand() until all widgets have been initialized to prevent
1692 // uninitialized pointers from crashing the program
1693 widgetPtrsSet
= FALSE
;
1695 pParamODBCSourceMsg
= new wxStaticText(this, PARAMETER_DIALOG_SOURCE_MSG
, wxT("ODBC data sources:"), wxPoint( 10, 10), wxSize( -1, -1), 0, wxT("ParamODBCSourceMsg"));
1696 pParamODBCSourceList
= new wxListBox(this, PARAMETER_DIALOG_SOURCE_LISTBOX
, wxPoint( 10, 29), wxSize(285, 150), 0, 0, wxLB_SINGLE
|wxLB_ALWAYS_SB
, wxDefaultValidator
, wxT("ParamODBCSourceList"));
1697 pParamUserNameMsg
= new wxStaticText(this, PARAMETER_DIALOG_NAME_MSG
, wxT("Database user name:"), wxPoint( 10, 193), wxSize( -1, -1), 0, wxT("ParamUserNameMsg"));
1698 pParamUserNameTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_NAME_TEXT
, wxT(""), wxPoint(10, 209), wxSize( 140, 25), 0, wxDefaultValidator
, wxT("ParamUserNameTxt"));
1699 pParamPasswordMsg
= new wxStaticText(this, PARAMETER_DIALOG_PASSWORD_MSG
, wxT("Password:"), wxPoint(156, 193), wxSize( -1, -1), 0, wxT("ParamPasswordMsg"));
1700 pParamPasswordTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_PASSWORD_TEXT
, wxT(""), wxPoint(156, 209), wxSize( 140, 25), 0, wxDefaultValidator
, wxT("ParamPasswordTxt"));
1701 pParamDirPathMsg
= new wxStaticText(this, PARAMETER_DIALOG_DIRPATH_MSG
, wxT("Directory:"), wxPoint( 10, 243), wxSize( -1, -1), 0, wxT("ParamDirPathMsg"));
1702 pParamDirPathTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_DIRPATH_TEXT
, wxT(""), wxPoint( 10, 259), wxSize(140, 25), 0, wxDefaultValidator
, wxT("ParamDirPathTxt"));
1703 pParamSaveBtn
= new wxButton(this, PARAMETER_DIALOG_SAVE
, wxT("&Save"), wxPoint(310, 21), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("ParamSaveBtn"));
1704 pParamCancelBtn
= new wxButton(this, PARAMETER_DIALOG_CANCEL
, wxT("C&ancel"), wxPoint(310, 66), wxSize( 70, 35), 0, wxDefaultValidator
, wxT("ParamCancelBtn"));
1706 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
1707 // handle all widget processing
1708 widgetPtrsSet
= TRUE
;
1711 savedParamSettings
= wxGetApp().params
;
1716 } // CparameterDlg constructor
1719 void CparameterDlg::OnCloseWindow(wxCloseEvent
& event
)
1721 // Put any additional checking necessary to make certain it is alright
1722 // to close the program here that is not done elsewhere
1725 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
);
1733 wxGetApp().params
= savedParamSettings
;
1736 if (GetParent() != NULL
)
1737 GetParent()->SetFocus();
1743 SetReturnCode(0); // added so BoundsChecker would not report use of uninitialized variable
1746 } // CparameterDlg::OnCloseWindow()
1749 void CparameterDlg::OnButton( wxCommandEvent
&event
)
1751 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
1752 OnCommand( *win
, event
);
1756 void CparameterDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
1758 wxString widgetName
;
1760 widgetName
= win
.GetName();
1765 if (widgetName
== pParamSaveBtn
->GetName())
1770 tStr
= wxT("Database parameters have been saved.");
1771 if (GetParent() != NULL
) // The parameter dialog was not called during startup due to a missing cfg file
1772 tStr
+= wxT("\nNew parameters will take effect the next time the program is started.");
1773 wxMessageBox(tStr
,wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
1780 if (widgetName
== pParamCancelBtn
->GetName())
1785 } // CparameterDlg::OnCommand()
1788 bool CparameterDlg::PutData()
1790 // Fill the data source list box
1791 FillDataSourceList();
1793 // Fill in the fields from the params object
1794 if (wxGetApp().params
.ODBCSource
&& wxStrlen(wxGetApp().params
.ODBCSource
))
1795 pParamODBCSourceList
->SetStringSelection(wxGetApp().params
.ODBCSource
);
1796 pParamUserNameTxt
->SetValue(wxGetApp().params
.UserName
);
1797 pParamPasswordTxt
->SetValue(wxGetApp().params
.Password
);
1798 pParamDirPathTxt
->SetValue(wxGetApp().params
.DirPath
);
1800 } // CparameterDlg::PutData()
1803 bool CparameterDlg::GetData()
1806 if (pParamODBCSourceList
->GetStringSelection() != wxT(""))
1808 tStr
= pParamODBCSourceList
->GetStringSelection();
1809 if (tStr
.Length() > (sizeof(wxGetApp().params
.ODBCSource
)-1))
1812 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());
1813 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1816 wxStrcpy(wxGetApp().params
.ODBCSource
, tStr
);
1821 tStr
= pParamUserNameTxt
->GetValue();
1822 if (tStr
.Length() > (sizeof(wxGetApp().params
.UserName
)-1))
1825 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());
1826 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1829 wxStrcpy(wxGetApp().params
.UserName
, tStr
);
1831 tStr
= pParamPasswordTxt
->GetValue();
1832 if (tStr
.Length() > (sizeof(wxGetApp().params
.Password
)-1))
1835 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());
1836 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1839 wxStrcpy(wxGetApp().params
.Password
,tStr
);
1841 tStr
= pParamDirPathTxt
->GetValue();
1842 tStr
.Replace(wxT("\\"),wxT("/"));
1843 if (tStr
.Length() > (sizeof(wxGetApp().params
.DirPath
)-1))
1846 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());
1847 wxMessageBox(errmsg
,wxT("Internal program error..."),wxOK
| wxICON_EXCLAMATION
);
1850 wxStrcpy(wxGetApp().params
.DirPath
,tStr
);
1852 } // CparameterDlg::GetData()
1855 bool CparameterDlg::Save()
1857 // Copy the current params in case user cancels changing
1858 // the params, so that we can reset them.
1861 wxGetApp().params
= savedParamSettings
;
1865 wxGetApp().WriteParamFile(wxGetApp().params
);
1868 } // CparameterDlg::Save()
1871 void CparameterDlg::FillDataSourceList()
1873 wxChar Dsn
[SQL_MAX_DSN_LENGTH
+ 1];
1875 wxStringList strList
;
1877 while (wxDbGetDataSource(wxGetApp().DbConnectInf
->GetHenv(), Dsn
,
1878 SQL_MAX_DSN_LENGTH
+1, DsDesc
, 255))
1882 strList
.Add(wxT(""));
1883 wxChar
**p
= strList
.ListToArray();
1886 for (i
= 0; wxStrlen(p
[i
]); i
++)
1887 pParamODBCSourceList
->Append(p
[i
]);
1890 } // CparameterDlg::FillDataSourceList()
1893 BEGIN_EVENT_TABLE(CqueryDlg
, wxDialog
)
1894 EVT_BUTTON(-1, CqueryDlg::OnButton
)
1895 EVT_CLOSE(CqueryDlg::OnCloseWindow
)
1899 // CqueryDlg() constructor
1900 CqueryDlg::CqueryDlg(wxWindow
*parent
, wxDb
*pDb
, wxChar
*tblName
[],
1901 const wxString
&pWhereArg
) :
1902 wxDialog (parent
, QUERY_DIALOG
, wxT("Query"), wxPoint(-1, -1), wxSize(480, 360))
1904 wxBeginBusyCursor();
1908 masterTableName
= tblName
[0];
1909 widgetPtrsSet
= FALSE
;
1912 // Initialize the WHERE clause from the string passed in
1913 pWhere
= pWhereArg
; // Save a pointer to the output buffer
1914 if (pWhere
.Length() > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN
) // Check the length of the buffer passed in
1917 s
.Printf(wxT("Maximum where clause length exceeded.\nLength must be less than %d"), DB_MAX_WHERE_CLAUSE_LEN
+1);
1918 wxMessageBox(s
,wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
1923 pQueryCol1Msg
= new wxStaticText(this, QUERY_DIALOG_COL_MSG
, wxT("Column 1:"), wxPoint( 10, 10), wxSize( 69, 16), 0, wxT("QueryCol1Msg"));
1924 pQueryCol1Choice
= new wxChoice(this, QUERY_DIALOG_COL_CHOICE
, wxPoint( 10, 27), wxSize(250, 27), 0, 0, 0, wxDefaultValidator
, wxT("QueryCol1Choice"));
1925 pQueryNotMsg
= new wxStaticText(this, QUERY_DIALOG_NOT_MSG
, wxT("NOT"), wxPoint(268, 10), wxSize( -1, -1), 0, wxT("QueryNotMsg"));
1926 pQueryNotCheck
= new wxCheckBox(this, QUERY_DIALOG_NOT_CHECKBOX
, wxT(""), wxPoint(275, 37), wxSize( 20, 20), 0, wxDefaultValidator
, wxT("QueryNotCheck"));
1928 wxString choice_strings
[9];
1929 choice_strings
[0] = wxT("=");
1930 choice_strings
[1] = wxT("<");
1931 choice_strings
[2] = wxT(">");
1932 choice_strings
[3] = wxT("<=");
1933 choice_strings
[4] = wxT(">=");
1934 choice_strings
[5] = wxT("Begins");
1935 choice_strings
[6] = wxT("Contains");
1936 choice_strings
[7] = wxT("Like");
1937 choice_strings
[8] = wxT("Between");
1939 pQueryOperatorMsg
= new wxStaticText(this, QUERY_DIALOG_OP_MSG
, wxT("Operator:"), wxPoint(305, 10), wxSize( -1, -1), 0, wxT("QueryOperatorMsg"));
1940 pQueryOperatorChoice
= new wxChoice(this, QUERY_DIALOG_OP_CHOICE
, wxPoint(305, 27), wxSize( 80, 27), 9, choice_strings
, 0, wxDefaultValidator
, wxT("QueryOperatorChoice"));
1941 pQueryCol2Msg
= new wxStaticText(this, QUERY_DIALOG_COL2_MSG
, wxT("Column 2:"), wxPoint( 10, 65), wxSize( 69, 16), 0, wxT("QueryCol2Msg"));
1942 pQueryCol2Choice
= new wxChoice(this, QUERY_DIALOG_COL2_CHOICE
, wxPoint( 10, 82), wxSize(250, 27), 0, 0, 0, wxDefaultValidator
, wxT("QueryCol2Choice"));
1943 pQuerySqlWhereMsg
= new wxStaticText(this, QUERY_DIALOG_WHERE_MSG
, wxT("SQL where clause:"), wxPoint( 10, 141), wxSize( -1, -1), 0, wxT("QuerySqlWhereMsg"));
1944 pQuerySqlWhereMtxt
= new wxTextCtrl(this, QUERY_DIALOG_WHERE_TEXT
, wxT(""), wxPoint( 10, 159), wxSize(377, 134), wxTE_MULTILINE
, wxDefaultValidator
, wxT("QuerySqlWhereMtxt"));
1945 pQueryAddBtn
= new wxButton(this, QUERY_DIALOG_ADD
, wxT("&Add"), wxPoint(406, 24), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryAddBtn"));
1946 pQueryAndBtn
= new wxButton(this, QUERY_DIALOG_AND
, wxT("A&nd"), wxPoint(406, 58), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryAndBtn"));
1947 pQueryOrBtn
= new wxButton(this, QUERY_DIALOG_OR
, wxT("&Or"), wxPoint(406, 92), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryOrBtn"));
1948 pQueryLParenBtn
= new wxButton(this, QUERY_DIALOG_LPAREN
, wxT("("), wxPoint(406, 126), wxSize( 26, 26), 0, wxDefaultValidator
, wxT("QueryLParenBtn"));
1949 pQueryRParenBtn
= new wxButton(this, QUERY_DIALOG_RPAREN
, wxT(")"), wxPoint(436, 126), wxSize( 26, 26), 0, wxDefaultValidator
, wxT("QueryRParenBtn"));
1950 pQueryDoneBtn
= new wxButton(this, QUERY_DIALOG_DONE
, wxT("&Done"), wxPoint(406, 185), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryDoneBtn"));
1951 pQueryClearBtn
= new wxButton(this, QUERY_DIALOG_CLEAR
, wxT("C&lear"), wxPoint(406, 218), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryClearBtn"));
1952 pQueryCountBtn
= new wxButton(this, QUERY_DIALOG_COUNT
, wxT("&Count"), wxPoint(406, 252), wxSize( 56, 26), 0, wxDefaultValidator
, wxT("QueryCountBtn"));
1953 pQueryValue1Msg
= new wxStaticText(this, QUERY_DIALOG_VALUE1_MSG
, wxT("Value:"), wxPoint(277, 66), wxSize( -1, -1), 0, wxT("QueryValue1Msg"));
1954 pQueryValue1Txt
= new wxTextCtrl(this, QUERY_DIALOG_VALUE1_TEXT
, wxT(""), wxPoint(277, 83), wxSize(108, 25), 0, wxDefaultValidator
, wxT("QueryValue1Txt"));
1955 pQueryValue2Msg
= new wxStaticText(this, QUERY_DIALOG_VALUE2_MSG
, wxT("AND"), wxPoint(238, 126), wxSize( -1, -1), 0, wxT("QueryValue2Msg"));
1956 pQueryValue2Txt
= new wxTextCtrl(this, QUERY_DIALOG_VALUE2_TEXT
, wxT(""), wxPoint(277, 120), wxSize(108, 25), 0, wxDefaultValidator
, wxT("QueryValue2Txt"));
1957 pQueryHintGrp
= new wxStaticBox(this, QUERY_DIALOG_HINT_GROUP
, wxT(""), wxPoint( 10, 291), wxSize(377, 40), 0, wxT("QueryHintGrp"));
1958 pQueryHintMsg
= new wxStaticText(this, QUERY_DIALOG_HINT_MSG
, wxT(""), wxPoint( 16, 306), wxSize( -1, -1), 0, wxT("QueryHintMsg"));
1960 widgetPtrsSet
= TRUE
;
1961 // Initialize the dialog
1963 pQueryCol2Choice
->Append(wxT("VALUE -->"));
1964 colInf
= pDB
->GetColumns(tblName
);
1970 tStr
= wxT("ODBC error during GetColumns()\n\n");
1971 tStr
+= GetExtendedDBErrorMsg(pDb
,__FILE__
,__LINE__
);
1972 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
1977 for (i
= 0; colInf
[i
].colName
&& wxStrlen(colInf
[i
].colName
); i
++)
1979 // If there is more than one table being queried, qualify
1980 // the column names with the table name prefix.
1981 if (tblName
[1] && wxStrlen(tblName
[1]))
1983 qualName
.Printf(wxT("%s.%s"), colInf
[i
].tableName
, colInf
[i
].colName
);
1984 pQueryCol1Choice
->Append(qualName
);
1985 pQueryCol2Choice
->Append(qualName
);
1987 else // Single table query, append just the column names
1989 pQueryCol1Choice
->Append(colInf
[i
].colName
);
1990 pQueryCol2Choice
->Append(colInf
[i
].colName
);
1994 pQueryCol1Choice
->SetSelection(0);
1995 pQueryCol2Choice
->SetSelection(0);
1996 pQueryOperatorChoice
->SetSelection(0);
1998 pQueryValue2Msg
->Show(FALSE
);
1999 pQueryValue2Txt
->Show(FALSE
);
2001 pQueryHintMsg
->SetLabel(langQRY_EQ
);
2003 pQuerySqlWhereMtxt
->SetValue(pWhere
.c_str());
2007 // Display the dialog window
2010 } // CqueryDlg() constructor
2013 CqueryDlg::~CqueryDlg()
2015 } // CqueryDlg::~CqueryDlg() destructor
2018 void CqueryDlg::OnButton(wxCommandEvent
&event
)
2020 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
2021 OnCommand( *win
, event
);
2022 } // CqueryDlg::OnButton()
2025 void CqueryDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
2027 // Widget pointers won't be set when the dialog is constructed.
2028 // Control is passed through this function once for each widget on
2029 // a dialog as the dialog is constructed.
2033 wxString widgetName
= win
.GetName();
2035 // Operator choice box
2036 if (widgetName
== pQueryOperatorChoice
->GetName())
2038 // Set the help text
2039 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
2042 pQueryHintMsg
->SetLabel(langQRY_EQ
);
2045 pQueryHintMsg
->SetLabel(langQRY_LT
);
2048 pQueryHintMsg
->SetLabel(langQRY_GT
);
2051 pQueryHintMsg
->SetLabel(langQRY_LE
);
2054 pQueryHintMsg
->SetLabel(langQRY_GE
);
2057 pQueryHintMsg
->SetLabel(langQRY_BEGINS
);
2060 pQueryHintMsg
->SetLabel(langQRY_CONTAINS
);
2063 pQueryHintMsg
->SetLabel(langQRY_LIKE
);
2066 pQueryHintMsg
->SetLabel(langQRY_BETWEEN
);
2070 // Hide the value2 widget
2071 pQueryValue2Msg
->Show(FALSE
); // BETWEEN will show this widget
2072 pQueryValue2Txt
->Show(FALSE
); // BETWEEN will show this widget
2074 // Disable the NOT operator for <, <=, >, >=
2075 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
2081 pQueryNotCheck
->SetValue(0);
2082 pQueryNotCheck
->Enable(FALSE
);
2085 pQueryNotCheck
->Enable(TRUE
);
2089 // Manipulate the dialog to handle the selected operator
2090 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
2097 pQueryCol2Choice
->Enable(TRUE
);
2098 if (pQueryCol2Choice
->GetSelection()) // Column name is highlighted
2100 pQueryValue1Msg
->Show(FALSE
);
2101 pQueryValue1Txt
->Show(FALSE
);
2103 else // "Value" is highlighted
2105 pQueryValue1Msg
->Show(TRUE
);
2106 pQueryValue1Txt
->Show(TRUE
);
2107 pQueryValue1Txt
->SetFocus();
2113 pQueryCol2Choice
->SetSelection(0);
2114 pQueryCol2Choice
->Enable(FALSE
);
2115 pQueryValue1Msg
->Show(TRUE
);
2116 pQueryValue1Txt
->Show(TRUE
);
2117 pQueryValue1Txt
->SetFocus();
2120 pQueryCol2Choice
->SetSelection(0);
2121 pQueryCol2Choice
->Enable(FALSE
);
2122 pQueryValue2Msg
->Show(TRUE
);
2123 pQueryValue2Txt
->Show(TRUE
);
2124 pQueryValue1Msg
->Show(TRUE
);
2125 pQueryValue1Txt
->Show(TRUE
);
2126 pQueryValue1Txt
->SetFocus();
2132 } // Operator choice box
2135 if (widgetName
== pQueryCol2Choice
->GetName())
2137 if (pQueryCol2Choice
->GetSelection()) // Column name is highlighted
2139 pQueryValue1Msg
->Show(FALSE
);
2140 pQueryValue1Txt
->Show(FALSE
);
2142 else // "Value" is highlighted
2144 pQueryValue1Msg
->Show(TRUE
);
2145 pQueryValue1Txt
->Show(TRUE
);
2146 pQueryValue1Txt
->SetFocus();
2149 } // Column 2 choice
2152 if (widgetName
== pQueryAddBtn
->GetName())
2159 if (widgetName
== pQueryAndBtn
->GetName())
2161 AppendToWhere(wxT(" AND\n"));
2166 if (widgetName
== pQueryOrBtn
->GetName())
2168 AppendToWhere(wxT(" OR\n"));
2172 // Left Paren button
2173 if (widgetName
== pQueryLParenBtn
->GetName())
2175 AppendToWhere(wxT("("));
2177 } // Left Paren button
2179 // Right paren button
2180 if (widgetName
== pQueryRParenBtn
->GetName())
2182 AppendToWhere(wxT(")"));
2184 } // Right Paren button
2187 if (widgetName
== pQueryDoneBtn
->GetName())
2189 // Be sure the where clause will not overflow the output buffer
2190 if (wxStrlen(pQuerySqlWhereMtxt
->GetValue()) > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN
)
2193 s
.Printf(wxT("Maximum where clause length exceeded.\nLength must be less than %d"), DB_MAX_WHERE_CLAUSE_LEN
+1);
2194 wxMessageBox(s
,wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
2197 // Validate the where clause for things such as matching parens
2198 if (!ValidateWhereClause())
2200 // Copy the where clause to the output buffer and exit
2201 pWhere
= pQuerySqlWhereMtxt
->GetValue();
2207 if (widgetName
== pQueryClearBtn
->GetName())
2209 bool Ok
= (wxMessageBox(wxT("Are you sure you wish to clear the Query?"),wxT("Confirm"),wxYES_NO
|wxICON_QUESTION
) == wxYES
);
2212 pQuerySqlWhereMtxt
->SetValue(wxT(""));
2217 if (widgetName
== pQueryCountBtn
->GetName())
2219 wxBeginBusyCursor();
2225 } // CqueryDlg::OnCommand
2228 void CqueryDlg::OnCloseWindow(wxCloseEvent
& event
)
2243 GetParent()->SetFocus();
2248 SetReturnCode(1); // added so BoundsChecker would not report use of uninitialized variable
2251 } // CqueryDlg::OnCloseWindow()
2254 void CqueryDlg::AppendToWhere(wxChar
*s
)
2256 wxString whereStr
= pQuerySqlWhereMtxt
->GetValue();
2258 pQuerySqlWhereMtxt
->SetValue(whereStr
);
2259 } // CqueryDlg::AppendToWhere()
2262 void CqueryDlg::ProcessAddBtn()
2264 qryOp oper
= (qryOp
) pQueryOperatorChoice
->GetSelection();
2266 // Verify that eveything is filled in correctly
2267 if (pQueryCol2Choice
->GetSelection() == 0) // "Value" is selected
2269 // Verify that value 1 is filled in
2270 if (wxStrlen(pQueryValue1Txt
->GetValue()) == 0)
2273 pQueryValue1Txt
->SetFocus();
2276 // For the BETWEEN operator, value 2 must be filled in as well
2277 if (oper
== qryOpBETWEEN
&&
2278 wxStrlen(pQueryValue2Txt
->GetValue()) == 0)
2281 pQueryValue2Txt
->SetFocus();
2286 // Build the expression and append it to the where clause window
2287 wxString s
= pQueryCol1Choice
->GetStringSelection();
2289 if (pQueryNotCheck
->GetValue() && (oper
!= qryOpEQ
))
2295 if (pQueryNotCheck
->GetValue()) // NOT box is checked
2318 s
+= wxT(" BETWEEN");
2324 int col1Idx
= pQueryCol1Choice
->GetSelection();
2327 if (colInf
[col1Idx
].sqlDataType
== SQL_VARCHAR
||
2328 oper
== qryOpBEGINS
||
2329 oper
== qryOpCONTAINS
||
2333 if (pQueryCol2Choice
->GetSelection()) // Column name
2334 s
+= pQueryCol2Choice
->GetStringSelection();
2335 else // Column 2 is a "value"
2339 if (oper
== qryOpCONTAINS
)
2341 s
+= pQueryValue1Txt
->GetValue();
2342 if (oper
== qryOpCONTAINS
|| oper
== qryOpBEGINS
)
2348 if (oper
== qryOpBETWEEN
)
2353 s
+= pQueryValue2Txt
->GetValue();
2358 AppendToWhere((wxChar
*) (const wxChar
*) s
);
2360 } // CqueryDlg::ProcessAddBtn()
2363 void CqueryDlg::ProcessCountBtn()
2365 if (!ValidateWhereClause())
2368 if (!dbTable
) // wxDbTable object needs to be created and opened
2370 dbTable
= new wxDbTable(pDB
, masterTableName
, 0, wxT(""),
2372 wxGetApp().DbConnectInf
->GetDefaultDir());
2375 wxMessageBox(wxT("Memory allocation failed creating a wxDbTable object."),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
2378 if (!dbTable
->Open())
2381 tStr
= wxT("ODBC error during Open()\n\n");
2382 tStr
+= GetExtendedDBErrorMsg(dbTable
->GetDb(),__FILE__
,__LINE__
);
2383 wxMessageBox(tStr
,wxT("ODBC Error..."),wxOK
| wxICON_EXCLAMATION
);
2388 // Count() with WHERE clause
2391 whereStr
= pQuerySqlWhereMtxt
->GetValue();
2392 dbTable
->SetWhereClause(whereStr
.c_str());
2394 ULONG whereCnt
= dbTable
->Count();
2396 // Count() of all records in the table
2397 dbTable
->SetWhereClause(wxT(""));
2398 ULONG totalCnt
= dbTable
->Count();
2400 if (whereCnt
> 0 || totalCnt
== 0)
2403 tStr
.Printf(wxT("%lu of %lu records match the query criteria."),whereCnt
,totalCnt
);
2404 wxMessageBox(tStr
,wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
2409 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
);
2410 wxMessageBox(tStr
,wxT("Notice..."),wxOK
| wxICON_INFORMATION
);
2413 // After a wxMessageBox, the focus does not necessarily return to the
2414 // window which was the focus when the message box popped up, so return
2415 // focus to the Query dialog for certain
2418 } // CqueryDlg::ProcessCountBtn()
2421 bool CqueryDlg::ValidateWhereClause()
2423 wxString where
= pQuerySqlWhereMtxt
->GetValue();
2425 if (where
.Freq(wxT('(')) != where
.Freq(wxT(')')))
2427 wxMessageBox(wxT("There are mismatched parenthesis in the constructed where clause"),wxT("Error..."),wxOK
| wxICON_EXCLAMATION
);
2430 // After a wxMessageBox, the focus does not necessarily return to the
2431 // window which was the focus when the message box popped up, so return
2432 // focus to the Query dialog for certain
2437 } // CqueryDlg::ValidateWhereClause()
2443 TEST CODE FOR TESTING THE wxDbCreateDataSource() FUNCTION
2446 result = wxDbCreateDataSource(wxT("Microsoft Access Driver (*.mdb)"),wxT("GLT-TEST2"),wxT("GLT-Descrip"),FALSE,wxT(""),this);
2449 // check for errors caused by ConfigDSN based functions
2452 wxChar errMsg[500+1];
2453 errMsg[0] = wxT('\0');
2455 SQLInstallerError(1,&retcode,errMsg,500,&cb);
2457 wxMessageBox(wxT("FAILED creating data source"),wxT("FAILED"));
2460 wxMessageBox(wxT("SUCCEEDED creating data source"),wxT("SUCCESS"));