1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxWindows database demo app
4 // Author: George Tasker
8 // Copyright: (c) 1998 Remstar International, Inc.
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
15 This sample program demonstrates the cross-platform ODBC database classes
16 donated by the development team at Remstar International.
18 The table this sample is based on is developer contact table, and shows
19 some of the simple uses of the database classes wxDb and wxDbTable.
25 #pragma implementation "dbtest.h"
28 #include "wx/wxprec.h"
42 #include <stdio.h> /* Included strictly for reading the text file with the database parameters */
44 #include <wx/db.h> /* Required in the file which will get the data source connection */
45 #include <wx/dbtable.h> /* Has the wxDbTable object from which all data objects will inherit their data table functionality */
47 extern wxDbList WXDLLEXPORT
*PtrBegDbList
; /* from db.cpp, used in getting back error results from db connections */
49 #include "dbtest.h" /* Header file for this demonstration program */
50 #include "listdb.h" /* Code to support the "Lookup" button on the editor dialog */
52 IMPLEMENT_APP(DatabaseDemoApp
)
54 extern char ListDB_Selection
[]; /* Used to return the first column value for the selected line from the listDB routines */
55 extern char ListDB_Selection2
[]; /* Used to return the second column value for the selected line from the listDB routines */
57 DatabaseDemoFrame
*DemoFrame
; /* Pointer to the main frame */
59 /* Pointer to the main database connection used in the program. This
60 * pointer would normally be used for doing things as database lookups
61 * for user login names and passwords, getting workstation settings, etc.
64 * For each database object created which uses this wxDb pointer
65 * connection to the database, when a CommitTrans() or RollBackTrans()
66 * will commit or rollback EVERY object which uses this wxDb pointer.
68 * To allow each table object (those derived from wxDbTable) to be
69 * individually committed or rolled back, you MUST use a different
70 * instance of wxDb in the constructor of the table. Doing so creates
71 * more overhead, and will use more database connections (some DBs have
72 * connection limits...), so use connections sparringly.
74 * It is recommended that one "main" database connection be created for
75 * the entire program to use for READ-ONLY database accesses, but for each
76 * table object which will do a CommitTrans() or RollbackTrans() that a
77 * new wxDb object be created and used for it.
83 * This function will return the exact string(s) from the database engine
84 * indicating all error conditions which have just occured during the
85 * last call to the database engine for the database connection pointed
88 * This demo uses the returned string by displaying it in a wxMessageBox. The
89 * formatting therefore is not the greatest, but this is just a demo, not a
90 * finished product. :-) gt
92 * NOTE: The value returned by this function is for temporary use only and
93 * should be copied for long term use
95 const char *GetExtendedDBErrorMsg(wxDb
*pDb
, char *ErrFile
, int ErrLine
)
102 if (ErrFile
|| ErrLine
)
107 tStr
.Printf("%d",ErrLine
);
112 msg
.Append ("\nODBC errors:\n");
115 // Display errors for this connection
117 for (i
= 0; i
< DB_MAX_ERROR_HISTORY
; i
++)
119 if (pDb
->errorList
[i
])
121 msg
.Append(pDb
->errorList
[i
]);
122 if (wxStrcmp(pDb
->errorList
[i
],"") != 0)
124 // Clear the errmsg buffer so the next error will not
125 // end up showing the previous error that have occurred
126 wxStrcpy(pDb
->errorList
[i
],"");
132 } // GetExtendedDBErrorMsg
135 bool DatabaseDemoApp::OnInit()
137 // Create the main frame window
138 DemoFrame
= new DatabaseDemoFrame(NULL
, "wxWindows Database Demo", wxPoint(50, 50), wxSize(537, 480));
141 DemoFrame
->SetIcon(wxICON(db
));
144 wxMenu
*file_menu
= new wxMenu
;
145 file_menu
->Append(FILE_CREATE
, "&Create CONTACT table");
146 file_menu
->Append(FILE_RECREATE_TABLE
, "&Recreate CONTACT table");
147 file_menu
->Append(FILE_RECREATE_INDEXES
, "&Recreate CONTACT indexes");
148 file_menu
->Append(FILE_EXIT
, "E&xit");
150 wxMenu
*edit_menu
= new wxMenu
;
151 edit_menu
->Append(EDIT_PARAMETERS
, "&Parameters...");
153 wxMenu
*about_menu
= new wxMenu
;
154 about_menu
->Append(ABOUT_DEMO
, "&About");
156 wxMenuBar
*menu_bar
= new wxMenuBar
;
157 menu_bar
->Append(file_menu
, "&File");
158 menu_bar
->Append(edit_menu
, "&Edit");
159 menu_bar
->Append(about_menu
, "&About");
160 DemoFrame
->SetMenuBar(menu_bar
);
162 // Initialize the ODBC Environment for Database Operations
163 if (SQLAllocEnv(&DbConnectInf
.Henv
) != SQL_SUCCESS
)
165 wxMessageBox("A problem occured while trying to get a connection to the data source","DB CONNECTION ERROR",wxOK
| wxICON_EXCLAMATION
);
169 params
.ODBCSource
[0] = 0;
170 params
.UserName
[0] = 0;
171 params
.Password
[0] = 0;
172 params
.DirPath
[0] = 0;
175 DemoFrame
->Show(TRUE
);
178 if ((paramFile
= fopen(paramFilename
, "r")) == NULL
)
181 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
);
182 wxMessageBox(tStr
,"File I/O Error...",wxOK
| wxICON_EXCLAMATION
);
184 DemoFrame
->BuildParameterDialog(NULL
);
185 if ((paramFile
= fopen(paramFilename
, "r")) == NULL
)
190 fgets(buffer
, sizeof(params
.ODBCSource
), paramFile
);
191 buffer
[wxStrlen(buffer
)-1] = '\0';
192 wxStrcpy(params
.ODBCSource
,buffer
);
194 fgets(buffer
, sizeof(params
.UserName
), paramFile
);
195 buffer
[wxStrlen(buffer
)-1] = '\0';
196 wxStrcpy(params
.UserName
,buffer
);
198 fgets(buffer
, sizeof(params
.Password
), paramFile
);
199 buffer
[wxStrlen(buffer
)-1] = '\0';
200 wxStrcpy(params
.Password
,buffer
);
202 fgets(buffer
, sizeof(params
.DirPath
), paramFile
);
203 buffer
[wxStrlen(buffer
)-1] = '\0';
204 wxStrcpy(params
.DirPath
,buffer
);
208 // Connect to datasource
209 wxStrcpy(DbConnectInf
.Dsn
, params
.ODBCSource
); // ODBC data source name (created with ODBC Administrator under Win95/NT)
210 wxStrcpy(DbConnectInf
.Uid
, params
.UserName
); // database username - must already exist in the data source
211 wxStrcpy(DbConnectInf
.AuthStr
, params
.Password
); // password database username
212 wxStrcpy(DbConnectInf
.defaultDir
, params
.DirPath
); // path where the table exists (needed for dBase)
214 READONLY_DB
= wxDbGetConnection(&DbConnectInf
);
215 if (READONLY_DB
== 0)
217 wxMessageBox("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)", "DB CONNECTION ERROR...",wxOK
| wxICON_EXCLAMATION
);
218 DemoFrame
->BuildParameterDialog(NULL
);
219 wxStrcpy(DbConnectInf
.Dsn
, "");
220 wxStrcpy(DbConnectInf
.Uid
, "");
221 wxStrcpy(DbConnectInf
.AuthStr
, "");
222 wxMessageBox("Now exiting program.\n\nRestart program to try any new settings.","Notice...",wxOK
| wxICON_INFORMATION
);
226 DemoFrame
->BuildEditorDialog();
229 DemoFrame
->Refresh();
232 } // DatabaseDemoApp::OnInit()
235 BEGIN_EVENT_TABLE(DatabaseDemoFrame
, wxFrame
)
236 EVT_MENU(FILE_CREATE
, DatabaseDemoFrame::OnCreate
)
237 EVT_MENU(FILE_RECREATE_TABLE
, DatabaseDemoFrame::OnRecreateTable
)
238 EVT_MENU(FILE_RECREATE_INDEXES
, DatabaseDemoFrame::OnRecreateIndexes
)
239 EVT_MENU(FILE_EXIT
, DatabaseDemoFrame::OnExit
)
240 EVT_MENU(EDIT_PARAMETERS
, DatabaseDemoFrame::OnEditParameters
)
241 EVT_MENU(ABOUT_DEMO
, DatabaseDemoFrame::OnAbout
)
242 EVT_CLOSE(DatabaseDemoFrame::OnCloseWindow
)
246 // DatabaseDemoFrame constructor
247 DatabaseDemoFrame::DatabaseDemoFrame(wxFrame
*frame
, const wxString
& title
,
248 const wxPoint
& pos
, const wxSize
& size
):
249 wxFrame(frame
, -1, title
, pos
, size
)
251 // Put any code in necessary for initializing the main frame here
254 } // DatabaseDemoFrame constructor
257 void DatabaseDemoFrame::OnCreate(wxCommandEvent
& event
)
259 CreateDataTable(FALSE
);
260 } // DatabaseDemoFrame::OnCreate()
263 void DatabaseDemoFrame::OnRecreateTable(wxCommandEvent
& event
)
265 CreateDataTable(TRUE
);
266 } // DatabaseDemoFrame::OnRecreate()
269 void DatabaseDemoFrame::OnRecreateIndexes(wxCommandEvent
& event
)
271 // Using a new connection to the database so as not to disturb
272 // the current cursors on the table in use in the editor dialog
273 Ccontact
*Contact
= new Ccontact();
278 wxMessageBox("Error allocating memory for 'Ccontact'object.\n\nTable could not be opened.","Error...",wxOK
| wxICON_EXCLAMATION
);
282 if (!Contact
->CreateIndexes())
286 tStr
= "Error creating CONTACTS indexes.\nNew indexes will be unavailable.\n\n";
287 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
288 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
293 } // DatabaseDemoFrame::OnRecreateIndexes()
295 void DatabaseDemoFrame::OnExit(wxCommandEvent
& event
)
298 } // DatabaseDemoFrame::OnExit()
301 void DatabaseDemoFrame::OnEditParameters(wxCommandEvent
& event
)
303 if ((pEditorDlg
->mode
!= mCreate
) && (pEditorDlg
->mode
!= mEdit
))
304 BuildParameterDialog(this);
306 wxMessageBox("Cannot change database parameters while creating or editing a record","Notice...",wxOK
| wxICON_INFORMATION
);
307 } // DatabaseDemoFrame::OnEditParameters()
310 void DatabaseDemoFrame::OnAbout(wxCommandEvent
& event
)
312 wxMessageBox("wxWindows sample program for database classes\n\nContributed on 27 July 1998","About...",wxOK
| wxICON_INFORMATION
);
313 } // DatabaseDemoFrame::OnAbout()
316 void DatabaseDemoFrame::OnCloseWindow(wxCloseEvent
& event
)
318 // Put any additional checking necessary to make certain it is alright
319 // to close the program here that is not done elsewhere
322 if (pEditorDlg
&& pEditorDlg
->Close())
333 // This function will close all the connections to the database that have been
334 // previously cached.
335 wxDbCloseConnections();
337 // Cleans up the environment space allocated for the SQL/ODBC connection handle
338 SQLFreeEnv(DbConnectInf
.Henv
);
342 } // DatabaseDemoFrame::OnCloseWindow()
345 void DatabaseDemoFrame::CreateDataTable(bool recreate
)
349 Ok
= (wxMessageBox("Any data currently residing in the table will be erased.\n\nAre you sure?","Confirm",wxYES_NO
|wxICON_QUESTION
) == wxYES
);
358 Ccontact
*Contact
= new Ccontact();
362 wxMessageBox("Error allocating memory for 'Ccontact'object.\n\nTable was not created.","Error...",wxOK
| wxICON_EXCLAMATION
);
366 if (!Contact
->CreateTable(recreate
))
370 tStr
= "Error creating CONTACTS table.\nTable was not created.\n\n";
371 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
372 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
377 if (!Contact
->CreateIndexes())
381 tStr
= "Error creating CONTACTS indexes.\nIndexes will be unavailable.\n\n";
382 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
383 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
394 wxMessageBox("Table and index(es) were successfully created.","Notice...",wxOK
| wxICON_INFORMATION
);
395 } // DatabaseDemoFrame::CreateDataTable()
398 void DatabaseDemoFrame::BuildEditorDialog()
401 pEditorDlg
= new CeditorDlg(this);
404 pEditorDlg
->Initialize();
405 if (!pEditorDlg
->initialized
)
409 wxMessageBox("Unable to initialize the editor dialog for some reason","Error...",wxOK
| wxICON_EXCLAMATION
);
415 wxMessageBox("Unable to create the editor dialog for some reason","Error...",wxOK
| wxICON_EXCLAMATION
);
418 } // DatabaseDemoFrame::BuildEditorDialog()
421 void DatabaseDemoFrame::BuildParameterDialog(wxWindow
*parent
)
423 pParamDlg
= new CparameterDlg(parent
);
426 wxMessageBox("Unable to create the parameter dialog for some reason","Error...",wxOK
| wxICON_EXCLAMATION
);
427 } // DatabaseDemoFrame::BuildParameterDialog()
431 * Constructor note: If no wxDb object is passed in, a new connection to the database
432 * is created for this instance of Ccontact. This can be a slow process depending
433 * on the database engine being used, and some database engines have a limit on the
434 * number of connections (either hard limits, or license restricted) so care should
435 * be used to use as few connections as is necessary.
437 * IMPORTANT: Objects which share a wxDb pointer are ALL acted upon whenever a member
438 * function of pDb is called (i.e. CommitTrans() or RollbackTrans(), so if modifying
439 * or creating a table objects which use the same pDb, know that all the objects
440 * will be committed or rolled back when any of the objects has this function call made.
442 Ccontact::Ccontact (wxDb
*pwxDb
) : wxDbTable(pwxDb
? pwxDb
: wxDbGetConnection(&DbConnectInf
),CONTACT_TABLE_NAME
,CONTACT_NO_COLS
,NULL
,!wxDB_QUERY_ONLY
,DbConnectInf
.defaultDir
)
444 // This is used to represent whether the database connection should be released
445 // when this instance of the object is deleted. If using the same connection
446 // for multiple instance of database objects, then the connection should only be
447 // released when the last database instance using the connection is deleted
452 } // Ccontact Constructor
455 void Ccontact::Initialize()
464 JoinDate
.year
= 1980;
470 JoinDate
.fraction
= 0;
471 NativeLanguage
= langENGLISH
;
475 } // Ccontact::Initialize
478 Ccontact::~Ccontact()
482 if (!wxDbFreeConnection(GetDb()))
485 tStr
= "Unable to Free the Ccontact data table handle\n\n";
486 tStr
+= GetExtendedDBErrorMsg(GetDb(),__FILE__
,__LINE__
);
487 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
490 } // Ccontract destructor
494 * Handles setting up all the connections for the interface from the wxDbTable
495 * functions to interface to the data structure used to store records in
496 * memory, and for all the column definitions that define the table structure
498 void Ccontact::SetupColumns()
500 // NOTE: Columns now are 8 character names, as that is all dBase can support. Longer
501 // names can be used for other database engines
502 SetColDefs ( 0,"NAME", DB_DATA_TYPE_VARCHAR
, Name
, SQL_C_CHAR
, sizeof(Name
), TRUE
, TRUE
); // Primary index
503 SetColDefs ( 1,"ADDRESS1", DB_DATA_TYPE_VARCHAR
, Addr1
, SQL_C_CHAR
, sizeof(Addr1
), FALSE
,TRUE
);
504 SetColDefs ( 2,"ADDRESS2", DB_DATA_TYPE_VARCHAR
, Addr2
, SQL_C_CHAR
, sizeof(Addr2
), FALSE
,TRUE
);
505 SetColDefs ( 3,"CITY", DB_DATA_TYPE_VARCHAR
, City
, SQL_C_CHAR
, sizeof(City
), FALSE
,TRUE
);
506 SetColDefs ( 4,"STATE", DB_DATA_TYPE_VARCHAR
, State
, SQL_C_CHAR
, sizeof(State
), FALSE
,TRUE
);
507 SetColDefs ( 5,"POSTCODE", DB_DATA_TYPE_VARCHAR
, PostalCode
, SQL_C_CHAR
, sizeof(PostalCode
), FALSE
,TRUE
);
508 SetColDefs ( 6,"COUNTRY", DB_DATA_TYPE_VARCHAR
, Country
, SQL_C_CHAR
, sizeof(Country
), FALSE
,TRUE
);
509 SetColDefs ( 7,"JOINDATE", DB_DATA_TYPE_DATE
, &JoinDate
, SQL_C_TIMESTAMP
, sizeof(JoinDate
), FALSE
,TRUE
);
510 SetColDefs ( 8,"IS_DEV", DB_DATA_TYPE_INTEGER
, &IsDeveloper
, SQL_C_BOOLEAN(IsDeveloper
), sizeof(IsDeveloper
), FALSE
,TRUE
);
511 SetColDefs ( 9,"CONTRIBS", DB_DATA_TYPE_INTEGER
, &Contributions
, SQL_C_USHORT
, sizeof(Contributions
), FALSE
,TRUE
);
512 SetColDefs (10,"LINE_CNT", DB_DATA_TYPE_INTEGER
, &LinesOfCode
, SQL_C_ULONG
, sizeof(LinesOfCode
), FALSE
,TRUE
);
513 SetColDefs (11,"LANGUAGE", DB_DATA_TYPE_INTEGER
, &NativeLanguage
, SQL_C_ENUM
, sizeof(NativeLanguage
), FALSE
,TRUE
);
514 } // Ccontact::SetupColumns
517 bool Ccontact::CreateIndexes(void)
519 // This index could easily be accomplished with an "orderBy" clause,
520 // but is done to show how to construct a non-primary index.
522 wxDbIdxDef idxDef
[2];
526 wxStrcpy(idxDef
[0].ColName
, "IS_DEV");
527 idxDef
[0].Ascending
= TRUE
;
529 wxStrcpy(idxDef
[1].ColName
, "NAME");
530 idxDef
[1].Ascending
= TRUE
;
532 indexName
= GetTableName();
533 indexName
+= "_IDX1";
534 Ok
= CreateIndex(indexName
.c_str(), TRUE
, 2, idxDef
);
537 } // Ccontact::CreateIndexes()
541 * Having a function to do a query on the primary key (and possibly others) is
542 * very efficient and tighter coding so that it is available where ever the object
543 * is. Great for use with multiple tables when not using views or outer joins
545 bool Ccontact::FetchByName(char *name
)
547 whereStr
.Printf("NAME = '%s'",name
);
548 SetWhereClause(whereStr
.c_str());
549 SetOrderByClause("");
557 } // Ccontact::FetchByName()
562 * ************* DIALOGS ***************
567 /* CeditorDlg constructor
569 * Creates the dialog used for creating/editing/deleting/copying a Ccontact object.
570 * This dialog actually is drawn in the main frame of the program
572 * An instance of Ccontact is created - "Contact" - which is used to hold the Ccontact
573 * object that is currently being worked with.
576 BEGIN_EVENT_TABLE(CeditorDlg
, wxPanel
)
577 EVT_BUTTON(-1, CeditorDlg::OnButton
)
578 EVT_CLOSE(CeditorDlg::OnCloseWindow
)
581 CeditorDlg::CeditorDlg(wxWindow
*parent
) : wxPanel (parent
, 0, 0, 537, 480)
583 // Since the ::OnCommand() function is overridden, this prevents the widget
584 // detection in ::OnCommand() until all widgets have been initialized to prevent
585 // uninitialized pointers from crashing the program
586 widgetPtrsSet
= FALSE
;
593 } // CeditorDlg constructor
596 void CeditorDlg::OnCloseWindow(wxCloseEvent
& event
)
599 if ((mode
!= mCreate
) && (mode
!= mEdit
))
610 wxMessageBox("Must finish processing the current record being created/modified before exiting","Notice...",wxOK
| wxICON_INFORMATION
);
613 } // CeditorDlg::OnCloseWindow()
616 void CeditorDlg::OnButton(wxCommandEvent
&event
)
618 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
619 OnCommand( *win
, event
);
620 } // CeditorDlg::OnButton()
623 void CeditorDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
627 widgetName
= win
.GetName();
632 if (widgetName
== pCreateBtn
->GetName())
634 Contact
->Initialize();
637 pNameTxt
->SetValue("");
638 pNameTxt
->SetFocus();
642 if (widgetName
== pEditBtn
->GetName())
644 saveName
= Contact
->Name
;
646 pNameTxt
->SetFocus();
650 if (widgetName
== pCopyBtn
->GetName())
653 pNameTxt
->SetValue("");
654 pNameTxt
->SetFocus();
659 if (widgetName
== pDeleteBtn
->GetName())
661 bool Ok
= (wxMessageBox("Are you sure?","Confirm",wxYES_NO
|wxICON_QUESTION
) == wxYES
);
666 if (Ok
&& Contact
->Delete())
668 // NOTE: Deletions are not finalized until a CommitTrans() is performed.
669 // If the commit were not performed, the program will continue to
670 // show the table contents as if they were deleted until this instance
671 // of Ccontact is deleted. If the Commit wasn't performed, the
672 // database will automatically Rollback the changes when the database
673 // connection is terminated
674 Contact
->GetDb()->CommitTrans();
676 // Try to get the row that followed the just deleted row in the orderBy sequence
679 // There was now row (in sequence) after the just deleted row, so get the
680 // row which preceded the just deleted row
683 // There are now no rows remaining, so clear the dialog widgets
684 Contact
->Initialize();
688 SetMode(mode
); // force reset of button enable/disable
692 Contact
->GetDb()->RollbackTrans();
698 if (widgetName
== pSaveBtn
->GetName())
704 if (widgetName
== pCancelBtn
->GetName())
706 bool Ok
= (wxMessageBox("Are you sure?","Confirm",wxYES_NO
|wxICON_QUESTION
) == wxYES
);
711 if (!wxStrcmp((const char*) saveName
,""))
713 Contact
->Initialize();
720 // Requery previous record
721 if (Contact
->FetchByName((char*) (const char*) saveName
))
729 // Previous record not available, retrieve first record in table
730 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
732 Contact
->whereStr
= "NAME = (SELECT MIN(NAME) FROM ";
733 Contact
->whereStr
+= Contact
->GetTableName();
734 Contact
->whereStr
+= ")";
735 Contact
->SetWhereClause(Contact
->whereStr
.c_str());
738 Contact
->SetWhereClause("");
740 if (!Contact
->Query())
743 tStr
= "ODBC error during Query()\n\n";
744 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
745 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
749 if (Contact
->GetNext()) // Successfully read first record
755 // No contacts are available, clear dialog
756 Contact
->Initialize();
762 if (widgetName
== pPrevBtn
->GetName())
769 if (widgetName
== pNextBtn
->GetName())
776 if (widgetName
== pQueryBtn
->GetName())
778 // Display the query dialog box
779 char qryWhere
[DB_MAX_WHERE_CLAUSE_LEN
+1];
780 wxStrcpy(qryWhere
, (const char*) Contact
->qryWhereStr
);
781 char *tblName
[] = {(char *)CONTACT_TABLE_NAME
, 0};
782 new CqueryDlg(GetParent(), Contact
->GetDb(), tblName
, qryWhere
);
784 // Query the first record in the new record set and
785 // display it, if the query string has changed.
786 if (wxStrcmp(qryWhere
, (const char*) Contact
->qryWhereStr
))
788 Contact
->whereStr
= "";
789 Contact
->SetOrderByClause("NAME");
791 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
793 Contact
->whereStr
= "NAME = (SELECT MIN(NAME) FROM ";
794 Contact
->whereStr
+= CONTACT_TABLE_NAME
;
797 // Append the query where string (if there is one)
798 Contact
->qryWhereStr
= qryWhere
;
799 if (wxStrlen(qryWhere
))
801 Contact
->whereStr
+= " WHERE ";
802 Contact
->whereStr
+= Contact
->qryWhereStr
;
804 // Close the expression with a right paren
805 Contact
->whereStr
+= ")";
807 Contact
->SetWhereClause(Contact
->whereStr
.c_str());
808 if (!Contact
->Query())
811 tStr
= "ODBC error during Query()\n\n";
812 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
813 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
816 // Display the first record from the query set
817 if (!Contact
->GetNext())
818 Contact
->Initialize();
822 // Enable/Disable the reset button
823 pResetBtn
->Enable(!Contact
->qryWhereStr
.IsEmpty());
829 if (widgetName
== pResetBtn
->GetName())
831 // Clear the additional where criteria established by the query feature
832 Contact
->qryWhereStr
= "";
833 Contact
->SetOrderByClause("NAME");
835 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
837 Contact
->whereStr
= "NAME = (SELECT MIN(NAME) FROM ";
838 Contact
->whereStr
+= CONTACT_TABLE_NAME
;
839 Contact
->whereStr
+= ")";
842 Contact
->SetWhereClause(Contact
->whereStr
.c_str());
843 if (!Contact
->Query())
846 tStr
= "ODBC error during Query()\n\n";
847 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
848 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
851 if (!Contact
->GetNext())
852 Contact
->Initialize();
854 pResetBtn
->Enable(FALSE
);
860 if (widgetName
== pNameListBtn
->GetName())
862 new ClookUpDlg(/* wxWindow *parent */ this,
863 /* char *windowTitle */ "Select contact name",
864 /* char *tableName */ (char *) CONTACT_TABLE_NAME
,
865 /* char *dispCol1 */ "NAME",
866 /* char *dispCol2 */ "JOINDATE",
867 /* char *where */ "",
868 /* char *orderBy */ "NAME",
869 /* bool distinctValues */ TRUE
);
871 if (ListDB_Selection
&& wxStrlen(ListDB_Selection
))
873 wxString w
= "NAME = '";
874 w
+= ListDB_Selection
;
876 GetRec((char*) (const char*) w
);
881 } // CeditorDlg::OnCommand()
884 bool CeditorDlg::Initialize()
886 // Create the data structure and a new database connection.
887 // (As there is not a pDb being passed in the constructor, a new database
888 // connection is created)
889 Contact
= new Ccontact();
893 wxMessageBox("Unable to instantiate an instance of Ccontact","Error...",wxOK
| wxICON_EXCLAMATION
);
897 // Check if the table exists or not. If it doesn't, ask the user if they want to
898 // create the table. Continue trying to create the table until it exists, or user aborts
899 while (!Contact
->GetDb()->TableExists((char *)CONTACT_TABLE_NAME
,DbConnectInf
.Uid
,DbConnectInf
.defaultDir
))
902 tStr
.Printf("Unable to open the table '%s'.\n\nTable may need to be created...?\n\n",CONTACT_TABLE_NAME
);
903 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
904 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
906 bool createTable
= (wxMessageBox("Do you wish to try to create/clear the CONTACTS table?","Confirm",wxYES_NO
|wxICON_QUESTION
) == wxYES
);
914 DemoFrame
->CreateDataTable(TRUE
);
917 // Tables must be "opened" before anything other than creating/deleting table can be done
918 if (!Contact
->Open())
920 // Table does exist, or there was some problem opening it. Currently this should
921 // never fail, except in the case of the table not exisiting or the current
922 // user has insufficent privileges to access the table
924 // This code is experimenting with a new function that will hopefully be available
925 // in the 2.4 release. This check will determine whether the open failing was due
926 // to the table not existing, or the users privileges being insufficient to
928 if (!Contact
->GetDb()->TablePrivileges(CONTACT_TABLE_NAME
,"SELECT",Contact
->GetDb()->GetUsername(),DbConnectInf
.defaultDir
))
931 tStr
.Printf("Unable to open the table '%s'.\n\n",CONTACT_TABLE_NAME
);
932 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
933 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
937 if (Contact
->GetDb()->TableExists(CONTACT_TABLE_NAME
,Contact
->GetDb()->GetUsername(),DbConnectInf
.defaultDir
))
940 tStr
.Printf("Unable to open the table '%s'.\n\n",CONTACT_TABLE_NAME
);
941 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
942 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
950 (void)new wxStaticBox(this, EDITOR_DIALOG_FN_GROUP
, "", wxPoint(15, 1), wxSize(497, 69), 0, "FunctionGrp");
951 (void)new wxStaticBox(this, EDITOR_DIALOG_SEARCH_GROUP
, "", wxPoint(417, 1), wxSize(95, 242), 0, "SearchGrp");
953 pCreateBtn
= new wxButton(this, EDITOR_DIALOG_CREATE
, "&Create", wxPoint( 25, 21), wxSize( 70, 35), 0, wxDefaultValidator
, "CreateBtn");
954 pEditBtn
= new wxButton(this, EDITOR_DIALOG_EDIT
, "&Edit", wxPoint(102, 21), wxSize( 70, 35), 0, wxDefaultValidator
, "EditBtn");
955 pDeleteBtn
= new wxButton(this, EDITOR_DIALOG_DELETE
, "&Delete", wxPoint(179, 21), wxSize( 70, 35), 0, wxDefaultValidator
, "DeleteBtn");
956 pCopyBtn
= new wxButton(this, EDITOR_DIALOG_COPY
, "Cop&y", wxPoint(256, 21), wxSize( 70, 35), 0, wxDefaultValidator
, "CopyBtn");
957 pSaveBtn
= new wxButton(this, EDITOR_DIALOG_SAVE
, "&Save", wxPoint(333, 21), wxSize( 70, 35), 0, wxDefaultValidator
, "SaveBtn");
958 pCancelBtn
= new wxButton(this, EDITOR_DIALOG_CANCEL
, "C&ancel", wxPoint(430, 21), wxSize( 70, 35), 0, wxDefaultValidator
, "CancelBtn");
959 pPrevBtn
= new wxButton(this, EDITOR_DIALOG_PREV
, "<< &Prev", wxPoint(430, 81), wxSize( 70, 35), 0, wxDefaultValidator
, "PrevBtn");
960 pNextBtn
= new wxButton(this, EDITOR_DIALOG_NEXT
, "&Next >>", wxPoint(430, 121), wxSize( 70, 35), 0, wxDefaultValidator
, "NextBtn");
961 pQueryBtn
= new wxButton(this, EDITOR_DIALOG_QUERY
, "&Query", wxPoint(430, 161), wxSize( 70, 35), 0, wxDefaultValidator
, "QueryBtn");
962 pResetBtn
= new wxButton(this, EDITOR_DIALOG_RESET
, "&Reset", wxPoint(430, 200), wxSize( 70, 35), 0, wxDefaultValidator
, "ResetBtn");
963 pNameMsg
= new wxStaticText(this, EDITOR_DIALOG_NAME_MSG
, "Name:", wxPoint( 17, 80), wxSize( -1, -1), 0, "NameMsg");
964 pNameTxt
= new wxTextCtrl(this, EDITOR_DIALOG_NAME_TEXT
, "", wxPoint( 17, 97), wxSize(308, 25), 0, wxDefaultValidator
, "NameTxt");
965 pNameListBtn
= new wxButton(this, EDITOR_DIALOG_LOOKUP
, "&Lookup", wxPoint(333, 97), wxSize( 70, 24), 0, wxDefaultValidator
, "LookupBtn");
966 pAddress1Msg
= new wxStaticText(this, EDITOR_DIALOG_ADDRESS1_MSG
, "Address:", wxPoint( 17, 130), wxSize( -1, -1), 0, "Address1Msg");
967 pAddress1Txt
= new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT
, "", wxPoint( 17, 147), wxSize(308, 25), 0, wxDefaultValidator
, "Address1Txt");
968 pAddress2Msg
= new wxStaticText(this, EDITOR_DIALOG_ADDRESS2_MSG
, "Address:", wxPoint( 17, 180), wxSize( -1, -1), 0, "Address2Msg");
969 pAddress2Txt
= new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT
, "", wxPoint( 17, 197), wxSize(308, 25), 0, wxDefaultValidator
, "Address2Txt");
970 pCityMsg
= new wxStaticText(this, EDITOR_DIALOG_CITY_MSG
, "City:", wxPoint( 17, 230), wxSize( -1, -1), 0, "CityMsg");
971 pCityTxt
= new wxTextCtrl(this, EDITOR_DIALOG_CITY_TEXT
, "", wxPoint( 17, 247), wxSize(225, 25), 0, wxDefaultValidator
, "CityTxt");
972 pStateMsg
= new wxStaticText(this, EDITOR_DIALOG_STATE_MSG
, "State:", wxPoint(250, 230), wxSize( -1, -1), 0, "StateMsg");
973 pStateTxt
= new wxTextCtrl(this, EDITOR_DIALOG_STATE_TEXT
, "", wxPoint(250, 247), wxSize(153, 25), 0, wxDefaultValidator
, "StateTxt");
974 pCountryMsg
= new wxStaticText(this, EDITOR_DIALOG_COUNTRY_MSG
, "Country:", wxPoint( 17, 280), wxSize( -1, -1), 0, "CountryMsg");
975 pCountryTxt
= new wxTextCtrl(this, EDITOR_DIALOG_COUNTRY_TEXT
, "", wxPoint( 17, 297), wxSize(225, 25), 0, wxDefaultValidator
, "CountryTxt");
976 pPostalCodeMsg
= new wxStaticText(this, EDITOR_DIALOG_POSTAL_MSG
, "Postal Code:",wxPoint(250, 280), wxSize( -1, -1), 0, "PostalCodeMsg");
977 pPostalCodeTxt
= new wxTextCtrl(this, EDITOR_DIALOG_POSTAL_TEXT
, "", wxPoint(250, 297), wxSize(153, 25), 0, wxDefaultValidator
, "PostalCodeTxt");
979 wxString choice_strings
[5];
980 choice_strings
[0] = "English";
981 choice_strings
[1] = "French";
982 choice_strings
[2] = "German";
983 choice_strings
[3] = "Spanish";
984 choice_strings
[4] = "Other";
986 pNativeLangChoice
= new wxChoice(this, EDITOR_DIALOG_LANG_CHOICE
, wxPoint( 17, 346), wxSize(277, -1), 5, choice_strings
);
987 pNativeLangMsg
= new wxStaticText(this, EDITOR_DIALOG_LANG_MSG
, "Native language:", wxPoint( 17, 330), wxSize( -1, -1), 0, "NativeLangMsg");
989 wxString radio_strings
[2];
990 radio_strings
[0] = "No";
991 radio_strings
[1] = "Yes";
992 pDeveloperRadio
= new wxRadioBox(this,EDITOR_DIALOG_DEVELOPER
, "Developer:", wxPoint(303, 330), wxSize( -1, -1), 2, radio_strings
, 2, wxHORIZONTAL
);
993 pJoinDateMsg
= new wxStaticText(this, EDITOR_DIALOG_JOIN_MSG
, "Date joined:", wxPoint( 17, 380), wxSize( -1, -1), 0, "JoinDateMsg");
994 pJoinDateTxt
= new wxTextCtrl(this, EDITOR_DIALOG_JOIN_TEXT
, "", wxPoint( 17, 397), wxSize(150, 25), 0, wxDefaultValidator
, "JoinDateTxt");
995 pContribMsg
= new wxStaticText(this, EDITOR_DIALOG_CONTRIB_MSG
,"Contributions:", wxPoint(175, 380), wxSize( -1, -1), 0, "ContribMsg");
996 pContribTxt
= new wxTextCtrl(this, EDITOR_DIALOG_CONTRIB_TEXT
, "", wxPoint(175, 397), wxSize(120, 25), 0, wxDefaultValidator
, "ContribTxt");
997 pLinesMsg
= new wxStaticText(this, EDITOR_DIALOG_LINES_MSG
, "Lines of code:", wxPoint(303, 380), wxSize( -1, -1), 0, "LinesMsg");
998 pLinesTxt
= new wxTextCtrl(this, EDITOR_DIALOG_LINES_TEXT
, "", wxPoint(303, 397), wxSize(100, 25), 0, wxDefaultValidator
, "LinesTxt");
1000 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
1001 // handle all widget processing
1002 widgetPtrsSet
= TRUE
;
1004 // Setup the orderBy and where clauses to return back a single record as the result set,
1005 // as there will only be one record being shown on the dialog at a time, this optimizes
1006 // network traffic by only returning a one row result
1008 Contact
->SetOrderByClause("NAME"); // field name to sort by
1010 // The wxString "whereStr" is not a member of the wxDbTable object, it is a member variable
1011 // specifically in the Ccontact class. It is used here for simpler construction of a varying
1012 // length string, and then after the string is built, the wxDbTable member variable "where" is
1013 // assigned the pointer to the constructed string.
1015 // The constructed where clause below has a sub-query within it "SELECT MIN(NAME) FROM %s"
1016 // to achieve a single row (in this case the first name in alphabetical order).
1018 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1020 Contact
->whereStr
.sprintf("NAME = (SELECT MIN(NAME) FROM %s)",Contact
->GetTableName());
1021 // NOTE: (const char*) returns a pointer which may not be valid later, so this is short term use only
1022 Contact
->SetWhereClause(Contact
->whereStr
.c_str());
1025 Contact
->SetWhereClause("");
1027 // Perform the Query to get the result set.
1028 // NOTE: If there are no rows returned, that is a valid result, so Query() would return TRUE.
1029 // Only if there is a database error will Query() come back as FALSE
1030 if (!Contact
->Query())
1033 tStr
= "ODBC error during Query()\n\n";
1034 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1035 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
1036 // GetParent()->Close();
1040 // Since Query succeeded, now get the row that was returned
1041 if (!Contact
->GetNext())
1042 // If the GetNext() failed at this point, then there are no rows to retrieve,
1043 // so clear the values in the members of "Contact" so that PutData() blanks the
1044 // widgets on the dialog
1045 Contact
->Initialize();
1054 } // CeditorDlg::Initialize()
1057 void CeditorDlg::FieldsEditable()
1059 pNameTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1060 pAddress1Txt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1061 pAddress2Txt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1062 pCityTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1063 pStateTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1064 pPostalCodeTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1065 pCountryTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1067 pJoinDateTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1068 pContribTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1069 pLinesTxt
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1070 pNativeLangChoice
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1071 pDeveloperRadio
->Enable((mode
== mCreate
) || (mode
== mEdit
));
1073 } // CeditorDlg::FieldsEditable()
1076 void CeditorDlg::SetMode(enum DialogModes m
)
1097 pCreateBtn
->Enable( !edit
);
1098 pEditBtn
->Enable( !edit
&& (wxStrcmp(Contact
->Name
,"")!=0) );
1099 pDeleteBtn
->Enable( !edit
&& (wxStrcmp(Contact
->Name
,"")!=0) );
1100 pCopyBtn
->Enable( !edit
&& (wxStrcmp(Contact
->Name
,"")!=0) );
1101 pSaveBtn
->Enable( edit
);
1102 pCancelBtn
->Enable( edit
);
1103 pPrevBtn
->Enable( !edit
);
1104 pNextBtn
->Enable( !edit
);
1105 pQueryBtn
->Enable( !edit
);
1106 pResetBtn
->Enable( !edit
&& !Contact
->qryWhereStr
.IsEmpty() );
1107 pNameListBtn
->Enable( !edit
);
1111 } // CeditorDlg::SetMode()
1114 bool CeditorDlg::PutData()
1118 pNameTxt
->SetValue(Contact
->Name
);
1119 pAddress1Txt
->SetValue(Contact
->Addr1
);
1120 pAddress2Txt
->SetValue(Contact
->Addr2
);
1121 pCityTxt
->SetValue(Contact
->City
);
1122 pStateTxt
->SetValue(Contact
->State
);
1123 pCountryTxt
->SetValue(Contact
->Country
);
1124 pPostalCodeTxt
->SetValue(Contact
->PostalCode
);
1126 tStr
.Printf("%d/%d/%d",Contact
->JoinDate
.month
,Contact
->JoinDate
.day
,Contact
->JoinDate
.year
);
1127 pJoinDateTxt
->SetValue(tStr
);
1129 tStr
.Printf("%d",Contact
->Contributions
);
1130 pContribTxt
->SetValue(tStr
);
1132 tStr
.Printf("%lu",Contact
->LinesOfCode
);
1133 pLinesTxt
->SetValue(tStr
);
1135 pNativeLangChoice
->SetSelection(Contact
->NativeLanguage
);
1137 pDeveloperRadio
->SetSelection(Contact
->IsDeveloper
);
1140 } // Ceditor::PutData()
1144 * Reads the data out of all the widgets on the dialog. Some data evaluation is done
1145 * to ensure that there is a name entered and that the date field is valid.
1147 * A return value of TRUE means that valid data was retrieved from the dialog, otherwise
1148 * invalid data was found (and a message was displayed telling the user what to fix), and
1149 * the data was not placed into the appropraite fields of Ccontact
1151 bool CeditorDlg::GetData()
1153 // Validate that the data currently entered into the widgets is valid data
1156 tStr
= pNameTxt
->GetValue();
1157 if (!wxStrcmp((const char*) tStr
,""))
1159 wxMessageBox("A name is required for entry into the contact table","Notice...",wxOK
| wxICON_INFORMATION
);
1163 bool invalid
= FALSE
;
1167 tStr
= pJoinDateTxt
->GetValue();
1168 if (tStr
.Freq('/') != 2)
1171 // Find the month, day, and year tokens
1174 first
= tStr
.First('/');
1175 second
= tStr
.Last('/');
1177 mm
= atoi(tStr
.SubString(0,first
));
1178 dd
= atoi(tStr
.SubString(first
+1,second
));
1179 yyyy
= atoi(tStr
.SubString(second
+1,tStr
.Length()-1));
1181 invalid
= !(mm
&& dd
&& yyyy
);
1184 // Force Year 2000 compliance
1185 if (!invalid
&& (yyyy
< 1000))
1188 // Check the token ranges for validity
1193 else if ((mm
< 1) || (mm
> 12))
1201 int days
[12] = {31,28,31,30,31,30,
1203 if (dd
> days
[mm
-1])
1206 if ((dd
== 29) && (mm
== 2))
1208 if (((yyyy
% 4) == 0) && (((yyyy
% 100) != 0) || ((yyyy
% 400) == 0)))
1218 Contact
->JoinDate
.month
= mm
;
1219 Contact
->JoinDate
.day
= dd
;
1220 Contact
->JoinDate
.year
= yyyy
;
1224 wxMessageBox("Improper date format. Please check the date\nspecified and try again.\n\nNOTE: Dates are in american format (MM/DD/YYYY)","Notice...",wxOK
| wxICON_INFORMATION
);
1228 tStr
= pNameTxt
->GetValue();
1229 wxStrcpy(Contact
->Name
,(const char*) tStr
);
1230 wxStrcpy(Contact
->Addr1
,pAddress1Txt
->GetValue());
1231 wxStrcpy(Contact
->Addr2
,pAddress2Txt
->GetValue());
1232 wxStrcpy(Contact
->City
,pCityTxt
->GetValue());
1233 wxStrcpy(Contact
->State
,pStateTxt
->GetValue());
1234 wxStrcpy(Contact
->Country
,pCountryTxt
->GetValue());
1235 wxStrcpy(Contact
->PostalCode
,pPostalCodeTxt
->GetValue());
1237 Contact
->Contributions
= atoi(pContribTxt
->GetValue());
1238 Contact
->LinesOfCode
= atol(pLinesTxt
->GetValue());
1240 Contact
->NativeLanguage
= (enum Language
) pNativeLangChoice
->GetSelection();
1241 Contact
->IsDeveloper
= pDeveloperRadio
->GetSelection() > 0;
1244 } // CeditorDlg::GetData()
1248 * Retrieve data from the dialog, verify the validity of the data, and if it is valid,
1249 * try to insert/update the data to the table based on the current 'mode' the dialog
1252 * A return value of TRUE means the insert/update was completed successfully, a return
1253 * value of FALSE means that Save() failed. If returning FALSE, then this function
1254 * has displayed a detailed error message for the user.
1256 bool CeditorDlg::Save()
1258 bool failed
= FALSE
;
1260 // Read the data in the widgets of the dialog to get the user's data
1264 // Perform any other required validations necessary before saving
1267 wxBeginBusyCursor();
1269 if (mode
== mCreate
)
1271 RETCODE result
= Contact
->Insert();
1273 failed
= (result
!= DB_SUCCESS
);
1276 // Some errors may be expected, like a duplicate key, so handle those instances with
1277 // specific error messages.
1278 if (result
== DB_ERR_INTEGRITY_CONSTRAINT_VIOL
)
1281 tStr
= "A duplicate key value already exists in the table.\nUnable to save record\n\n";
1282 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1283 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
1287 // Some other unexpexted error occurred
1289 tStr
= "Database insert failed\n\n";
1290 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1291 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
1295 else // mode == mEdit
1297 if (!Contact
->Update())
1300 tStr
= "Database update failed\n\n";
1301 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1302 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
1309 Contact
->GetDb()->CommitTrans();
1310 SetMode(mView
); // Sets the dialog mode back to viewing after save is successful
1313 Contact
->GetDb()->RollbackTrans();
1319 } // CeditorDlg::Save()
1323 * Where this program is only showing a single row at a time in the dialog,
1324 * a special where clause must be built to find just the single row which,
1325 * in sequence, would follow the currently displayed row.
1327 bool CeditorDlg::GetNextRec()
1331 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1333 w
= "NAME = (SELECT MIN(NAME) FROM ";
1334 w
+= Contact
->GetTableName();
1335 w
+= " WHERE NAME > '";
1343 // If a query where string is currently set, append that criteria
1344 if (!Contact
->qryWhereStr
.IsEmpty())
1347 w
+= Contact
->qryWhereStr
;
1352 return(GetRec((char*) (const char*) w
));
1354 } // CeditorDlg::GetNextRec()
1358 * Where this program is only showing a single row at a time in the dialog,
1359 * a special where clause must be built to find just the single row which,
1360 * in sequence, would precede the currently displayed row.
1362 bool CeditorDlg::GetPrevRec()
1366 if (Contact
->GetDb()->Dbms() != dbmsPOSTGRES
&& Contact
->GetDb()->Dbms() != dbmsMY_SQL
)
1368 w
= "NAME = (SELECT MAX(NAME) FROM ";
1369 w
+= Contact
->GetTableName();
1370 w
+= " WHERE NAME < '";
1378 // If a query where string is currently set, append that criteria
1379 if (!Contact
->qryWhereStr
.IsEmpty())
1382 w
+= Contact
->qryWhereStr
;
1388 return(GetRec((char*) (const char*)w
));
1390 } // CeditorDlg::GetPrevRec()
1394 * This function is here to avoid duplicating this same code in both the
1395 * GetPrevRec() and GetNextRec() functions
1397 bool CeditorDlg::GetRec(char *whereStr
)
1399 Contact
->SetWhereClause(whereStr
);
1400 Contact
->SetOrderByClause("NAME");
1402 if (!Contact
->Query())
1405 tStr
= "ODBC error during Query()\n\n";
1406 tStr
+= GetExtendedDBErrorMsg(Contact
->GetDb(),__FILE__
,__LINE__
);
1407 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
1412 if (Contact
->GetNext())
1419 } // CeditorDlg::GetRec()
1424 * CparameterDlg constructor
1427 BEGIN_EVENT_TABLE(CparameterDlg
, wxDialog
)
1428 EVT_BUTTON(PARAMETER_DIALOG_SAVE
, CparameterDlg::OnButton
)
1429 EVT_BUTTON(PARAMETER_DIALOG_CANCEL
, CparameterDlg::OnButton
)
1430 EVT_CLOSE(CparameterDlg::OnCloseWindow
)
1433 CparameterDlg::CparameterDlg(wxWindow
*parent
) : wxDialog (parent
, PARAMETER_DIALOG
, "ODBC parameter settings", wxPoint(-1, -1), wxSize(400, 325))
1435 // Since the ::OnCommand() function is overridden, this prevents the widget
1436 // detection in ::OnCommand() until all widgets have been initialized to prevent
1437 // uninitialized pointers from crashing the program
1438 widgetPtrsSet
= FALSE
;
1440 pParamODBCSourceMsg
= new wxStaticText(this, PARAMETER_DIALOG_SOURCE_MSG
, "ODBC data sources:", wxPoint( 10, 10), wxSize( -1, -1), 0, "ParamODBCSourceMsg");
1441 pParamODBCSourceList
= new wxListBox(this, PARAMETER_DIALOG_SOURCE_LISTBOX
, wxPoint( 10, 29), wxSize(285, 150), 0, 0, wxLB_SINGLE
|wxLB_ALWAYS_SB
, wxDefaultValidator
, "ParamODBCSourceList");
1442 pParamUserNameMsg
= new wxStaticText(this, PARAMETER_DIALOG_NAME_MSG
, "Database user name:", wxPoint( 10, 193), wxSize( -1, -1), 0, "ParamUserNameMsg");
1443 pParamUserNameTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_NAME_TEXT
, "", wxPoint(10, 209), wxSize( 140, 25), 0, wxDefaultValidator
, "ParamUserNameTxt");
1444 pParamPasswordMsg
= new wxStaticText(this, PARAMETER_DIALOG_PASSWORD_MSG
, "Password:", wxPoint(156, 193), wxSize( -1, -1), 0, "ParamPasswordMsg");
1445 pParamPasswordTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_PASSWORD_TEXT
, "", wxPoint(156, 209), wxSize( 140, 25), 0, wxDefaultValidator
, "ParamPasswordTxt");
1446 pParamDirPathMsg
= new wxStaticText(this, PARAMETER_DIALOG_DIRPATH_MSG
, "Directory:", wxPoint( 10, 243), wxSize( -1, -1), 0, "ParamDirPathMsg");
1447 pParamDirPathTxt
= new wxTextCtrl(this, PARAMETER_DIALOG_DIRPATH_TEXT
, "", wxPoint( 10, 259), wxSize(140, 25), 0, wxDefaultValidator
, "ParamDirPathTxt");
1448 pParamSaveBtn
= new wxButton(this, PARAMETER_DIALOG_SAVE
, "&Save", wxPoint(310, 21), wxSize( 70, 35), 0, wxDefaultValidator
, "ParamSaveBtn");
1449 pParamCancelBtn
= new wxButton(this, PARAMETER_DIALOG_CANCEL
, "C&ancel", wxPoint(310, 66), wxSize( 70, 35), 0, wxDefaultValidator
, "ParamCancelBtn");
1451 // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to
1452 // handle all widget processing
1453 widgetPtrsSet
= TRUE
;
1456 savedParamSettings
= wxGetApp().params
;
1461 } // CparameterDlg constructor
1464 void CparameterDlg::OnCloseWindow(wxCloseEvent
& event
)
1466 // Put any additional checking necessary to make certain it is alright
1467 // to close the program here that is not done elsewhere
1470 bool Ok
= (wxMessageBox("No changes have been saved.\n\nAre you sure you wish exit the parameter screen?","Confirm",wxYES_NO
|wxICON_QUESTION
) == wxYES
);
1478 wxGetApp().params
= savedParamSettings
;
1481 if (GetParent() != NULL
)
1482 GetParent()->SetFocus();
1488 SetReturnCode(0); // added so BoundsChecker would not report use of uninitialized variable
1491 } // CparameterDlg::OnCloseWindow()
1494 void CparameterDlg::OnButton( wxCommandEvent
&event
)
1496 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
1497 OnCommand( *win
, event
);
1501 void CparameterDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
1503 wxString widgetName
;
1505 widgetName
= win
.GetName();
1510 if (widgetName
== pParamSaveBtn
->GetName())
1515 tStr
= "Database parameters have been saved.";
1516 if (GetParent() != NULL
) // The parameter dialog was not called during startup due to a missing cfg file
1517 tStr
+= "\nNew parameters will take effect the next time the program is started.";
1518 wxMessageBox(tStr
,"Notice...",wxOK
| wxICON_INFORMATION
);
1525 if (widgetName
== pParamCancelBtn
->GetName())
1530 } // CparameterDlg::OnCommand()
1533 bool CparameterDlg::PutData()
1535 // Fill the data source list box
1536 FillDataSourceList();
1538 // Fill in the fields from the params object
1539 if (wxGetApp().params
.ODBCSource
&& wxStrlen(wxGetApp().params
.ODBCSource
))
1540 pParamODBCSourceList
->SetStringSelection(wxGetApp().params
.ODBCSource
);
1541 pParamUserNameTxt
->SetValue(wxGetApp().params
.UserName
);
1542 pParamPasswordTxt
->SetValue(wxGetApp().params
.Password
);
1543 pParamDirPathTxt
->SetValue(wxGetApp().params
.DirPath
);
1545 } // CparameterDlg::PutData()
1548 bool CparameterDlg::GetData()
1551 if (pParamODBCSourceList
->GetStringSelection() != "")
1553 tStr
= pParamODBCSourceList
->GetStringSelection();
1554 if (tStr
.Length() > (sizeof(wxGetApp().params
.ODBCSource
)-1))
1557 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());
1558 wxMessageBox(errmsg
,"Internal program error...",wxOK
| wxICON_EXCLAMATION
);
1561 wxStrcpy(wxGetApp().params
.ODBCSource
, tStr
);
1566 tStr
= pParamUserNameTxt
->GetValue();
1567 if (tStr
.Length() > (sizeof(wxGetApp().params
.UserName
)-1))
1570 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());
1571 wxMessageBox(errmsg
,"Internal program error...",wxOK
| wxICON_EXCLAMATION
);
1574 wxStrcpy(wxGetApp().params
.UserName
, tStr
);
1576 tStr
= pParamPasswordTxt
->GetValue();
1577 if (tStr
.Length() > (sizeof(wxGetApp().params
.Password
)-1))
1580 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());
1581 wxMessageBox(errmsg
,"Internal program error...",wxOK
| wxICON_EXCLAMATION
);
1584 wxStrcpy(wxGetApp().params
.Password
,tStr
);
1586 tStr
= pParamDirPathTxt
->GetValue();
1587 tStr
.Replace("\\","/");
1588 if (tStr
.Length() > (sizeof(wxGetApp().params
.DirPath
)-1))
1591 errmsg
.Printf("DirPath is longer than the data structure to hold it.\n'Cparameter.DirPath' must have a larger character array\nto handle a data source with this long of a name\n\nThe password currently specified is %d characters long.",tStr
.Length());
1592 wxMessageBox(errmsg
,"Internal program error...",wxOK
| wxICON_EXCLAMATION
);
1595 wxStrcpy(wxGetApp().params
.DirPath
,tStr
);
1597 } // CparameterDlg::GetData()
1600 bool CparameterDlg::Save()
1602 Cparameters saveParams
= wxGetApp().params
;
1605 wxGetApp().params
= saveParams
;
1610 if ((paramFile
= fopen(paramFilename
, "wt")) == NULL
)
1613 tStr
.Printf("Unable to write/overwrite '%s'.",paramFilename
);
1614 wxMessageBox(tStr
,"File I/O Error...",wxOK
| wxICON_EXCLAMATION
);
1618 fputs(wxGetApp().params
.ODBCSource
, paramFile
);
1619 fputc('\n', paramFile
);
1620 fputs(wxGetApp().params
.UserName
, paramFile
);
1621 fputc('\n', paramFile
);
1622 fputs(wxGetApp().params
.Password
, paramFile
);
1623 fputc('\n', paramFile
);
1624 fputs(wxGetApp().params
.DirPath
, paramFile
);
1625 fputc('\n', paramFile
);
1629 } // CparameterDlg::Save()
1632 void CparameterDlg::FillDataSourceList()
1634 char Dsn
[SQL_MAX_DSN_LENGTH
+ 1];
1636 wxStringList strList
;
1638 while (wxDbGetDataSource(DbConnectInf
.Henv
, Dsn
, SQL_MAX_DSN_LENGTH
+1, DsDesc
, 255))
1643 char **p
= strList
.ListToArray();
1646 for (i
= 0; wxStrlen(p
[i
]); i
++)
1647 pParamODBCSourceList
->Append(p
[i
]);
1650 } // CparameterDlg::CparameterDlg::FillDataSourceList()
1653 BEGIN_EVENT_TABLE(CqueryDlg
, wxDialog
)
1654 EVT_BUTTON(-1, CqueryDlg::OnButton
)
1655 EVT_CLOSE(CqueryDlg::OnCloseWindow
)
1659 // CqueryDlg() constructor
1660 CqueryDlg::CqueryDlg(wxWindow
*parent
, wxDb
*pDb
, char *tblName
[], char *pWhereArg
) : wxDialog (parent
, QUERY_DIALOG
, "Query", wxPoint(-1, -1), wxSize(480, 360))
1662 wxBeginBusyCursor();
1666 masterTableName
= tblName
[0];
1667 widgetPtrsSet
= FALSE
;
1670 // Initialize the WHERE clause from the string passed in
1671 pWhere
= pWhereArg
; // Save a pointer to the output buffer
1672 if (wxStrlen(pWhere
) > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN
) // Check the length of the buffer passed in
1675 s
.Printf("Maximum where clause length exceeded.\nLength must be less than %d", DB_MAX_WHERE_CLAUSE_LEN
+1);
1676 wxMessageBox(s
,"Error...",wxOK
| wxICON_EXCLAMATION
);
1681 pQueryCol1Msg
= new wxStaticText(this, QUERY_DIALOG_COL_MSG
, "Column 1:", wxPoint( 10, 10), wxSize( 69, 16), 0, "QueryCol1Msg");
1682 pQueryCol1Choice
= new wxChoice(this, QUERY_DIALOG_COL_CHOICE
, wxPoint( 10, 27), wxSize(250, 27), 0, 0, 0, wxDefaultValidator
, "QueryCol1Choice");
1683 pQueryNotMsg
= new wxStaticText(this, QUERY_DIALOG_NOT_MSG
, "NOT", wxPoint(268, 10), wxSize( -1, -1), 0, "QueryNotMsg");
1684 pQueryNotCheck
= new wxCheckBox(this, QUERY_DIALOG_NOT_CHECKBOX
, "", wxPoint(275, 37), wxSize( 20, 20), 0, wxDefaultValidator
, "QueryNotCheck");
1686 wxString choice_strings
[9];
1687 choice_strings
[0] = "=";
1688 choice_strings
[1] = "<";
1689 choice_strings
[2] = ">";
1690 choice_strings
[3] = "<=";
1691 choice_strings
[4] = ">=";
1692 choice_strings
[5] = "Begins";
1693 choice_strings
[6] = "Contains";
1694 choice_strings
[7] = "Like";
1695 choice_strings
[8] = "Between";
1697 pQueryOperatorMsg
= new wxStaticText(this, QUERY_DIALOG_OP_MSG
, "Operator:", wxPoint(305, 10), wxSize( -1, -1), 0, "QueryOperatorMsg");
1698 pQueryOperatorChoice
= new wxChoice(this, QUERY_DIALOG_OP_CHOICE
, wxPoint(305, 27), wxSize( 80, 27), 9, choice_strings
, 0, wxDefaultValidator
, "QueryOperatorChoice");
1699 pQueryCol2Msg
= new wxStaticText(this, QUERY_DIALOG_COL2_MSG
, "Column 2:", wxPoint( 10, 65), wxSize( 69, 16), 0, "QueryCol2Msg");
1700 pQueryCol2Choice
= new wxChoice(this, QUERY_DIALOG_COL2_CHOICE
, wxPoint( 10, 82), wxSize(250, 27), 0, 0, 0, wxDefaultValidator
, "QueryCol2Choice");
1701 pQuerySqlWhereMsg
= new wxStaticText(this, QUERY_DIALOG_WHERE_MSG
, "SQL where clause:", wxPoint( 10, 141), wxSize( -1, -1), 0, "QuerySqlWhereMsg");
1702 pQuerySqlWhereMtxt
= new wxTextCtrl(this, QUERY_DIALOG_WHERE_TEXT
, "", wxPoint( 10, 159), wxSize(377, 134), wxTE_MULTILINE
, wxDefaultValidator
, "QuerySqlWhereMtxt");
1703 pQueryAddBtn
= new wxButton(this, QUERY_DIALOG_ADD
, "&Add", wxPoint(406, 24), wxSize( 56, 26), 0, wxDefaultValidator
, "QueryAddBtn");
1704 pQueryAndBtn
= new wxButton(this, QUERY_DIALOG_AND
, "A&nd", wxPoint(406, 58), wxSize( 56, 26), 0, wxDefaultValidator
, "QueryAndBtn");
1705 pQueryOrBtn
= new wxButton(this, QUERY_DIALOG_OR
, "&Or", wxPoint(406, 92), wxSize( 56, 26), 0, wxDefaultValidator
, "QueryOrBtn");
1706 pQueryLParenBtn
= new wxButton(this, QUERY_DIALOG_LPAREN
, "(", wxPoint(406, 126), wxSize( 26, 26), 0, wxDefaultValidator
, "QueryLParenBtn");
1707 pQueryRParenBtn
= new wxButton(this, QUERY_DIALOG_RPAREN
, ")", wxPoint(436, 126), wxSize( 26, 26), 0, wxDefaultValidator
, "QueryRParenBtn");
1708 pQueryDoneBtn
= new wxButton(this, QUERY_DIALOG_DONE
, "&Done", wxPoint(406, 185), wxSize( 56, 26), 0, wxDefaultValidator
, "QueryDoneBtn");
1709 pQueryClearBtn
= new wxButton(this, QUERY_DIALOG_CLEAR
, "C&lear", wxPoint(406, 218), wxSize( 56, 26), 0, wxDefaultValidator
, "QueryClearBtn");
1710 pQueryCountBtn
= new wxButton(this, QUERY_DIALOG_COUNT
, "&Count", wxPoint(406, 252), wxSize( 56, 26), 0, wxDefaultValidator
, "QueryCountBtn");
1711 pQueryValue1Msg
= new wxStaticText(this, QUERY_DIALOG_VALUE1_MSG
, "Value:", wxPoint(277, 66), wxSize( -1, -1), 0, "QueryValue1Msg");
1712 pQueryValue1Txt
= new wxTextCtrl(this, QUERY_DIALOG_VALUE1_TEXT
, "", wxPoint(277, 83), wxSize(108, 25), 0, wxDefaultValidator
, "QueryValue1Txt");
1713 pQueryValue2Msg
= new wxStaticText(this, QUERY_DIALOG_VALUE2_MSG
, "AND", wxPoint(238, 126), wxSize( -1, -1), 0, "QueryValue2Msg");
1714 pQueryValue2Txt
= new wxTextCtrl(this, QUERY_DIALOG_VALUE2_TEXT
, "", wxPoint(277, 120), wxSize(108, 25), 0, wxDefaultValidator
, "QueryValue2Txt");
1715 pQueryHintGrp
= new wxStaticBox(this, QUERY_DIALOG_HINT_GROUP
, "", wxPoint( 10, 291), wxSize(377, 40), 0, "QueryHintGrp");
1716 pQueryHintMsg
= new wxStaticText(this, QUERY_DIALOG_HINT_MSG
, "", wxPoint( 16, 306), wxSize( -1, -1), 0, "QueryHintMsg");
1718 widgetPtrsSet
= TRUE
;
1719 // Initialize the dialog
1721 pQueryCol2Choice
->Append("VALUE -->");
1722 colInf
= pDB
->GetColumns(tblName
);
1728 tStr
= "ODBC error during GetColumns()\n\n";
1729 tStr
+= GetExtendedDBErrorMsg(pDb
,__FILE__
,__LINE__
);
1730 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
1735 for (i
= 0; colInf
[i
].colName
&& wxStrlen(colInf
[i
].colName
); i
++)
1737 // If there is more than one table being queried, qualify
1738 // the column names with the table name prefix.
1739 if (tblName
[1] && wxStrlen(tblName
[1]))
1741 qualName
.Printf("%s.%s", colInf
[i
].tableName
, colInf
[i
].colName
);
1742 pQueryCol1Choice
->Append(qualName
);
1743 pQueryCol2Choice
->Append(qualName
);
1745 else // Single table query, append just the column names
1747 pQueryCol1Choice
->Append(colInf
[i
].colName
);
1748 pQueryCol2Choice
->Append(colInf
[i
].colName
);
1752 pQueryCol1Choice
->SetSelection(0);
1753 pQueryCol2Choice
->SetSelection(0);
1754 pQueryOperatorChoice
->SetSelection(0);
1756 pQueryValue2Msg
->Show(FALSE
);
1757 pQueryValue2Txt
->Show(FALSE
);
1759 pQueryHintMsg
->SetLabel(langQRY_EQ
);
1761 pQuerySqlWhereMtxt
->SetValue(pWhere
);
1765 // Display the dialog window
1768 } // CqueryDlg() constructor
1771 CqueryDlg::~CqueryDlg()
1773 } // CqueryDlg::~CqueryDlg() destructor
1776 void CqueryDlg::OnButton(wxCommandEvent
&event
)
1778 wxWindow
*win
= (wxWindow
*) event
.GetEventObject();
1779 OnCommand( *win
, event
);
1780 } // CqueryDlg::OnButton()
1783 void CqueryDlg::OnCommand(wxWindow
& win
, wxCommandEvent
& event
)
1785 // Widget pointers won't be set when the dialog is constructed.
1786 // Control is passed through this function once for each widget on
1787 // a dialog as the dialog is constructed.
1791 wxString widgetName
= win
.GetName();
1793 // Operator choice box
1794 if (widgetName
== pQueryOperatorChoice
->GetName())
1796 // Set the help text
1797 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
1800 pQueryHintMsg
->SetLabel(langQRY_EQ
);
1803 pQueryHintMsg
->SetLabel(langQRY_LT
);
1806 pQueryHintMsg
->SetLabel(langQRY_GT
);
1809 pQueryHintMsg
->SetLabel(langQRY_LE
);
1812 pQueryHintMsg
->SetLabel(langQRY_GE
);
1815 pQueryHintMsg
->SetLabel(langQRY_BEGINS
);
1818 pQueryHintMsg
->SetLabel(langQRY_CONTAINS
);
1821 pQueryHintMsg
->SetLabel(langQRY_LIKE
);
1824 pQueryHintMsg
->SetLabel(langQRY_BETWEEN
);
1828 // Hide the value2 widget
1829 pQueryValue2Msg
->Show(FALSE
); // BETWEEN will show this widget
1830 pQueryValue2Txt
->Show(FALSE
); // BETWEEN will show this widget
1832 // Disable the NOT operator for <, <=, >, >=
1833 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
1839 pQueryNotCheck
->SetValue(0);
1840 pQueryNotCheck
->Enable(FALSE
);
1843 pQueryNotCheck
->Enable(TRUE
);
1847 // Manipulate the dialog to handle the selected operator
1848 switch((qryOp
) pQueryOperatorChoice
->GetSelection())
1855 pQueryCol2Choice
->Enable(TRUE
);
1856 if (pQueryCol2Choice
->GetSelection()) // Column name is highlighted
1858 pQueryValue1Msg
->Show(FALSE
);
1859 pQueryValue1Txt
->Show(FALSE
);
1861 else // "Value" is highlighted
1863 pQueryValue1Msg
->Show(TRUE
);
1864 pQueryValue1Txt
->Show(TRUE
);
1865 pQueryValue1Txt
->SetFocus();
1871 pQueryCol2Choice
->SetSelection(0);
1872 pQueryCol2Choice
->Enable(FALSE
);
1873 pQueryValue1Msg
->Show(TRUE
);
1874 pQueryValue1Txt
->Show(TRUE
);
1875 pQueryValue1Txt
->SetFocus();
1878 pQueryCol2Choice
->SetSelection(0);
1879 pQueryCol2Choice
->Enable(FALSE
);
1880 pQueryValue2Msg
->Show(TRUE
);
1881 pQueryValue2Txt
->Show(TRUE
);
1882 pQueryValue1Msg
->Show(TRUE
);
1883 pQueryValue1Txt
->Show(TRUE
);
1884 pQueryValue1Txt
->SetFocus();
1890 } // Operator choice box
1893 if (widgetName
== pQueryCol2Choice
->GetName())
1895 if (pQueryCol2Choice
->GetSelection()) // Column name is highlighted
1897 pQueryValue1Msg
->Show(FALSE
);
1898 pQueryValue1Txt
->Show(FALSE
);
1900 else // "Value" is highlighted
1902 pQueryValue1Msg
->Show(TRUE
);
1903 pQueryValue1Txt
->Show(TRUE
);
1904 pQueryValue1Txt
->SetFocus();
1907 } // Column 2 choice
1910 if (widgetName
== pQueryAddBtn
->GetName())
1917 if (widgetName
== pQueryAndBtn
->GetName())
1919 AppendToWhere(" AND\n");
1924 if (widgetName
== pQueryOrBtn
->GetName())
1926 AppendToWhere(" OR\n");
1930 // Left Paren button
1931 if (widgetName
== pQueryLParenBtn
->GetName())
1935 } // Left Paren button
1937 // Right paren button
1938 if (widgetName
== pQueryRParenBtn
->GetName())
1942 } // Right Paren button
1945 if (widgetName
== pQueryDoneBtn
->GetName())
1947 // Be sure the where clause will not overflow the output buffer
1948 if (wxStrlen(pQuerySqlWhereMtxt
->GetValue()) > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN
)
1951 s
.Printf("Maximum where clause length exceeded.\nLength must be less than %d", DB_MAX_WHERE_CLAUSE_LEN
+1);
1952 wxMessageBox(s
,"Error...",wxOK
| wxICON_EXCLAMATION
);
1955 // Validate the where clause for things such as matching parens
1956 if (!ValidateWhereClause())
1958 // Copy the where clause to the output buffer and exit
1959 wxStrcpy(pWhere
, pQuerySqlWhereMtxt
->GetValue());
1965 if (widgetName
== pQueryClearBtn
->GetName())
1967 bool Ok
= (wxMessageBox("Are you sure you wish to clear the Query?","Confirm",wxYES_NO
|wxICON_QUESTION
) == wxYES
);
1970 pQuerySqlWhereMtxt
->SetValue("");
1975 if (widgetName
== pQueryCountBtn
->GetName())
1977 wxBeginBusyCursor();
1983 } // CqueryDlg::OnCommand
1986 void CqueryDlg::OnCloseWindow(wxCloseEvent
& event
)
2001 GetParent()->SetFocus();
2006 SetReturnCode(1); // added so BoundsChecker would not report use of uninitialized variable
2009 } // CqueryDlg::OnCloseWindow()
2012 void CqueryDlg::AppendToWhere(char *s
)
2014 wxString whereStr
= pQuerySqlWhereMtxt
->GetValue();
2016 pQuerySqlWhereMtxt
->SetValue(whereStr
);
2017 } // CqueryDlg::AppendToWhere()
2020 void CqueryDlg::ProcessAddBtn()
2022 qryOp oper
= (qryOp
) pQueryOperatorChoice
->GetSelection();
2024 // Verify that eveything is filled in correctly
2025 if (pQueryCol2Choice
->GetSelection() == 0) // "Value" is selected
2027 // Verify that value 1 is filled in
2028 if (wxStrlen(pQueryValue1Txt
->GetValue()) == 0)
2031 pQueryValue1Txt
->SetFocus();
2034 // For the BETWEEN operator, value 2 must be filled in as well
2035 if (oper
== qryOpBETWEEN
&&
2036 wxStrlen(pQueryValue2Txt
->GetValue()) == 0)
2039 pQueryValue2Txt
->SetFocus();
2044 // Build the expression and append it to the where clause window
2045 wxString s
= pQueryCol1Choice
->GetStringSelection();
2047 if (pQueryNotCheck
->GetValue() && (oper
!= qryOpEQ
))
2053 if (pQueryNotCheck
->GetValue()) // NOT box is checked
2082 int col1Idx
= pQueryCol1Choice
->GetSelection();
2085 if (colInf
[col1Idx
].sqlDataType
== SQL_VARCHAR
||
2086 oper
== qryOpBEGINS
||
2087 oper
== qryOpCONTAINS
||
2091 if (pQueryCol2Choice
->GetSelection()) // Column name
2092 s
+= pQueryCol2Choice
->GetStringSelection();
2093 else // Column 2 is a "value"
2097 if (oper
== qryOpCONTAINS
)
2099 s
+= pQueryValue1Txt
->GetValue();
2100 if (oper
== qryOpCONTAINS
|| oper
== qryOpBEGINS
)
2106 if (oper
== qryOpBETWEEN
)
2111 s
+= pQueryValue2Txt
->GetValue();
2116 AppendToWhere((char*) (const char*) s
);
2118 } // CqueryDlg::ProcessAddBtn()
2121 void CqueryDlg::ProcessCountBtn()
2123 if (!ValidateWhereClause())
2126 if (dbTable
== 0) // wxDbTable object needs to be created and opened
2128 if (!(dbTable
= new wxDbTable(pDB
, masterTableName
, 0, NULL
, !wxDB_QUERY_ONLY
, DbConnectInf
.defaultDir
)))
2130 wxMessageBox("Memory allocation failed creating a wxDbTable object.","Error...",wxOK
| wxICON_EXCLAMATION
);
2133 if (!dbTable
->Open())
2136 tStr
= "ODBC error during Open()\n\n";
2137 tStr
+= GetExtendedDBErrorMsg(dbTable
->GetDb(),__FILE__
,__LINE__
);
2138 wxMessageBox(tStr
,"ODBC Error...",wxOK
| wxICON_EXCLAMATION
);
2143 // Count() with WHERE clause
2146 whereStr
= pQuerySqlWhereMtxt
->GetValue();
2147 dbTable
->SetWhereClause(whereStr
.c_str());
2148 ULONG whereCnt
= dbTable
->Count();
2150 // Count() of all records in the table
2151 dbTable
->SetWhereClause("");
2152 ULONG totalCnt
= dbTable
->Count();
2154 if (whereCnt
> 0 || totalCnt
== 0)
2157 tStr
.Printf("%lu of %lu records match the query criteria.",whereCnt
,totalCnt
);
2158 wxMessageBox(tStr
,"Notice...",wxOK
| wxICON_INFORMATION
);
2163 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
);
2164 wxMessageBox(tStr
,"Notice...",wxOK
| wxICON_INFORMATION
);
2167 // After a wxMessageBox, the focus does not necessarily return to the
2168 // window which was the focus when the message box popped up, so return
2169 // focus to the Query dialog for certain
2172 } // CqueryDlg::ProcessCountBtn()
2175 bool CqueryDlg::ValidateWhereClause()
2177 wxString where
= pQuerySqlWhereMtxt
->GetValue();
2179 if (where
.Freq('(') != where
.Freq(')'))
2181 wxMessageBox("There are mismatched parenthesis in the constructed where clause","Error...",wxOK
| wxICON_EXCLAMATION
);
2184 // After a wxMessageBox, the focus does not necessarily return to the
2185 // window which was the focus when the message box popped up, so return
2186 // focus to the Query dialog for certain
2191 } // CqueryDlg::ValidateWhereClause()
2197 TEST CODE FOR TESTING THE wxDbCreateDataSource() FUNCTION
2200 result = wxDbCreateDataSource("Microsoft Access Driver (*.mdb)","GLT-TEST2","GLT-Descrip",FALSE,"",this);
2203 // check for errors caused by ConfigDSN based functions
2206 wxChar errMsg[500+1];
2209 SQLInstallerError(1,&retcode,errMsg,500,&cb);
2211 wxMessageBox("FAILED creating data source","FAILED");
2214 wxMessageBox("SUCCEEDED creating data source","SUCCESS");