From 1fc5dd6f8eb590992150b3998266fb50dfaab227 Mon Sep 17 00:00:00 2001 From: Julian Smart Date: Wed, 30 Dec 1998 17:40:53 +0000 Subject: [PATCH] Updated the Remstar ODBC files, got the db sample compiling; added Freq and SubString to wxString git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1283 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/word/odbc.doc | Bin 238080 -> 198656 bytes include/wx/db.h | 85 ++++--- include/wx/dbtable.h | 108 ++++----- include/wx/string.h | 7 + samples/db/dbtest.cpp | 485 +++++++++++++++++++--------------------- samples/db/dbtest.h | 142 +++++++++--- samples/db/listdb.cpp | 64 ++---- samples/db/listdb.h | 10 +- samples/db/makefile.nt | 68 ++---- samples/db/makefile.unx | 70 +----- src/common/db.cpp | 199 +++++++++++++++-- src/common/dbtable.cpp | 134 ++++++++--- src/common/string.cpp | 13 ++ 13 files changed, 802 insertions(+), 583 deletions(-) diff --git a/docs/word/odbc.doc b/docs/word/odbc.doc index 7f60405dd2fa03ce26d8a5f726a55f97e51e5bb0..8f6929136d94f9607632e11a91cfb823202c39d2 100644 GIT binary patch literal 198656 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�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 literal 238080 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 diff --git a/include/wx/db.h b/include/wx/db.h index 9f47abf00b..25edff65da 100644 --- a/include/wx/db.h +++ b/include/wx/db.h @@ -5,6 +5,8 @@ // source such as opening and closing the data source. // Author: Doug Card // Modified by: +// Mods: Dec, 1998: Added support for SQL statement logging and database +// cataloging // Created: 9.96 // RCS-ID: $Id$ // Copyright: (c) 1996 Remstar International, Inc. @@ -18,6 +20,7 @@ // 3) These classes may not be distributed as part of any other class library, // DLL, text (written or electronic), other than a complete distribution of // the wxWindows GUI development toolkit. +// /////////////////////////////////////////////////////////////////////////////// /* @@ -27,12 +30,12 @@ #ifndef DB_DOT_H #define DB_DOT_H - + #ifdef __GNUG__ #pragma interface "db.h" #endif -#if defined(wx_msw) || defined(WIN32) +#if defined(__WXMSW__) || defined(WIN32) #include #endif @@ -45,20 +48,6 @@ enum enumDummy {enumDum1}; #define SQL_C_BOOLEAN (sizeof(int) == 2 ? SQL_C_USHORT : SQL_C_ULONG) #define SQL_C_ENUM (sizeof(enumDummy) == 2 ? SQL_C_USHORT : SQL_C_ULONG) //glt 2-21-97 -/* -#ifndef Bool -#define Bool int -#endif - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif -*/ - // Database Globals const DB_TYPE_NAME_LEN = 40; const DB_MAX_STATEMENT_LEN = 2048; @@ -224,15 +213,23 @@ public: int sqlDataType; }; +enum sqlLog +{ + sqlLogOFF, + sqlLogON +}; + class wxDB { private: // Private data - bool dbIsOpen; - char *dsn; // Data source name - char *uid; // User ID - char *authStr; // Authorization string (password) + bool dbIsOpen; + char *dsn; // Data source name + char *uid; // User ID + char *authStr; // Authorization string (password) + FILE *fpSqlLog; // Sql Log file pointer + enum sqlLog sqlLogState; // On or Off // Private member functions bool getDbInfo(void); @@ -303,28 +300,31 @@ public: // Public member functions wxDB(HENV &aHenv); - bool Open(char *Dsn, char *Uid, char *AuthStr); // Data Source Name, User ID, Password - void Close(void); - bool CommitTrans(void); - bool RollbackTrans(void); - bool DispAllErrors(HENV aHenv, HDBC aHdbc = SQL_NULL_HDBC, HSTMT aHstmt = SQL_NULL_HSTMT); - bool GetNextError(HENV aHenv, HDBC aHdbc = SQL_NULL_HDBC, HSTMT aHstmt = SQL_NULL_HSTMT); - void DispNextError(void); - bool CreateView(char *viewName, char *colList, char *pSqlStmt); - bool ExecSql(char *pSqlStmt); - bool Grant(int privileges, char *tableName, char *userList = "PUBLIC"); - int TranslateSqlState(char *SQLState); - CcolInf *GetColumns(char *tableName[]); - char *GetDatabaseName(void) {return dbInf.dbmsName;} - char *GetDataSource(void) {return dsn;} - char *GetUsername(void) {return uid;} - char *GetPassword(void) {return authStr;} - bool IsOpen(void) {return dbIsOpen;} - HENV GetHENV(void) {return henv;} - HDBC GetHDBC(void) {return hdbc;} - HSTMT GetHSTMT(void) {return hstmt;} - bool TableExists(char *tableName); // Table name can refer to a table, view, alias or synonym - void LogError(char *errMsg, char *SQLState = 0) {logError(errMsg, SQLState);} + bool Open(char *Dsn, char *Uid, char *AuthStr); // Data Source Name, User ID, Password + void Close(void); + bool CommitTrans(void); + bool RollbackTrans(void); + bool DispAllErrors(HENV aHenv, HDBC aHdbc = SQL_NULL_HDBC, HSTMT aHstmt = SQL_NULL_HSTMT); + bool GetNextError(HENV aHenv, HDBC aHdbc = SQL_NULL_HDBC, HSTMT aHstmt = SQL_NULL_HSTMT); + void DispNextError(void); + bool CreateView(char *viewName, char *colList, char *pSqlStmt); + bool ExecSql(char *pSqlStmt); + bool Grant(int privileges, char *tableName, char *userList = "PUBLIC"); + int TranslateSqlState(char *SQLState); + bool Catalog(char *userID, char *fileName = "Catalog.txt"); + CcolInf *GetColumns(char *tableName[]); + char *GetDatabaseName(void) {return dbInf.dbmsName;} + char *GetDataSource(void) {return dsn;} + char *GetUsername(void) {return uid;} + char *GetPassword(void) {return authStr;} + bool IsOpen(void) {return dbIsOpen;} + HENV GetHENV(void) {return henv;} + HDBC GetHDBC(void) {return hdbc;} + HSTMT GetHSTMT(void) {return hstmt;} + bool TableExists(char *tableName); // Table name can refer to a table, view, alias or synonym + void LogError(char *errMsg, char *SQLState = 0) {logError(errMsg, SQLState);} + bool SqlLog(enum sqlLog state, char *filename = "sqllog.txt", bool append = FALSE); + bool WriteSqlLog(char *logMsg); }; // wxDB @@ -359,4 +359,3 @@ bool GetDataSource(HENV henv, char *Dsn, SWORD DsnMax, char *DsDesc, SWORD DsDes UWORD direction = SQL_FETCH_NEXT); #endif - diff --git a/include/wx/dbtable.h b/include/wx/dbtable.h index 23e6d10f8a..0fa4fef0b9 100644 --- a/include/wx/dbtable.h +++ b/include/wx/dbtable.h @@ -46,24 +46,24 @@ const ROWID_LEN = 24; // 18 is the max, 24 is in case it gets larger class CcolDef { public: - char ColName[DB_MAX_COLUMN_NAME_LEN+1]; // Column Name glt 4/19/97 added one for the null terminator - int DbDataType; // Logical Data Type; e.g. DB_DATA_TYPE_INTEGER - int SqlCtype; // C data type; e.g. SQL_C_LONG - void *PtrDataObj; // Address of the data object - int SzDataObj; // Size, in bytes, of the data object - bool KeyField; // TRUE if this column is part of the PRIMARY KEY to the table; Date fields should NOT be KeyFields. - bool Updateable; // Specifies whether this column is updateable - bool InsertAllowed; // Specifies whether this column should be included in an INSERT statement - bool DerivedCol; // Specifies whether this column is a derived value - SDWORD CbValue; // Internal use only!!! + char ColName[DB_MAX_COLUMN_NAME_LEN+1]; // Column Name glt 4/19/97 added one for the null terminator + int DbDataType; // Logical Data Type; e.g. DB_DATA_TYPE_INTEGER + int SqlCtype; // C data type; e.g. SQL_C_LONG + void *PtrDataObj; // Address of the data object + int SzDataObj; // Size, in bytes, of the data object + bool KeyField; // TRUE if this column is part of the PRIMARY KEY to the table; Date fields should NOT be KeyFields. + bool Updateable; // Specifies whether this column is updateable + bool InsertAllowed; // Specifies whether this column should be included in an INSERT statement + bool DerivedCol; // Specifies whether this column is a derived value + SDWORD CbValue; // Internal use only!!! }; // CcolDef // This structure is used when creating secondary indexes. class CidxDef { public: - char ColName[DB_MAX_COLUMN_NAME_LEN+1]; // Column Name glt 4/19/97 added one for the null terminator - bool Ascending; + char ColName[DB_MAX_COLUMN_NAME_LEN+1]; // Column Name glt 4/19/97 added one for the null terminator + bool Ascending; }; // CidxDef class wxTable @@ -106,9 +106,10 @@ public: // Column Definitions CcolDef *colDefs; // Array of CcolDef structures - // Where and Order By clauses + // Where, Order By and From clauses char *where; // Standard SQL where clause, minus the word WHERE char *orderBy; // Standard SQL order by clause, minus the ORDER BY + char *from; // Allows for joins in a Ctable::Query(). Format: ",tbl,tbl..." // Flags bool selectForUpdate; @@ -116,50 +117,49 @@ public: // Public member functions wxTable(wxDB *pwxDB, const char *tblName, const int nCols, const char *qryTblName = 0); ~wxTable(); - bool Open(void); - bool CreateTable(void); - bool CreateIndex(char * idxName, bool unique, int noIdxCols, CidxDef *pIdxDefs); - bool CloseCursor(HSTMT cursor); - int Insert(void); - bool Update(void); - bool Update(char *pSqlStmt); - bool UpdateWhere(char *pWhereClause); - bool Delete(void); - bool DeleteWhere(char *pWhereClause); - bool DeleteMatching(void); - bool Query(bool forUpdate = FALSE, bool distinct = FALSE); - bool QueryBySqlStmt(char *pSqlStmt); - bool QueryMatching(bool forUpdate = FALSE, bool distinct = FALSE); - bool QueryOnKeyFields(bool forUpdate = FALSE, bool distinct = FALSE); - bool GetNext(void) { return(getRec(SQL_FETCH_NEXT)); } - bool operator++(int) { return(getRec(SQL_FETCH_NEXT)); } + bool Open(void); + bool CreateTable(void); + bool CreateIndex(char * idxName, bool unique, int noIdxCols, CidxDef *pIdxDefs); + bool CloseCursor(HSTMT cursor); + int Insert(void); + bool Update(void); + bool Update(char *pSqlStmt); + bool UpdateWhere(char *pWhereClause); + bool Delete(void); + bool DeleteWhere(char *pWhereClause); + bool DeleteMatching(void); + virtual bool Query(bool forUpdate = FALSE, bool distinct = FALSE); + bool QueryBySqlStmt(char *pSqlStmt); + bool QueryMatching(bool forUpdate = FALSE, bool distinct = FALSE); + bool QueryOnKeyFields(bool forUpdate = FALSE, bool distinct = FALSE); + bool GetNext(void) { return(getRec(SQL_FETCH_NEXT)); } + bool operator++(int) { return(getRec(SQL_FETCH_NEXT)); } #ifndef FWD_ONLY_CURSORS - bool GetPrev(void) { return(getRec(SQL_FETCH_PRIOR)); } - bool operator--(int) { return(getRec(SQL_FETCH_PRIOR)); } - bool GetFirst(void) { return(getRec(SQL_FETCH_FIRST)); } - bool GetLast(void) { return(getRec(SQL_FETCH_LAST)); } + bool GetPrev(void) { return(getRec(SQL_FETCH_PRIOR)); } + bool operator--(int) { return(getRec(SQL_FETCH_PRIOR)); } + bool GetFirst(void) { return(getRec(SQL_FETCH_FIRST)); } + bool GetLast(void) { return(getRec(SQL_FETCH_LAST)); } #endif - bool IsCursorClosedOnCommit(void); - bool IsColNull(int colNo); - UWORD GetRowNum(void); - void GetSelectStmt(char *pSqlStmt, int typeOfSelect, bool distinct); - void GetDeleteStmt(char *pSqlStmt, int typeOfDel, char *pWhereClause = 0); - void GetUpdateStmt(char *pSqlStmt, int typeOfUpd, char *pWhereClause = 0); - void GetWhereClause(char *pWhereClause, int typeOfWhere); - bool CanSelectForUpdate(void); - bool CanUpdByROWID(void); - void ClearMemberVars(void); - bool SetQueryTimeout(UDWORD nSeconds); - void SetColDefs (int index, char *fieldName, int dataType, void *pData, int cType, - int size, bool keyField = FALSE, bool upd = TRUE, - bool insAllow = TRUE, bool derivedCol = FALSE); - bool SetCursor(int cursorNo = DB_CURSOR0); - int GetCursor(void) { return(currCursorNo); } - ULONG Count(void); - int DB_STATUS(void) { return(pDb->DB_STATUS); } - bool Refresh(void); + bool IsCursorClosedOnCommit(void); + bool IsColNull(int colNo); + UWORD GetRowNum(void); + void GetSelectStmt(char *pSqlStmt, int typeOfSelect, bool distinct); + void GetDeleteStmt(char *pSqlStmt, int typeOfDel, char *pWhereClause = 0); + void GetUpdateStmt(char *pSqlStmt, int typeOfUpd, char *pWhereClause = 0); + void GetWhereClause(char *pWhereClause, int typeOfWhere, char *qualTableName = 0); + bool CanSelectForUpdate(void); + bool CanUpdByROWID(void); + void ClearMemberVars(void); + bool SetQueryTimeout(UDWORD nSeconds); + void SetColDefs (int index, char *fieldName, int dataType, void *pData, int cType, + int size, bool keyField = FALSE, bool upd = TRUE, + bool insAllow = TRUE, bool derivedCol = FALSE); + bool SetCursor(int cursorNo = DB_CURSOR0); + int GetCursor(void) { return(currCursorNo); } + ULONG Count(void); + int DB_STATUS(void) { return(pDb->DB_STATUS); } + bool Refresh(void); }; // wxTable #endif - diff --git a/include/wx/string.h b/include/wx/string.h index f9f731380f..9e7a4fe95b 100644 --- a/include/wx/string.h +++ b/include/wx/string.h @@ -433,6 +433,11 @@ public: nCount (or till the end if nCount = default value) */ wxString Mid(size_t nFirst, size_t nCount = STRING_MAXLEN) const; + /// Compatibility with wxWindows 1.xx + wxString SubString(size_t from, size_t to) const + { + return Mid(from, (to - from + 1)); + } /// get first nCount characters wxString Left(size_t nCount) const; /// get all characters before the first occurence of ch @@ -547,6 +552,8 @@ public: { *this = str + *this; return *this; } /// same as Len size_t Length() const { return Len(); } + /// Count the number of characters + int Freq(char ch) const; /// same as MakeLower void LowerCase() { MakeLower(); } /// same as MakeUpper diff --git a/samples/db/dbtest.cpp b/samples/db/dbtest.cpp index 165444a0ad..b6dc66390a 100644 --- a/samples/db/dbtest.cpp +++ b/samples/db/dbtest.cpp @@ -37,17 +37,18 @@ #include #endif //WX_PRECOMP -IMPLEMENT_APP(DatabaseDemoApp) - #include // Included strictly for reading the text file with the database parameters #include // Required in the file which will get the data source connection #include // Has the wxTable object from which all data objects will inherit their data table functionality -extern DbList *PtrBegDbList; // from wx_db.cpp, used in getting back error results from db connections +extern DbList *PtrBegDbList; // from db.cpp, used in getting back error results from db connections #include "dbtest.h" // Header file for this demonstration program #include "listdb.h" // Code to support the "Lookup" button on the editor dialog + +IMPLEMENT_APP(DatabaseDemoApp) + extern char ListDB_Selection[]; // Used to return the first column value for the selected line from the listDB routines extern char ListDB_Selection2[]; // Used to return the second column value for the selected line from the listDB routines @@ -87,7 +88,7 @@ wxDB *READONLY_DB; * last call to the database engine. * * This demo uses the returned string by displaying it in a wxMessageBox. The - * formatting therefore is not the greatest, but this is just a demo, not a + * formatting therefore is not the greatest, but this is just a demo, not a * finished product. :-) gt * * NOTE: The value returned by this function is for temporary use only and @@ -106,7 +107,7 @@ char *GetExtendedDBErrorMsg(char *ErrFile, int ErrLine) msg += "\nFile: "; msg += ErrFile; msg += " Line: "; - tStr.sprintf("%d",ErrLine); + tStr.Printf("%d",ErrLine); msg += tStr.GetData(); msg += "\n"; } @@ -135,24 +136,17 @@ char *GetExtendedDBErrorMsg(char *ErrFile, int ErrLine) } msg += "\n"; - return msg.GetData(); + return (char*) (const char*) msg; } // GetExtendedDBErrorMsg - -// `Main program' equivalent, creating windows and returning main app frame -wxFrame *DatabaseDemoApp::OnInit(void) +bool DatabaseDemoApp::OnInit() { // Create the main frame window - DemoFrame = new DatabaseDemoFrame(NULL, "wxWindows Database Demo", 50, 50, 537, 480); + DemoFrame = new DatabaseDemoFrame(NULL, "wxWindows Database Demo", wxPoint(50, 50), wxSize(537, 480)); // Give it an icon -#ifdef __WXMSW__ - DemoFrame->SetIcon(wxIcon("db_icon")); -#endif -#ifdef __X__ - DemoFrame->SetIcon(wxIcon("db.xbm")); -#endif + DemoFrame->SetIcon(wxICON(db)); // Make a menubar wxMenu *file_menu = new wxMenu; @@ -182,8 +176,8 @@ wxFrame *DatabaseDemoApp::OnInit(void) if ((paramFile = fopen(paramFilename, "r")) == NULL) { wxString tStr; - tStr.sprintf("Unable to open the parameter file '%s' for reading.\n\nYou must specify the data source, user name, and\npassword that will be used and save those settings.",paramFilename); - wxMessageBox(tStr.GetData(),"File I/O Error...",wxOK | wxICON_EXCLAMATION); + tStr.Printf("Unable to open the parameter file '%s' for reading.\n\nYou must specify the data source, user name, and\npassword that will be used and save those settings.",paramFilename); + wxMessageBox(tStr,"File I/O Error...",wxOK | wxICON_EXCLAMATION); DemoFrame->BuildParameterDialog(NULL); if ((paramFile = fopen(paramFilename, "r")) == NULL) return FALSE; @@ -225,63 +219,67 @@ wxFrame *DatabaseDemoApp::OnInit(void) // Show the frame DemoFrame->Show(TRUE); - // Return the main frame window - return DemoFrame; + return TRUE; } // DatabaseDemoApp::OnInit() - +BEGIN_EVENT_TABLE(DatabaseDemoFrame, wxFrame) + EVT_MENU(FILE_CREATE, DatabaseDemoFrame::OnCreate) + EVT_MENU(FILE_EXIT, DatabaseDemoFrame::OnExit) + EVT_MENU(EDIT_PARAMETERS, DatabaseDemoFrame::OnEditParameters) + EVT_MENU(ABOUT_DEMO, DatabaseDemoFrame::OnAbout) + EVT_CLOSE(DatabaseDemoFrame::OnCloseWindow) +END_EVENT_TABLE() // DatabaseDemoFrame constructor -DatabaseDemoFrame::DatabaseDemoFrame(wxFrame *frame, char *title, int x, int y, int w, int h): - wxFrame(frame, title, x, y, w, h) +DatabaseDemoFrame::DatabaseDemoFrame(wxFrame *frame, const wxString& title, + const wxPoint& pos, const wxSize& size): + wxFrame(frame, -1, title, pos, size) { // Put any code in necessary for initializing the main frame here } +void DatabaseDemoFrame::OnCreate(wxCommandEvent& event) +{ + CreateDataTable(); +} -// Intercept menu commands -void DatabaseDemoFrame::OnMenuCommand(int id) +void DatabaseDemoFrame::OnExit(wxCommandEvent& event) { - switch (id) - { - case FILE_CREATE: - CreateDataTable(); - break; - case FILE_EXIT: - Close(); - break; - case EDIT_PARAMETERS: - if ((pEditorDlg->mode != mCreate) && (pEditorDlg->mode != mEdit)) - BuildParameterDialog(this); - else - wxMessageBox("Cannot change database parameters while creating or editing a record","Notice...",wxOK | wxICON_INFORMATION); - break; - case ABOUT_DEMO: - wxMessageBox("wxWindows sample program for database classes\n\nContributed on 27 July 1998","About...",wxOK | wxICON_INFORMATION); - break; - } -} // DatabaseDemoFrame::OnMenuCommand() + this->Destroy(); +} +void DatabaseDemoFrame::OnEditParameters(wxCommandEvent& event) +{ + if ((pEditorDlg->mode != mCreate) && (pEditorDlg->mode != mEdit)) + BuildParameterDialog(this); + else + wxMessageBox("Cannot change database parameters while creating or editing a record","Notice...",wxOK | wxICON_INFORMATION); +} + +void DatabaseDemoFrame::OnAbout(wxCommandEvent& event) +{ + wxMessageBox("wxWindows sample program for database classes\n\nContributed on 27 July 1998","About...",wxOK | wxICON_INFORMATION); +} -Bool DatabaseDemoFrame::OnClose(void) +void DatabaseDemoFrame::OnCloseWindow(wxCloseEvent& event) { // Put any additional checking necessary to make certain it is alright // to close the program here that is not done elsewhere - return TRUE; + this->Destroy(); } // DatabaseDemoFrame::OnClose() void DatabaseDemoFrame::CreateDataTable() { - Bool Ok = (wxMessageBox("Any data currently residing in the table will be erased.\n\nAre you sure?","Confirm",wxYES_NO|wxICON_QUESTION) == wxYES); + bool Ok = (wxMessageBox("Any data currently residing in the table will be erased.\n\nAre you sure?","Confirm",wxYES_NO|wxICON_QUESTION) == wxYES); if (!Ok) return; wxBeginBusyCursor(); - Bool success = TRUE; + bool success = TRUE; Ccontact *Contact = new Ccontact(); if (!Contact) @@ -297,7 +295,7 @@ void DatabaseDemoFrame::CreateDataTable() wxString tStr; tStr = "Error creating CONTACTS table.\nTable was not created.\n\n"; tStr += GetExtendedDBErrorMsg(__FILE__,__LINE__); - wxMessageBox(tStr.GetData(),"ODBC Error...",wxOK | wxICON_EXCLAMATION); + wxMessageBox(tStr,"ODBC Error...",wxOK | wxICON_EXCLAMATION); success = FALSE; } else @@ -308,7 +306,7 @@ void DatabaseDemoFrame::CreateDataTable() wxString tStr; tStr = "Error creating CONTACTS indexes.\nIndexes will be unavailable.\n\n"; tStr += GetExtendedDBErrorMsg(__FILE__,__LINE__); - wxMessageBox(tStr.GetData(),"ODBC Error...",wxOK | wxICON_EXCLAMATION); + wxMessageBox(tStr,"ODBC Error...",wxOK | wxICON_EXCLAMATION); success = FALSE; } } @@ -394,7 +392,7 @@ Ccontact::~Ccontact() wxString tStr; tStr = "Unable to Free the Ccontact data table handle\n\n"; tStr += GetExtendedDBErrorMsg(__FILE__,__LINE__); - wxMessageBox(tStr.GetData(),"ODBC Error...",wxOK | wxICON_EXCLAMATION); + wxMessageBox(tStr,"ODBC Error...",wxOK | wxICON_EXCLAMATION); } } } // Ccontract destructor @@ -416,20 +414,20 @@ void Ccontact::SetupColumns() SetColDefs ( 6,"COUNTRY", DB_DATA_TYPE_VARCHAR, Country, SQL_C_CHAR, sizeof(Country), FALSE,TRUE); SetColDefs ( 7,"JOIN_DATE", DB_DATA_TYPE_DATE, &JoinDate, SQL_C_TIMESTAMP, sizeof(JoinDate), FALSE,TRUE); SetColDefs ( 8,"NATIVE_LANGUAGE", DB_DATA_TYPE_INTEGER, &NativeLanguage, SQL_C_ENUM, sizeof(NativeLanguage), FALSE,TRUE); - SetColDefs ( 9,"IS_DEVELOPER", DB_DATA_TYPE_INTEGER, &IsDeveloper, SQL_C_BOOLEAN, sizeof(Bool), FALSE,TRUE); + SetColDefs ( 9,"IS_DEVELOPER", DB_DATA_TYPE_INTEGER, &IsDeveloper, SQL_C_BOOLEAN, sizeof(bool), FALSE,TRUE); SetColDefs (10,"CONTRIBUTIONS", DB_DATA_TYPE_INTEGER, &Contributions, SQL_C_USHORT, sizeof(Contributions), FALSE,TRUE); SetColDefs (11,"LINES_OF_CODE", DB_DATA_TYPE_INTEGER, &LinesOfCode, SQL_C_ULONG, sizeof(LinesOfCode), FALSE,TRUE); } // Ccontact::SetupColumns -Bool Ccontact::CreateIndexes(void) +bool Ccontact::CreateIndexes(void) { // This index could easily be accomplished with an "orderBy" clause, // but is done to show how to construct a non-primary index. wxString indexName; CidxDef idxDef[2]; - Bool Ok = TRUE; + bool Ok = TRUE; strcpy(idxDef[0].ColName, "IS_DEVELOPER"); idxDef[0].Ascending = TRUE; @@ -439,7 +437,7 @@ Bool Ccontact::CreateIndexes(void) indexName = CONTACT_TABLE_NAME; indexName += "_IDX1"; - Ok = CreateIndex(indexName.GetData(), TRUE, 2, idxDef); + Ok = CreateIndex((char*) (const char*) indexName, TRUE, 2, idxDef); return Ok; } // Ccontact::CreateIndexes() @@ -450,10 +448,10 @@ Bool Ccontact::CreateIndexes(void) * very efficient and tighter coding so that it is available where ever the object * is. Great for use with multiple tables when not using views or outer joins */ -Bool Ccontact::FetchByName(char *name) +bool Ccontact::FetchByName(char *name) { - whereStr.sprintf("NAME = '%s'",name); - where = this->whereStr.GetData(); + whereStr.Printf("NAME = '%s'",name); + where = (char*) (const char*) this->whereStr; orderBy = 0; if (!Query()) @@ -503,11 +501,11 @@ CeditorDlg::CeditorDlg(wxWindow *parent) : wxPanel (parent, 1, 1, 460, 455) while (!Contact->pDb->TableExists((char *)CONTACT_TABLE_NAME)) { wxString tStr; - tStr.sprintf("Unable to open the table '%s'.\n\nTable may need to be created...?\n\n",CONTACT_TABLE_NAME); + tStr.Printf("Unable to open the table '%s'.\n\nTable may need to be created...?\n\n",CONTACT_TABLE_NAME); tStr += GetExtendedDBErrorMsg(__FILE__,__LINE__); - wxMessageBox(tStr.GetData(),"ODBC Error...",wxOK | wxICON_EXCLAMATION); + wxMessageBox(tStr,"ODBC Error...",wxOK | wxICON_EXCLAMATION); - Bool createTable = (wxMessageBox("Do you wish to try to create/clear the CONTACTS table?","Confirm",wxYES_NO|wxICON_QUESTION) == wxYES); + bool createTable = (wxMessageBox("Do you wish to try to create/clear the CONTACTS table?","Confirm",wxYES_NO|wxICON_QUESTION) == wxYES); if (!createTable) { @@ -529,9 +527,9 @@ CeditorDlg::CeditorDlg(wxWindow *parent) : wxPanel (parent, 1, 1, 460, 455) if (Contact->pDb->TableExists((char *)CONTACT_TABLE_NAME)) { wxString tStr; - tStr.sprintf("Unable to open the table '%s'.\n\n",CONTACT_TABLE_NAME); + tStr.Printf("Unable to open the table '%s'.\n\n",CONTACT_TABLE_NAME); tStr += GetExtendedDBErrorMsg(__FILE__,__LINE__); - wxMessageBox(tStr.GetData(),"ODBC Error...",wxOK | wxICON_EXCLAMATION); + wxMessageBox(tStr,"ODBC Error...",wxOK | wxICON_EXCLAMATION); delete Contact; Close(); DemoFrame->Close(); @@ -540,74 +538,66 @@ CeditorDlg::CeditorDlg(wxWindow *parent) : wxPanel (parent, 1, 1, 460, 455) } // Build the dialog - SetLabelPosition(wxHORIZONTAL); - - wxFont *ButtonFont = new wxFont(12,wxSWISS,wxNORMAL,wxBOLD); - wxFont *TextFont = new wxFont(12,wxSWISS,wxNORMAL,wxNORMAL); - SetButtonFont(ButtonFont); - SetLabelFont(TextFont); - SetLabelPosition(wxVERTICAL); + wxStaticBox *FunctionGrp = new wxStaticBox(this, EDITOR_DIALOG_FN_GROUP, "", wxPoint(15, 1), wxSize(497, 69), 0, "FunctionGrp"); + wxStaticBox *SearchGrp = new wxStaticBox(this, EDITOR_DIALOG_SEARCH_GROUP, "", wxPoint(417, 1), wxSize(95, 242), 0, "SearchGrp"); - wxGroupBox *FunctionGrp = new wxGroupBox(this, "", 15, 1, 497, 69, 0, "FunctionGrp"); - wxGroupBox *SearchGrp = new wxGroupBox(this, "", 417, 1, 95, 242, 0, "SearchGrp"); + pCreateBtn = new wxButton(this, EDITOR_DIALOG_CREATE, "&Create", wxPoint(25, 21), wxSize(70, 35), 0, wxDefaultValidator, "CreateBtn"); + pEditBtn = new wxButton(this, EDITOR_DIALOG_EDIT, "&Edit", wxPoint(102, 21), wxSize(70, 35), 0, wxDefaultValidator, "EditBtn"); + pDeleteBtn = new wxButton(this, EDITOR_DIALOG_DELETE, "&Delete", wxPoint(179, 21), wxSize(70, 35), 0, wxDefaultValidator, "DeleteBtn"); + pCopyBtn = new wxButton(this, EDITOR_DIALOG_COPY, "Cop&y", wxPoint(256, 21), wxSize(70, 35), 0, wxDefaultValidator, "CopyBtn"); + pSaveBtn = new wxButton(this, EDITOR_DIALOG_SAVE, "&Save", wxPoint(333, 21), wxSize(70, 35), 0, wxDefaultValidator, "SaveBtn"); + pCancelBtn = new wxButton(this, EDITOR_DIALOG_CANCEL, "C&ancel", wxPoint(430, 21), wxSize(70, 35), 0, wxDefaultValidator, "CancelBtn"); - pCreateBtn = new wxButton(this, NULL, "&Create", 25, 21, 70, 35, 0, "CreateBtn"); - pEditBtn = new wxButton(this, NULL, "&Edit", 102, 21, 70, 35, 0, "EditBtn"); - pDeleteBtn = new wxButton(this, NULL, "&Delete", 179, 21, 70, 35, 0, "DeleteBtn"); - pCopyBtn = new wxButton(this, NULL, "Cop&y", 256, 21, 70, 35, 0, "CopyBtn"); - pSaveBtn = new wxButton(this, NULL, "&Save", 333, 21, 70, 35, 0, "SaveBtn"); - pCancelBtn = new wxButton(this, NULL, "C&ancel", 430, 21, 70, 35, 0, "CancelBtn"); + pPrevBtn = new wxButton(this, EDITOR_DIALOG_PREV, "<< &Prev", wxPoint(430, 81), wxSize(70, 35), 0, wxDefaultValidator, "PrevBtn"); + pNextBtn = new wxButton(this, EDITOR_DIALOG_NEXT, "&Next >>", wxPoint(430, 121), wxSize(70, 35), 0, wxDefaultValidator, "NextBtn"); + pQueryBtn = new wxButton(this, EDITOR_DIALOG_QUERY, "&Query", wxPoint(430, 161), wxSize(70, 35), 0, wxDefaultValidator, "QueryBtn"); + pResetBtn = new wxButton(this, EDITOR_DIALOG_RESET, "&Reset", wxPoint(430, 200), wxSize(70, 35), 0, wxDefaultValidator, "ResetBtn"); - pPrevBtn = new wxButton(this, NULL, "<< &Prev",430, 81, 70, 35, 0, "PrevBtn"); - pNextBtn = new wxButton(this, NULL, "&Next >>",430, 121, 70, 35, 0, "NextBtn"); - pQueryBtn = new wxButton(this, NULL, "&Query", 430, 161, 70, 35, 0, "QueryBtn"); - pResetBtn = new wxButton(this, NULL, "&Reset", 430, 200, 70, 35, 0, "ResetBtn"); + pNameMsg = new wxStaticText(this, EDITOR_DIALOG_NAME_MSG, "Name:", wxPoint(17, 80), wxSize(-1, -1), 0, "NameMsg"); + pNameTxt = new wxTextCtrl(this, EDITOR_DIALOG_NAME_TEXT, "", wxPoint(17, 97), wxSize(308, 25), 0, wxDefaultValidator, "NameTxt"); + pNameListBtn = new wxButton(this, EDITOR_DIALOG_LOOKUP, "&Lookup", wxPoint(333, 99), wxSize(70, 24), 0, wxDefaultValidator, "LookupBtn"); - pNameMsg = new wxMessage(this, "Name:", 17, 80, -1, -1, 0, "NameMsg"); - pNameTxt = new wxText(this, NULL, "", "", 17, 97, 308, 25, 0, "NameTxt"); - pNameListBtn = new wxButton(this, NULL, "&Lookup", 333, 99, 70, 24, 0, "LookupBtn"); + pAddress1Msg = new wxStaticText(this, EDITOR_DIALOG_ADDRESS1_MSG, "Address:", wxPoint(17, 130), wxSize(-1, -1), 0, "Address1Msg"); + pAddress1Txt = new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT, "", wxPoint(17, 147), wxSize(308, 25), 0, wxDefaultValidator, "Address1Txt"); - pAddress1Msg = new wxMessage(this, "Address:", 17, 130, -1, -1, 0, "Address1Msg"); - pAddress1Txt = new wxText(this, NULL, "", "", 17, 147, 308, 25, 0, "Address1Txt"); + pAddress2Msg = new wxStaticText(this, EDITOR_DIALOG_ADDRESS2_MSG, "Address:", wxPoint(17, 180), wxSize(-1, -1), 0, "Address2Msg"); + pAddress2Txt = new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT, "", wxPoint(17, 197), wxSize(308, 25), 0, wxDefaultValidator, "Address2Txt"); - pAddress2Msg = new wxMessage(this, "Address:", 17, 180, -1, -1, 0, "Address2Msg"); - pAddress2Txt = new wxText(this, NULL, "", "", 17, 197, 308, 25, 0, "Address2Txt"); + pCityMsg = new wxStaticText(this, EDITOR_DIALOG_CITY_MSG, "City:", wxPoint(17, 230), wxSize(-1, -1), 0, "CityMsg"); + pCityTxt = new wxTextCtrl(this, EDITOR_DIALOG_CITY_TEXT, "", wxPoint(17, 247), wxSize(225, 25), 0, wxDefaultValidator, "CityTxt"); - pCityMsg = new wxMessage(this, "City:", 17, 230, -1, -1, 0, "CityMsg"); - pCityTxt = new wxText(this, NULL, "", "", 17, 247, 225, 25, 0, "CityTxt"); + pStateMsg = new wxStaticText(this, EDITOR_DIALOG_STATE_MSG, "State:", wxPoint(250, 230), wxSize(-1, -1), 0, "StateMsg"); + pStateTxt = new wxTextCtrl(this, EDITOR_DIALOG_STATE_TEXT, "", wxPoint(250, 247), wxSize(153, 25), 0, wxDefaultValidator, "StateTxt"); - pStateMsg = new wxMessage(this, "State:", 250, 230, -1, -1, 0, "StateMsg"); - pStateTxt = new wxText(this, NULL, "", "", 250, 247, 153, 25, 0, "StateTxt"); + pCountryMsg = new wxStaticText(this, EDITOR_DIALOG_COUNTRY_MSG, "Country:", wxPoint(17, 280), wxSize(-1, -1), 0, "CountryMsg"); + pCountryTxt = new wxTextCtrl(this, EDITOR_DIALOG_COUNTRY_TEXT, "", wxPoint(17, 297), wxSize(225, 25), 0, wxDefaultValidator, "CountryTxt"); - pCountryMsg = new wxMessage(this, "Country:", 17, 280, -1, -1, 0, "CountryMsg"); - pCountryTxt = new wxText(this, NULL, "", "", 17, 297, 225, 25, 0, "CountryTxt"); + pPostalCodeMsg = new wxStaticText(this, EDITOR_DIALOG_POSTAL_MSG, "Postal Code:", wxPoint(250, 280), wxSize(-1, -1), 0, "PostalCodeMsg"); + pPostalCodeTxt = new wxTextCtrl(this, EDITOR_DIALOG_POSTAL_TEXT, "", wxPoint(250, 297), wxSize(153, 25), 0, wxDefaultValidator, "PostalCodeTxt"); - pPostalCodeMsg = new wxMessage(this, "Postal Code:", 250, 280, -1, -1, 0, "PostalCodeMsg"); - pPostalCodeTxt = new wxText(this, NULL, "", "", 250, 297, 153, 25, 0, "PostalCodeTxt"); - - char *choice_strings[5]; + wxString choice_strings[5]; choice_strings[0] = "English"; choice_strings[1] = "French"; choice_strings[2] = "German"; choice_strings[3] = "Spanish"; choice_strings[4] = "Other"; - pNativeLangChoice = new wxChoice(this, NULL, "",17, 346, 277, -1, 5, choice_strings); - pNativeLangMsg = new wxMessage(this, "Native language:", 17, 330, -1, -1, 0, "NativeLangMsg"); + pNativeLangChoice = new wxChoice(this, EDITOR_DIALOG_LANG_CHOICE, wxPoint(17, 346), wxSize(277, -1), 5, choice_strings); + pNativeLangMsg = new wxStaticText(this, EDITOR_DIALOG_LANG_MSG, "Native language:", wxPoint(17, 330), wxSize(-1, -1), 0, "NativeLangMsg"); - char *radio_strings[2]; + wxString radio_strings[2]; radio_strings[0] = "No"; radio_strings[1] = "Yes"; - pDeveloperRadio = new wxRadioBox(this,NULL,"Developer:",303,330,-1,-1,2,radio_strings,2,wxHORIZONTAL|wxFLAT); + pDeveloperRadio = new wxRadioBox(this,EDITOR_DIALOG_DEVELOPER,"Developer:",wxPoint(303,330),wxSize(-1,-1),2,radio_strings,2,wxHORIZONTAL); - pJoinDateMsg = new wxMessage(this, "Date joined:", 17, 380, -1, -1, 0, "JoinDateMsg"); - pJoinDateTxt = new wxText(this, NULL, "", "", 17, 397, 150, 25, 0, "JoinDateTxt"); + pJoinDateMsg = new wxStaticText(this, EDITOR_DIALOG_JOIN_MSG, "Date joined:", wxPoint(17, 380), wxSize(-1, -1), 0, "JoinDateMsg"); + pJoinDateTxt = new wxTextCtrl(this, EDITOR_DIALOG_JOIN_TEXT, "", wxPoint(17, 397), wxSize(150, 25), 0, wxDefaultValidator, "JoinDateTxt"); - pContribMsg = new wxMessage(this, "Contributions:", 175, 380, -1, -1, 0, "ContribMsg"); - pContribTxt = new wxText(this, NULL, "", "", 175, 397, 120, 25, 0, "ContribTxt"); + pContribMsg = new wxStaticText(this, EDITOR_DIALOG_CONTRIB_MSG, "Contributions:", wxPoint(175, 380), wxSize(-1, -1), 0, "ContribMsg"); + pContribTxt = new wxTextCtrl(this, EDITOR_DIALOG_CONTRIB_TEXT, "", wxPoint(175, 397), wxSize(120, 25), 0, wxDefaultValidator, "ContribTxt"); - pLinesMsg = new wxMessage(this, "Lines of code:", 303, 380, -1, -1, 0, "LinesMsg"); - pLinesTxt = new wxText(this, NULL, "", "", 303, 397, 100, 25, 0, "LinesTxt"); + pLinesMsg = new wxStaticText(this, EDITOR_DIALOG_LINES_MSG, "Lines of code:", wxPoint(303, 380), wxSize(-1, -1), 0, "LinesMsg"); + pLinesTxt = new wxTextCtrl(this, EDITOR_DIALOG_LINES_TEXT, "", wxPoint(303, 397), wxSize(100, 25), 0, wxDefaultValidator, "LinesTxt"); // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to // handle all widget processing @@ -626,10 +616,10 @@ CeditorDlg::CeditorDlg(wxWindow *parent) : wxPanel (parent, 1, 1, 460, 455) // // The constructed where clause below has a sub-query within it "SELECT MIN(NAME) FROM %s" // to achieve a single row (in this case the first name in alphabetical order). - Contact->whereStr.sprintf("NAME = (SELECT MIN(NAME) FROM %s)",Contact->tableName); - - // NOTE: GetData() returns a pointer which may not be valid later, so this is short term use only - Contact->where = Contact->whereStr.GetData(); + Contact->whereStr.Printf("NAME = (SELECT MIN(NAME) FROM %s)",Contact->tableName); + + // NOTE: (const char*) returns a pointer which may not be valid later, so this is short term use only + Contact->where = (char*) (const char*) Contact->whereStr; // Perform the Query to get the result set. // NOTE: If there are no rows returned, that is a valid result, so Query() would return TRUE. @@ -639,7 +629,7 @@ CeditorDlg::CeditorDlg(wxWindow *parent) : wxPanel (parent, 1, 1, 460, 455) wxString tStr; tStr = "ODBC error during Query()\n\n"; tStr += GetExtendedDBErrorMsg(__FILE__,__LINE__); - wxMessageBox(tStr.GetData(),"ODBC Error...",wxOK | wxICON_EXCLAMATION); + wxMessageBox(tStr,"ODBC Error...",wxOK | wxICON_EXCLAMATION); GetParent()->Close(); return; } @@ -658,7 +648,7 @@ CeditorDlg::CeditorDlg(wxWindow *parent) : wxPanel (parent, 1, 1, 460, 455) } // CeditorDlg constructor -Bool CeditorDlg::OnClose() +bool CeditorDlg::OnClose() { // Clean up time if ((mode != mCreate) && (mode != mEdit)) @@ -712,7 +702,7 @@ void CeditorDlg::OnCommand(wxWindow& win, wxCommandEvent& event) if (widgetName == pDeleteBtn->GetName()) { - Bool Ok = (wxMessageBox("Are you sure?","Confirm",wxYES_NO|wxICON_QUESTION) == wxYES); + bool Ok = (wxMessageBox("Are you sure?","Confirm",wxYES_NO|wxICON_QUESTION) == wxYES); if (!Ok) return; @@ -757,12 +747,12 @@ void CeditorDlg::OnCommand(wxWindow& win, wxCommandEvent& event) if (widgetName == pCancelBtn->GetName()) { - Bool Ok = (wxMessageBox("Are you sure?","Confirm",wxYES_NO|wxICON_QUESTION) == wxYES); + bool Ok = (wxMessageBox("Are you sure?","Confirm",wxYES_NO|wxICON_QUESTION) == wxYES); if (!Ok) return; - if (!strcmp(saveName.GetData(),"")) + if (!strcmp((const char*) saveName,"")) { Contact->Initialize(); PutData(); @@ -772,7 +762,7 @@ void CeditorDlg::OnCommand(wxWindow& win, wxCommandEvent& event) else { // Requery previous record - if (Contact->FetchByName(saveName.GetData())) + if (Contact->FetchByName((char*) (const char*) saveName)) { PutData(); SetMode(mView); @@ -785,13 +775,13 @@ void CeditorDlg::OnCommand(wxWindow& win, wxCommandEvent& event) Contact->whereStr += Contact->tableName; Contact->whereStr += ")"; - Contact->where = Contact->whereStr.GetData(); + Contact->where = (char*) (const char*) Contact->whereStr; if (!Contact->Query()) { wxString tStr; tStr = "ODBC error during Query()\n\n"; tStr += GetExtendedDBErrorMsg(__FILE__,__LINE__); - wxMessageBox(tStr.GetData(),"ODBC Error...",wxOK | wxICON_EXCLAMATION); + wxMessageBox(tStr,"ODBC Error...",wxOK | wxICON_EXCLAMATION); SetMode(mView); return; } @@ -826,13 +816,13 @@ void CeditorDlg::OnCommand(wxWindow& win, wxCommandEvent& event) { // Display the query dialog box char qryWhere[DB_MAX_WHERE_CLAUSE_LEN+1]; - strcpy(qryWhere, Contact->qryWhereStr.GetData()); + strcpy(qryWhere, (const char*) Contact->qryWhereStr); char *tblName[] = {(char *)CONTACT_TABLE_NAME, 0}; new CqueryDlg(GetParent(), Contact->pDb, tblName, qryWhere); // Query the first record in the new record set and // display it, if the query string has changed. - if (strcmp(qryWhere, Contact->qryWhereStr.GetData())) + if (strcmp(qryWhere, (const char*) Contact->qryWhereStr)) { Contact->orderBy = "NAME"; Contact->whereStr = "NAME = (SELECT MIN(NAME) FROM "; @@ -847,13 +837,13 @@ void CeditorDlg::OnCommand(wxWindow& win, wxCommandEvent& event) // Close the expression with a right paren Contact->whereStr += ")"; // Requery the table - Contact->where = Contact->whereStr.GetData(); + Contact->where = (char*) (const char*) Contact->whereStr; if (!Contact->Query()) { wxString tStr; tStr = "ODBC error during Query()\n\n"; tStr += GetExtendedDBErrorMsg(__FILE__,__LINE__); - wxMessageBox(tStr.GetData(),"ODBC Error...",wxOK | wxICON_EXCLAMATION); + wxMessageBox(tStr,"ODBC Error...",wxOK | wxICON_EXCLAMATION); return; } // Display the first record from the query set @@ -863,7 +853,7 @@ void CeditorDlg::OnCommand(wxWindow& win, wxCommandEvent& event) } // Enable/Disable the reset button - pResetBtn->Enable(!Contact->qryWhereStr.Empty()); + pResetBtn->Enable(!Contact->qryWhereStr.IsEmpty()); return; } // Query button @@ -879,13 +869,13 @@ void CeditorDlg::OnCommand(wxWindow& win, wxCommandEvent& event) Contact->whereStr = "NAME = (SELECT MIN(NAME) FROM "; Contact->whereStr += CONTACT_TABLE_NAME; Contact->whereStr += ")"; - Contact->where = Contact->whereStr.GetData(); + Contact->where = (char*) (const char*) Contact->whereStr; if (!Contact->Query()) { wxString tStr; tStr = "ODBC error during Query()\n\n"; tStr += GetExtendedDBErrorMsg(__FILE__,__LINE__); - wxMessageBox(tStr.GetData(),"ODBC Error...",wxOK | wxICON_EXCLAMATION); + wxMessageBox(tStr,"ODBC Error...",wxOK | wxICON_EXCLAMATION); return; } if (!Contact->GetNext()) @@ -906,14 +896,14 @@ void CeditorDlg::OnCommand(wxWindow& win, wxCommandEvent& event) /* char *dispCol2 */ "JOIN_DATE", /* char *where */ "", /* char *orderBy */ "NAME", - /* Bool distinctValues */ TRUE); + /* bool distinctValues */ TRUE); if (ListDB_Selection && strlen(ListDB_Selection)) { wxString w = "NAME = '"; w += ListDB_Selection; w += "'"; - GetRec(w.GetData()); + GetRec((char*) (const char*) w); } return; @@ -943,7 +933,7 @@ void CeditorDlg::FieldsEditable() void CeditorDlg::SetMode(enum DialogModes m) { - Bool edit = FALSE; + bool edit = FALSE; mode = m; switch (mode) @@ -971,7 +961,7 @@ void CeditorDlg::SetMode(enum DialogModes m) pPrevBtn->Enable( !edit ); pNextBtn->Enable( !edit ); pQueryBtn->Enable( !edit ); - pResetBtn->Enable( !edit && !Contact->qryWhereStr.Empty() ); + pResetBtn->Enable( !edit && !Contact->qryWhereStr.IsEmpty() ); pNameListBtn->Enable( !edit ); } @@ -979,7 +969,7 @@ void CeditorDlg::SetMode(enum DialogModes m) } // CeditorDlg::SetMode() -Bool CeditorDlg::PutData() +bool CeditorDlg::PutData() { wxString tStr; @@ -991,14 +981,14 @@ Bool CeditorDlg::PutData() pCountryTxt->SetValue(Contact->Country); pPostalCodeTxt->SetValue(Contact->PostalCode); - tStr.sprintf("%d/%d/%d",Contact->JoinDate.month,Contact->JoinDate.day,Contact->JoinDate.year); - pJoinDateTxt->SetValue(tStr.GetData()); + tStr.Printf("%d/%d/%d",Contact->JoinDate.month,Contact->JoinDate.day,Contact->JoinDate.year); + pJoinDateTxt->SetValue(tStr); - tStr.sprintf("%d",Contact->Contributions); - pContribTxt->SetValue(tStr.GetData()); + tStr.Printf("%d",Contact->Contributions); + pContribTxt->SetValue(tStr); - tStr.sprintf("%lu",Contact->LinesOfCode); - pLinesTxt->SetValue(tStr.GetData()); + tStr.Printf("%lu",Contact->LinesOfCode); + pLinesTxt->SetValue(tStr); pNativeLangChoice->SetSelection(Contact->NativeLanguage); @@ -1016,19 +1006,19 @@ Bool CeditorDlg::PutData() * invalid data was found (and a message was displayed telling the user what to fix), and * the data was not placed into the appropraite fields of Ccontact */ -Bool CeditorDlg::GetData() +bool CeditorDlg::GetData() { // Validate that the data currently entered into the widgets is valid data wxString tStr; tStr = pNameTxt->GetValue(); - if (!strcmp(tStr.GetData(),"")) + if (!strcmp((const char*) tStr,"")) { wxMessageBox("A name is required for entry into the contact table","Notice...",wxOK | wxICON_INFORMATION); return FALSE; } - Bool invalid = FALSE; + bool invalid = FALSE; int mm,dd,yyyy; int first, second; @@ -1094,7 +1084,7 @@ Bool CeditorDlg::GetData() } tStr = pNameTxt->GetValue(); - strcpy(Contact->Name,tStr.GetData()); + strcpy(Contact->Name,(const char*) tStr); strcpy(Contact->Addr1,pAddress1Txt->GetValue()); strcpy(Contact->Addr2,pAddress2Txt->GetValue()); strcpy(Contact->City,pCityTxt->GetValue()); @@ -1106,7 +1096,7 @@ Bool CeditorDlg::GetData() Contact->LinesOfCode = atol(pLinesTxt->GetValue()); Contact->NativeLanguage = (enum Language) pNativeLangChoice->GetSelection(); - Contact->IsDeveloper = pDeveloperRadio->GetSelection(); + Contact->IsDeveloper = (bool) pDeveloperRadio->GetSelection(); return TRUE; } // CeditorDlg::GetData() @@ -1121,9 +1111,9 @@ Bool CeditorDlg::GetData() * value of FALSE means that Save() failed. If returning FALSE, then this function * has displayed a detailed error message for the user. */ -Bool CeditorDlg::Save() +bool CeditorDlg::Save() { - Bool failed = FALSE; + bool failed = FALSE; // Read the data in the widgets of the dialog to get the user's data if (!GetData()) @@ -1150,7 +1140,7 @@ Bool CeditorDlg::Save() wxString tStr; tStr = "A duplicate key value already exists in the table.\nUnable to save record\n\n"; tStr += GetExtendedDBErrorMsg(__FILE__,__LINE__); - wxMessageBox(tStr.GetData(),"ODBC Error...",wxOK | wxICON_EXCLAMATION); + wxMessageBox(tStr,"ODBC Error...",wxOK | wxICON_EXCLAMATION); } else { @@ -1158,7 +1148,7 @@ Bool CeditorDlg::Save() wxString tStr; tStr = "Database insert failed\n\n"; tStr += GetExtendedDBErrorMsg(__FILE__,__LINE__); - wxMessageBox(tStr.GetData(),"ODBC Error...",wxOK | wxICON_EXCLAMATION); + wxMessageBox(tStr,"ODBC Error...",wxOK | wxICON_EXCLAMATION); } } } @@ -1169,7 +1159,7 @@ Bool CeditorDlg::Save() wxString tStr; tStr = "Database update failed\n\n"; tStr += GetExtendedDBErrorMsg(__FILE__,__LINE__); - wxMessageBox(tStr.GetData(),"ODBC Error...",wxOK | wxICON_EXCLAMATION); + wxMessageBox(tStr,"ODBC Error...",wxOK | wxICON_EXCLAMATION); failed = TRUE; } } @@ -1194,7 +1184,7 @@ Bool CeditorDlg::Save() * a special where clause must be built to find just the single row which, * in sequence, would follow the currently displayed row. */ -Bool CeditorDlg::GetNextRec() +bool CeditorDlg::GetNextRec() { wxString w; @@ -1205,7 +1195,7 @@ Bool CeditorDlg::GetNextRec() w += "'"; // If a query where string is currently set, append that criteria - if (!Contact->qryWhereStr.Empty()) + if (!Contact->qryWhereStr.IsEmpty()) { w += " AND ("; w += Contact->qryWhereStr; @@ -1214,7 +1204,7 @@ Bool CeditorDlg::GetNextRec() w += ")"; - return(GetRec(w.GetData())); + return(GetRec((char*) (const char*) w)); } // CeditorDlg::GetNextRec() @@ -1224,7 +1214,7 @@ Bool CeditorDlg::GetNextRec() * a special where clause must be built to find just the single row which, * in sequence, would precede the currently displayed row. */ -Bool CeditorDlg::GetPrevRec() +bool CeditorDlg::GetPrevRec() { wxString w; @@ -1235,7 +1225,7 @@ Bool CeditorDlg::GetPrevRec() w += "'"; // If a query where string is currently set, append that criteria - if (!Contact->qryWhereStr.Empty()) + if (!Contact->qryWhereStr.IsEmpty()) { w += " AND ("; w += Contact->qryWhereStr; @@ -1244,7 +1234,7 @@ Bool CeditorDlg::GetPrevRec() w += ")"; - return(GetRec(w.GetData())); + return(GetRec((char*) (const char*)w)); } // CeditorDlg::GetPrevRec() @@ -1253,7 +1243,7 @@ Bool CeditorDlg::GetPrevRec() * This function is here to avoid duplicating this same code in both the * GetPrevRec() and GetNextRec() functions */ -Bool CeditorDlg::GetRec(char *whereStr) +bool CeditorDlg::GetRec(char *whereStr) { Contact->where = whereStr; Contact->orderBy = "NAME"; @@ -1263,7 +1253,7 @@ Bool CeditorDlg::GetRec(char *whereStr) wxString tStr; tStr = "ODBC error during Query()\n\n"; tStr += GetExtendedDBErrorMsg(__FILE__,__LINE__); - wxMessageBox(tStr.GetData(),"ODBC Error...",wxOK | wxICON_EXCLAMATION); + wxMessageBox(tStr,"ODBC Error...",wxOK | wxICON_EXCLAMATION); return(FALSE); } @@ -1282,34 +1272,24 @@ Bool CeditorDlg::GetRec(char *whereStr) /* * CparameterDlg constructor */ -CparameterDlg::CparameterDlg(wxWindow *parent) : wxDialogBox (parent, "ODBC parameter settings", 1, -1, -1, 400, 275) +CparameterDlg::CparameterDlg(wxWindow *parent) : wxDialog (parent, PARAMETER_DIALOG, "ODBC parameter settings", wxPoint(-1, -1), wxSize(400, 275)) { // Since the ::OnCommand() function is overridden, this prevents the widget // detection in ::OnCommand() until all widgets have been initialized to prevent // uninitialized pointers from crashing the program widgetPtrsSet = FALSE; - // Build the dialog - SetLabelPosition(wxVERTICAL); - - wxFont *ButtonFont = new wxFont(12,wxSWISS,wxNORMAL,wxBOLD); - wxFont *TextFont = new wxFont(12,wxSWISS,wxNORMAL,wxNORMAL); + pParamODBCSourceMsg = new wxStaticText(this, PARAMETER_DIALOG_SOURCE_MSG, "ODBC data sources:", wxPoint(10, 10), wxSize(-1, -1), 0, "ParamODBCSourceMsg"); + pParamODBCSourceList = new wxListBox(this, PARAMETER_DIALOG_SOURCE_LISTBOX, wxPoint(10, 29), wxSize(285, 150), 0, 0, wxLB_SINGLE|wxLB_ALWAYS_SB, wxDefaultValidator, "ParamODBCSourceList"); - SetButtonFont(ButtonFont); - SetLabelFont(TextFont); - SetLabelPosition(wxVERTICAL); + pParamUserNameMsg = new wxStaticText(this, PARAMETER_DIALOG_NAME_MSG, "Database user name:", wxPoint(10, 193), wxSize(-1, -1), 0, "ParamUserNameMsg"); + pParamUserNameTxt = new wxTextCtrl(this, PARAMETER_DIALOG_NAME_TEXT, "", wxPoint(10, 209), wxSize(140, 25), 0, wxDefaultValidator, "ParamUserNameTxt"); - pParamODBCSourceMsg = new wxMessage(this, "ODBC data sources:", 10, 10, -1, -1, 0, "ParamODBCSourceMsg"); - pParamODBCSourceList = new wxListBox(this, NULL, "", wxSINGLE|wxALWAYS_SB, 10, 29, 285, 150, 0, 0, 0, "ParamODBCSourceList"); + pParamPasswordMsg = new wxStaticText(this, PARAMETER_DIALOG_PASSWORD_MSG, "Password:", wxPoint(156, 193), wxSize(-1, -1), 0, "ParamPasswordMsg"); + pParamPasswordTxt = new wxTextCtrl(this, PARAMETER_DIALOG_PASSWORD_TEXT, "", wxPoint(156, 209), wxSize(140, 25), 0, wxDefaultValidator, "ParamPasswordTxt"); - pParamUserNameMsg = new wxMessage(this, "Database user name:", 10, 193, -1, -1, 0, "ParamUserNameMsg"); - pParamUserNameTxt = new wxText(this, NULL, "", "", 10, 209, 140, 25, 0, "ParamUserNameTxt"); - - pParamPasswordMsg = new wxMessage(this, "Password:", 156, 193, -1, -1, 0, "ParamPasswordMsg"); - pParamPasswordTxt = new wxText(this, NULL, "", "", 156, 209, 140, 25, 0, "ParamPasswordTxt"); - - pParamSaveBtn = new wxButton(this, NULL, "&Save", 310, 21, 70, 35, 0, "ParamSaveBtn"); - pParamCancelBtn = new wxButton(this, NULL, "C&ancel", 310, 66, 70, 35, 0, "ParamCancelBtn"); + pParamSaveBtn = new wxButton(this, PARAMETER_DIALOG_SAVE, "&Save", wxPoint(310, 21), wxSize(70, 35), 0, wxDefaultValidator, "ParamSaveBtn"); + pParamCancelBtn = new wxButton(this, PARAMETER_DIALOG_CANCEL, "C&ancel", wxPoint(310, 66), wxSize(70, 35), 0, wxDefaultValidator, "ParamCancelBtn"); // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to // handle all widget processing @@ -1320,17 +1300,17 @@ CparameterDlg::CparameterDlg(wxWindow *parent) : wxDialogBox (parent, "ODBC para Centre(wxBOTH); PutData(); - Show(TRUE); + ShowModal(); } // CparameterDlg constructor -Bool CparameterDlg::OnClose() +bool CparameterDlg::OnClose() { // Put any additional checking necessary to make certain it is alright // to close the program here that is not done elsewhere if (!saved) { - Bool Ok = (wxMessageBox("No changes have been saved.\n\nAre you sure you wish exit the parameter screen?","Confirm",wxYES_NO|wxICON_QUESTION) == wxYES); + bool Ok = (wxMessageBox("No changes have been saved.\n\nAre you sure you wish exit the parameter screen?","Confirm",wxYES_NO|wxICON_QUESTION) == wxYES); if (!Ok) return FALSE; @@ -1361,7 +1341,7 @@ void CparameterDlg::OnCommand(wxWindow& win, wxCommandEvent& event) tStr = "Database parameters have been saved."; if (GetParent() != NULL) // The parameter dialog was not called during startup due to a missing cfg file tStr += "\nNew parameters will take effect the next time the program is started."; - wxMessageBox(tStr.GetData(),"Notice...",wxOK | wxICON_INFORMATION); + wxMessageBox(tStr,"Notice...",wxOK | wxICON_INFORMATION); saved = TRUE; Close(); } @@ -1376,7 +1356,7 @@ void CparameterDlg::OnCommand(wxWindow& win, wxCommandEvent& event) } // CparameterDlg::OnCommand() -Bool CparameterDlg::PutData() +bool CparameterDlg::PutData() { // Fill the data source list box FillDataSourceList(); @@ -1389,7 +1369,7 @@ Bool CparameterDlg::PutData() } // CparameterDlg::PutData() -Bool CparameterDlg::GetData() +bool CparameterDlg::GetData() { wxString tStr; if (pParamODBCSourceList->GetStringSelection()) @@ -1398,11 +1378,11 @@ Bool CparameterDlg::GetData() if (tStr.Length() > (sizeof(DatabaseDemoApp.params.ODBCSource)-1)) { wxString errmsg; - errmsg.sprintf("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()); - wxMessageBox(errmsg.GetData(),"Internal program error...",wxOK | wxICON_EXCLAMATION); + errmsg.Printf("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()); + wxMessageBox(errmsg,"Internal program error...",wxOK | wxICON_EXCLAMATION); return FALSE; } - strcpy(DatabaseDemoApp.params.ODBCSource, tStr.GetData()); + strcpy(DatabaseDemoApp.params.ODBCSource, tStr); } else return FALSE; @@ -1411,26 +1391,26 @@ Bool CparameterDlg::GetData() if (tStr.Length() > (sizeof(DatabaseDemoApp.params.UserName)-1)) { wxString errmsg; - errmsg.sprintf("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()); - wxMessageBox(errmsg.GetData(),"Internal program error...",wxOK | wxICON_EXCLAMATION); + errmsg.Printf("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()); + wxMessageBox(errmsg,"Internal program error...",wxOK | wxICON_EXCLAMATION); return FALSE; } - strcpy(DatabaseDemoApp.params.UserName, tStr.GetData()); + strcpy(DatabaseDemoApp.params.UserName, tStr); tStr = pParamPasswordTxt->GetValue(); if (tStr.Length() > (sizeof(DatabaseDemoApp.params.Password)-1)) { wxString errmsg; - errmsg.sprintf("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()); - wxMessageBox(errmsg.GetData(),"Internal program error...",wxOK | wxICON_EXCLAMATION); + errmsg.Printf("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()); + wxMessageBox(errmsg,"Internal program error...",wxOK | wxICON_EXCLAMATION); return FALSE; } - strcpy(DatabaseDemoApp.params.Password,tStr.GetData()); + strcpy(DatabaseDemoApp.params.Password,tStr); return TRUE; } // CparameterDlg::GetData() -Bool CparameterDlg::Save() +bool CparameterDlg::Save() { Cparameters saveParams = DatabaseDemoApp.params; if (!GetData()) @@ -1443,8 +1423,8 @@ Bool CparameterDlg::Save() if ((paramFile = fopen(paramFilename, "wt")) == NULL) { wxString tStr; - tStr.sprintf("Unable to write/overwrite '%s'.",paramFilename); - wxMessageBox(tStr.GetData(),"File I/O Error...",wxOK | wxICON_EXCLAMATION); + tStr.Printf("Unable to write/overwrite '%s'.",paramFilename); + wxMessageBox(tStr,"File I/O Error...",wxOK | wxICON_EXCLAMATION); return FALSE; } @@ -1479,7 +1459,7 @@ void CparameterDlg::FillDataSourceList() // CqueryDlg() constructor -CqueryDlg::CqueryDlg(wxWindow *parent, wxDB *pDb, char *tblName[], char *pWhereArg) : wxDialogBox (parent, "Query", 1, -1, -1, 480, 360) +CqueryDlg::CqueryDlg(wxWindow *parent, wxDB *pDb, char *tblName[], char *pWhereArg) : wxDialog (parent, QUERY_DIALOG, "Query", wxPoint(-1, -1), wxSize(480, 360)) { wxBeginBusyCursor(); @@ -1494,29 +1474,19 @@ CqueryDlg::CqueryDlg(wxWindow *parent, wxDB *pDb, char *tblName[], char *pWhereA if (strlen(pWhere) > DB_MAX_WHERE_CLAUSE_LEN) // Check the length of the buffer passed in { wxString s; - s.sprintf("Maximum where clause length exceeded.\nLength must be less than %d", DB_MAX_WHERE_CLAUSE_LEN+1); - wxMessageBox(s.GetData(),"Error...",wxOK | wxICON_EXCLAMATION); + s.Printf("Maximum where clause length exceeded.\nLength must be less than %d", DB_MAX_WHERE_CLAUSE_LEN+1); + wxMessageBox(s,"Error...",wxOK | wxICON_EXCLAMATION); Close(); return; } - // Build the dialog - SetLabelPosition(wxVERTICAL); - - wxFont *ButtonFont = new wxFont(12,wxSWISS,wxNORMAL,wxBOLD); - wxFont *TextFont = new wxFont(12,wxSWISS,wxNORMAL,wxNORMAL); + pQueryCol1Msg = new wxStaticText(this, QUERY_DIALOG_COL_MSG, "Column 1:", wxPoint(10, 10), wxSize(69, 16), 0, "QueryCol1Msg"); + pQueryCol1Choice = new wxChoice(this, QUERY_DIALOG_COL_CHOICE, wxPoint(10, 27), wxSize(250, 27), 0, 0, 0, wxDefaultValidator, "QueryCol1Choice"); - SetButtonFont(ButtonFont); - SetLabelFont(TextFont); - SetLabelPosition(wxVERTICAL); + pQueryNotMsg = new wxStaticText(this, QUERY_DIALOG_NOT_MSG, "NOT", wxPoint(268, 10), wxSize(-1, -1), 0, "QueryNotMsg"); + pQueryNotCheck = new wxCheckBox(this, QUERY_DIALOG_NOT_CHECKBOX, "", wxPoint(275, 37), wxSize(20, 20), 0, wxDefaultValidator, "QueryNotCheck"); - pQueryCol1Msg = new wxMessage(this, "Column 1:", 10, 10, 69, 16, 0, "QueryCol1Msg"); - pQueryCol1Choice = new wxChoice(this, NULL, "", 10, 27, 250, 27, 0, 0, 0, "QueryCol1Choice"); - - pQueryNotMsg = new wxMessage(this, "NOT", 268, 10, -1, -1, 0, "QueryNotMsg"); - pQueryNotCheck = new wxCheckBox(this, NULL, "", 275, 37, 20, 20, 0, "QueryNotCheck"); - - char *choice_strings[9]; + wxString choice_strings[9]; choice_strings[0] = "="; choice_strings[1] = "<"; choice_strings[2] = ">"; @@ -1526,34 +1496,34 @@ CqueryDlg::CqueryDlg(wxWindow *parent, wxDB *pDb, char *tblName[], char *pWhereA choice_strings[6] = "Contains"; choice_strings[7] = "Like"; choice_strings[8] = "Between"; - pQueryOperatorMsg = new wxMessage(this, "Operator:", 305, 10, -1, -1, 0, "QueryOperatorMsg"); - pQueryOperatorChoice = new wxChoice(this, NULL, "", 305, 27, 80, 27, 9, choice_strings, 0, "QueryOperatorChoice"); - - pQueryCol2Msg = new wxMessage(this, "Column 2:", 10, 65, 69, 16, 0, "QueryCol2Msg"); - pQueryCol2Choice = new wxChoice(this, NULL, "", 10, 82, 250, 27, 0, 0, 0, "QueryCol2Choice"); + pQueryOperatorMsg = new wxStaticText(this, QUERY_DIALOG_OP_MSG, "Operator:", wxPoint(305, 10), wxSize(-1, -1), 0, "QueryOperatorMsg"); + pQueryOperatorChoice = new wxChoice(this, QUERY_DIALOG_OP_CHOICE, wxPoint(305, 27), wxSize(80, 27), 9, choice_strings, 0, wxDefaultValidator, "QueryOperatorChoice"); - pQuerySqlWhereMsg = new wxMessage(this, "SQL where clause:", 10, 141, -1, -1, 0, "QuerySqlWhereMsg"); - pQuerySqlWhereMtxt = new wxMultiText(this, NULL, "", "", 10, 159, 377, 134, 0, "QuerySqlWhereMtxt"); + pQueryCol2Msg = new wxStaticText(this, QUERY_DIALOG_COL2_MSG, "Column 2:", wxPoint(10, 65), wxSize(69, 16), 0, "QueryCol2Msg"); + pQueryCol2Choice = new wxChoice(this, QUERY_DIALOG_COL2_CHOICE, wxPoint(10, 82), wxSize(250, 27), 0, 0, 0, wxDefaultValidator, "QueryCol2Choice"); - pQueryAddBtn = new wxButton(this, NULL, "&Add", 406, 24, 56, 26, 0, "QueryAddBtn"); - pQueryAndBtn = new wxButton(this, NULL, "A&nd", 406, 58, 56, 26, 0, "QueryAndBtn"); - pQueryOrBtn = new wxButton(this, NULL, "&Or", 406, 92, 56, 26, 0, "QueryOrBtn"); + pQuerySqlWhereMsg = new wxStaticText(this, QUERY_DIALOG_WHERE_MSG, "SQL where clause:", wxPoint(10, 141), wxSize(-1, -1), 0, "QuerySqlWhereMsg"); + pQuerySqlWhereMtxt = new wxTextCtrl(this, QUERY_DIALOG_WHERE_TEXT, "", wxPoint(10, 159), wxSize(377, 134), wxTE_MULTILINE, wxDefaultValidator, "QuerySqlWhereMtxt"); - pQueryLParenBtn = new wxButton(this, NULL, "(", 406, 126, 26, 26, 0, "QueryLParenBtn"); - pQueryRParenBtn = new wxButton(this, NULL, ")", 436, 126, 26, 26, 0, "QueryRParenBtn"); + pQueryAddBtn = new wxButton(this, QUERY_DIALOG_ADD, "&Add", wxPoint(406, 24), wxSize(56, 26), 0, wxDefaultValidator, "QueryAddBtn"); + pQueryAndBtn = new wxButton(this, QUERY_DIALOG_AND, "A&nd", wxPoint(406, 58), wxSize(56, 26), 0, wxDefaultValidator, "QueryAndBtn"); + pQueryOrBtn = new wxButton(this, QUERY_DIALOG_OR, "&Or", wxPoint(406, 92), wxSize(56, 26), 0, wxDefaultValidator, "QueryOrBtn"); - pQueryDoneBtn = new wxButton(this, NULL, "&Done", 406, 185, 56, 26, 0, "QueryDoneBtn"); - pQueryClearBtn = new wxButton(this, NULL, "C&lear", 406, 218, 56, 26, 0, "QueryClearBtn"); - pQueryCountBtn = new wxButton(this, NULL, "&Count", 406, 252, 56, 26, 0, "QueryCountBtn"); + pQueryLParenBtn = new wxButton(this, QUERY_DIALOG_LPAREN, "(", wxPoint(406, 126), wxSize(26, 26), 0, wxDefaultValidator, "QueryLParenBtn"); + pQueryRParenBtn = new wxButton(this, QUERY_DIALOG_RPAREN, ")", wxPoint(436, 126), wxSize(26, 26), 0, wxDefaultValidator, "QueryRParenBtn"); - pQueryValue1Msg = new wxMessage(this, "Value:", 277, 66, -1, -1, 0, "QueryValue1Msg"); - pQueryValue1Txt = new wxText(this, NULL, "", "", 277, 83, 108, 25, 0, "QueryValue1Txt"); + pQueryDoneBtn = new wxButton(this, QUERY_DIALOG_DONE, "&Done", wxPoint(406, 185), wxSize(56, 26), 0, wxDefaultValidator, "QueryDoneBtn"); + pQueryClearBtn = new wxButton(this, QUERY_DIALOG_CLEAR, "C&lear", wxPoint(406, 218), wxSize(56, 26), 0, wxDefaultValidator, "QueryClearBtn"); + pQueryCountBtn = new wxButton(this, QUERY_DIALOG_COUNT, "&Count", wxPoint(406, 252), wxSize(56, 26), 0, wxDefaultValidator, "QueryCountBtn"); - pQueryValue2Msg = new wxMessage(this, "AND", 238, 126, -1, -1, 0, "QueryValue2Msg"); - pQueryValue2Txt = new wxText(this, NULL, "", "", 277, 120, 108, 25, 0, "QueryValue2Txt"); + pQueryValue1Msg = new wxStaticText(this, QUERY_DIALOG_VALUE1_MSG, "Value:", wxPoint(277, 66), wxSize(-1, -1), 0, "QueryValue1Msg"); + pQueryValue1Txt = new wxTextCtrl(this, QUERY_DIALOG_VALUE1_TEXT, "", wxPoint(277, 83), wxSize(108, 25), 0, wxDefaultValidator, "QueryValue1Txt"); - pQueryHintGrp = new wxGroupBox(this, "", 10, 291, 377, 40, 0, "QueryHintGrp"); - pQueryHintMsg = new wxMessage(this, "", 16, 306, -1, -1, 0, "QueryHintMsg"); + pQueryValue2Msg = new wxStaticText(this, QUERY_DIALOG_VALUE2_MSG, "AND", wxPoint(238, 126), wxSize(-1, -1), 0, "QueryValue2Msg"); + pQueryValue2Txt = new wxTextCtrl(this, QUERY_DIALOG_VALUE2_TEXT, "", wxPoint(277, 120), wxSize(108, 25), 0, wxDefaultValidator, "QueryValue2Txt"); + + pQueryHintGrp = new wxStaticBox(this, QUERY_DIALOG_HINT_GROUP, "", wxPoint(10, 291), wxSize(377, 40), 0, "QueryHintGrp"); + pQueryHintMsg = new wxStaticText(this, QUERY_DIALOG_HINT_MSG, "", wxPoint(16, 306), wxSize(-1, -1), 0, "QueryHintMsg"); widgetPtrsSet = TRUE; // Initialize the dialog @@ -1566,9 +1536,9 @@ CqueryDlg::CqueryDlg(wxWindow *parent, wxDB *pDb, char *tblName[], char *pWhereA // the column names with the table name prefix. if (tblName[1] && strlen(tblName[1])) { - qualName.sprintf("%s.%s", colInf[i].tableName, colInf[i].colName); - pQueryCol1Choice->Append(qualName.GetData()); - pQueryCol2Choice->Append(qualName.GetData()); + qualName.Printf("%s.%s", colInf[i].tableName, colInf[i].colName); + pQueryCol1Choice->Append(qualName); + pQueryCol2Choice->Append(qualName); } else // Single table query, append just the column names { @@ -1591,9 +1561,8 @@ CqueryDlg::CqueryDlg(wxWindow *parent, wxDB *pDb, char *tblName[], char *pWhereA wxEndBusyCursor(); // Display the dialog window - SetModal(TRUE); Centre(wxBOTH); - Show(TRUE); + ShowModal(); } // CqueryDlg() constructor @@ -1772,8 +1741,8 @@ void CqueryDlg::OnCommand(wxWindow& win, wxCommandEvent& event) if (strlen(pQuerySqlWhereMtxt->GetValue()) > DB_MAX_WHERE_CLAUSE_LEN) { wxString s; - s.sprintf("Maximum where clause length exceeded.\nLength must be less than %d", DB_MAX_WHERE_CLAUSE_LEN+1); - wxMessageBox(s.GetData(),"Error...",wxOK | wxICON_EXCLAMATION); + s.Printf("Maximum where clause length exceeded.\nLength must be less than %d", DB_MAX_WHERE_CLAUSE_LEN+1); + wxMessageBox(s,"Error...",wxOK | wxICON_EXCLAMATION); return; } // Validate the where clause for things such as matching parens @@ -1789,7 +1758,7 @@ void CqueryDlg::OnCommand(wxWindow& win, wxCommandEvent& event) // Clear button if (widgetName == pQueryClearBtn->GetName()) { - Bool Ok = (wxMessageBox("Are you sure you wish to clear the Query?","Confirm",wxYES_NO|wxICON_QUESTION) == wxYES); + bool Ok = (wxMessageBox("Are you sure you wish to clear the Query?","Confirm",wxYES_NO|wxICON_QUESTION) == wxYES); if (Ok) pQuerySqlWhereMtxt->SetValue(""); @@ -1810,7 +1779,7 @@ void CqueryDlg::OnCommand(wxWindow& win, wxCommandEvent& event) } // CqueryDlg::OnCommand -Bool CqueryDlg::OnClose() +bool CqueryDlg::OnClose() { // Clean up if (colInf) @@ -1832,16 +1801,16 @@ Bool CqueryDlg::OnClose() } // CqueryDlg::OnClose() /* -Bool CqueryDlg::SetWidgetPtrs() +bool CqueryDlg::SetWidgetPtrs() { - Bool abort = FALSE; + bool abort = FALSE; abort = abort || !(pQueryCol1Choice = (wxChoice *)GetWidgetPtr("QueryCol1Choice",this)); abort = abort || !(pQueryNotCheck = (wxCheckBox *)GetWidgetPtr("QueryNotCheck",this)); abort = abort || !(pQueryOperatorChoice = (wxChoice *)GetWidgetPtr("QueryOperatorChoice",this)); abort = abort || !(pQueryCol2Choice = (wxChoice *)GetWidgetPtr("QueryCol2Choice",this)); - abort = abort || !(pQueryValue1Txt = (wxText *)GetWidgetPtr("QueryValue1Txt",this)); - abort = abort || !(pQueryValue2Txt = (wxText *)GetWidgetPtr("QueryValue2Txt",this)); + abort = abort || !(pQueryValue1Txt = (wxTextCtrl *)GetWidgetPtr("QueryValue1Txt",this)); + abort = abort || !(pQueryValue2Txt = (wxTextCtrl *)GetWidgetPtr("QueryValue2Txt",this)); abort = abort || !(pQuerySqlWhereMtxt = (wxMultiText *)GetWidgetPtr("QuerySqlWhereMtxt",this)); abort = abort || !(pQueryAddBtn = (wxButton *)GetWidgetPtr("QueryAddBtn",this)); abort = abort || !(pQueryAndBtn = (wxButton *)GetWidgetPtr("QueryAndBtn",this)); @@ -1852,7 +1821,7 @@ Bool CqueryDlg::SetWidgetPtrs() abort = abort || !(pQueryClearBtn = (wxButton *)GetWidgetPtr("QueryClearBtn",this)); abort = abort || !(pQueryCountBtn = (wxButton *)GetWidgetPtr("QueryCountBtn",this)); abort = abort || !(pQueryHelpBtn = (wxButton *)GetWidgetPtr("QueryHelpBtn",this)); - abort = abort || !(pQueryHintMsg = (wxMessage *)GetWidgetPtr("QueryHintMsg",this)); + abort = abort || !(pQueryHintMsg = (wxStaticText *)GetWidgetPtr("QueryHintMsg",this)); pFocusTxt = NULL; @@ -1865,7 +1834,7 @@ void CqueryDlg::AppendToWhere(char *s) { wxString whereStr = pQuerySqlWhereMtxt->GetValue(); whereStr += s; - pQuerySqlWhereMtxt->SetValue(whereStr.GetData()); + pQuerySqlWhereMtxt->SetValue(whereStr); } // CqueryDlg::AppendToWhere() @@ -1934,8 +1903,8 @@ void CqueryDlg::ProcessAddBtn() int col1Idx = pQueryCol1Choice->GetSelection(); - Bool quote = FALSE; - if (colInf[col1Idx].sqlDataType == SQL_VARCHAR || + bool quote = FALSE; + if (colInf[col1Idx].sqlDataType == SQL_VARCHAR || oper == qryOpBEGINS || oper == qryOpCONTAINS || oper == qryOpLIKE) @@ -1966,7 +1935,7 @@ void CqueryDlg::ProcessAddBtn() s += "'"; } - AppendToWhere(s.GetData()); + AppendToWhere((char*) (const char*) s); } // CqueryDlg::ProcessAddBtn() @@ -1988,13 +1957,13 @@ void CqueryDlg::ProcessCountBtn() wxString tStr; tStr = "ODBC error during Open()\n\n"; tStr += GetExtendedDBErrorMsg(__FILE__,__LINE__); - wxMessageBox(tStr.GetData(),"ODBC Error...",wxOK | wxICON_EXCLAMATION); + wxMessageBox(tStr,"ODBC Error...",wxOK | wxICON_EXCLAMATION); return; } } // Count() with WHERE clause - dbTable->where = pQuerySqlWhereMtxt->GetValue(); + dbTable->where = (char*) (const char*) pQuerySqlWhereMtxt->GetValue(); ULONG whereCnt = dbTable->Count(); // Count() of all records in the table @@ -2004,14 +1973,14 @@ void CqueryDlg::ProcessCountBtn() if (whereCnt > 0 || totalCnt == 0) { wxString tStr; - tStr.sprintf("%lu of %lu records match the query criteria.",whereCnt,totalCnt); - wxMessageBox(tStr.GetData(),"Notice...",wxOK | wxICON_INFORMATION); + tStr.Printf("%lu of %lu records match the query criteria.",whereCnt,totalCnt); + wxMessageBox(tStr,"Notice...",wxOK | wxICON_INFORMATION); } else { wxString tStr; - tStr.sprintf("%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); - wxMessageBox(tStr.GetData(),"Notice...",wxOK | wxICON_INFORMATION); + tStr.Printf("%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); + wxMessageBox(tStr,"Notice...",wxOK | wxICON_INFORMATION); } // After a wxMessageBox, the focus does not necessarily return to the @@ -2022,7 +1991,7 @@ void CqueryDlg::ProcessCountBtn() } // CqueryDlg::ProcessCountBtn() -Bool CqueryDlg::ValidateWhereClause() +bool CqueryDlg::ValidateWhereClause() { wxString where = pQuerySqlWhereMtxt->GetValue(); diff --git a/samples/db/dbtest.h b/samples/db/dbtest.h index 76ee48eaba..6689d522ea 100644 --- a/samples/db/dbtest.h +++ b/samples/db/dbtest.h @@ -9,7 +9,9 @@ // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ #pragma interface "dbtest.h" +#endif #include #include @@ -104,7 +106,7 @@ class DatabaseDemoApp: public wxApp { public: Cparameters params; - wxFrame *OnInit(void); + bool OnInit(); }; // DatabaseDemoApp DECLARE_APP(DatabaseDemoApp) @@ -117,14 +119,19 @@ class DatabaseDemoFrame: public wxFrame CparameterDlg *pParamDlg; public: - DatabaseDemoFrame(wxFrame *frame, char *title, int x, int y, int w, int h); + DatabaseDemoFrame(wxFrame *frame, const wxString& title, const wxPoint& pos, const wxSize& sz); - void OnMenuCommand(int id); - bool OnClose(void); + void OnCloseWindow(wxCloseEvent& event); + void OnCreate(wxCommandEvent& event); + void OnExit(wxCommandEvent& event); + void OnEditParameters(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); void CreateDataTable(); void BuildEditorDialog(); void BuildParameterDialog(wxWindow *parent); + +DECLARE_EVENT_TABLE() }; // DatabaseDemoFrame @@ -141,13 +148,13 @@ class CeditorDlg : public wxPanel wxButton *pCreateBtn, *pEditBtn, *pDeleteBtn, *pCopyBtn, *pSaveBtn, *pCancelBtn; wxButton *pPrevBtn, *pNextBtn, *pQueryBtn, *pResetBtn, *pDoneBtn, *pHelpBtn; wxButton *pNameListBtn; - wxText *pNameTxt, *pAddress1Txt, *pAddress2Txt,*pCityTxt, *pStateTxt, *pCountryTxt,*pPostalCodeTxt; - wxMessage *pNameMsg, *pAddress1Msg, *pAddress2Msg,*pCityMsg, *pStateMsg, *pCountryMsg,*pPostalCodeMsg; - wxText *pJoinDateTxt,*pContribTxt, *pLinesTxt; - wxMessage *pJoinDateMsg,*pContribMsg, *pLinesMsg; + wxTextCtrl *pNameTxt, *pAddress1Txt, *pAddress2Txt,*pCityTxt, *pStateTxt, *pCountryTxt,*pPostalCodeTxt; + wxStaticText *pNameMsg, *pAddress1Msg, *pAddress2Msg,*pCityMsg, *pStateMsg, *pCountryMsg,*pPostalCodeMsg; + wxTextCtrl *pJoinDateTxt,*pContribTxt, *pLinesTxt; + wxStaticText *pJoinDateMsg,*pContribMsg, *pLinesMsg; wxRadioBox *pDeveloperRadio; wxChoice *pNativeLangChoice; - wxMessage *pNativeLangMsg; + wxStaticText *pNativeLangMsg; public: enum DialogModes mode; @@ -168,10 +175,51 @@ class CeditorDlg : public wxPanel bool GetRec(char *whereStr); }; // CeditorDlg +#define EDITOR_DIALOG 199 + +// Editor dialog control ids +#define EDITOR_DIALOG_FN_GROUP 200 +#define EDITOR_DIALOG_SEARCH_GROUP 201 +#define EDITOR_DIALOG_CREATE 202 +#define EDITOR_DIALOG_EDIT 203 +#define EDITOR_DIALOG_DELETE 204 +#define EDITOR_DIALOG_COPY 205 +#define EDITOR_DIALOG_SAVE 206 +#define EDITOR_DIALOG_CANCEL 207 +#define EDITOR_DIALOG_PREV 208 +#define EDITOR_DIALOG_NEXT 209 +#define EDITOR_DIALOG_QUERY 211 +#define EDITOR_DIALOG_RESET 212 +#define EDITOR_DIALOG_NAME_MSG 213 +#define EDITOR_DIALOG_NAME_TEXT 214 +#define EDITOR_DIALOG_LOOKUP 215 +#define EDITOR_DIALOG_ADDRESS1_MSG 216 +#define EDITOR_DIALOG_ADDRESS1_TEXT 217 +#define EDITOR_DIALOG_ADDRESS2_MSG 218 +#define EDITOR_DIALOG_ADDRESS2_TEXT 219 +#define EDITOR_DIALOG_CITY_MSG 220 +#define EDITOR_DIALOG_CITY_TEXT 221 +#define EDITOR_DIALOG_COUNTRY_MSG 222 +#define EDITOR_DIALOG_COUNTRY_TEXT 223 +#define EDITOR_DIALOG_POSTAL_MSG 224 +#define EDITOR_DIALOG_POSTAL_TEXT 225 +#define EDITOR_DIALOG_LANG_MSG 226 +#define EDITOR_DIALOG_LANG_CHOICE 227 +#define EDITOR_DIALOG_DATE_MSG 228 +#define EDITOR_DIALOG_DATE_TEXT 229 +#define EDITOR_DIALOG_CONTRIB_MSG 230 +#define EDITOR_DIALOG_CONTRIB_TEXT 231 +#define EDITOR_DIALOG_LINES_MSG 232 +#define EDITOR_DIALOG_LINES_TEXT 233 +#define EDITOR_DIALOG_STATE_MSG 234 +#define EDITOR_DIALOG_STATE_TEXT 235 +#define EDITOR_DIALOG_DEVELOPER 236 +#define EDITOR_DIALOG_JOIN_MSG 237 +#define EDITOR_DIALOG_JOIN_TEXT 238 // *************************** CparameterDlg *************************** -class CparameterDlg : public wxDialogBox +class CparameterDlg : public wxDialog { private: bool widgetPtrsSet; @@ -180,10 +228,10 @@ class CparameterDlg : public wxDialogBox Cparameters savedParamSettings; // Pointers to all widgets on the dialog - wxMessage *pParamODBCSourceMsg; + wxStaticText *pParamODBCSourceMsg; wxListBox *pParamODBCSourceList; - wxMessage *pParamUserNameMsg, *pParamPasswordMsg; - wxText *pParamUserNameTxt, *pParamPasswordTxt; + wxStaticText *pParamUserNameMsg, *pParamPasswordMsg; + wxTextCtrl *pParamUserNameTxt, *pParamPasswordTxt; wxButton *pParamSaveBtn, *pParamCancelBtn; public: @@ -199,6 +247,17 @@ class CparameterDlg : public wxDialogBox }; // CparameterDlg +#define PARAMETER_DIALOG 400 + +// Parameter dialog control ids +#define PARAMETER_DIALOG_SOURCE_MSG 401 +#define PARAMETER_DIALOG_SOURCE_LISTBOX 402 +#define PARAMETER_DIALOG_NAME_MSG 403 +#define PARAMETER_DIALOG_NAME_TEXT 404 +#define PARAMETER_DIALOG_PASSWORD_MSG 405 +#define PARAMETER_DIALOG_PASSWORD_TEXT 406 +#define PARAMETER_DIALOG_SAVE 407 +#define PARAMETER_DIALOG_CANCEL 408 // *************************** CqueryDlg *************************** @@ -230,7 +289,7 @@ char * const langQRY_LIKE = "% matches 0 or more of any char; _ matches char * const langQRY_BETWEEN = "column BETWEEN value AND value"; -class CqueryDlg : public wxDialogBox +class CqueryDlg : public wxDialog { private: CcolInf *colInf; // Column inf. returned by db->GetColumns() @@ -243,20 +302,20 @@ class CqueryDlg : public wxDialogBox bool widgetPtrsSet; // Widget pointers - wxMessage *pQueryCol1Msg; + wxStaticText *pQueryCol1Msg; wxChoice *pQueryCol1Choice; - wxMessage *pQueryNotMsg; + wxStaticText *pQueryNotMsg; wxCheckBox *pQueryNotCheck; - wxMessage *pQueryOperatorMsg; + wxStaticText *pQueryOperatorMsg; wxChoice *pQueryOperatorChoice; - wxMessage *pQueryCol2Msg; + wxStaticText *pQueryCol2Msg; wxChoice *pQueryCol2Choice; - wxMessage *pQueryValue1Msg; - wxText *pQueryValue1Txt; - wxMessage *pQueryValue2Msg; - wxText *pQueryValue2Txt; - wxMessage *pQuerySqlWhereMsg; - wxMultiText *pQuerySqlWhereMtxt; + wxStaticText *pQueryValue1Msg; + wxTextCtrl *pQueryValue1Txt; + wxStaticText *pQueryValue2Msg; + wxTextCtrl *pQueryValue2Txt; + wxStaticText *pQuerySqlWhereMsg; + wxTextCtrl *pQuerySqlWhereMtxt; wxButton *pQueryAddBtn; wxButton *pQueryAndBtn; wxButton *pQueryOrBtn; @@ -266,10 +325,10 @@ class CqueryDlg : public wxDialogBox wxButton *pQueryClearBtn; wxButton *pQueryCountBtn; wxButton *pQueryHelpBtn; - wxGroupBox *pQueryHintGrp; - wxMessage *pQueryHintMsg; + wxStaticBox *pQueryHintGrp; + wxStaticText *pQueryHintMsg; - wxText *pFocusTxt; + wxTextCtrl *pFocusTxt; CqueryDlg(wxWindow *parent, wxDB *pDb, char *tblName[], char *pWhereArg); @@ -284,3 +343,32 @@ class CqueryDlg : public wxDialogBox bool ValidateWhereClause(); }; // CqueryDlg + +#define QUERY_DIALOG 300 + +// Parameter dialog control ids +#define QUERY_DIALOG_COL_MSG 301 +#define QUERY_DIALOG_COL_CHOICE 302 +#define QUERY_DIALOG_NOT_MSG 303 +#define QUERY_DIALOG_NOT_CHECKBOX 304 +#define QUERY_DIALOG_OP_MSG 305 +#define QUERY_DIALOG_OP_CHOICE 306 +#define QUERY_DIALOG_COL2_MSG 307 +#define QUERY_DIALOG_COL2_CHOICE 308 +#define QUERY_DIALOG_WHERE_MSG 309 +#define QUERY_DIALOG_WHERE_TEXT 310 +#define QUERY_DIALOG_ADD 311 +#define QUERY_DIALOG_AND 312 +#define QUERY_DIALOG_OR 313 +#define QUERY_DIALOG_LPAREN 314 +#define QUERY_DIALOG_RPAREN 315 +#define QUERY_DIALOG_DONE 316 +#define QUERY_DIALOG_CLEAR 317 +#define QUERY_DIALOG_COUNT 318 +#define QUERY_DIALOG_VALUE1_MSG 319 +#define QUERY_DIALOG_VALUE1_TEXT 320 +#define QUERY_DIALOG_VALUE2_MSG 321 +#define QUERY_DIALOG_VALUE2_TEXT 322 +#define QUERY_DIALOG_HINT_GROUP 323 +#define QUERY_DIALOG_HINT_MSG 324 + diff --git a/samples/db/listdb.cpp b/samples/db/listdb.cpp index 330c79db2a..bea0ddc717 100644 --- a/samples/db/listdb.cpp +++ b/samples/db/listdb.cpp @@ -103,7 +103,7 @@ Clookup2::Clookup2(char *tblName, char *colName1, char *colName2, wxDB *pDb) // This is a generic lookup constructor that will work with any table and any column ClookUpDlg::ClookUpDlg(wxWindow *parent, char *windowTitle, char *tableName, char *colName, - char *where, char *orderBy) : wxDialogBox (parent, "Select...", 1, -1, -1, 400, 290) + char *where, char *orderBy) : wxDialog (parent, LOOKUP_DIALOG, "Select...", wxPoint(-1, -1), wxSize(400, 290)) { wxBeginBusyCursor(); @@ -114,19 +114,9 @@ ClookUpDlg::ClookUpDlg(wxWindow *parent, char *windowTitle, char *tableName, cha noDisplayCols = 1; col1Len = 0; - // Build the dialog - SetLabelPosition(wxVERTICAL); - - wxFont *ButtonFont = new wxFont(12,wxSWISS,wxNORMAL,wxBOLD); - wxFont *TextFont = new wxFont(12,wxSWISS,wxNORMAL,wxNORMAL); - - SetButtonFont(ButtonFont); - SetLabelFont(TextFont); - SetLabelPosition(wxVERTICAL); - - pLookUpSelectList = new wxListBox(this, NULL, "", wxSINGLE|wxALWAYS_SB, 5, 15, 384, 195, 0, 0, 0, "LookUpSelectList"); - pLookUpOkBtn = new wxButton(this, NULL, "&Ok", 113, 222, 70, 35, 0, "LookUpOkBtn"); - pLookUpCancelBtn = new wxButton(this, NULL, "C&ancel", 212, 222, 70, 35, 0, "LookUpCancelBtn"); + pLookUpSelectList = new wxListBox(this, LOOKUP_DIALOG_SELECT, wxPoint(5, 15), wxSize(384, 195), 0, 0, wxLB_SINGLE|wxLB_ALWAYS_SB, wxDefaultValidator, "LookUpSelectList"); + pLookUpOkBtn = new wxButton(this, LOOKUP_DIALOG_OK, "&Ok", wxPoint(113, 222), wxSize(70, 35), 0, wxDefaultValidator, "LookUpOkBtn"); + pLookUpCancelBtn = new wxButton(this, LOOKUP_DIALOG_CANCEL, "C&ancel", wxPoint(212, 222), wxSize(70, 35), 0, wxDefaultValidator, "LookUpCancelBtn"); widgetPtrsSet = TRUE; @@ -141,8 +131,8 @@ ClookUpDlg::ClookUpDlg(wxWindow *parent, char *windowTitle, char *tableName, cha if (!lookup->Open()) { wxString tStr; - tStr.sprintf("Unable to open the table '%s'.",tableName); - wxMessageBox(tStr.GetData(),"ODBC Error..."); + tStr.Printf("Unable to open the table '%s'.",tableName); + wxMessageBox(tStr,"ODBC Error..."); Close(); return; } @@ -176,7 +166,7 @@ ClookUpDlg::ClookUpDlg(wxWindow *parent, char *windowTitle, char *tableName, cha SetTitle(windowTitle); Centre(wxBOTH); wxEndBusyCursor(); - Show(TRUE); + ShowModal(); } // Generic lookup constructor @@ -207,7 +197,7 @@ ClookUpDlg::ClookUpDlg(wxWindow *parent, char *windowTitle, char *tableName, cha // ClookUpDlg::ClookUpDlg(wxWindow *parent, char *windowTitle, char *tableName, char *dispCol1, char *dispCol2, char *where, char *orderBy, bool distinctValues, - char *selectStmt, int maxLenCol1, wxDB *pDb, bool allowOk) : wxDialogBox (parent, "Select...", 1, -1, -1, 400, 290) + char *selectStmt, int maxLenCol1, wxDB *pDb, bool allowOk) : wxDialog (parent, LOOKUP_DIALOG, "Select...", wxPoint(-1, -1), wxSize(400, 290)) { wxBeginBusyCursor(); @@ -219,24 +209,16 @@ ClookUpDlg::ClookUpDlg(wxWindow *parent, char *windowTitle, char *tableName, noDisplayCols = (strlen(dispCol2) ? 2 : 1); col1Len = 0; - // Build the dialog - SetLabelPosition(wxVERTICAL); - - wxFont *ButtonFont = new wxFont(12,wxSWISS,wxNORMAL,wxBOLD); - wxFont *TextFont = new wxFont(12,wxSWISS,wxNORMAL,wxNORMAL); - wxFont *FixedFont = new wxFont(12,wxMODERN,wxNORMAL,wxNORMAL); - - SetButtonFont(ButtonFont); - SetLabelFont(TextFont); - SetLabelPosition(wxVERTICAL); + wxFont fixedFont(12,wxMODERN,wxNORMAL,wxNORMAL); // this is done with fixed font so that the second column (if any) will be left // justified in the second column - SetButtonFont(FixedFont); - pLookUpSelectList = new wxListBox(this, NULL, "", wxSINGLE|wxALWAYS_SB, 5, 15, 384, 195, 0, 0, 0, "LookUpSelectList"); - SetButtonFont(ButtonFont); - pLookUpOkBtn = new wxButton(this, NULL, "&Ok", 113, 222, 70, 35, 0, "LookUpOkBtn"); - pLookUpCancelBtn = new wxButton(this, NULL, "C&ancel", 212, 222, 70, 35, 0, "LookUpCancelBtn"); + pLookUpSelectList = new wxListBox(this, LOOKUP_DIALOG_SELECT, wxPoint(5, 15), wxSize(384, 195), 0, 0, wxLB_SINGLE|wxLB_ALWAYS_SB, wxDefaultValidator, "LookUpSelectList"); + + pLookUpSelectList->SetFont(fixedFont); + + pLookUpOkBtn = new wxButton(this, LOOKUP_DIALOG_OK, "&Ok", wxPoint(113, 222), wxSize(70, 35), 0, wxDefaultValidator, "LookUpOkBtn"); + pLookUpCancelBtn = new wxButton(this, LOOKUP_DIALOG_CANCEL, "C&ancel", wxPoint(212, 222), wxSize(70, 35), 0, wxDefaultValidator, "LookUpCancelBtn"); widgetPtrsSet = TRUE; @@ -251,8 +233,8 @@ ClookUpDlg::ClookUpDlg(wxWindow *parent, char *windowTitle, char *tableName, if (!lookup2->Open()) { wxString tStr; - tStr.sprintf("Unable to open the table '%s'.",tableName); - wxMessageBox(tStr.GetData(),"ODBC Error..."); + tStr.Printf("Unable to open the table '%s'.",tableName); + wxMessageBox(tStr,"ODBC Error..."); Close(); return; } @@ -276,7 +258,7 @@ ClookUpDlg::ClookUpDlg(wxWindow *parent, char *windowTitle, char *tableName, q += " WHERE "; q += where; } - if (!lookup2->QueryBySqlStmt(q.GetData())) + if (!lookup2->QueryBySqlStmt((char*) (const char*) q)) { wxMessageBox("ODBC error during QueryBySqlStmt()","ODBC Error..."); Close(); @@ -321,7 +303,7 @@ ClookUpDlg::ClookUpDlg(wxWindow *parent, char *windowTitle, char *tableName, s.Append(' ', (maxColLen + LISTDB_NO_SPACES_BETWEEN_COLS - strlen(lookup2->lookupCol1))); s.Append(lookup2->lookupCol2); } - pLookUpSelectList->Append(s.GetData()); + pLookUpSelectList->Append(s); } // Highlight the first list item @@ -342,7 +324,7 @@ ClookUpDlg::ClookUpDlg(wxWindow *parent, char *windowTitle, char *tableName, SetTitle(windowTitle); Centre(wxBOTH); wxEndBusyCursor(); - Show(TRUE); + ShowModal(); } // Generic lookup constructor 2 @@ -382,12 +364,12 @@ void ClookUpDlg::OnCommand(wxWindow& win, wxCommandEvent& event) // Column 1 s = s.SubString(0, col1Len-1); s = s.Strip(); - strcpy(ListDB_Selection, s.GetData()); + strcpy(ListDB_Selection, s); // Column 2 s = pLookUpSelectList->GetStringSelection(); - s = s.From(col1Len + LISTDB_NO_SPACES_BETWEEN_COLS); + s = s.Mid(col1Len + LISTDB_NO_SPACES_BETWEEN_COLS); s = s.Strip(); - strcpy(ListDB_Selection2, s.GetData()); + strcpy(ListDB_Selection2, s); } } else diff --git a/samples/db/listdb.h b/samples/db/listdb.h index 0d966c961e..f510fbf130 100644 --- a/samples/db/listdb.h +++ b/samples/db/listdb.h @@ -9,7 +9,9 @@ // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ #pragma interface "listdb.h" +#endif /* /* @@ -54,7 +56,7 @@ class Clookup2 : public wxTable }; // Clookup2 -class ClookUpDlg : public wxDialogBox +class ClookUpDlg : public wxDialog { private: bool widgetPtrsSet; @@ -120,6 +122,12 @@ class ClookUpDlg : public wxDialogBox void OnActivate(bool) {}; // necessary for hot keys }; +#define LOOKUP_DIALOG 500 + +#define LOOKUP_DIALOG_SELECT 501 +#define LOOKUP_DIALOG_OK 502 +#define LOOKUP_DIALOG_CANCEL 503 + #endif // LISTDB_DOT_H // ************************************ listdb.h ********************************* diff --git a/samples/db/makefile.nt b/samples/db/makefile.nt index 2db0a71c6e..1888b9caf0 100644 --- a/samples/db/makefile.nt +++ b/samples/db/makefile.nt @@ -1,53 +1,31 @@ # # File: makefile.nt -# Author: George Tasker -# Created: 1998 +# Author: Julian Smart +# Created: 1993 # Updated: +# Copyright: (c) 1993, AIAI, University of Edinburgh # # "%W% %G%" # -# Makefile : Builds database example (MS VC++). - -!if "$(FINAL)" == "" -FINAL=0 -!endif - - -!if "$(MSVCDIR)" == "" -MSVCDIR=c:\devstudio\vc -!endif +# Makefile : Builds db example (MS VC++). +# Use FINAL=1 argument to nmake to build final version with no debugging +# info # Set WXDIR for your system -WXDIR = $(WXWIN) -THISDIR = $(WXDIR)\samples\database -WXODBCDIR = $(WXDIR)\utils\wxodbc - -!if "$(MSVCDIR)" == "" -DBLIBS=$(MSDEVDIR)\lib\odbc32.lib -!else -DBLIBS=$(MSVCDIR)\lib\odbc32.lib -!endif +WXDIR = $(WXWIN) -EXTRAINC = -I$(WXODBCDIR)\src -EXTRALIBS = $(DBLIBS) $(WXODBCDIR)\lib\wxodbc.lib +WXUSINGDLL=0 !include $(WXDIR)\src\ntwxwin.mak -PROGRAM=database +THISDIR = $(WXDIR)\samples\db +PROGRAM=dbtest -OBJECTS = $(PROGRAM).$(OBJSUFF) listdb.$(OBJSUFF) - -all: wxodbc $(PROGRAM).exe +OBJECTS = $(PROGRAM).obj listdb.obj $(PROGRAM): $(PROGRAM).exe -gt: - cd $(CPPFLAGS) - -wxodbc: - cd $(WXODBCDIR)\src - nmake -f makefile.nt FINAL=$(FINAL) - cd $(THISDIR) +all: wx $(PROGRAM).exe wx: cd $(WXDIR)\src\msw @@ -58,12 +36,8 @@ wxclean: cd $(WXDIR)\src\msw nmake -f makefile.nt clean cd $(THISDIR) - cd $(WXODBCDIR)\src - nmake -f makefile.nt clean - cd $(THISDIR) - -$(PROGRAM).exe: $(DUMMYOBJ) $(OBJECTS) $(PROGRAM).res +$(PROGRAM).exe: $(DUMMYOBJ) $(WXLIB) $(OBJECTS) $(PROGRAM).res $(link) @<< -out:$(PROGRAM).exe $(LINKFLAGS) @@ -72,19 +46,17 @@ $(LIBS) << -listdb.$(OBJSUFF): $(*B).$(SRCSUFF) $(*B).h - $(cc) @<< -$(CPPFLAGS) /c /Fo$(*B).$(OBJSUFF) /Tp $(*B).$(SRCSUFF) +$(PROGRAM).obj: $(PROGRAM).$(SRCSUFF) $(DUMMYOBJ) + $(cc) @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) << - -$(PROGRAM).$(OBJSUFF): $(PROGRAM).$(SRCSUFF) $(PROGRAM).h listdb.h - $(cc) @<< -$(CPPFLAGS) /c /Fo$(*B).$(OBJSUFF) /Tp $(*B).$(SRCSUFF) +listdb.obj: listdb.cpp $(DUMMYOBJ) + $(cc) @<< +$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) << - -$(PROGRAM).res: $(PROGRAM).rc $(WXDIR)\include\wx\msw\wx.rc +$(PROGRAM).res : $(PROGRAM).rc $(WXDIR)\include\wx\msw\wx.rc $(rc) -r /i$(WXDIR)\include -fo$@ $(PROGRAM).rc diff --git a/samples/db/makefile.unx b/samples/db/makefile.unx index 3c4142d09b..2c8bf754e9 100644 --- a/samples/db/makefile.unx +++ b/samples/db/makefile.unx @@ -1,71 +1,17 @@ # # File: makefile.unx -# Author: Terry Tompkins +# Author: Julian Smart # Created: 1998 # Updated: -# Copyright: (c) 1998, Remstar International +# Copyright: (c) 1998 Julian Smart # -# Makefile for wxDB (UNIX). - -OBJDIR=database -OBJSUFF=.o -SRCSUFF=.cpp -WXDIR = $(WXWIN) - -# All common UNIX compiler flags and options are now in -# this central makefile. -include $(WXDIR)/src/make.env - -PROGRAM=database - -OBJECTS = $(OBJDIR)/$(PROGRAM).$(OBJSUFF) $(OBJDIR)/table.$(OBJSUFF) $(OBJDIR)/db.$(OBJSUFF) $(OBJDIR)/listdb.$(OBJSUFF) - -.SUFFIXES: - -all: $(OBJDIR) $(PROGRAM)$(GUISUFFIX) - -wx: - - -motif: - $(MAKE) -f makefile.unx GUISUFFIX=_motif GUI=-Dwx_motif GUISUFFIX=_motif OPT='$(OPT)' LDLIBS='$(MOTIFLDLIBS)' WXLIB=$(WXDIR)/lib/libwx_motif.a OPTIONS='$(OPTIONS)' DEBUG='$(DEBUG)' WARN='$(WARN)' XLIB='$(XLIB)' XINCLUDE='$(XINCLUDE)' XVIEW_LINK= - -xview: - cd $(WXDIR)/src/x; $(MAKE) -f makefile.unx xview - $(MAKE) -f makefile.unx GUI=-Dwx_xview GUISUFFIX=_ol CC=$(CC) OPTIONS='$(OPTIONS)' DEBUG='$(DEBUG)' WARN='$(WARN)' XLIB='$(XLIB)' XINCLUDE='$(XINCLUDE)' - -hp: - cd $(WXDIR)/src/x; $(MAKE) -f makefile.unx hp - $(MAKE) -f makefile.unx GUI=-Dwx_motif GUISUFFIX=_hp CC=CC DEBUG='$(DEBUG)' WARN='-w' \ - XINCLUDE='$(HPXINCLUDE)' XLIB='$(HPXLIB)' XVIEW_LINK='' LDLIBS='$(HPLDLIBS)' - -$(OBJDIR): - mkdir $(OBJDIR) - -$(PROGRAM)$(GUISUFFIX): $(DUMMYOBJ) $(DBLIBS) $(OBJECTS) $(WXLIB) - $(CC) $(LDFLAGS) -o $(PROGRAM)$(GUISUFFIX) $(OBJECTS) $(XVIEW_LINK) $(LDLIBS) - -$(OBJDIR)/$(PROGRAM).$(OBJSUFF): $(PROGRAM).$(SRCSUFF) - $(CC) -c $(CPPFLAGS) -o $@ $(PROGRAM).$(SRCSUFF) - -$(OBJDIR)/table.$(OBJSUFF): table.$(SRCSUFF) - $(CC) -c $(CPPFLAGS) -o $@ table.$(SRCSUFF) - -$(OBJDIR)/db.$(OBJSUFF): db.$(SRCSUFF) - $(CC) -c $(CPPFLAGS) -o $@ db.$(SRCSUFF) - -$(OBJDIR)/listdb.$(OBJSUFF): listdb.$(SRCSUFF) - $(CC) -c $(CPPFLAGS) -o $@ listdb.$(SRCSUFF) - -clean_motif: - $(MAKE) -f makefile.unx GUISUFFIX=_motif cleanany +# "%W% %G%" +# +# Makefile for dbtest example (UNIX). -clean_ol: - $(MAKE) -f makefile.unx GUISUFFIX=_ol cleanany +PROGRAM=dbtest -clean_hp: - $(MAKE) -f makefile.unx GUISUFFIX=_hp cleanany +OBJECTS=$(PROGRAM).o listdb.o -cleanany: - rm -f $(OBJECTS) $(PROGRAM)$(GUISUFFIX) core +include ../../src/makeprog.env diff --git a/src/common/db.cpp b/src/common/db.cpp index 1c2c703f42..9125384a3f 100644 --- a/src/common/db.cpp +++ b/src/common/db.cpp @@ -5,6 +5,8 @@ // source such as opening and closing the data source. // Author: Doug Card // Modified by: +// Mods: Dec, 1998: Added support for SQL statement logging and database +// cataloging // Created: 9.96 // RCS-ID: $Id$ // Copyright: (c) 1996 Remstar International, Inc. @@ -20,17 +22,17 @@ // the wxWindows GUI development toolkit. /////////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ +#pragma implementation "db.h" +#endif + /* // SYNOPSIS START // SYNOPSIS STOP */ -#ifdef __GNUG__ -#pragma implementation "db.h" -#endif - /* -#ifdef _CONSOLE +#ifdef DBDEBUG_CONSOLE #include #endif */ @@ -47,11 +49,10 @@ #if wxUSE_ODBC -#include - #include #include #include +#include "wx/db.h" DbList *PtrBegDbList = 0; @@ -59,6 +60,9 @@ DbList *PtrBegDbList = 0; wxDB::wxDB(HENV &aHenv) { int i; + + fpSqlLog = 0; // Sql Log file pointer + sqlLogState = sqlLogOFF; // By default, logging is turned off strcpy(sqlState,""); strcpy(errorMsg,""); @@ -112,7 +116,7 @@ wxDB::wxDB(HENV &aHenv) /********** wxDB::Open() **********/ bool wxDB::Open(char *Dsn, char *Uid, char *AuthStr) { - assert(Dsn); + assert(Dsn && strlen(Dsn)); dsn = Dsn; uid = Uid; authStr = AuthStr; @@ -125,7 +129,7 @@ bool wxDB::Open(char *Dsn, char *Uid, char *AuthStr) // specified before the connection is made. retcode = SQLSetConnectOption(hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_IF_NEEDED); - #ifdef _CONSOLE + #ifdef DBDEBUG_CONSOLE if (retcode == SQL_SUCCESS) cout << "SQLSetConnectOption(CURSOR_LIB) successful" << endl; else @@ -240,7 +244,7 @@ bool wxDB::Open(char *Dsn, char *Uid, char *AuthStr) else typeInfDate.FsqlType = SQL_TIMESTAMP; -#ifdef _CONSOLE +#ifdef DBDEBUG_CONSOLE cout << "VARCHAR DATA TYPE: " << typeInfVarchar.TypeName << endl; cout << "INTEGER DATA TYPE: " << typeInfInteger.TypeName << endl; cout << "FLOAT DATA TYPE: " << typeInfFloat.TypeName << endl; @@ -262,7 +266,7 @@ bool wxDB::setConnectionOptions(void) SQLSetConnectOption(hdbc, SQL_OPT_TRACE, SQL_OPT_TRACE_OFF); // Display the connection options to verify them -#ifdef _CONSOLE +#ifdef DBDEBUG_CONSOLE long l; cout << ">>>>> CONNECTION OPTIONS <<<<<<" << endl; @@ -394,7 +398,7 @@ bool wxDB::getDbInfo(void) if (SQLGetInfo(hdbc, SQL_LOGIN_TIMEOUT, &dbInf.loginTimeout, sizeof(dbInf.loginTimeout), &cb) != SQL_SUCCESS) return(DispAllErrors(henv, hdbc)); -#ifdef _CONSOLE +#ifdef DBDEBUG_CONSOLE cout << ">>>>> DATA SOURCE INFORMATION <<<<<" << endl; cout << "SERVER Name: " << dbInf.serverName << endl; cout << "DBMS Name: " << dbInf.dbmsName << "; DBMS Version: " << dbInf.dbmsVer << endl; @@ -612,7 +616,7 @@ bool wxDB::getDataTypeInfo(SWORD fSqlType, SqlTypeInfo &structSQLTypeInfo) // Fetch the record if ((retcode = SQLFetch(hstmt)) != SQL_SUCCESS) { -#ifdef _CONSOLE +#ifdef DBDEBUG_CONSOLE if (retcode == SQL_NO_DATA_FOUND) cout << "SQL_NO_DATA_FOUND fetching inf. about data type." << endl; #endif @@ -647,6 +651,13 @@ bool wxDB::getDataTypeInfo(SWORD fSqlType, SqlTypeInfo &structSQLTypeInfo) /********** wxDB::Close() **********/ void wxDB::Close(void) { + // Close the Sql Log file + if (fpSqlLog) + { + fclose(fpSqlLog); + fpSqlLog = 0; //glt + } + // Free statement handle if (dbIsOpen) { @@ -699,7 +710,7 @@ bool wxDB::DispAllErrors(HENV aHenv, HDBC aHdbc, HSTMT aHstmt) logError(odbcErrMsg, sqlState); if (!silent) { -#ifdef _CONSOLE +#ifdef DBDEBUG_CONSOLE // When run in console mode, use standard out to display errors. cout << odbcErrMsg << endl; cout << "Press any key to continue..." << endl; @@ -733,7 +744,7 @@ void wxDB::DispNextError(void) if (silent) return; -#ifdef _CONSOLE +#ifdef DBDEBUG_CONSOLE // When run in console mode, use standard out to display errors. cout << odbcErrMsg << endl; cout << "Press any key to continue..." << endl; @@ -994,10 +1005,12 @@ bool wxDB::Grant(int privileges, char *tableName, char *userList) strcat(sqlStmt, " TO "); strcat(sqlStmt, userList); -#ifdef _CONSOLE +#ifdef DBDEBUG_CONSOLE cout << endl << sqlStmt << endl; #endif + WriteSqlLog(sqlStmt); + return(ExecSql(sqlStmt)); } // wxDB::Grant() @@ -1025,7 +1038,9 @@ bool wxDB::CreateView(char *viewName, char *colList, char *pSqlStmt) } } -#ifdef _CONSOLE + WriteSqlLog(sqlStmt); + +#ifdef DBDEBUG_CONSOLE cout << endl << sqlStmt << endl; #endif @@ -1043,7 +1058,9 @@ bool wxDB::CreateView(char *viewName, char *colList, char *pSqlStmt) strcat(sqlStmt, " AS "); strcat(sqlStmt, pSqlStmt); -#ifdef _CONSOLE + WriteSqlLog(sqlStmt); + +#ifdef DBDEBUG_CONSOLE cout << sqlStmt << endl; #endif @@ -1161,6 +1178,101 @@ CcolInf *wxDB::GetColumns(char *tableName[]) } // wxDB::GetColumns() +/********** wxDB::Catalog() **********/ +bool wxDB::Catalog(char *userID, char *fileName) +{ + assert(userID && strlen(userID)); + assert(fileName && strlen(fileName)); + + RETCODE retcode; + SDWORD cb; + char tblName[DB_MAX_TABLE_NAME_LEN+1]; + char tblNameSave[DB_MAX_TABLE_NAME_LEN+1]; + char colName[DB_MAX_COLUMN_NAME_LEN+1]; + SWORD sqlDataType; + char typeName[16]; + SWORD precision, length; + + FILE *fp = fopen(fileName,"wt"); + if (fp == NULL) + return(FALSE); + + SQLFreeStmt(hstmt, SQL_CLOSE); + + int i = 0; + char userIdUC[81]; + for (char *p = userID; *p; p++) + userIdUC[i++] = toupper(*p); + userIdUC[i] = 0; + + retcode = SQLColumns(hstmt, + NULL, 0, // All qualifiers + (UCHAR *) userIdUC, SQL_NTS, // User specified + NULL, 0, // All tables + NULL, 0); // All columns + if (retcode != SQL_SUCCESS) + { + DispAllErrors(henv, hdbc, hstmt); + fclose(fp); + return(FALSE); + } + + SQLBindCol(hstmt, 3, SQL_C_CHAR, tblName, DB_MAX_TABLE_NAME_LEN+1, &cb); + SQLBindCol(hstmt, 4, SQL_C_CHAR, colName, DB_MAX_COLUMN_NAME_LEN+1, &cb); + SQLBindCol(hstmt, 5, SQL_C_SSHORT, &sqlDataType, 0, &cb); + SQLBindCol(hstmt, 6, SQL_C_CHAR, typeName, 16, &cb); + SQLBindCol(hstmt, 7, SQL_C_SSHORT, &precision, 0, &cb); + SQLBindCol(hstmt, 8, SQL_C_SSHORT, &length, 0, &cb); + + char outStr[256]; + strcpy(tblNameSave,""); + int cnt = 0; + + while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS) + { + if (strcmp(tblName,tblNameSave)) + { + if (cnt) + fputs("\n", fp); + fputs("================================ ", fp); + fputs("================================ ", fp); + fputs("===================== ", fp); + fputs("========= ", fp); + fputs("=========\n", fp); + sprintf(outStr, "%-32s %-32s %-21s %9s %9s\n", + "TABLE NAME", "COLUMN NAME", "DATA TYPE", "PRECISION", "LENGTH"); + fputs(outStr, fp); + fputs("================================ ", fp); + fputs("================================ ", fp); + fputs("===================== ", fp); + fputs("========= ", fp); + fputs("=========\n", fp); + strcpy(tblNameSave,tblName); + } + sprintf(outStr, "%-32s %-32s (%04d)%-15s %9d %9d\n", + tblName, colName, sqlDataType, typeName, precision, length); + if (fputs(outStr, fp) == EOF) + { + fclose(fp); + return(FALSE); + } + cnt++; + } + + if (retcode != SQL_NO_DATA_FOUND) + { + DispAllErrors(henv, hdbc, hstmt); + fclose(fp); + return(FALSE); + } + + SQLFreeStmt(hstmt, SQL_CLOSE); + fclose(fp); + return(TRUE); + +} // wxDB::Catalog() + + // Table name can refer to a table, view, alias or synonym. Returns true // if the object exists in the database. This function does not indicate // whether or not the user has privleges to query or perform other functions @@ -1190,6 +1302,54 @@ bool wxDB::TableExists(char *tableName) } // wxDB::TableExists() +/********** wxDB::SqlLog() **********/ +bool wxDB::SqlLog(enum sqlLog state, char *filename, bool append) +{ + assert(state == sqlLogON || state == sqlLogOFF); + assert(state == sqlLogOFF || filename); + + if (state == sqlLogON) + { + if (fpSqlLog == 0) + { + fpSqlLog = fopen(filename, (append ? "at" : "wt")); + if (fpSqlLog == NULL) + return(FALSE); + } + } + else // sqlLogOFF + { + if (fpSqlLog) + { + if (fclose(fpSqlLog)) + return(FALSE); + fpSqlLog = 0; + } + } + + sqlLogState = state; + return(TRUE); + +} // wxDB::SqlLog() + + +/********** wxDB::WriteSqlLog() **********/ +bool wxDB::WriteSqlLog(char *logMsg) +{ + assert(logMsg); + + if (fpSqlLog == 0 || sqlLogState == sqlLogOFF) + return(FALSE); + + if (fputs("\n", fpSqlLog) == EOF) return(FALSE); + if (fputs(logMsg, fpSqlLog) == EOF) return(FALSE); + if (fputs("\n", fpSqlLog) == EOF) return(FALSE); + + return(TRUE); + +} // wxDB::WriteSqlLog() + + /********** GetDbConnection() **********/ wxDB *GetDbConnection(DbStuff *pDbStuff) { @@ -1319,4 +1479,5 @@ bool GetDataSource(HENV henv, char *Dsn, SWORD DsnMax, char *DsDesc, SWORD DsDes } // GetDataSource() #endif - // wxUSE_ODBC + // wxUSE_ODBC + diff --git a/src/common/dbtable.cpp b/src/common/dbtable.cpp index 5a888dec03..decce99426 100644 --- a/src/common/dbtable.cpp +++ b/src/common/dbtable.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Name: table.cpp +// Name: dbtable.cpp // Purpose: Implementation of the wxTable class. // Author: Doug Card // Modified by: @@ -18,6 +18,10 @@ // the wxWindows GUI development toolkit. /////////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ +#pragma implementation "dbtable.h" +#endif + /* // SYNOPSIS START // SYNOPSIS STOP @@ -46,14 +50,15 @@ #include #include #include +#include -#ifdef __WXUNIX__ +#ifdef __UNIX__ // The HPUX preprocessor lines below were commented out on 8/20/97 // because macros.h currently redefines DEBUG and is unneeded. // # ifdef HPUX // # include // # endif -# ifdef __WXLINUX__ +# ifdef LINUX # include # endif #endif @@ -63,16 +68,22 @@ wxTable::wxTable(wxDB *pwxDB, const char *tblName, const int nCols, const char * { // Assign member variables pDb = pwxDB; // Pointer to the wxDB object + strcpy(tableName, tblName); // Table Name if (qryTblName) // Name of the table/view to query strcpy(queryTableName, qryTblName); else strcpy(queryTableName, tblName); - noCols = nCols; // No. of cols in the table - where = 0; // Where clause - orderBy = 0; // Order By clause - selectForUpdate = FALSE; // SELECT ... FOR UPDATE; Indicates whether to include the FOR UPDATE phrase + assert(pDb); // Assert is placed after table name is assigned for error reporting reasons + if (!pDb) + return; + + noCols = nCols; // No. of cols in the table + where = 0; // Where clause + orderBy = 0; // Order By clause + from = 0; // From clause + selectForUpdate = FALSE; // SELECT ... FOR UPDATE; Indicates whether to include the FOR UPDATE phrase // Grab the HENV and HDBC from the wxDB object henv = pDb->henv; @@ -214,15 +225,18 @@ wxTable::~wxTable() /********** wxTable::Open() **********/ bool wxTable::Open(void) { + if (!pDb) + return FALSE; + int i; char sqlStmt[DB_MAX_STATEMENT_LEN]; // Verify that the table exists in the database if (!pDb->TableExists(tableName)) { - wxString s; - s.Printf("Error opening '%s', table/view does not exist in the database.", tableName); - pDb->LogError(WXSTRINGCAST(s)); + char s[128]; + sprintf(s, "Error opening '%s', table/view does not exist in the database.", tableName); + pDb->LogError(s); return(FALSE); } @@ -272,6 +286,8 @@ bool wxTable::Open(void) } strcat(sqlStmt, ")"); + pDb->WriteSqlLog(sqlStmt); + // Prepare the insert statement for execution if (SQLPrepare(hstmtInsert, (UCHAR FAR *) sqlStmt, SQL_NTS) != SQL_SUCCESS) return(pDb->DispAllErrors(henv, hdbc, hstmtInsert)); @@ -293,6 +309,7 @@ bool wxTable::Query(bool forUpdate, bool distinct) /********** wxTable::QueryBySqlStmt() **********/ bool wxTable::QueryBySqlStmt(char *pSqlStmt) { + pDb->WriteSqlLog(pSqlStmt); return(query(DB_SELECT_STATEMENT, FALSE, FALSE, pSqlStmt)); @@ -328,7 +345,10 @@ bool wxTable::query(int queryType, bool forUpdate, bool distinct, char *pSqlStmt // Set the SQL SELECT string if (queryType != DB_SELECT_STATEMENT) // A select statement was not passed in, - GetSelectStmt(sqlStmt, queryType, distinct); // so generate a select statement. + { // so generate a select statement. + GetSelectStmt(sqlStmt, queryType, distinct); + pDb->WriteSqlLog(sqlStmt); + } // Make sure the cursor is closed first if (! CloseCursor(hstmt)) @@ -358,9 +378,21 @@ void wxTable::GetSelectStmt(char *pSqlStmt, int typeOfSelect, bool distinct) if (distinct) strcat(pSqlStmt, "DISTINCT "); + // Was a FROM clause specified to join tables to the base table? + // Available for ::Query() only!!! + bool appendFromClause = FALSE; + if (typeOfSelect == DB_SELECT_WHERE && from && strlen(from)) + appendFromClause = TRUE; + // Add the column list for (int i = 0; i < noCols; i++) { + // If joining tables, the base table column names must be qualified to avoid ambiguity + if (appendFromClause) + { + strcat(pSqlStmt, queryTableName); + strcat(pSqlStmt, "."); + } strcat(pSqlStmt, colDefs[i].ColName); if (i + 1 < noCols) strcat(pSqlStmt, ","); @@ -369,11 +401,23 @@ void wxTable::GetSelectStmt(char *pSqlStmt, int typeOfSelect, bool distinct) // If the datasource supports ROWID, get this column as well. Exception: Don't retrieve // the ROWID if querying distinct records. The rowid will always be unique. if (!distinct && CanUpdByROWID()) - strcat(pSqlStmt, ",ROWID"); + { + // If joining tables, the base table column names must be qualified to avoid ambiguity + if (appendFromClause) + { + strcat(pSqlStmt, ","); + strcat(pSqlStmt, queryTableName); + strcat(pSqlStmt, ".ROWID"); + } + else + strcat(pSqlStmt, ",ROWID"); + } // Append the FROM tablename portion strcat(pSqlStmt, " FROM "); strcat(pSqlStmt, queryTableName); + if (appendFromClause) + strcat(pSqlStmt, from); // Append the WHERE clause. Either append the where clause for the class // or build a where clause. The typeOfSelect determines this. @@ -468,12 +512,9 @@ bool wxTable::bindInsertParams(void) UDWORD precision; SWORD scale; -//glt CcolDef *tColDef; - // Bind each column (that can be inserted) of the table to a parameter marker for (int i = 0; i < noCols; i++) { -//glt tColDef = &colDefs[i]; if (! colDefs[i].InsertAllowed) continue; switch(colDefs[i].DbDataType) @@ -606,6 +647,9 @@ bool wxTable::CloseCursor(HSTMT cursor) /********** wxTable::CreateTable() **********/ bool wxTable::CreateTable(void) { + if (!pDb) + return FALSE; + int i, j; char sqlStmt[DB_MAX_STATEMENT_LEN]; @@ -632,6 +676,8 @@ bool wxTable::CreateTable(void) } } + pDb->WriteSqlLog(sqlStmt); + // Commit the transaction and close the cursor if (! pDb->CommitTrans()) return(FALSE); @@ -694,11 +740,11 @@ bool wxTable::CreateTable(void) // For varchars, append the size of the string if (colDefs[i].DbDataType == DB_DATA_TYPE_VARCHAR) { + char s[10]; // strcat(sqlStmt, "("); // strcat(sqlStmt, itoa(colDefs[i].SzDataObj, s, 10)); // strcat(sqlStmt, ")"); - wxString s; - s.Printf("(%d)", colDefs[i].SzDataObj); + sprintf(s, "(%d)", colDefs[i].SzDataObj); strcat(sqlStmt, s); } needComma = TRUE; @@ -732,6 +778,8 @@ bool wxTable::CreateTable(void) // Append the closing parentheses for the create table statement strcat(sqlStmt, ")"); + pDb->WriteSqlLog(sqlStmt); + #ifdef _CONSOLE cout << endl << sqlStmt << endl; #endif @@ -787,6 +835,8 @@ bool wxTable::CreateIndex(char * idxName, bool unique, int noIdxCols, CidxDef *p // Append closing parentheses strcat(sqlStmt, ")"); + pDb->WriteSqlLog(sqlStmt); + #ifdef _CONSOLE cout << endl << sqlStmt << endl << endl; #endif @@ -837,6 +887,7 @@ int wxTable::Insert(void) /********** wxTable::Update(pSqlStmt) **********/ bool wxTable::Update(char *pSqlStmt) { + pDb->WriteSqlLog(pSqlStmt); return(execUpdate(pSqlStmt)); @@ -850,6 +901,8 @@ bool wxTable::Update(void) // Build the SQL UPDATE statement GetUpdateStmt(sqlStmt, DB_UPD_KEYFIELDS); + pDb->WriteSqlLog(sqlStmt); + #ifdef _CONSOLE cout << endl << sqlStmt << endl << endl; #endif @@ -867,6 +920,8 @@ bool wxTable::UpdateWhere(char *pWhereClause) // Build the SQL UPDATE statement GetUpdateStmt(sqlStmt, DB_UPD_WHERE, pWhereClause); + pDb->WriteSqlLog(sqlStmt); + #ifdef _CONSOLE cout << endl << sqlStmt << endl << endl; #endif @@ -884,6 +939,8 @@ bool wxTable::Delete(void) // Build the SQL DELETE statement GetDeleteStmt(sqlStmt, DB_DEL_KEYFIELDS); + pDb->WriteSqlLog(sqlStmt); + // Execute the SQL DELETE statement return(execDelete(sqlStmt)); @@ -897,6 +954,8 @@ bool wxTable::DeleteWhere(char *pWhereClause) // Build the SQL DELETE statement GetDeleteStmt(sqlStmt, DB_DEL_WHERE, pWhereClause); + pDb->WriteSqlLog(sqlStmt); + // Execute the SQL DELETE statement return(execDelete(sqlStmt)); @@ -910,6 +969,8 @@ bool wxTable::DeleteMatching(void) // Build the SQL DELETE statement GetDeleteStmt(sqlStmt, DB_DEL_MATCHING); + pDb->WriteSqlLog(sqlStmt); + // Execute the SQL DELETE statement return(execDelete(sqlStmt)); @@ -1061,10 +1122,10 @@ void wxTable::GetDeleteStmt(char *pSqlStmt, int typeOfDel, char *pWhereClause) * They are not included as part of the where clause. */ -void wxTable::GetWhereClause(char *pWhereClause, int typeOfWhere) +void wxTable::GetWhereClause(char *pWhereClause, int typeOfWhere, char *qualTableName) { bool moreThanOneColumn = FALSE; - wxString colValue; + char colValue[255]; // Loop through the columns building a where clause as you go for (int i = 0; i < noCols; i++) @@ -1082,30 +1143,35 @@ void wxTable::GetWhereClause(char *pWhereClause, int typeOfWhere) else moreThanOneColumn = TRUE; // Concatenate where phrase for the column + if (qualTableName && strlen(qualTableName)) + { + strcat(pWhereClause, qualTableName); + strcat(pWhereClause, "."); + } strcat(pWhereClause, colDefs[i].ColName); strcat(pWhereClause, " = "); switch(colDefs[i].SqlCtype) { case SQL_C_CHAR: - colValue.Printf("'%s'", (UCHAR FAR *) colDefs[i].PtrDataObj); + sprintf(colValue, "'%s'", (UCHAR FAR *) colDefs[i].PtrDataObj); break; case SQL_C_SSHORT: - colValue.Printf("%hi", *((SWORD *) colDefs[i].PtrDataObj)); + sprintf(colValue, "%hi", *((SWORD *) colDefs[i].PtrDataObj)); break; case SQL_C_USHORT: - colValue.Printf("%hu", *((UWORD *) colDefs[i].PtrDataObj)); + sprintf(colValue, "%hu", *((UWORD *) colDefs[i].PtrDataObj)); break; case SQL_C_SLONG: - colValue.Printf("%li", *((SDWORD *) colDefs[i].PtrDataObj)); + sprintf(colValue, "%li", *((SDWORD *) colDefs[i].PtrDataObj)); break; case SQL_C_ULONG: - colValue.Printf("%lu", *((UDWORD *) colDefs[i].PtrDataObj)); + sprintf(colValue, "%lu", *((UDWORD *) colDefs[i].PtrDataObj)); break; case SQL_C_FLOAT: - colValue.Printf("%.6f", *((SFLOAT *) colDefs[i].PtrDataObj)); + sprintf(colValue, "%.6f", *((SFLOAT *) colDefs[i].PtrDataObj)); break; case SQL_C_DOUBLE: - colValue.Printf("%.6f", *((SDOUBLE *) colDefs[i].PtrDataObj)); + sprintf(colValue, "%.6f", *((SDOUBLE *) colDefs[i].PtrDataObj)); break; } strcat(pWhereClause, colValue); @@ -1161,7 +1227,8 @@ bool wxTable::CanSelectForUpdate(void) bool wxTable::CanUpdByROWID(void) { -//@@@@@@glt - returning FALSE for testing purposes, as the ROWID is not getting updated correctly +//NOTE: Returning FALSE for now until this can be debugged, +// as the ROWID is not getting updated correctly return FALSE; if ((! strcmp(pDb->dbInf.dbmsName, "Oracle")) || (! strcmp(pDb->dbInf.dbmsName, "ORACLE"))) @@ -1345,6 +1412,9 @@ ULONG wxTable::Count(void) strcpy(sqlStmt, "SELECT COUNT(*) FROM "); strcat(sqlStmt, queryTableName); + if (from && strlen(from)) + strcat(sqlStmt, from); + // Add the where clause if one is provided if (where && strlen(where)) { @@ -1352,6 +1422,8 @@ ULONG wxTable::Count(void) strcat(sqlStmt, where); } + pDb->WriteSqlLog(sqlStmt); + // Execute the SQL statement if (SQLExecDirect(hstmtCount, (UCHAR FAR *) sqlStmt, SQL_NTS) != SQL_SUCCESS) { @@ -1410,7 +1482,8 @@ bool wxTable::Refresh(void) // based on the key fields. if (SQLGetData(hstmt, noCols+1, SQL_C_CHAR, rowid, ROWID_LEN, &cb) == SQL_SUCCESS) { - strcat(whereClause, "ROWID = '"); + strcat(whereClause, queryTableName); + strcat(whereClause, ".ROWID = '"); strcat(whereClause, rowid); strcat(whereClause, "'"); } @@ -1418,7 +1491,7 @@ bool wxTable::Refresh(void) // If unable to use the ROWID, build a where clause from the keyfields if (strlen(whereClause) == 0) - GetWhereClause(whereClause, DB_WHERE_KEYFIELDS); + GetWhereClause(whereClause, DB_WHERE_KEYFIELDS, queryTableName); // Requery the record where = whereClause; @@ -1442,4 +1515,5 @@ bool wxTable::Refresh(void) } // wxTable::Refresh() #endif - // wxUSE_ODBC + // wxUSE_ODBC + diff --git a/src/common/string.cpp b/src/common/string.cpp index dcd371e0d2..9d05639046 100644 --- a/src/common/string.cpp +++ b/src/common/string.cpp @@ -1075,6 +1075,19 @@ bool wxString::Matches(const char *pszMask) const return *pszTxt == '\0'; } +// Count the number of chars +int wxString::Freq(char ch) const +{ + int count = 0; + int len = Len(); + for (int i = 0; i < len; i++) + { + if (GetChar(i) == ch) + count ++; + } + return count; +} + // --------------------------------------------------------------------------- // standard C++ library string functions // --------------------------------------------------------------------------- -- 2.45.2