]> git.saurik.com Git - wxWidgets.git/blame - samples/db/listdb.cpp
Fixed a problem in ConvertWXArrayToC() that would assign a string to an incorrect...
[wxWidgets.git] / samples / db / listdb.cpp
CommitLineData
108106cf
JS
1///////////////////////////////////////////////////////////////////////////////
2// Name: listdb.cpp
3// Purpose: Data table lookup listbox code
4// Author: George Tasker/Doug Card
5// Modified by:
6// Created: 1996
7// RCS-ID: $Id$
8// Copyright: (c) 1996 Remstar International, Inc.
9// Licence: wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12/*
13// SYNOPSIS START
14
15 Member functions for the classes defined in LISTDB.H
16
e70e8f4c
GT
17 This class is used to present a generic ListBox lookup window for
18 use with any of the object creation/selection choice widgets. This
19 dialog window will present a (possibly) scrolling list of values
20 that come from a data table source. Based on the object type passed
21 in the constructor, a ListBox is built to present the user with a
22 single selection listbox.
23
24 The string selected from the list box is stored in the Global variable
25 "ListDB_Seclection", and will remain set until another interation of this
26 routine is called.
27
28 For each object (database) type that is to be used, an overridden
29 constructor should be written to appropriately link to the proper
30 data table/object for building the list.
31
108106cf 32 The data table record access is all handled through the routines
f6bcfd97 33 in this module, interfacing with the methods defined in wxDbTable.
108106cf 34
e70e8f4c
GT
35 All objects which use data table access must be initialized and
36 have opened the table prior to passing them in the dialog
37 constructor, and the 'where' query should already have been set
38 and performed before creating this dialog instance.
108106cf
JS
39
40// SYNOPSIS STOP
41*/
42
43#ifdef __GNUG__
44#pragma implementation "listdb.h"
45#endif
46
47#include "wx/wxprec.h"
48
49#ifdef __BORLANDC__
50#pragma hdrstop
51#endif //__BORLANDC__
52
53#ifndef WX_PRECOMP
54#include <wx/wx.h>
55#endif //WX_PRECOMP
56
57#include <wx/dbtable.h>
58
3f755e2d 59extern wxDbList WXDLLEXPORT *PtrBegDbList; /* from db.cpp, used in getting back error results from db connections */
65d7ddc4 60
108106cf
JS
61#include "listdb.h"
62
63// Global structure for holding ODBC connection information
3f755e2d 64extern wxDbConnectInf DbConnectInf;
108106cf
JS
65
66// Global database connection
f6bcfd97 67extern wxDb *READONLY_DB;
108106cf
JS
68
69
70// Used for passing the selected listbox selection back to the calling
71// routine. This variable must be declared as 'extern' in the calling
72// source module
73char ListDB_Selection[LOOKUP_COL_LEN+1];
74
75// If the listbox contains two columns of data, the second column is
76// returned in this variable.
77char ListDB_Selection2[LOOKUP_COL_LEN+1];
78
79// Constants
5b077d48 80const int LISTDB_NO_SPACES_BETWEEN_COLS = 3;
108106cf
JS
81
82
65d7ddc4
GT
83
84/*
85 * This function will return the exact string(s) from the database engine
86 * indicating all error conditions which have just occured during the
87 * last call to the database engine.
88 *
89 * This demo uses the returned string by displaying it in a wxMessageBox. The
90 * formatting therefore is not the greatest, but this is just a demo, not a
91 * finished product. :-) gt
92 *
93 * NOTE: The value returned by this function is for temporary use only and
94 * should be copied for long term use
95 */
3ca6a5f0 96const char *GetExtendedDBErrorMsg2(char *ErrFile, int ErrLine)
65d7ddc4 97{
e70e8f4c 98 static wxString msg;
3ca6a5f0 99 msg = "";
e70e8f4c
GT
100
101 wxString tStr;
102
103 if (ErrFile || ErrLine)
104 {
105 msg += "File: ";
106 msg += ErrFile;
107 msg += " Line: ";
108 tStr.Printf("%d",ErrLine);
f6bcfd97 109 msg += tStr.c_str();
e70e8f4c
GT
110 msg += "\n";
111 }
112
113 msg.Append ("\nODBC errors:\n");
114 msg += "\n";
115
116 /* Scan through each database connection displaying
117 * any ODBC errors that have occured. */
3f755e2d
GT
118 wxDbList *pDbList;
119 for (pDbList = PtrBegDbList; pDbList; pDbList = pDbList->PtrNext)
e70e8f4c
GT
120 {
121 // Skip over any free connections
122 if (pDbList->Free)
123 continue;
124 // Display errors for this connection
125 for (int i = 0; i < DB_MAX_ERROR_HISTORY; i++)
126 {
127 if (pDbList->PtrDb->errorList[i])
128 {
129 msg.Append(pDbList->PtrDb->errorList[i]);
f6bcfd97 130 if (wxStrcmp(pDbList->PtrDb->errorList[i],"") != 0)
e70e8f4c 131 msg.Append("\n");
3ca6a5f0
BP
132 // Clear the errmsg buffer so the next error will not
133 // end up showing the previous error that have occurred
134 wxStrcpy(pDbList->PtrDb->errorList[i],"");
e70e8f4c
GT
135 }
136 }
137 }
138 msg += "\n";
139
3ca6a5f0 140 return /*(char*) (const char*) msg*/msg.c_str();
65d7ddc4
GT
141} // GetExtendedDBErrorMsg
142
143
144
108106cf 145// Clookup constructor
f6bcfd97 146Clookup::Clookup(char *tblName, char *colName) : wxDbTable(READONLY_DB, tblName, 1, NULL, !wxDB_QUERY_ONLY, DbConnectInf.defaultDir)
108106cf
JS
147{
148
e70e8f4c 149 SetColDefs (0, colName, DB_DATA_TYPE_VARCHAR, lookupCol, SQL_C_CHAR, LOOKUP_COL_LEN+1, FALSE, FALSE);
108106cf
JS
150
151} // Clookup()
152
153
154// Clookup2 constructor
f6bcfd97
BP
155Clookup2::Clookup2(char *tblName, char *colName1, char *colName2, wxDb *pDb)
156 : wxDbTable(pDb, tblName, (1 + (wxStrlen(colName2) > 0)), NULL, !wxDB_QUERY_ONLY, DbConnectInf.defaultDir)
108106cf 157{
e70e8f4c 158 int i = 0;
108106cf 159
e70e8f4c 160 SetColDefs (i, colName1, DB_DATA_TYPE_VARCHAR, lookupCol1, SQL_C_CHAR, LOOKUP_COL_LEN+1, FALSE, FALSE);
108106cf 161
f6bcfd97 162 if (wxStrlen(colName2) > 0)
e70e8f4c 163 SetColDefs (++i, colName2, DB_DATA_TYPE_VARCHAR, lookupCol2, SQL_C_CHAR, LOOKUP_COL_LEN+1, FALSE, FALSE);
108106cf
JS
164
165} // Clookup2()
166
167
65d7ddc4 168BEGIN_EVENT_TABLE(ClookUpDlg, wxDialog)
e70e8f4c 169// EVT_LISTBOX(LOOKUP_DIALOG_SELECT, ClookUpDlg::SelectCallback)
65d7ddc4
GT
170 EVT_BUTTON(LOOKUP_DIALOG_OK, ClookUpDlg::OnButton)
171 EVT_BUTTON(LOOKUP_DIALOG_CANCEL, ClookUpDlg::OnButton)
172 EVT_CLOSE(ClookUpDlg::OnClose)
173END_EVENT_TABLE()
174
108106cf
JS
175// This is a generic lookup constructor that will work with any table and any column
176ClookUpDlg::ClookUpDlg(wxWindow *parent, char *windowTitle, char *tableName, char *colName,
e70e8f4c 177 char *where, char *orderBy) : wxDialog (parent, LOOKUP_DIALOG, "Select...", wxPoint(-1, -1), wxSize(400, 290))
108106cf 178{
e70e8f4c
GT
179 wxBeginBusyCursor();
180
f6bcfd97 181 wxStrcpy(ListDB_Selection,"");
e70e8f4c
GT
182 widgetPtrsSet = FALSE;
183 lookup = 0;
184 lookup2 = 0;
185 noDisplayCols = 1;
186 col1Len = 0;
187
188 pLookUpSelectList = new wxListBox(this, LOOKUP_DIALOG_SELECT, wxPoint( 5, 15), wxSize(384, 195), 0, 0, wxLB_SINGLE|wxLB_ALWAYS_SB, wxDefaultValidator, "LookUpSelectList");
189 pLookUpOkBtn = new wxButton(this, LOOKUP_DIALOG_OK, "&Ok", wxPoint(113, 222), wxSize( 70, 35), 0, wxDefaultValidator, "LookUpOkBtn");
190 pLookUpCancelBtn = new wxButton(this, LOOKUP_DIALOG_CANCEL, "C&ancel", wxPoint(212, 222), wxSize( 70, 35), 0, wxDefaultValidator, "LookUpCancelBtn");
191
192 widgetPtrsSet = TRUE;
193
194 // Query the lookup table and display the result set
195 if (!(lookup = new Clookup(tableName, colName)))
196 {
197 wxMessageBox("Error allocating memory for 'Clookup'object.","Error...");
198 Close();
199 return;
200 }
201
202 if (!lookup->Open())
203 {
204 wxString tStr;
205 tStr.Printf("Unable to open the table '%s'.",tableName);
206 wxMessageBox(tStr,"ODBC Error...");
207 Close();
208 return;
209 }
210
f6bcfd97
BP
211 lookup->SetOrderByClause(orderBy);
212 lookup->SetWhereClause(where);
e70e8f4c
GT
213 if (!lookup->Query())
214 {
215 wxMessageBox("ODBC error during Query()","ODBC Error...");
216 Close();
217 return;
218 }
219
220 // Fill in the list box from the query result set
221 while (lookup->GetNext())
222 pLookUpSelectList->Append(lookup->lookupCol);
223
224 // Highlight the first list item
225 pLookUpSelectList->SetSelection(0);
226
227 // Make the OK activate by pressing Enter
228 if (pLookUpSelectList->Number())
229 pLookUpOkBtn->SetDefault();
230 else
231 {
232 pLookUpCancelBtn->SetDefault();
233 pLookUpOkBtn->Enable(FALSE);
234 }
235
236 // Display the dialog window
237 SetTitle(windowTitle);
238 Centre(wxBOTH);
239 wxEndBusyCursor();
240 ShowModal();
108106cf
JS
241
242} // Generic lookup constructor
243
244
245//
246// This is a generic lookup constructor that will work with any table and any column.
247// It extends the capabilites of the lookup dialog in the following ways:
248//
e70e8f4c 249// 1) 2 columns rather than one
108106cf
JS
250// 2) The ability to select DISTINCT column values
251//
252// Only set distinctValues equal to true if necessary. In many cases, the constraints
253// of the index(es) will enforce this uniqueness. Selecting DISTINCT does require
254// overhead by the database to ensure that all values returned are distinct. Therefore,
255// use this ONLY when you need it.
256//
257// For complicated queries, you can pass in the sql select statement. This would be
258// necessary if joins are involved since by default both columns must come from the
259// same table.
260//
261// If you do query by sql statement, you must pass in the maximum lenght of column1,
262// since it cannot be derived when you query using your own sql statement.
263//
264// The optional database connection can be used if you'd like the lookup class
265// to use a database pointer other than the global READONLY_DB. This is necessary if
266// records are being saved, but not committed to the db, yet should be included
267// in the lookup window.
268//
269ClookUpDlg::ClookUpDlg(wxWindow *parent, char *windowTitle, char *tableName,
e70e8f4c 270 char *dispCol1, char *dispCol2, char *where, char *orderBy, bool distinctValues,
f6bcfd97 271 char *selectStmt, int maxLenCol1, wxDb *pDb, bool allowOk) : wxDialog (parent, LOOKUP_DIALOG, "Select...", wxPoint(-1, -1), wxSize(400, 290))
108106cf 272{
e70e8f4c
GT
273 wxBeginBusyCursor();
274
f6bcfd97
BP
275 wxStrcpy(ListDB_Selection,"");
276 wxStrcpy(ListDB_Selection2,"");
e70e8f4c
GT
277 widgetPtrsSet = FALSE;
278 lookup = 0;
279 lookup2 = 0;
f6bcfd97 280 noDisplayCols = (wxStrlen(dispCol2) ? 2 : 1);
e70e8f4c
GT
281 col1Len = 0;
282
283 wxFont fixedFont(12,wxMODERN,wxNORMAL,wxNORMAL);
284
285 // this is done with fixed font so that the second column (if any) will be left
286 // justified in the second column
287 pLookUpSelectList = new wxListBox(this, LOOKUP_DIALOG_SELECT, wxPoint(5, 15), wxSize(384, 195), 0, 0, wxLB_SINGLE|wxLB_ALWAYS_SB, wxDefaultValidator, "LookUpSelectList");
1fc5dd6f
JS
288
289 pLookUpSelectList->SetFont(fixedFont);
290
e70e8f4c
GT
291 pLookUpOkBtn = new wxButton(this, LOOKUP_DIALOG_OK, "&Ok", wxPoint(113, 222), wxSize(70, 35), 0, wxDefaultValidator, "LookUpOkBtn");
292 pLookUpCancelBtn = new wxButton(this, LOOKUP_DIALOG_CANCEL, "C&ancel", wxPoint(212, 222), wxSize(70, 35), 0, wxDefaultValidator, "LookUpCancelBtn");
293
294 widgetPtrsSet = TRUE;
295
296 // Query the lookup table and display the result set
297 if (!(lookup2 = new Clookup2(tableName, dispCol1, dispCol2, pDb)))
298 {
299 wxMessageBox("Error allocating memory for 'Clookup2'object.","Error...");
300 Close();
301 return;
302 }
303
304 if (!lookup2->Open())
305 {
306 wxString tStr;
307 tStr.Printf("Unable to open the table '%s'.",tableName);
308 tStr += GetExtendedDBErrorMsg2(__FILE__,__LINE__);
309 wxMessageBox(tStr,"ODBC Error...");
310 Close();
311 return;
312 }
313
314 // If displaying 2 columns, determine the maximum length of column1
315 int maxColLen;
316 if (maxLenCol1)
317 maxColLen = col1Len = maxLenCol1; // user passed in max col length for column 1
318 else
319 {
320 maxColLen = LOOKUP_COL_LEN;
f6bcfd97 321 if (wxStrlen(dispCol2))
e70e8f4c
GT
322 {
323 wxString q = "SELECT MAX({fn LENGTH(";
324 q += dispCol1;
325 q += ")}), NULL";
326 q += " FROM ";
327 q += tableName;
f6bcfd97 328 if (wxStrlen(where))
e70e8f4c
GT
329 {
330 q += " WHERE ";
331 q += where;
332 }
333 if (!lookup2->QueryBySqlStmt((char*) (const char*) q))
334 {
335 wxMessageBox("ODBC error during QueryBySqlStmt()","ODBC Error...");
336 Close();
337 return;
338 }
339 if (lookup2->GetNext())
340 maxColLen = col1Len = atoi(lookup2->lookupCol1);
341 else
342 wxMessageBox("ODBC error during GetNext()","ODBC Error...");
343 }
344 }
345
346 // Query the actual record set
f6bcfd97 347 if (selectStmt && wxStrlen(selectStmt)) // Query by sql stmt passed in
e70e8f4c
GT
348 {
349 if (!lookup2->QueryBySqlStmt(selectStmt))
350 {
351 wxMessageBox("ODBC error during QueryBySqlStmt()","ODBC Error...");
352 Close();
353 return;
354 }
355 }
356 else // Query using where and order by clauses
357 {
f6bcfd97
BP
358 lookup2->SetOrderByClause(orderBy);
359 lookup2->SetWhereClause(where);
e70e8f4c
GT
360 if (!lookup2->Query(FALSE, distinctValues))
361 {
362 wxMessageBox("ODBC error during Query()","ODBC Error...");
363 Close();
364 return;
365 }
366 }
367
368 // Fill in the list box from the query result set
369 wxString s;
370 while (lookup2->GetNext())
371 {
372 s = lookup2->lookupCol1;
f6bcfd97 373 if (wxStrlen(dispCol2)) // Append the optional column 2
e70e8f4c 374 {
f6bcfd97 375 s.Append(' ', (maxColLen + LISTDB_NO_SPACES_BETWEEN_COLS - wxStrlen(lookup2->lookupCol1)));
e70e8f4c
GT
376 s.Append(lookup2->lookupCol2);
377 }
378 pLookUpSelectList->Append(s);
379 }
380
381 // Highlight the first list item
382 pLookUpSelectList->SetSelection(0);
383
384 // Make the OK activate by pressing Enter
385 if (pLookUpSelectList->Number())
386 pLookUpOkBtn->SetDefault();
387 else
388 {
389 pLookUpCancelBtn->SetDefault();
390 pLookUpOkBtn->Enable(FALSE);
391 }
392
393 pLookUpOkBtn->Enable(allowOk);
394
395 // Display the dialog window
396 SetTitle(windowTitle);
397 Centre(wxBOTH);
398 wxEndBusyCursor();
399 ShowModal();
108106cf
JS
400
401} // Generic lookup constructor 2
402
403
65d7ddc4 404void ClookUpDlg::OnClose(wxCloseEvent& event)
108106cf 405{
e70e8f4c
GT
406 widgetPtrsSet = FALSE;
407 GetParent()->Enable(TRUE);
108106cf 408
e70e8f4c
GT
409 if (lookup)
410 delete lookup;
411 if (lookup2)
412 delete lookup2;
108106cf 413
3ca6a5f0
BP
414 SetReturnCode(1);
415
e70e8f4c 416 while (wxIsBusy()) wxEndBusyCursor();
3ca6a5f0 417 event.Skip();
65d7ddc4 418
e70e8f4c 419// return TRUE;
108106cf
JS
420
421} // ClookUpDlg::OnClose
422
423
65d7ddc4
GT
424void ClookUpDlg::OnButton( wxCommandEvent &event )
425{
426 wxWindow *win = (wxWindow*) event.GetEventObject();
427 OnCommand( *win, event );
428}
429
430
108106cf
JS
431void ClookUpDlg::OnCommand(wxWindow& win, wxCommandEvent& event)
432{
e70e8f4c
GT
433 wxString widgetName = win.GetName();
434
435 if (widgetPtrsSet)
436 {
437 // OK Button
438 if (widgetName == pLookUpOkBtn->GetName())
439 {
440 if (pLookUpSelectList->GetSelection() != -1)
441 {
442 if (noDisplayCols == 1)
f6bcfd97 443 wxStrcpy (ListDB_Selection, pLookUpSelectList->GetStringSelection());
e70e8f4c
GT
444 else // 2 display columns
445 {
446 wxString s = pLookUpSelectList->GetStringSelection();
447 // Column 1
448 s = s.SubString(0, col1Len-1);
449 s = s.Strip();
f6bcfd97 450 wxStrcpy(ListDB_Selection, s);
e70e8f4c
GT
451 // Column 2
452 s = pLookUpSelectList->GetStringSelection();
453 s = s.Mid(col1Len + LISTDB_NO_SPACES_BETWEEN_COLS);
454 s = s.Strip();
f6bcfd97 455 wxStrcpy(ListDB_Selection2, s);
e70e8f4c
GT
456 }
457 }
458 else
459 {
f6bcfd97
BP
460 wxStrcpy(ListDB_Selection,"");
461 wxStrcpy(ListDB_Selection2,"");
e70e8f4c
GT
462 }
463 Close();
464 } // OK Button
465
466 // Cancel Button
467 if (widgetName == pLookUpCancelBtn->GetName())
468 {
f6bcfd97
BP
469 wxStrcpy (ListDB_Selection,"");
470 wxStrcpy (ListDB_Selection2,"");
e70e8f4c
GT
471 Close();
472 } // Cancel Button
473 }
108106cf
JS
474
475}; // ClookUpDlg::OnCommand
476
477// *********************************** listdb.cpp **********************************