IMPLEMENT_APP(DatabaseDemoApp)
-extern wxChar ListDB_Selection[]; /* Used to return the first column value for the selected line from the listDB routines */
-extern wxChar ListDB_Selection2[]; /* Used to return the second column value for the selected line from the listDB routines */
-
-DatabaseDemoFrame *DemoFrame; /* Pointer to the main frame */
-
-/* Pointer to the main database connection used in the program. This
- * pointer would normally be used for doing things as database lookups
- * for user login names and passwords, getting workstation settings, etc.
- * ---> IMPORTANT <---
- *
- * For each database object created which uses this wxDb pointer
- * connection to the database, when a CommitTrans() or RollBackTrans()
- * will commit or rollback EVERY object which uses this wxDb pointer.
- *
- * To allow each table object (those derived from wxDbTable) to be
- * individually committed or rolled back, you MUST use a different
- * instance of wxDb in the constructor of the table. Doing so creates
- * more overhead, and will use more database connections (some DBs have
- * connection limits...), so use connections sparringly.
- *
- * It is recommended that one "main" database connection be created for
- * the entire program to use for READ-ONLY database accesses, but for each
- * table object which will do a CommitTrans() or RollbackTrans() that a
- * new wxDb object be created and used for it.
- */
-
-wxDb *READONLY_DB;
+extern wxChar ListDB_Selection[]; /* Used to return the first column value for the selected line from the listDB routines */
+extern wxChar ListDB_Selection2[]; /* Used to return the second column value for the selected line from the listDB routines */
const char *GetExtendedDBErrorMsg(wxDb *pDb, char *ErrFile, int ErrLine)
{
bool DatabaseDemoApp::OnInit()
{
+ DbConnectInf = NULL;
+
// Create the main frame window
DemoFrame = new DatabaseDemoFrame(NULL, wxT("wxWindows Database Demo"), wxPoint(50, 50), wxSize(537, 480));
menu_bar->Append(about_menu, wxT("&About"));
DemoFrame->SetMenuBar(menu_bar);
- // Initialize the ODBC Environment for Database Operations
- if (SQLAllocEnv(&DbConnectInf.Henv) != SQL_SUCCESS)
- {
- wxMessageBox(wxT("A problem occured while trying to get a connection to the data source"),wxT("DB CONNECTION ERROR"),wxOK | wxICON_EXCLAMATION);
- return NULL;
- }
-
params.ODBCSource[0] = 0;
params.UserName[0] = 0;
params.Password[0] = 0;
// Show the frame
DemoFrame->Show(TRUE);
+ ReadParamFile(params);
+
+ // Passing NULL for the SQL environment handle causes
+ // the wxDbConnectInf constructor to obtain a handle
+ // for you.
+ //
+ // WARNING: Be certain that you do not free this handle
+ // directly with SQLFreeEnv(). Use either the
+ // method ::FreeHenv() or delete the DbConnectInf.
+ DbConnectInf = new wxDbConnectInf(NULL, params.ODBCSource, params.UserName,
+ params.Password, params.DirPath);
+
+ if (!DbConnectInf || !DbConnectInf->GetHenv())
+ {
+ wxMessageBox(wxT("Unable to define data source connection info."), wxT("DB CONNECTION ERROR..."),wxOK | wxICON_EXCLAMATION);
+ delete DbConnectInf;
+ }
+
+
+ READONLY_DB = wxDbGetConnection(DbConnectInf);
+ if (READONLY_DB == 0)
+ {
+ wxMessageBox(wxT("Unable to connect to the data source.\n\nCheck the name of your data source to verify it has been correctly entered/spelled.\n\nWith some databases, the user name and password must\nbe created with full rights to the CONTACT table prior to making a connection\n(using tools provided by the database manufacturer)"), wxT("DB CONNECTION ERROR..."),wxOK | wxICON_EXCLAMATION);
+ DemoFrame->BuildParameterDialog(NULL);
+ DbConnectInf->SetDsn("");
+ DbConnectInf->SetUid("");
+ DbConnectInf->SetPassword("");
+ wxMessageBox(wxT("Now exiting program.\n\nRestart program to try any new settings."),wxT("Notice..."),wxOK | wxICON_INFORMATION);
+ return(FALSE);
+ }
+
+ DemoFrame->BuildEditorDialog();
+
+ // Show the frame
+ DemoFrame->Refresh();
+
+ return TRUE;
+} // DatabaseDemoApp::OnInit()
+
+
+bool DatabaseDemoApp::ReadParamFile(Cparameters ¶ms)
+{
FILE *paramFile;
- if ((paramFile = fopen(paramFilename, wxT("r"))) == NULL)
+ if ((paramFile = fopen(PARAM_FILENAME, wxT("r"))) == NULL)
{
wxString tStr;
- tStr.Printf(wxT("Unable to open the parameter file '%s' for reading.\n\nYou must specify the data source, user name, and\npassword that will be used and save those settings."),paramFilename);
+ tStr.Printf(wxT("Unable to open the parameter file '%s' for reading.\n\nYou must specify the data source, user name, and\npassword that will be used and save those settings."),PARAM_FILENAME);
wxMessageBox(tStr,wxT("File I/O Error..."),wxOK | wxICON_EXCLAMATION);
DemoFrame->BuildParameterDialog(NULL);
- if ((paramFile = fopen(paramFilename, wxT("r"))) == NULL)
+ if ((paramFile = fopen(PARAM_FILENAME, wxT("r"))) == NULL)
return FALSE;
}
fclose(paramFile);
- // Connect to datasource
- DbConnectInf.Dsn = params.ODBCSource; // ODBC data source name (created with ODBC Administrator under Win95/NT)
- DbConnectInf.Uid = params.UserName; // database username - must already exist in the data source
- DbConnectInf.AuthStr = params.Password; // password database username
- DbConnectInf.defaultDir = params.DirPath; // path where the table exists (needed for dBase)
+ return TRUE;
+} // DatabaseDemoApp::ReadParamFile()
- READONLY_DB = wxDbGetConnection(&DbConnectInf);
- if (READONLY_DB == 0)
+
+bool DatabaseDemoApp::WriteParamFile(Cparameters ¶ms)
+{
+ FILE *paramFile;
+ if ((paramFile = fopen(PARAM_FILENAME, wxT("wt"))) == NULL)
{
- wxMessageBox(wxT("Unable to connect to the data source.\n\nCheck the name of your data source to verify it has been correctly entered/spelled.\n\nWith some databases, the user name and password must\nbe created with full rights to the CONTACT table prior to making a connection\n(using tools provided by the database manufacturer)"), wxT("DB CONNECTION ERROR..."),wxOK | wxICON_EXCLAMATION);
- DemoFrame->BuildParameterDialog(NULL);
- DbConnectInf.Dsn.Empty();
- DbConnectInf.Uid.Empty();
- DbConnectInf.AuthStr.Empty();
- wxMessageBox(wxT("Now exiting program.\n\nRestart program to try any new settings."),wxT("Notice..."),wxOK | wxICON_INFORMATION);
- return(FALSE);
+ wxString tStr;
+ tStr.Printf(wxT("Unable to write/overwrite '%s'."),PARAM_FILENAME);
+ wxMessageBox(tStr,wxT("File I/O Error..."),wxOK | wxICON_EXCLAMATION);
+ return FALSE;
}
- DemoFrame->BuildEditorDialog();
-
- // Show the frame
- DemoFrame->Refresh();
+ fputs(wxGetApp().params.ODBCSource, paramFile);
+ fputc(wxT('\n'), paramFile);
+ fputs(wxGetApp().params.UserName, paramFile);
+ fputc(wxT('\n'), paramFile);
+ fputs(wxGetApp().params.Password, paramFile);
+ fputc(wxT('\n'), paramFile);
+ fputs(wxGetApp().params.DirPath, paramFile);
+ fputc(wxT('\n'), paramFile);
+ fclose(paramFile);
return TRUE;
-} // DatabaseDemoApp::OnInit()
+} // DatabaseDemoApp::WriteParamFile()
+
+
+void DatabaseDemoApp::CreateDataTable(bool recreate)
+{
+ bool Ok = TRUE;
+ if (recreate)
+ Ok = (wxMessageBox(wxT("Any data currently residing in the table will be erased.\n\nAre you sure?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
+
+ if (!Ok)
+ return;
+
+ wxBeginBusyCursor();
+
+ bool success = TRUE;
+
+ // Use a temporary instance of a new Ccontact table object
+ // for creating the table within the datasource.
+ Ccontact *Contact = new Ccontact();
+
+ if (!Contact)
+ {
+ wxEndBusyCursor();
+ wxMessageBox(wxT("Error allocating memory for 'Ccontact'object.\n\nTable was not created."),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
+ return;
+ }
+
+ if (!Contact->CreateTable(recreate))
+ {
+ wxEndBusyCursor();
+ wxString tStr;
+ tStr = wxT("Error creating CONTACTS table.\nTable was not created.\n\n");
+ tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
+ wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
+ success = FALSE;
+ }
+ else
+ {
+ if (!Contact->CreateIndexes())
+ {
+ wxEndBusyCursor();
+ wxString tStr;
+ tStr = wxT("Error creating CONTACTS indexes.\nIndexes will be unavailable.\n\n");
+ tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
+ wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
+ success = FALSE;
+ }
+ }
+ while (wxIsBusy())
+ wxEndBusyCursor();
+
+ delete Contact;
+ Contact = NULL;
+
+ if (success)
+ wxMessageBox(wxT("Table and index(es) were successfully created."),wxT("Notice..."),wxOK | wxICON_INFORMATION);
+} // DatabaseDemoApp::CreateDataTable()
BEGIN_EVENT_TABLE(DatabaseDemoFrame, wxFrame)
void DatabaseDemoFrame::OnCreate(wxCommandEvent& event)
{
- CreateDataTable(FALSE);
+ wxGetApp().CreateDataTable(FALSE);
} // DatabaseDemoFrame::OnCreate()
void DatabaseDemoFrame::OnRecreateTable(wxCommandEvent& event)
{
- CreateDataTable(TRUE);
+ wxGetApp().CreateDataTable(TRUE);
} // DatabaseDemoFrame::OnRecreate()
} // DatabaseDemoFrame::OnAbout()
+// Put any additional checking necessary to make certain it is alright
+// to close the program here that is not done elsewhere
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
-
// Clean up time
if (pEditorDlg && pEditorDlg->Close())
pEditorDlg = NULL;
// previously cached.
wxDbCloseConnections();
- // Cleans up the environment space allocated for the SQL/ODBC connection handle
- SQLFreeEnv(DbConnectInf.Henv);
+ // Deletion of the wxDbConnectInf instance must be the LAST thing done that
+ // has anything to do with the database. Deleting this before disconnecting,
+ // freeing/closing connections, etc will result in a crash!
+ delete wxGetApp().DbConnectInf;
+ wxGetApp().DbConnectInf = NULL;
this->Destroy();
} // DatabaseDemoFrame::OnCloseWindow()
-void DatabaseDemoFrame::CreateDataTable(bool recreate)
-{
- bool Ok = TRUE;
- if (recreate)
- Ok = (wxMessageBox(wxT("Any data currently residing in the table will be erased.\n\nAre you sure?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
-
- if (!Ok)
- return;
-
- wxBeginBusyCursor();
-
- bool success = TRUE;
-
- Ccontact *Contact = new Ccontact();
- if (!Contact)
- {
- wxEndBusyCursor();
- wxMessageBox(wxT("Error allocating memory for 'Ccontact'object.\n\nTable was not created."),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
- return;
- }
-
- if (!Contact->CreateTable(recreate))
- {
- wxEndBusyCursor();
- wxString tStr;
- tStr = wxT("Error creating CONTACTS table.\nTable was not created.\n\n");
- tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
- wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
- success = FALSE;
- }
- else
- {
- if (!Contact->CreateIndexes())
- {
- wxEndBusyCursor();
- wxString tStr;
- tStr = wxT("Error creating CONTACTS indexes.\nIndexes will be unavailable.\n\n");
- tStr += GetExtendedDBErrorMsg(Contact->GetDb(),__FILE__,__LINE__);
- wxMessageBox(tStr,wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
- success = FALSE;
- }
- }
- while (wxIsBusy())
- wxEndBusyCursor();
-
- delete Contact;
- Contact = NULL;
-
- if (success)
- wxMessageBox(wxT("Table and index(es) were successfully created."),wxT("Notice..."),wxOK | wxICON_INFORMATION);
-} // DatabaseDemoFrame::CreateDataTable()
-
-
void DatabaseDemoFrame::BuildEditorDialog()
{
pEditorDlg = NULL;
pEditorDlg->Close();
pEditorDlg = NULL;
wxMessageBox(wxT("Unable to initialize the editor dialog for some reason"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
- DemoFrame->Close();
+ Close();
}
}
else
{
wxMessageBox(wxT("Unable to create the editor dialog for some reason"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
- DemoFrame->Close();
+ Close();
}
} // DatabaseDemoFrame::BuildEditorDialog()
* or creating a table objects which use the same pDb, know that all the objects
* will be committed or rolled back when any of the objects has this function call made.
*/
-Ccontact::Ccontact (wxDb *pwxDb) : wxDbTable(pwxDb ? pwxDb : wxDbGetConnection(&DbConnectInf), CONTACT_TABLE_NAME,CONTACT_NO_COLS, wxT(""), !wxDB_QUERY_ONLY, DbConnectInf.defaultDir)
+Ccontact::Ccontact (wxDb *pwxDb) : wxDbTable(pwxDb ? pwxDb : wxDbGetConnection(wxGetApp().DbConnectInf),
+ CONTACT_TABLE_NAME, CONTACT_NO_COLS, wxT(""),
+ !wxDB_QUERY_ONLY, wxGetApp().DbConnectInf->GetDefaultDir())
{
// This is used to represent whether the database connection should be released
// when this instance of the object is deleted. If using the same connection
* 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(wxChar *name)
+bool Ccontact::FetchByName(const wxString &name)
{
whereStr.Printf(wxT("NAME = '%s'"),name);
SetWhereClause(whereStr.c_str());
else
{
// Requery previous record
- if (Contact->FetchByName((wxChar*) (const wxChar*) saveName))
+ if (Contact->FetchByName(saveName))
{
PutData();
SetMode(mView);
if (Contact->GetDb()->Dbms() != dbmsPOSTGRES && Contact->GetDb()->Dbms() != dbmsMY_SQL)
{
- Contact->whereStr = wxT("NAME = (SELECT MIN(NAME) FROM ");
- Contact->whereStr += CONTACT_TABLE_NAME;
- Contact->whereStr += wxT(")");
+ Contact->whereStr = wxT("NAME = (SELECT MIN(NAME) FROM ");
+ Contact->whereStr += CONTACT_TABLE_NAME;
+ Contact->whereStr += wxT(")");
}
Contact->SetWhereClause(Contact->whereStr.c_str());
if (widgetName == pNameListBtn->GetName())
{
- new ClookUpDlg(/* wxWindow *parent */ this,
+ new ClookUpDlg(/* wxWindow *parent */ this,
/* wxChar *windowTitle */ wxT("Select contact name"),
/* wxChar *tableName */ (wxChar *) CONTACT_TABLE_NAME,
/* wxChar *dispCol1 */ wxT("NAME"),
/* wxChar *dispCol2 */ wxT("JOINDATE"),
/* wxChar *where */ wxT(""),
/* wxChar *orderBy */ wxT("NAME"),
- /* bool distinctValues */ TRUE);
+ /* wxDb *pDb */ wxGetApp().READONLY_DB,
+ /* const wxString &defDir */ wxGetApp().DbConnectInf->GetDefaultDir(),
+ /* bool distinctValues */ TRUE);
if (ListDB_Selection && wxStrlen(ListDB_Selection))
{
wxString w = wxT("NAME = '");
w += ListDB_Selection;
w += wxT("'");
- GetRec((wxChar*) (const wxChar*) w);
+ GetRec(w);
}
return;
// Check if the table exists or not. If it doesn't, ask the user if they want to
// create the table. Continue trying to create the table until it exists, or user aborts
- while (!Contact->GetDb()->TableExists((wxChar *)CONTACT_TABLE_NAME,DbConnectInf.Uid,DbConnectInf.defaultDir))
+ while (!Contact->GetDb()->TableExists((wxChar *)CONTACT_TABLE_NAME,
+ wxGetApp().DbConnectInf->GetUserID(),
+ wxGetApp().DbConnectInf->GetDefaultDir()))
{
wxString tStr;
tStr.Printf(wxT("Unable to open the table '%s'.\n\nTable may need to be created...?\n\n"),CONTACT_TABLE_NAME);
return FALSE;
}
else
- DemoFrame->CreateDataTable(TRUE);
+ wxGetApp().CreateDataTable(TRUE);
}
// Tables must be "opened" before anything other than creating/deleting table can be done
// in the 2.4 release. This check will determine whether the open failing was due
// to the table not existing, or the users privileges being insufficient to
// open the table.
- if (!Contact->GetDb()->TablePrivileges(CONTACT_TABLE_NAME,wxT("SELECT"),Contact->GetDb()->GetUsername(),Contact->GetDb()->GetUsername(),DbConnectInf.defaultDir))
+ if (!Contact->GetDb()->TablePrivileges(CONTACT_TABLE_NAME,wxT("SELECT"),Contact->GetDb()->GetUsername(),Contact->GetDb()->GetUsername(),DbConnectInf->GetDefaultDir()))
{
wxString tStr;
tStr.Printf(wxT("Unable to open the table '%s'.\n\n"),CONTACT_TABLE_NAME);
}
else
#endif
- if (Contact->GetDb()->TableExists(CONTACT_TABLE_NAME,Contact->GetDb()->GetUsername(),DbConnectInf.defaultDir))
+ if (Contact->GetDb()->TableExists(CONTACT_TABLE_NAME, Contact->GetDb()->GetUsername(),
+ wxGetApp().DbConnectInf->GetDefaultDir()))
{
wxString tStr;
tStr.Printf(wxT("Unable to open the table '%s'.\n\n"),CONTACT_TABLE_NAME);
if (Contact->GetDb()->Dbms() != dbmsPOSTGRES && Contact->GetDb()->Dbms() != dbmsMY_SQL)
{
- Contact->whereStr.sprintf(wxT("NAME = (SELECT MIN(NAME) FROM %s)"),Contact->GetTableName());
+ Contact->whereStr.Printf(wxT("NAME = (SELECT MIN(NAME) FROM %s)"),Contact->GetTableName());
// NOTE: (const wxChar*) returns a pointer which may not be valid later, so this is short term use only
- Contact->SetWhereClause(Contact->whereStr.c_str());
+ Contact->SetWhereClause(Contact->whereStr);
}
else
Contact->SetWhereClause(wxT(""));
return FALSE;
}
- bool invalid = FALSE;
+ bool invalid = FALSE;
int mm,dd,yyyy;
int first, second;
}
else // mode == mEdit
{
- if (!Contact->Update())
+ Contact->whereStr.Printf("NAME = '%s'",saveName.c_str());
+ if (!Contact->UpdateWhere(Contact->whereStr))
{
wxString tStr;
tStr = wxT("Database update failed\n\n");
}
w += wxT(")");
- return(GetRec((wxChar*) (const wxChar*) w));
+ return(GetRec(w));
} // CeditorDlg::GetNextRec()
w += wxT(")");
- return(GetRec((wxChar*) (const wxChar*)w));
+ return(GetRec(w));
} // CeditorDlg::GetPrevRec()
* This function is here to avoid duplicating this same code in both the
* GetPrevRec() and GetNextRec() functions
*/
-bool CeditorDlg::GetRec(wxChar *whereStr)
+bool CeditorDlg::GetRec(const wxString &whereStr)
{
Contact->SetWhereClause(whereStr);
Contact->SetOrderByClause(wxT("NAME"));
bool CparameterDlg::Save()
{
- Cparameters saveParams = wxGetApp().params;
+ // Copy the current params in case user cancels changing
+ // the params, so that we can reset them.
if (!GetData())
{
- wxGetApp().params = saveParams;
- return FALSE;
- }
-
- FILE *paramFile;
- if ((paramFile = fopen(paramFilename, wxT("wt"))) == NULL)
- {
- wxString tStr;
- tStr.Printf(wxT("Unable to write/overwrite '%s'."),paramFilename);
- wxMessageBox(tStr,wxT("File I/O Error..."),wxOK | wxICON_EXCLAMATION);
+ wxGetApp().params = savedParamSettings;
return FALSE;
}
- fputs(wxGetApp().params.ODBCSource, paramFile);
- fputc(wxT('\n'), paramFile);
- fputs(wxGetApp().params.UserName, paramFile);
- fputc(wxT('\n'), paramFile);
- fputs(wxGetApp().params.Password, paramFile);
- fputc(wxT('\n'), paramFile);
- fputs(wxGetApp().params.DirPath, paramFile);
- fputc(wxT('\n'), paramFile);
- fclose(paramFile);
+ wxGetApp().WriteParamFile(wxGetApp().params);
return TRUE;
} // CparameterDlg::Save()
wxChar DsDesc[255];
wxStringList strList;
- while (wxDbGetDataSource(DbConnectInf.Henv, Dsn, SQL_MAX_DSN_LENGTH+1, DsDesc, 255))
+ while (wxDbGetDataSource(wxGetApp().DbConnectInf->GetHenv(), Dsn,
+ SQL_MAX_DSN_LENGTH+1, DsDesc, 255))
strList.Add(Dsn);
strList.Sort();
if (dbTable == 0) // wxDbTable object needs to be created and opened
{
- if (!(dbTable = new wxDbTable(pDB, masterTableName, 0, wxT(""), !wxDB_QUERY_ONLY, DbConnectInf.defaultDir)))
+ if (!(dbTable = new wxDbTable(pDB, masterTableName, 0, wxT(""),
+ !wxDB_QUERY_ONLY,
+ wxGetApp().DbConnectInf->GetDefaultDir())))
{
wxMessageBox(wxT("Memory allocation failed creating a wxDbTable object."),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
return;
// this seems to be missing, Robert Roebling (?)
#ifndef MAX_PATH
-#define MAX_PATH 200
+ #if defined(__WXMAC__)
+ #define MAX_PATH 260 /* max. length of full pathname */
+ #else /* _MAC */
+ #define MAX_PATH 256 /* max. length of full pathname */
+ #endif
#endif
// Name of the table to be created/opened
-const wxChar CONTACT_TABLE_NAME[] = "contacts";
+const wxChar CONTACT_TABLE_NAME[] = "contacts";
-// Nuber of columns in the above table
-const int CONTACT_NO_COLS = 12; // 0-11
+// Number of columns in the CONTACT table
+const int CONTACT_NO_COLS = 12; // 0-11
+
+const wxChar PARAM_FILENAME[] = "dbtest.cfg";
-// Global structure for holding ODBC connection information
-struct wxDbConnectInf DbConnectInf;
enum Language {langENGLISH, langFRENCH, langGERMAN, langSPANISH, langOTHER};
class CeditorDlg;
class CparameterDlg;
-const wxChar paramFilename[] = "dbtest.cfg";
-
-
-/*
- * This class contains the actual data members that are used for transferring
- * data back and forth from the database to the program.
- *
- * NOTE: The object described in this class is just for example purposes, and has no
- * real meaning other than to show each type of field being used by the database
- */
+//
+// This class contains the actual data members that are used for transferring
+// data back and forth from the database to the program.
+//
+// NOTE: The object described in this class is just for example purposes, and has no
+// real meaning other than to show each type of field being used by the database
+//
class CstructContact : public wxObject
{
public:
- wxChar Name[50+1]; // Contact's name
- wxChar Addr1[50+1];
- wxChar Addr2[50+1];
- wxChar City[25+1];
- wxChar State[25+1];
- wxChar PostalCode[15+1];
- wxChar Country[20+1];
+ wxChar Name[50+1]; // Contact's name
+ wxChar Addr1[50+1];
+ wxChar Addr2[50+1];
+ wxChar City[25+1];
+ wxChar State[25+1];
+ wxChar PostalCode[15+1];
+ wxChar Country[20+1];
TIMESTAMP_STRUCT JoinDate; // Date on which this person joined the wxWindows project
Language NativeLanguage; // Enumerated type indicating person's native language
bool IsDeveloper; // Is this person a developer for wxWindows, or just a subscriber
//
-// NOTE: Ccontact inherits wxDbTable, which gives access to all the database functionality
+// The Ccontact class derives from wxDbTable, so we have access to all
+// of the database table functions and the local memory variables that
+// the database classes will store the data into (and read the data from)
+// all combined in this one class.
//
class Ccontact : public wxDbTable, public CstructContact
{
private:
+ // Used to keep track of whether this class had a wxDb instance
+ // passed in to it or not. If an existing wxDb instance was not
+ // passed in at Ccontact creation time, then when the Ccontact
+ // instance is deleted, the connection will be freed as Ccontact
+ // created its own connection when it was created.
bool freeDbConn;
+
+ // Calls wxDbTable::SetColDefs() once for each column that is
+ // to be associated with some member variable for use with
+ // this database object.
void SetupColumns();
public:
+ // Used in places where we need to construct a WHERE clause to
+ // be passed to the SetWhereClause() function. From example,
+ // where building the WHERE clause requires using ::Printf()
+ // to build the string.
wxString whereStr;
- wxString qryWhereStr; // Where string returned from the query dialog
+
+ // WHERE string returned from the query dialog
+ wxString qryWhereStr;
Ccontact(wxDb *pwxDb=NULL);
~Ccontact();
void Initialize();
+
+ // Contains all the index definitions and calls to wxDbTable::CreateIndex()
+ // required to create all the indexes we wish to define for this table.
bool CreateIndexes(void);
- bool FetchByName(wxChar *name);
+
+ // Since we do not wish to have duplicate code blocks all over our program
+ // for a common query/fetch that we will need to do in many places, we
+ // include this member function that does it all for us in one place.
+ bool FetchByName(const wxString &name);
}; // Ccontact class definition
typedef struct Cparameters
{
- // The length of these strings were arbitrarily picked, and are
- // dependent on the OS and database engine you will be using.
- wxChar ODBCSource[100+1];
- wxChar UserName[25+1];
- wxChar Password[25+1];
+ wxChar ODBCSource[SQL_MAX_DSN_LENGTH+1];
+ wxChar UserName[SQL_MAX_USER_NAME_LEN+1];
+ wxChar Password[SQL_MAX_AUTHSTR_LEN+1];
wxChar DirPath[MAX_PATH+1];
} Cparameters;
-// Define a new application type
-class DatabaseDemoApp: public wxApp
-{
- public:
- Cparameters params;
- bool OnInit();
-}; // DatabaseDemoApp
-
-DECLARE_APP(DatabaseDemoApp)
-
// Define a new frame type
class DatabaseDemoFrame: public wxFrame
{
void OnEditParameters(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
- void CreateDataTable(bool recreate);
void BuildEditorDialog();
void BuildParameterDialog(wxWindow *parent);
}; // DatabaseDemoFrame
+// Define a new application type
+class DatabaseDemoApp: public wxApp
+{
+ public:
+ // These are the parameters that are stored in the "PARAM_FILENAME" file
+ // that are read in at startup of the program that indicate the connection
+ // parameters to be used for connecting to the ODBC data source.
+ Cparameters params;
+
+ // Pointer to the main frame used by the App
+ DatabaseDemoFrame *DemoFrame;
+
+ // Pointer to the main database connection used in the program. This
+ // pointer would normally be used for doing things as database lookups
+ // for user login names and passwords, getting workstation settings, etc.
+ //
+ // ---> IMPORTANT <---
+ //
+ // For each database object created which uses this wxDb pointer
+ // connection to the database, when a CommitTrans() or RollBackTrans()
+ // will commit or rollback EVERY object which uses this wxDb pointer.
+ //
+ // To allow each table object (those derived from wxDbTable) to be
+ // individually committed or rolled back, you MUST use a different
+ // instance of wxDb in the constructor of the table. Doing so creates
+ // more overhead, and will use more database connections (some DBs have
+ // connection limits...), so use connections sparringly.
+ //
+ // It is recommended that one "main" database connection be created for
+ // the entire program to use for READ-ONLY database accesses, but for each
+ // table object which will do a CommitTrans() or RollbackTrans() that a
+ // new wxDb object be created and used for it.
+ wxDb *READONLY_DB;
+
+ // Contains the ODBC connection information used by
+ // all database connections
+ wxDbConnectInf *DbConnectInf;
+
+ bool OnInit();
+
+ // Read/Write ODBC connection parameters to the "PARAM_FILENAME" file
+ bool ReadParamFile(Cparameters ¶ms);
+ bool WriteParamFile(Cparameters ¶ms);
+
+ void CreateDataTable(bool recreate);
+}; // DatabaseDemoApp
+
+
+DECLARE_APP(DatabaseDemoApp)
+
// *************************** CeditorDlg ***************************
class CeditorDlg : public wxPanel
{
private:
+ // Used to indicate whether all of the widget pointers (defined
+ // below) have been initialized to point to the memory for
+ // the named widget. Used as a safeguard from using the widget
+ // before it has been initialized.
bool widgetPtrsSet;
+
+ // Used when the EDIT button has been pressed to maintain the
+ // original name that was displayed in the editor before the
+ // EDIT button was pressed, so that if CANCEL is pressed, a
+ // FetchByName() can be done to retrieve the original data
+ // to repopulate the dialog.
wxString saveName;
// Pointers to all widgets on the dialog
wxStaticText *pNativeLangMsg;
public:
+ // Indicates if the editor dialog has been initialized yet (used to
+ // help trap if the Initialize() function failed to load all required
+ // resources or not.
bool initialized;
+
enum DialogModes mode;
- Ccontact *Contact; // this is the table object that will be being manipulated
+
+ // Pointer to the wxDbTable instance that is used to manipulate
+ // the data in memory and in the database
+ Ccontact *Contact;
CeditorDlg(wxWindow *parent);
void OnActivate(bool) {}; // necessary for hot keys
bool Initialize();
+
+ // Sets wxStaticText fields to be editable or not depending
+ // on the current value of 'mode'
void FieldsEditable();
+
+ // Sets the editor mode, determining what state widgets
+ // on the dialog are to be in based on the operation
+ // being performed.
void SetMode(enum DialogModes m);
+
+ // Update/Retrieve data from the widgets on the dialog
bool PutData();
bool GetData();
+
+ // Inserts/updates the database with the current data
+ // retrieved from the editor dialog
bool Save();
+
+ // Database functions for changing the data that is to
+ // be displayed on the dialog. GetNextRec()/GetPrevRec()
+ // provide database independent methods that do not require
+ // backward scrolling cursors to obtain the record that
+ // is prior to the current record in the search sequence.
bool GetNextRec();
bool GetPrevRec();
- bool GetRec(wxChar *whereStr);
+ bool GetRec(const wxString &whereStr);
DECLARE_EVENT_TABLE()
}; // CeditorDlg
class CparameterDlg : public wxDialog
{
private:
+ // Used to indicate whether all of the widget pointers (defined
+ // below) have been initialized to point to the memory for
+ // the named widget. Used as a safeguard from using the widget
+ // before it has been initialized.
bool widgetPtrsSet;
+
enum DialogModes mode;
+
+ // Have the parameters been saved yet, or do they
+ // need to be saved to update the params on disk
bool saved;
+
+ // Original params
Cparameters savedParamSettings;
// Pointers to all widgets on the dialog
void OnCommand(wxWindow& win, wxCommandEvent& event);
void OnActivate(bool) {}; // necessary for hot keys
+ // Update/Retrieve data from the widgets on the dialog
bool PutData();
bool GetData();
+
+ // Stores the defined parameter for connecting to the selected ODBC
+ // data source to the config file name in "PARAM_FILENAME"
bool Save();
+
+ // Populates the 'pParamODBCSourceList' listbox with the names of all
+ // ODBC datasource defined for use at the current workstation
void FillDataSourceList();
DECLARE_EVENT_TABLE()
class CqueryDlg : public wxDialog
{
private:
- wxDbColInf *colInf; // Column inf. returned by db->GetColumns()
- wxDbTable *dbTable;
- wxChar *masterTableName;
- wxChar *pWhere; // A pointer to the storage for the resulting where clause
+ wxDbColInf *colInf; // Column inf. returned by db->GetColumns()
+ wxDbTable *dbTable; // generic wxDbTable object for attaching to the table to query
+ wxChar *masterTableName; // Name of the table that 'dbTable' will be associated with
+ wxChar *pWhere; // A pointer to the storage for the resulting where clause
wxDb *pDB;
public:
+ // Used to indicate whether all of the widget pointers (defined
+ // below) have been initialized to point to the memory for
+ // the named widget. Used as a safeguard from using the widget
+ // before it has been initialized.
bool widgetPtrsSet;
// Widget pointers
extern wxDbList WXDLLEXPORT *PtrBegDbList; /* from db.cpp, used in getting back error results from db connections */
#include "listdb.h"
-
-// Global structure for holding ODBC connection information
-extern wxDbConnectInf DbConnectInf;
-
-// Global database connection
-extern wxDb *READONLY_DB;
-
+//#include "dbtest.h"
// Used for passing the selected listbox selection back to the calling
// routine. This variable must be declared as 'extern' in the calling
const int LISTDB_NO_SPACES_BETWEEN_COLS = 3;
+extern wxApp *DatabaseDemoApp;
+
/*
* This function will return the exact string(s) from the database engine
// Clookup constructor
-Clookup::Clookup(wxChar *tblName, wxChar *colName) :
- wxDbTable(READONLY_DB, tblName, 1, wxT(""), !wxDB_QUERY_ONLY, DbConnectInf.defaultDir)
+Clookup::Clookup(wxChar *tblName, wxChar *colName, wxDb *pDb, const wxString &defDir)
+ : wxDbTable(pDb, tblName, 1, wxT(""), !wxDB_QUERY_ONLY,
+ defDir)
{
SetColDefs (0, colName, DB_DATA_TYPE_VARCHAR, lookupCol, SQL_C_CHAR, LOOKUP_COL_LEN+1, FALSE, FALSE);
// Clookup2 constructor
-Clookup2::Clookup2(wxChar *tblName, wxChar *colName1, wxChar *colName2, wxDb *pDb)
- : wxDbTable(pDb, tblName, (1 + (wxStrlen(colName2) > 0)), NULL, !wxDB_QUERY_ONLY, DbConnectInf.defaultDir)
+Clookup2::Clookup2(wxChar *tblName, wxChar *colName1, wxChar *colName2,
+ wxDb *pDb, const wxString &defDir)
+ : wxDbTable(pDb, tblName, (1 + (wxStrlen(colName2) > 0)), wxT(""),
+ !wxDB_QUERY_ONLY, defDir)
{
+ wxASSERT(pDb);
+ wxASSERT(tblName);
+ wxASSERT(colName1);
+ wxASSERT(colName2);
+
int i = 0;
SetColDefs (i, colName1, DB_DATA_TYPE_VARCHAR, lookupCol1, SQL_C_CHAR, LOOKUP_COL_LEN+1, FALSE, FALSE);
BEGIN_EVENT_TABLE(ClookUpDlg, wxDialog)
-// EVT_LISTBOX(LOOKUP_DIALOG_SELECT, ClookUpDlg::SelectCallback)
EVT_BUTTON(LOOKUP_DIALOG_OK, ClookUpDlg::OnButton)
EVT_BUTTON(LOOKUP_DIALOG_CANCEL, ClookUpDlg::OnButton)
EVT_CLOSE(ClookUpDlg::OnClose)
END_EVENT_TABLE()
+
// This is a generic lookup constructor that will work with any table and any column
-ClookUpDlg::ClookUpDlg(wxWindow *parent, wxChar *windowTitle, wxChar *tableName, wxChar *colName,
- wxChar *where, wxChar *orderBy) : wxDialog (parent, LOOKUP_DIALOG, wxT("Select..."), wxPoint(-1, -1), wxSize(400, 290))
+ClookUpDlg::ClookUpDlg(wxWindow *parent, wxChar *windowTitle, wxChar *tableName,
+ wxChar *colName, wxChar *where, wxChar *orderBy,
+ wxDb *pDb, const wxString &defDir)
+ : wxDialog (parent, LOOKUP_DIALOG, wxT("Select..."), wxPoint(-1, -1), wxSize(400, 290))
{
wxBeginBusyCursor();
noDisplayCols = 1;
col1Len = 0;
- pLookUpSelectList = new wxListBox(this, LOOKUP_DIALOG_SELECT, wxPoint( 5, 15), wxSize(384, 195), 0, 0, wxLB_SINGLE|wxLB_ALWAYS_SB, wxDefaultValidator, wxT("LookUpSelectList"));
- pLookUpOkBtn = new wxButton(this, LOOKUP_DIALOG_OK, wxT("&Ok"), wxPoint(113, 222), wxSize( 70, 35), 0, wxDefaultValidator, wxT("LookUpOkBtn"));
- pLookUpCancelBtn = new wxButton(this, LOOKUP_DIALOG_CANCEL, wxT("C&ancel"), wxPoint(212, 222), wxSize( 70, 35), 0, wxDefaultValidator, wxT("LookUpCancelBtn"));
+ pLookUpSelectList = new wxListBox(this, LOOKUP_DIALOG_SELECT, wxPoint( 5, 15), wxSize(384, 195), 0, 0, wxLB_SINGLE|wxLB_ALWAYS_SB, wxDefaultValidator, wxT("LookUpSelectList"));
+ pLookUpOkBtn = new wxButton(this, LOOKUP_DIALOG_OK, wxT("&Ok"), wxPoint(113, 222), wxSize( 70, 35), 0, wxDefaultValidator, wxT("LookUpOkBtn"));
+ pLookUpCancelBtn = new wxButton(this, LOOKUP_DIALOG_CANCEL, wxT("C&ancel"), wxPoint(212, 222), wxSize( 70, 35), 0, wxDefaultValidator, wxT("LookUpCancelBtn"));
widgetPtrsSet = TRUE;
// Query the lookup table and display the result set
- if (!(lookup = new Clookup(tableName, colName)))
+ if (!(lookup = new Clookup(tableName, colName, pDb, defDir)))
{
wxMessageBox(wxT("Error allocating memory for 'Clookup'object."),wxT("Error..."));
Close();
// since it cannot be derived when you query using your own sql statement.
//
// The optional database connection can be used if you'd like the lookup class
-// to use a database pointer other than the global READONLY_DB. This is necessary if
+// to use a database pointer other than wxGetApp().READONLY_DB. This is necessary if
// records are being saved, but not committed to the db, yet should be included
// in the lookup window.
//
ClookUpDlg::ClookUpDlg(wxWindow *parent, wxChar *windowTitle, wxChar *tableName,
- wxChar *dispCol1, wxChar *dispCol2, wxChar *where, wxChar *orderBy, bool distinctValues,
- wxChar *selectStmt, int maxLenCol1, wxDb *pDb, bool allowOk) : wxDialog (parent, LOOKUP_DIALOG, wxT("Select..."), wxPoint(-1, -1), wxSize(400, 290))
+ wxChar *dispCol1, wxChar *dispCol2, wxChar *where, wxChar *orderBy,
+ wxDb *pDb, const wxString &defDir, bool distinctValues,
+ wxChar *selectStmt, int maxLenCol1, bool allowOk)
+ : wxDialog (parent, LOOKUP_DIALOG, wxT("Select..."), wxPoint(-1, -1), wxSize(400, 290))
{
wxBeginBusyCursor();
widgetPtrsSet = TRUE;
// Query the lookup table and display the result set
- if (!(lookup2 = new Clookup2(tableName, dispCol1, dispCol2, pDb)))
+ if (!(lookup2 = new Clookup2(tableName, dispCol1, dispCol2, pDb, defDir)))
{
wxMessageBox(wxT("Error allocating memory for 'Clookup2' object."),wxT("Error..."));
Close();
const int LOOKUP_COL_LEN = 250;
-// Global database connection
-extern wxDb *READONLY_DB;
-
// Clookup class
class Clookup : public wxDbTable
{
wxChar lookupCol[LOOKUP_COL_LEN+1];
- Clookup(wxChar *tblName, wxChar *colName);
+ Clookup(wxChar *tblName, wxChar *colName, wxDb *pDb, const wxString &defDir="");
}; // Clookup
+
// Clookup2 class
class Clookup2 : public wxDbTable
{
wxChar lookupCol1[LOOKUP_COL_LEN+1];
wxChar lookupCol2[LOOKUP_COL_LEN+1];
- Clookup2(wxChar *tblName, wxChar *colName1, wxChar *colName2, wxDb *pDb);
+ Clookup2(wxChar *tblName, wxChar *colName1, wxChar *colName2, wxDb *pDb, const wxString &defDir="");
}; // Clookup2
+
+// ClookUpDlg class
class ClookUpDlg : public wxDialog
{
private:
wxChar *tableName,
wxChar *colName,
wxChar *where,
- wxChar *orderBy);
+ wxChar *orderBy,
+ wxDb *pDb,
+ const wxString &defDir);
//
// This is a generic lookup constructor that will work with any table and any column.
// It extends the capabilites of the lookup dialog in the following ways:
//
// 1) 2 columns rather than one
- // 2) The ability to select DISTINCT column values
+ // 2) The ability to select DISTINCT column values
//
// Only set distinctValues equal to true if necessary. In many cases, the constraints
// of the index(es) will enforce this uniqueness. Selecting DISTINCT does require
// since it cannot be derived when you query using your own sql statement.
//
// The optional database connection can be used if you'd like the lookup class
- // to use a database pointer other than the global READONLY_DB. This is necessary if
- // records are being saved, but not committed to the db, yet should be included
+ // to use a database pointer other than the READONLY_DB of the app. This is necessary
+ // if records are being saved, but not committed to the db, yet should be included
// in the lookup window.
//
ClookUpDlg(wxWindow *parent,
wxChar *dispCol2, // Optional
wxChar *where,
wxChar *orderBy,
+ wxDb *pDb, // Database connection pointer
+ const wxString &defDir,
bool distinctValues, // e.g. SELECT DISTINCT ...
wxChar *selectStmt = 0, // If you wish to query by SQLstmt (complicated lookups)
int maxLenCol1 = 0, // Mandatory if querying by SQLstmt
- wxDb *pDb = READONLY_DB, // Database connection pointer
bool allowOk = TRUE); // is the OK button enabled
void OnButton( wxCommandEvent &event );
void OnActivate(bool) {}; // necessary for hot keys
DECLARE_EVENT_TABLE()
-};
+}; // class ClookUpDlg
#define LOOKUP_DIALOG 500