]> git.saurik.com Git - wxWidgets.git/blame - samples/db/listdb.cpp
Factory some of wxFilterClassFactory into a base class.
[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 17 This class is used to present a generic ListBox lookup window for
925e9792 18 use with any of the object creation/selection choice widgets. This
e70e8f4c
GT
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
94613352 25 "ListDB_Selection", and will remain set until another interation of this
e70e8f4c
GT
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.
925e9792 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.
925e9792 39
108106cf
JS
40// SYNOPSIS STOP
41*/
42
108106cf
JS
43#include "wx/wxprec.h"
44
45#ifdef __BORLANDC__
46#pragma hdrstop
47#endif //__BORLANDC__
48
49#ifndef WX_PRECOMP
fb86524f 50#include "wx/wx.h"
108106cf
JS
51#endif //WX_PRECOMP
52
fb86524f 53#include "wx/dbtable.h"
108106cf 54
3f755e2d 55extern wxDbList WXDLLEXPORT *PtrBegDbList; /* from db.cpp, used in getting back error results from db connections */
65d7ddc4 56
108106cf 57#include "listdb.h"
049977d0 58//#include "dbtest.h"
108106cf
JS
59
60// Used for passing the selected listbox selection back to the calling
61// routine. This variable must be declared as 'extern' in the calling
62// source module
94613352 63wxChar ListDB_Selection[LOOKUP_COL_LEN+1];
108106cf
JS
64
65// If the listbox contains two columns of data, the second column is
66// returned in this variable.
94613352 67wxChar ListDB_Selection2[LOOKUP_COL_LEN+1];
108106cf
JS
68
69// Constants
5b077d48 70const int LISTDB_NO_SPACES_BETWEEN_COLS = 3;
108106cf
JS
71
72
049977d0
GT
73extern wxApp *DatabaseDemoApp;
74
65d7ddc4
GT
75
76/*
77 * This function will return the exact string(s) from the database engine
3103e8a9 78 * indicating all error conditions which have just occurred during the
65d7ddc4
GT
79 * last call to the database engine.
80 *
81 * This demo uses the returned string by displaying it in a wxMessageBox. The
82 * formatting therefore is not the greatest, but this is just a demo, not a
83 * finished product. :-) gt
84 *
85 * NOTE: The value returned by this function is for temporary use only and
86 * should be copied for long term use
87 */
e689d52a 88wxString GetExtendedDBErrorMsg2(wxDb *pDb, wxChar *ErrFile, int ErrLine)
65d7ddc4 89{
e70e8f4c 90 static wxString msg;
3fe813a9 91 msg = wxT("");
e70e8f4c
GT
92
93 wxString tStr;
94
95 if (ErrFile || ErrLine)
96 {
94613352 97 msg += wxT("File: ");
e70e8f4c 98 msg += ErrFile;
94613352
GT
99 msg += wxT(" Line: ");
100 tStr.Printf(wxT("%d"),ErrLine);
3fe813a9 101 msg += tStr.c_str();
94613352 102 msg += wxT("\n");
e70e8f4c
GT
103 }
104
94613352
GT
105 msg.Append (wxT("\nODBC errors:\n"));
106 msg += wxT("\n");
925e9792 107
3fe813a9
GT
108 // Display errors for this connection
109 int i;
110 for (i = 0; i < DB_MAX_ERROR_HISTORY; i++)
e70e8f4c 111 {
3fe813a9 112 if (pDb->errorList[i])
e70e8f4c 113 {
3fe813a9
GT
114 msg.Append(pDb->errorList[i]);
115 if (wxStrcmp(pDb->errorList[i],wxT("")) != 0)
116 msg.Append(wxT("\n"));
117 // Clear the errmsg buffer so the next error will not
118 // end up showing the previous error that have occurred
119 wxStrcpy(pDb->errorList[i],wxT(""));
e70e8f4c
GT
120 }
121 }
94613352 122 msg += wxT("\n");
e70e8f4c 123
e689d52a 124 return msg;
65d7ddc4
GT
125} // GetExtendedDBErrorMsg
126
127
108106cf 128// Clookup constructor
da1e87c4 129Clookup::Clookup(wxString tblName, wxString colName, wxDb *pDb, const wxString &defDir)
e689d52a 130 : wxDbTable(pDb, tblName, 1, (const wxString &)wxEmptyString, !wxDB_QUERY_ONLY,
049977d0 131 defDir)
108106cf
JS
132{
133
e689d52a 134 SetColDefs (0, colName, DB_DATA_TYPE_VARCHAR, lookupCol, SQL_C_WXCHAR, LOOKUP_COL_LEN+1, false, false);
108106cf
JS
135
136} // Clookup()
137
138
139// Clookup2 constructor
da1e87c4 140Clookup2::Clookup2(wxString tblName, wxString colName1, wxString colName2,
049977d0 141 wxDb *pDb, const wxString &defDir)
e689d52a 142 : wxDbTable(pDb, tblName, (UWORD)(1 + (wxStrlen(colName2) > 0)), (const wxString &)wxEmptyString,
049977d0 143 !wxDB_QUERY_ONLY, defDir)
108106cf 144{
049977d0
GT
145 wxASSERT(pDb);
146 wxASSERT(tblName);
147 wxASSERT(colName1);
148 wxASSERT(colName2);
149
e70e8f4c 150 int i = 0;
108106cf 151
e689d52a 152 SetColDefs ((UWORD)i, colName1, DB_DATA_TYPE_VARCHAR, lookupCol1, SQL_C_WXCHAR, LOOKUP_COL_LEN+1, false, false);
108106cf 153
f6bcfd97 154 if (wxStrlen(colName2) > 0)
e689d52a 155 SetColDefs ((UWORD)(++i), colName2, DB_DATA_TYPE_VARCHAR, lookupCol2, SQL_C_WXCHAR, LOOKUP_COL_LEN+1, false, false);
108106cf
JS
156
157} // Clookup2()
158
159
65d7ddc4 160BEGIN_EVENT_TABLE(ClookUpDlg, wxDialog)
65d7ddc4
GT
161 EVT_BUTTON(LOOKUP_DIALOG_OK, ClookUpDlg::OnButton)
162 EVT_BUTTON(LOOKUP_DIALOG_CANCEL, ClookUpDlg::OnButton)
163 EVT_CLOSE(ClookUpDlg::OnClose)
e689d52a 164 EVT_LISTBOX_DCLICK(LOOKUP_DIALOG_SELECT, ClookUpDlg::OnDClick)
65d7ddc4
GT
165END_EVENT_TABLE()
166
049977d0 167
108106cf 168// This is a generic lookup constructor that will work with any table and any column
e689d52a
GT
169ClookUpDlg::ClookUpDlg(wxWindow *parent, const wxString &windowTitle, const wxString &tableName,
170 const wxString &colName, const wxString &where, const wxString &orderBy,
049977d0 171 wxDb *pDb, const wxString &defDir)
6d841efd 172 : wxDialog (parent, LOOKUP_DIALOG, wxT("Select..."), wxDefaultPosition, wxSize(400, 290))
108106cf 173{
e70e8f4c 174 wxBeginBusyCursor();
925e9792 175
94613352 176 wxStrcpy(ListDB_Selection,wxT(""));
6d841efd 177 widgetPtrsSet = false;
e70e8f4c
GT
178 lookup = 0;
179 lookup2 = 0;
180 noDisplayCols = 1;
181 col1Len = 0;
182
e689d52a
GT
183 pLookUpSelectList = new wxListBox(this, LOOKUP_DIALOG_SELECT, wxPoint( 5, 15), wxSize(384, 195), 0, 0, wxLB_SINGLE|wxLB_ALWAYS_SB, wxDefaultValidator, wxT("LookUpSelectList"));
184 pLookUpOkBtn = new wxButton(this, LOOKUP_DIALOG_OK, wxT("&Ok"), wxPoint(113, 222), wxSize( 70, 35), 0, wxDefaultValidator, wxT("LookUpOkBtn"));
185 pLookUpCancelBtn = new wxButton(this, LOOKUP_DIALOG_CANCEL, wxT("C&ancel"), wxPoint(212, 222), wxSize( 70, 35), 0, wxDefaultValidator, wxT("LookUpCancelBtn"));
e70e8f4c 186
6d841efd 187 widgetPtrsSet = true;
e70e8f4c
GT
188
189 // Query the lookup table and display the result set
2f6c54eb 190 lookup = new Clookup(tableName, colName, pDb, defDir);
3fe813a9 191 if (!lookup)
e70e8f4c 192 {
e689d52a 193 wxMessageBox(wxT("Error allocating memory for 'Clookup' object."),wxT("Error..."));
e70e8f4c
GT
194 Close();
195 return;
196 }
197
198 if (!lookup->Open())
199 {
200 wxString tStr;
f0fb3b3b 201 tStr.Printf(wxT("Unable to open the table '%s'."), tableName.c_str());
ee377e7f
GT
202 wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),lookup->GetDb(),__TFILE__,__LINE__),
203 wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
204
e70e8f4c
GT
205 Close();
206 return;
207 }
208
f6bcfd97
BP
209 lookup->SetOrderByClause(orderBy);
210 lookup->SetWhereClause(where);
e70e8f4c
GT
211 if (!lookup->Query())
212 {
ee377e7f
GT
213 wxString tStr;
214 tStr = wxT("ODBC error during Query()\n\n");
215 wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),lookup->GetDb(),__TFILE__,__LINE__),
216 wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
217
e70e8f4c
GT
218 Close();
219 return;
220 }
221
222 // Fill in the list box from the query result set
223 while (lookup->GetNext())
224 pLookUpSelectList->Append(lookup->lookupCol);
225
e70e8f4c 226 // Make the OK activate by pressing Enter
2f8f7c77 227 if (pLookUpSelectList->GetCount())
ae883e9a
GT
228 {
229 pLookUpSelectList->SetSelection(0);
e70e8f4c 230 pLookUpOkBtn->SetDefault();
ae883e9a 231 }
e70e8f4c
GT
232 else
233 {
234 pLookUpCancelBtn->SetDefault();
6d841efd 235 pLookUpOkBtn->Enable(false);
e70e8f4c
GT
236 }
237
238 // Display the dialog window
239 SetTitle(windowTitle);
240 Centre(wxBOTH);
241 wxEndBusyCursor();
242 ShowModal();
108106cf
JS
243
244} // Generic lookup constructor
245
246
247//
248// This is a generic lookup constructor that will work with any table and any column.
249// It extends the capabilites of the lookup dialog in the following ways:
250//
e70e8f4c 251// 1) 2 columns rather than one
108106cf
JS
252// 2) The ability to select DISTINCT column values
253//
6d841efd 254// Only set distinctValues equal to true if necessary. In many cases, the constraints
108106cf
JS
255// of the index(es) will enforce this uniqueness. Selecting DISTINCT does require
256// overhead by the database to ensure that all values returned are distinct. Therefore,
257// use this ONLY when you need it.
258//
259// For complicated queries, you can pass in the sql select statement. This would be
260// necessary if joins are involved since by default both columns must come from the
261// same table.
262//
a0d9c6cb 263// If you do query by sql statement, you must pass in the maximum length of column1,
108106cf
JS
264// since it cannot be derived when you query using your own sql statement.
265//
266// The optional database connection can be used if you'd like the lookup class
049977d0 267// to use a database pointer other than wxGetApp().READONLY_DB. This is necessary if
108106cf
JS
268// records are being saved, but not committed to the db, yet should be included
269// in the lookup window.
270//
e689d52a 271ClookUpDlg::ClookUpDlg(wxWindow *parent, const wxString &windowTitle, const wxString &tableName,
f0fb3b3b 272 const wxString &dispCol1, const wxString &dispCol2,
e689d52a 273 const wxString &where, const wxString &orderBy,
925e9792 274 wxDb *pDb, const wxString &defDir, bool distinctValues,
e689d52a 275 const wxString &selectStmt, int maxLenCol1, bool allowOk)
6d841efd 276 : wxDialog (parent, LOOKUP_DIALOG, wxT("Select..."), wxDefaultPosition, wxSize(400, 290))
108106cf 277{
e70e8f4c 278 wxBeginBusyCursor();
925e9792 279
94613352
GT
280 wxStrcpy(ListDB_Selection,wxT(""));
281 wxStrcpy(ListDB_Selection2,wxT(""));
6d841efd 282 widgetPtrsSet = false;
e70e8f4c
GT
283 lookup = 0;
284 lookup2 = 0;
e689d52a
GT
285
286 noDisplayCols = (dispCol2.Length() == 0 ? 1 : 2);
e70e8f4c
GT
287 col1Len = 0;
288
e689d52a 289 wxFont fixedFont(12, wxMODERN, wxNORMAL, wxNORMAL);
e70e8f4c
GT
290
291 // this is done with fixed font so that the second column (if any) will be left
292 // justified in the second column
94613352 293 pLookUpSelectList = new wxListBox(this, LOOKUP_DIALOG_SELECT, wxPoint(5, 15), wxSize(384, 195), 0, 0, wxLB_SINGLE|wxLB_ALWAYS_SB, wxDefaultValidator, wxT("LookUpSelectList"));
1fc5dd6f
JS
294
295 pLookUpSelectList->SetFont(fixedFont);
296
94613352
GT
297 pLookUpOkBtn = new wxButton(this, LOOKUP_DIALOG_OK, wxT("&Ok"), wxPoint(113, 222), wxSize(70, 35), 0, wxDefaultValidator, wxT("LookUpOkBtn"));
298 pLookUpCancelBtn = new wxButton(this, LOOKUP_DIALOG_CANCEL, wxT("C&ancel"), wxPoint(212, 222), wxSize(70, 35), 0, wxDefaultValidator, wxT("LookUpCancelBtn"));
e70e8f4c 299
6d841efd 300 widgetPtrsSet = true;
e70e8f4c
GT
301
302 // Query the lookup table and display the result set
2f6c54eb 303 lookup2 = new Clookup2(tableName, dispCol1, dispCol2, pDb, defDir);
3fe813a9 304 if (!lookup2)
e70e8f4c 305 {
94613352 306 wxMessageBox(wxT("Error allocating memory for 'Clookup2' object."),wxT("Error..."));
e70e8f4c
GT
307 Close();
308 return;
309 }
310
311 if (!lookup2->Open())
312 {
313 wxString tStr;
f0fb3b3b 314 tStr.Printf(wxT("Unable to open the table '%s'."),tableName.c_str());
74de91cc 315 tStr += GetExtendedDBErrorMsg2(pDb,__TFILE__,__LINE__);
94613352 316 wxMessageBox(tStr,wxT("ODBC Error..."));
e70e8f4c
GT
317 Close();
318 return;
319 }
320
321 // If displaying 2 columns, determine the maximum length of column1
322 int maxColLen;
ee377e7f 323 if (maxLenCol1 > 0)
e70e8f4c
GT
324 maxColLen = col1Len = maxLenCol1; // user passed in max col length for column 1
325 else
326 {
ee377e7f
GT
327 // NOTE: Some databases (Firebird/Interbase) cannot handle the "fn" and "MAX()" functions
328
e70e8f4c 329 maxColLen = LOOKUP_COL_LEN;
f6bcfd97 330 if (wxStrlen(dispCol2))
e70e8f4c 331 {
94613352 332 wxString q = wxT("SELECT MAX({fn LENGTH(");
e70e8f4c 333 q += dispCol1;
94613352
GT
334 q += wxT(")}), NULL");
335 q += wxT(" FROM ");
e70e8f4c 336 q += tableName;
f6bcfd97 337 if (wxStrlen(where))
e70e8f4c 338 {
94613352 339 q += wxT(" WHERE ");
e70e8f4c
GT
340 q += where;
341 }
94613352 342 if (!lookup2->QueryBySqlStmt(q))
e70e8f4c 343 {
ee377e7f
GT
344 wxString tStr;
345 tStr = wxT("ODBC error during QueryBySqlStmt()\n\n");
346 wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),lookup2->GetDb(),__TFILE__,__LINE__),
347 wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
348
e70e8f4c
GT
349 Close();
350 return;
351 }
352 if (lookup2->GetNext())
74de91cc 353 maxColLen = col1Len = wxAtoi(lookup2->lookupCol1);
e70e8f4c 354 else
ee377e7f
GT
355 {
356 wxString tStr;
357 tStr = wxT("ODBC error during GetNext()\n\n");
358 wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),lookup2->GetDb(),__TFILE__,__LINE__),
359 wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
360 }
e70e8f4c
GT
361 }
362 }
363
364 // Query the actual record set
f6bcfd97 365 if (selectStmt && wxStrlen(selectStmt)) // Query by sql stmt passed in
e70e8f4c
GT
366 {
367 if (!lookup2->QueryBySqlStmt(selectStmt))
368 {
ee377e7f
GT
369 wxString tStr;
370 tStr = wxT("ODBC error during QueryBySqlStmt()\n\n");
371 wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),lookup2->GetDb(),__TFILE__,__LINE__),
372 wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
373
e70e8f4c
GT
374 Close();
375 return;
376 }
377 }
378 else // Query using where and order by clauses
379 {
f6bcfd97
BP
380 lookup2->SetOrderByClause(orderBy);
381 lookup2->SetWhereClause(where);
6d841efd 382 if (!lookup2->Query(false, distinctValues))
e70e8f4c 383 {
ee377e7f
GT
384 wxString tStr;
385 tStr = wxT("ODBC error during Query()\n\n");
386 wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),lookup2->GetDb(),__TFILE__,__LINE__),
387 wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
388
e70e8f4c
GT
389 Close();
390 return;
391 }
392 }
393
394 // Fill in the list box from the query result set
395 wxString s;
396 while (lookup2->GetNext())
397 {
398 s = lookup2->lookupCol1;
f6bcfd97 399 if (wxStrlen(dispCol2)) // Append the optional column 2
e70e8f4c 400 {
94613352 401 s.Append(wxT(' '), (maxColLen + LISTDB_NO_SPACES_BETWEEN_COLS - wxStrlen(lookup2->lookupCol1)));
e70e8f4c
GT
402 s.Append(lookup2->lookupCol2);
403 }
404 pLookUpSelectList->Append(s);
405 }
406
e70e8f4c 407 // Make the OK activate by pressing Enter
2f8f7c77 408 if (pLookUpSelectList->GetCount())
ae883e9a
GT
409 {
410 pLookUpSelectList->SetSelection(0);
e70e8f4c 411 pLookUpOkBtn->SetDefault();
ae883e9a 412 }
e70e8f4c
GT
413 else
414 {
415 pLookUpCancelBtn->SetDefault();
6d841efd 416 pLookUpOkBtn->Enable(false);
e70e8f4c
GT
417 }
418
419 pLookUpOkBtn->Enable(allowOk);
420
421 // Display the dialog window
422 SetTitle(windowTitle);
423 Centre(wxBOTH);
424 wxEndBusyCursor();
425 ShowModal();
108106cf
JS
426
427} // Generic lookup constructor 2
428
429
65d7ddc4 430void ClookUpDlg::OnClose(wxCloseEvent& event)
108106cf 431{
6d841efd
WS
432 widgetPtrsSet = false;
433 GetParent()->Enable(true);
108106cf 434
e70e8f4c
GT
435 if (lookup)
436 delete lookup;
437 if (lookup2)
438 delete lookup2;
108106cf 439
3ca6a5f0
BP
440 SetReturnCode(1);
441
e70e8f4c 442 while (wxIsBusy()) wxEndBusyCursor();
3ca6a5f0 443 event.Skip();
65d7ddc4 444
6d841efd 445// return true;
108106cf
JS
446
447} // ClookUpDlg::OnClose
448
449
e689d52a
GT
450void ClookUpDlg::OnDClick( wxCommandEvent &event )
451{
452 wxWindow *win = (wxWindow*) event.GetEventObject();
453 OnCommand( *win, event );
454}
455
456
65d7ddc4
GT
457void ClookUpDlg::OnButton( wxCommandEvent &event )
458{
459 wxWindow *win = (wxWindow*) event.GetEventObject();
460 OnCommand( *win, event );
461}
462
463
74de91cc 464void ClookUpDlg::OnCommand(wxWindow& win, wxCommandEvent& WXUNUSED(event))
108106cf 465{
e70e8f4c
GT
466 wxString widgetName = win.GetName();
467
468 if (widgetPtrsSet)
469 {
e689d52a
GT
470 bool doubleclick = false;
471 // Double click
472 if (widgetName == pLookUpSelectList->GetName())
473 {
474 doubleclick = true;
475 } // Double click
476
e70e8f4c 477 // OK Button
e689d52a 478 if (widgetName == pLookUpOkBtn->GetName() || doubleclick)
e70e8f4c
GT
479 {
480 if (pLookUpSelectList->GetSelection() != -1)
481 {
482 if (noDisplayCols == 1)
f6bcfd97 483 wxStrcpy (ListDB_Selection, pLookUpSelectList->GetStringSelection());
e70e8f4c
GT
484 else // 2 display columns
485 {
486 wxString s = pLookUpSelectList->GetStringSelection();
487 // Column 1
488 s = s.SubString(0, col1Len-1);
489 s = s.Strip();
f6bcfd97 490 wxStrcpy(ListDB_Selection, s);
e70e8f4c
GT
491 // Column 2
492 s = pLookUpSelectList->GetStringSelection();
493 s = s.Mid(col1Len + LISTDB_NO_SPACES_BETWEEN_COLS);
494 s = s.Strip();
f6bcfd97 495 wxStrcpy(ListDB_Selection2, s);
e70e8f4c
GT
496 }
497 }
498 else
499 {
94613352
GT
500 wxStrcpy(ListDB_Selection,wxT(""));
501 wxStrcpy(ListDB_Selection2,wxT(""));
e70e8f4c
GT
502 }
503 Close();
504 } // OK Button
505
506 // Cancel Button
507 if (widgetName == pLookUpCancelBtn->GetName())
508 {
94613352
GT
509 wxStrcpy (ListDB_Selection,wxT(""));
510 wxStrcpy (ListDB_Selection2,wxT(""));
e70e8f4c
GT
511 Close();
512 } // Cancel Button
e689d52a 513
e70e8f4c 514 }
108106cf 515
004f4002 516} // ClookUpDlg::OnCommand
108106cf
JS
517
518// *********************************** listdb.cpp **********************************