home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / samples / db / dbtest.cpp < prev    next >
C/C++ Source or Header  |  2002-09-01  |  122KB  |  3,264 lines

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Name:        dbtest.cpp
  3. // Purpose:     wxWindows database demo app
  4. // Author:      George Tasker
  5. // Modified by:
  6. // Created:     1998
  7. // RCS-ID:      $Id: dbtest.cpp,v 1.40 2002/08/31 22:36:12 GD Exp $
  8. // Copyright:   (c) 1998 Remstar International, Inc.
  9. // Licence:     wxWindows licence
  10. ///////////////////////////////////////////////////////////////////////////////
  11.  
  12. /*
  13.  *  SYNOPSIS START
  14.  
  15.     This sample program demonstrates the cross-platform ODBC database classes
  16.     donated by the development team at Remstar International.
  17.  
  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.
  20.  
  21.  *  SYNOPSIS END
  22.  */
  23.  
  24. #ifdef __GNUG__
  25. #pragma implementation "dbtest.h"
  26. #endif
  27.  
  28. #include  "wx/wxprec.h"
  29.  
  30. #ifdef    __BORLANDC__
  31. #pragma hdrstop
  32. #endif  //__BORLANDC__
  33.  
  34. #ifndef WX_PRECOMP
  35. #include  "wx/wx.h"
  36. #endif //WX_PRECOMP
  37.  
  38. #if defined(__WXGTK__) || defined(__WXX11__)
  39. #include "db.xpm"
  40. #endif
  41.  
  42. #include <stdio.h>                  /* Included strictly for reading the text file with the database parameters */
  43.  
  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 */
  46.  
  47. //extern wxDbList WXDLLEXPORT *PtrBegDbList;    /* from db.cpp, used in getting back error results from db connections */
  48.  
  49. #if wxUSE_NEW_GRID
  50. #include "wx/grid.h"
  51. #include "wx/generic/gridctrl.h"
  52. #include "wx/dbgrid.h"
  53.  
  54. #define CHOICEINT
  55. #endif
  56.  
  57. #include "dbtest.h"                 /* Header file for this demonstration program */
  58. #include "listdb.h"                 /* Code to support the "Lookup" button on the editor dialog */
  59.  
  60. IMPLEMENT_APP(DatabaseDemoApp)
  61.  
  62. extern wxChar ListDB_Selection[];   /* Used to return the first column value for the selected line from the listDB routines */
  63. extern wxChar ListDB_Selection2[];  /* Used to return the second column value for the selected line from the listDB routines */
  64.  
  65.  
  66. #if !wxUSE_ODBC
  67.   #error Sample cannot be compiled unless setup.h has wxUSE_ODBC set to 1
  68. #endif
  69.  
  70.  
  71. bool DataTypeSupported(wxDb *pDb, SWORD datatype, wxString *nativeDataTypeName)
  72. {
  73.     wxDbSqlTypeInfo sqlTypeInfo;
  74.  
  75.     bool breakpoint = FALSE;
  76.  
  77.     *nativeDataTypeName = wxEmptyString;
  78.     if (pDb->GetDataTypeInfo(datatype, sqlTypeInfo))
  79.     {
  80.         *nativeDataTypeName = sqlTypeInfo.TypeName;
  81.         breakpoint = TRUE;
  82.     }
  83.  
  84.     return breakpoint;
  85.  
  86. }  // GetDataTypesSupported();
  87.  
  88.  
  89.  
  90. void CheckSupportForAllDataTypes(wxDb *pDb)
  91. {
  92.     wxString nativeDataTypeName;
  93.  
  94.     wxLogMessage("\nThe following datatypes are supported by the\ndatabase you are currently connected to:");
  95. #ifdef SQL_C_BINARY
  96.     if (DataTypeSupported(pDb,SQL_C_BINARY, &nativeDataTypeName))
  97.     {
  98.         nativeDataTypeName = "SQL_C_BINARY (" + nativeDataTypeName;
  99.         nativeDataTypeName += ")";
  100.         wxLogMessage(nativeDataTypeName);
  101.     }
  102. #endif
  103. #ifdef SQL_C_BIT
  104.     if (DataTypeSupported(pDb,SQL_C_BIT, &nativeDataTypeName))
  105.     {
  106.         nativeDataTypeName = "SQL_C_BIT (" + nativeDataTypeName;
  107.         nativeDataTypeName += ")";
  108.         wxLogMessage(nativeDataTypeName);
  109.     }
  110. #endif
  111. #ifdef SQL_C_BOOKMARK
  112.     if (DataTypeSupported(pDb,SQL_C_BOOKMARK, &nativeDataTypeName))
  113.     {
  114.         nativeDataTypeName = "SQL_C_BOOKMARK (" + nativeDataTypeName;
  115.         nativeDataTypeName += ")";
  116.         wxLogMessage(nativeDataTypeName);
  117.     }
  118. #endif
  119. #ifdef SQL_C_CHAR
  120.     if (DataTypeSupported(pDb,SQL_C_CHAR, &nativeDataTypeName))
  121.     {
  122.         nativeDataTypeName = "SQL_C_CHAR (" + nativeDataTypeName;
  123.         nativeDataTypeName += ")";
  124.         wxLogMessage(nativeDataTypeName);
  125.     }
  126. #endif
  127. #ifdef SQL_C_DATE
  128.     if (DataTypeSupported(pDb,SQL_C_DATE, &nativeDataTypeName))
  129.     {
  130.         nativeDataTypeName = "SQL_C_DATE (" + nativeDataTypeName;
  131.         nativeDataTypeName += ")";
  132.         wxLogMessage(nativeDataTypeName);
  133.     }
  134. #endif
  135. #ifdef SQL_C_DEFAULT
  136.     if (DataTypeSupported(pDb,SQL_C_DEFAULT, &nativeDataTypeName))
  137.     {
  138.         nativeDataTypeName = "SQL_C_DEFAULT (" + nativeDataTypeName;
  139.         nativeDataTypeName += ")";
  140.         wxLogMessage(nativeDataTypeName);
  141.     }
  142. #endif
  143. #ifdef SQL_C_DOUBLE
  144.     if (DataTypeSupported(pDb,SQL_C_DOUBLE, &nativeDataTypeName))
  145.     {
  146.         nativeDataTypeName = "SQL_C_DOUBLE (" + nativeDataTypeName;
  147.         nativeDataTypeName += ")";
  148.         wxLogMessage(nativeDataTypeName);
  149.     }
  150. #endif
  151. #ifdef SQL_C_FLOAT
  152.     if (DataTypeSupported(pDb,SQL_C_FLOAT, &nativeDataTypeName))
  153.     {
  154.         nativeDataTypeName = "SQL_C_FLOAT (" + nativeDataTypeName;
  155.         nativeDataTypeName += ")";
  156.         wxLogMessage(nativeDataTypeName);
  157.     }
  158. #endif
  159. #ifdef SQL_C_GUID
  160.     if (DataTypeSupported(pDb,SQL_C_GUID, &nativeDataTypeName))
  161.     {
  162.         nativeDataTypeName = "SQL_C_GUID (" + nativeDataTypeName;
  163.         nativeDataTypeName += ")";
  164.         wxLogMessage(nativeDataTypeName);
  165.     }
  166. #endif
  167. #ifdef SQL_C_INTERVAL_DAY
  168.     if (DataTypeSupported(pDb,SQL_C_INTERVAL_DAY, &nativeDataTypeName))
  169.     {
  170.         nativeDataTypeName = "SQL_C_INTERVAL_DAY (" + nativeDataTypeName;
  171.         nativeDataTypeName += ")";
  172.         wxLogMessage(nativeDataTypeName);
  173.     }
  174. #endif
  175. #ifdef SQL_C_INTERVAL_DAY_TO_HOUR
  176.     if (DataTypeSupported(pDb,SQL_C_INTERVAL_DAY_TO_HOUR, &nativeDataTypeName))
  177.     {
  178.         nativeDataTypeName = "SQL_C_INTERVAL_DAY_TO_HOUR (" + nativeDataTypeName;
  179.         nativeDataTypeName += ")";
  180.         wxLogMessage(nativeDataTypeName);
  181.     }
  182. #endif
  183. #ifdef SQL_C_INTERVAL_DAY_TO_MINUTE
  184.     if (DataTypeSupported(pDb,SQL_C_INTERVAL_DAY_TO_MINUTE, &nativeDataTypeName))
  185.     {
  186.         nativeDataTypeName = "SQL_C_INTERVAL_DAY_TO_MINUTE (" + nativeDataTypeName;
  187.         nativeDataTypeName += ")";
  188.         wxLogMessage(nativeDataTypeName);
  189.     }
  190. #endif
  191. #ifdef SQL_C_INTERVAL_DAY_TO_SECOND
  192.     if (DataTypeSupported(pDb,SQL_C_INTERVAL_DAY_TO_SECOND, &nativeDataTypeName))
  193.     {
  194.         nativeDataTypeName = "SQL_C_INTERVAL_DAY_TO_SECOND (" + nativeDataTypeName;
  195.         nativeDataTypeName += ")";
  196.         wxLogMessage(nativeDataTypeName);
  197.     }
  198. #endif
  199. #ifdef SQL_C_INTERVAL_HOUR
  200.     if (DataTypeSupported(pDb,SQL_C_INTERVAL_HOUR, &nativeDataTypeName))
  201.     {
  202.         nativeDataTypeName = "SQL_C_INTERVAL_HOUR (" + nativeDataTypeName;
  203.         nativeDataTypeName += ")";
  204.         wxLogMessage(nativeDataTypeName);
  205.     }
  206. #endif
  207. #ifdef SQL_C_INTERVAL_HOUR_TO_MINUTE
  208.     if (DataTypeSupported(pDb,SQL_C_INTERVAL_HOUR_TO_MINUTE, &nativeDataTypeName))
  209.     {
  210.         nativeDataTypeName = "SQL_C_INTERVAL_HOUR_TO_MINUTE (" + nativeDataTypeName;
  211.         nativeDataTypeName += ")";
  212.         wxLogMessage(nativeDataTypeName);
  213.     }
  214. #endif
  215. #ifdef SQL_C_INTERVAL_HOUR_TO_SECOND
  216.     if (DataTypeSupported(pDb,SQL_C_INTERVAL_HOUR_TO_SECOND, &nativeDataTypeName))
  217.     {
  218.         nativeDataTypeName = "SQL_C_INTERVAL_HOUR_TO_SECOND (" + nativeDataTypeName;
  219.         nativeDataTypeName += ")";
  220.         wxLogMessage(nativeDataTypeName);
  221.     }
  222. #endif
  223. #ifdef SQL_C_INTERVAL_MINUTE
  224.     if (DataTypeSupported(pDb,SQL_C_INTERVAL_MINUTE, &nativeDataTypeName))
  225.     {
  226.         nativeDataTypeName = "SQL_C_INTERVAL_MINUTE (" + nativeDataTypeName;
  227.         nativeDataTypeName += ")";
  228.         wxLogMessage(nativeDataTypeName);
  229.     }
  230. #endif
  231. #ifdef SQL_C_INTERVAL_MINUTE_TO_SECOND
  232.     if (DataTypeSupported(pDb,SQL_C_INTERVAL_MINUTE_TO_SECOND, &nativeDataTypeName))
  233.     {
  234.         nativeDataTypeName = "SQL_C_INTERVAL_MINUTE_TO_SECOND (" + nativeDataTypeName;
  235.         nativeDataTypeName += ")";
  236.         wxLogMessage(nativeDataTypeName);
  237.     }
  238. #endif
  239. #ifdef SQL_C_INTERVAL_MONTH
  240.     if (DataTypeSupported(pDb,SQL_C_INTERVAL_MONTH, &nativeDataTypeName))
  241.     {
  242.         nativeDataTypeName = "SQL_C_INTERVAL_MONTH (" + nativeDataTypeName;
  243.         nativeDataTypeName += ")";
  244.         wxLogMessage(nativeDataTypeName);
  245.     }
  246. #endif
  247. #ifdef SQL_C_INTERVAL_SECOND
  248.     if (DataTypeSupported(pDb,SQL_C_INTERVAL_SECOND, &nativeDataTypeName))
  249.     {
  250.         nativeDataTypeName = "SQL_C_INTERVAL_SECOND (" + nativeDataTypeName;
  251.         nativeDataTypeName += ")";
  252.         wxLogMessage(nativeDataTypeName);
  253.     }
  254. #endif
  255. #ifdef SQL_C_INTERVAL_YEAR
  256.     if (DataTypeSupported(pDb,SQL_C_INTERVAL_YEAR, &nativeDataTypeName))
  257.     {
  258.         nativeDataTypeName = "SQL_C_INTERVAL_YEAR (" + nativeDataTypeName;
  259.         nativeDataTypeName += ")";
  260.         wxLogMessage(nativeDataTypeName);
  261.     }
  262. #endif
  263. #ifdef SQL_C_INTERVAL_YEAR_TO_MONTH
  264.     if (DataTypeSupported(pDb,SQL_C_INTERVAL_YEAR_TO_MONTH, &nativeDataTypeName))
  265.     {
  266.         nativeDataTypeName = "SQL_C_INTERVAL_YEAR_TO_MONTH (" + nativeDataTypeName;
  267.         nativeDataTypeName += ")";
  268.         wxLogMessage(nativeDataTypeName);
  269.     }
  270. #endif
  271. #ifdef SQL_C_LONG
  272.     if (DataTypeSupported(pDb,SQL_C_LONG, &nativeDataTypeName))
  273.     {
  274.         nativeDataTypeName = "SQL_C_LONG (" + nativeDataTypeName;
  275.         nativeDataTypeName += ")";
  276.         wxLogMessage(nativeDataTypeName);
  277.     }
  278. #endif
  279. #ifdef SQL_C_NUMERIC
  280.     if (DataTypeSupported(pDb,SQL_C_NUMERIC, &nativeDataTypeName))
  281.     {
  282.         nativeDataTypeName = "SQL_C_NUMERIC (" + nativeDataTypeName;
  283.         nativeDataTypeName += ")";
  284.         wxLogMessage(nativeDataTypeName);
  285.     }
  286. #endif
  287. #ifdef SQL_C_SBIGINT
  288.     if (DataTypeSupported(pDb,SQL_C_SBIGINT, &nativeDataTypeName))
  289.     {
  290.         nativeDataTypeName = "SQL_C_SBIGINT (" + nativeDataTypeName;
  291.         nativeDataTypeName += ")";
  292.         wxLogMessage(nativeDataTypeName);
  293.     }
  294. #endif
  295. #ifdef SQL_C_SHORT
  296.     if (DataTypeSupported(pDb,SQL_C_SHORT, &nativeDataTypeName))
  297.     {
  298.         nativeDataTypeName = "SQL_C_SHORT (" + nativeDataTypeName;
  299.         nativeDataTypeName += ")";
  300.         wxLogMessage(nativeDataTypeName);
  301.     }
  302. #endif
  303. #ifdef SQL_C_SLONG
  304.     if (DataTypeSupported(pDb,SQL_C_SLONG, &nativeDataTypeName))
  305.     {
  306.         nativeDataTypeName = "SQL_C_SLONG (" + nativeDataTypeName;
  307.         nativeDataTypeName += ")";
  308.         wxLogMessage(nativeDataTypeName);
  309.     }
  310. #endif
  311. #ifdef SQL_C_SSHORT
  312.     if (DataTypeSupported(pDb,SQL_C_SSHORT, &nativeDataTypeName))
  313.     {
  314.         nativeDataTypeName = "SQL_C_SSHORT (" + nativeDataTypeName;
  315.         nativeDataTypeName += ")";
  316.         wxLogMessage(nativeDataTypeName);
  317.     }
  318. #endif
  319. #ifdef SQL_C_STINYINT
  320.     if (DataTypeSupported(pDb,SQL_C_STINYINT, &nativeDataTypeName))
  321.     {
  322.         nativeDataTypeName = "SQL_C_STINYINT (" + nativeDataTypeName;
  323.         nativeDataTypeName += ")";
  324.         wxLogMessage(nativeDataTypeName);
  325.     }
  326. #endif
  327. #ifdef SQL_C_TIME
  328.     if (DataTypeSupported(pDb,SQL_C_TIME, &nativeDataTypeName))
  329.     {
  330.         nativeDataTypeName = "SQL_C_TIME (" + nativeDataTypeName;
  331.         nativeDataTypeName += ")";
  332.         wxLogMessage(nativeDataTypeName);
  333.     }
  334. #endif
  335. #ifdef SQL_C_TIMESTAMP
  336.     if (DataTypeSupported(pDb,SQL_C_TIMESTAMP, &nativeDataTypeName))
  337.     {
  338.         nativeDataTypeName = "SQL_C_TIMESTAMP (" + nativeDataTypeName;
  339.         nativeDataTypeName += ")";
  340.         wxLogMessage(nativeDataTypeName);
  341.     }
  342. #endif
  343. #ifdef SQL_C_TINYINT
  344.     if (DataTypeSupported(pDb,SQL_C_TINYINT, &nativeDataTypeName))
  345.     {
  346.         nativeDataTypeName = "SQL_C_TINYINT (" + nativeDataTypeName;
  347.         nativeDataTypeName += ")";
  348.         wxLogMessage(nativeDataTypeName);
  349.     }
  350. #endif
  351. #ifdef SQL_C_TYPE_DATE
  352.     if (DataTypeSupported(pDb,SQL_C_TYPE_DATE, &nativeDataTypeName))
  353.     {
  354.         nativeDataTypeName = "SQL_C_TYPE_DATE (" + nativeDataTypeName;
  355.         nativeDataTypeName += ")";
  356.         wxLogMessage(nativeDataTypeName);
  357.     }
  358. #endif
  359. #ifdef SQL_C_TYPE_TIME
  360.     if (DataTypeSupported(pDb,SQL_C_TYPE_TIME, &nativeDataTypeName))
  361.     {
  362.         nativeDataTypeName = "SQL_C_TYPE_TIME (" + nativeDataTypeName;
  363.         nativeDataTypeName += ")";
  364.         wxLogMessage(nativeDataTypeName);
  365.     }
  366. #endif
  367. #ifdef SQL_C_TYPE_TIMESTAMP
  368.     if (DataTypeSupported(pDb,SQL_C_TYPE_TIMESTAMP, &nativeDataTypeName))
  369.     {
  370.         nativeDataTypeName = "SQL_C_TYPE_TIMESTAMP (" + nativeDataTypeName;
  371.         nativeDataTypeName += ")";
  372.         wxLogMessage(nativeDataTypeName);
  373.     }
  374. #endif
  375. #ifdef SQL_C_UBIGINT
  376.     if (DataTypeSupported(pDb,SQL_C_UBIGINT, &nativeDataTypeName))
  377.     {
  378.         nativeDataTypeName = "SQL_C_UBIGINT (" + nativeDataTypeName;
  379.         nativeDataTypeName += ")";
  380.         wxLogMessage(nativeDataTypeName);
  381.     }
  382. #endif
  383. #ifdef SQL_C_ULONG
  384.     if (DataTypeSupported(pDb,SQL_C_ULONG, &nativeDataTypeName))
  385.     {
  386.         nativeDataTypeName = "SQL_C_ULONG (" + nativeDataTypeName;
  387.         nativeDataTypeName += ")";
  388.         wxLogMessage(nativeDataTypeName);
  389.     }
  390. #endif
  391. #ifdef SQL_C_USHORT
  392.     if (DataTypeSupported(pDb,SQL_C_USHORT, &nativeDataTypeName))
  393.     {
  394.         nativeDataTypeName = "SQL_C_USHORT (" + nativeDataTypeName;
  395.         nativeDataTypeName += ")";
  396.         wxLogMessage(nativeDataTypeName);
  397.     }
  398. #endif
  399. #ifdef SQL_C_UTINYINT
  400.     if (DataTypeSupported(pDb,SQL_C_UTINYINT, &nativeDataTypeName))
  401.     {
  402.         nativeDataTypeName = "SQL_C_UTINYINT (" + nativeDataTypeName;
  403.         nativeDataTypeName += ")";
  404.         wxLogMessage(nativeDataTypeName);
  405.     }
  406. #endif
  407. #ifdef SQL_C_VARBOOKMARK
  408.     if (DataTypeSupported(pDb,SQL_C_VARBOOKMARK, &nativeDataTypeName))
  409.     {
  410.         nativeDataTypeName = "SQL_C_VARBOOKMARK (" + nativeDataTypeName;
  411.         nativeDataTypeName += ")";
  412.         wxLogMessage(nativeDataTypeName);
  413.     }
  414. #endif
  415.  
  416. // Extended SQL types
  417. #ifdef SQL_DATE
  418.     if (DataTypeSupported(pDb,SQL_DATE, &nativeDataTypeName))
  419.     {
  420.         nativeDataTypeName = "SQL_DATE (" + nativeDataTypeName;
  421.         nativeDataTypeName += ")";
  422.         wxLogMessage(nativeDataTypeName);
  423.     }
  424. #endif
  425. #ifdef SQL_INTERVAL
  426.     if (DataTypeSupported(pDb,SQL_INTERVAL, &nativeDataTypeName))
  427.     {
  428.         nativeDataTypeName = "SQL_INTERVAL (" + nativeDataTypeName;
  429.         nativeDataTypeName += ")";
  430.         wxLogMessage(nativeDataTypeName);
  431.     }
  432. #endif
  433. #ifdef SQL_TIME
  434.     if (DataTypeSupported(pDb,SQL_TIME, &nativeDataTypeName))
  435.     {
  436.         nativeDataTypeName = "SQL_TIME (" + nativeDataTypeName;
  437.         nativeDataTypeName += ")";
  438.         wxLogMessage(nativeDataTypeName);
  439.     }
  440. #endif
  441. #ifdef SQL_TIMESTAMP
  442.     if (DataTypeSupported(pDb,SQL_TIMESTAMP, &nativeDataTypeName))
  443.     {
  444.         nativeDataTypeName = "SQL_TIMESTAMP (" + nativeDataTypeName;
  445.         nativeDataTypeName += ")";
  446.         wxLogMessage(nativeDataTypeName);
  447.     }
  448. #endif
  449. #ifdef SQL_LONGVARCHAR
  450.     if (DataTypeSupported(pDb,SQL_LONGVARCHAR, &nativeDataTypeName))
  451.     {
  452.         nativeDataTypeName = "SQL_LONGVARCHAR (" + nativeDataTypeName;
  453.         nativeDataTypeName += ")";
  454.         wxLogMessage(nativeDataTypeName);
  455.     }
  456. #endif
  457. #ifdef SQL_BINARY
  458.     if (DataTypeSupported(pDb,SQL_BINARY, &nativeDataTypeName))
  459.     {
  460.         nativeDataTypeName = "SQL_BINARY (" + nativeDataTypeName;
  461.         nativeDataTypeName += ")";
  462.         wxLogMessage(nativeDataTypeName);
  463.     }
  464. #endif
  465. #ifdef SQL_VARBINARY
  466.     if (DataTypeSupported(pDb,SQL_VARBINARY, &nativeDataTypeName))
  467.     {
  468.         nativeDataTypeName = "SQL_VARBINARY (" + nativeDataTypeName;
  469.         nativeDataTypeName += ")";
  470.         wxLogMessage(nativeDataTypeName);
  471.     }
  472. #endif
  473. #ifdef SQL_LONGVARBINARY
  474.     if (DataTypeSupported(pDb,SQL_LONGVARBINARY, &nativeDataTypeName))
  475.     {
  476.         nativeDataTypeName = "SQL_LOGVARBINARY (" + nativeDataTypeName;
  477.         nativeDataTypeName += ")";
  478.         wxLogMessage(nativeDataTypeName);
  479.     }
  480. #endif
  481. #ifdef SQL_BIGINT
  482.     if (DataTypeSupported(pDb,SQL_BIGINT, &nativeDataTypeName))
  483.     {
  484.         nativeDataTypeName = "SQL_BIGINT (" + nativeDataTypeName;
  485.         nativeDataTypeName += ")";
  486.         wxLogMessage(nativeDataTypeName);
  487.     }
  488. #endif
  489. #ifdef SQL_TINYINT
  490.     if (DataTypeSupported(pDb,SQL_TINYINT, &nativeDataTypeName))
  491.     {
  492.         nativeDataTypeName = "SQL_TINYINT (" + nativeDataTypeName;
  493.         nativeDataTypeName += ")";
  494.         wxLogMessage(nativeDataTypeName);
  495.     }
  496. #endif
  497. #ifdef SQL_BIT
  498.     if (DataTypeSupported(pDb,SQL_BIT, &nativeDataTypeName))
  499.     {
  500.         nativeDataTypeName = "SQL_BIT (" + nativeDataTypeName;
  501.         nativeDataTypeName += ")";
  502.         wxLogMessage(nativeDataTypeName);
  503.     }
  504. #endif
  505. #ifdef SQL_GUID
  506.     if (DataTypeSupported(pDb,SQL_GUID, &nativeDataTypeName))
  507.     {
  508.         nativeDataTypeName = "SQL_GUID (" + nativeDataTypeName;
  509.         nativeDataTypeName += ")";
  510.         wxLogMessage(nativeDataTypeName);
  511.     }
  512. #endif
  513.  
  514. #ifdef SQL_CHAR
  515.     if (DataTypeSupported(pDb,SQL_CHAR, &nativeDataTypeName))
  516.     {
  517.         nativeDataTypeName = "SQL_CHAR (" + nativeDataTypeName;
  518.         nativeDataTypeName += ")";
  519.         wxLogMessage(nativeDataTypeName);
  520.     }
  521. #endif
  522. #ifdef SQL_INTEGER
  523.     if (DataTypeSupported(pDb,SQL_INTEGER, &nativeDataTypeName))
  524.     {
  525.         nativeDataTypeName = "SQL_INTEGER (" + nativeDataTypeName;
  526.         nativeDataTypeName += ")";
  527.         wxLogMessage(nativeDataTypeName);
  528.     }
  529. #endif
  530. #ifdef SQL_SMALLINT
  531.     if (DataTypeSupported(pDb,SQL_SMALLINT, &nativeDataTypeName))
  532.     {
  533.         nativeDataTypeName = "SQL_SAMLLINT (" + nativeDataTypeName;
  534.         nativeDataTypeName += ")";
  535.         wxLogMessage(nativeDataTypeName);
  536.     }
  537. #endif
  538. #ifdef SQL_REAL
  539.     if (DataTypeSupported(pDb,SQL_REAL, &nativeDataTypeName))
  540.     {
  541.         nativeDataTypeName = "SQL_REAL (" + nativeDataTypeName;
  542.         nativeDataTypeName += ")";
  543.         wxLogMessage(nativeDataTypeName);
  544.     }
  545. #endif
  546. #ifdef SQL_DOUBLE
  547.     if (DataTypeSupported(pDb,SQL_DOUBLE, &nativeDataTypeName))
  548.     {
  549.         nativeDataTypeName = "SQL_DOUBLE (" + nativeDataTypeName;
  550.         nativeDataTypeName += ")";
  551.         wxLogMessage(nativeDataTypeName);
  552.     }
  553. #endif
  554. #ifdef SQL_NUMERIC
  555.     if (DataTypeSupported(pDb,SQL_NUMERIC, &nativeDataTypeName))
  556.     {
  557.         nativeDataTypeName = "SQL_NUMERIC (" + nativeDataTypeName;
  558.         nativeDataTypeName += ")";
  559.         wxLogMessage(nativeDataTypeName);
  560.     }
  561. #endif
  562. #ifdef SQL_DATE
  563.     if (DataTypeSupported(pDb,SQL_DATE, &nativeDataTypeName))
  564.     {
  565.         nativeDataTypeName = "SQL_DATE (" + nativeDataTypeName;
  566.         nativeDataTypeName += ")";
  567.         wxLogMessage(nativeDataTypeName);
  568.     }
  569. #endif
  570. #ifdef SQL_TIME
  571.     if (DataTypeSupported(pDb,SQL_TIME, &nativeDataTypeName))
  572.     {
  573.         nativeDataTypeName = "SQL_TIME (" + nativeDataTypeName;
  574.         nativeDataTypeName += ")";
  575.         wxLogMessage(nativeDataTypeName);
  576.     }
  577. #endif
  578. #ifdef SQL_TIMESTAMP
  579.     if (DataTypeSupported(pDb,SQL_TIMESTAMP, &nativeDataTypeName))
  580.     {
  581.         nativeDataTypeName = "SQL_TIMESTAMP (" + nativeDataTypeName;
  582.         nativeDataTypeName += ")";
  583.         wxLogMessage(nativeDataTypeName);
  584.     }
  585. #endif
  586. #ifdef SQL_VARCHAR
  587.     if (DataTypeSupported(pDb,SQL_VARCHAR, &nativeDataTypeName))
  588.     {
  589.         nativeDataTypeName = "SQL_VARCHAR (" + nativeDataTypeName;
  590.         nativeDataTypeName += ")";
  591.         wxLogMessage(nativeDataTypeName);
  592.     }
  593. #endif
  594.  
  595. // UNICODE
  596. #ifdef SQL_C_TCHAR
  597.     if (DataTypeSupported(pDb,SQL_C_TCHAR, &nativeDataTypeName))
  598.     {
  599.         nativeDataTypeName = "SQL_C_TCHAR (" + nativeDataTypeName;
  600.         nativeDataTypeName += ")";
  601.         wxLogMessage(nativeDataTypeName);
  602.     }
  603. #endif
  604.  
  605.     wxLogMessage("\n");
  606. }  // CheckSupportForAllDataTypes()
  607.  
  608.  
  609. bool DatabaseDemoApp::OnInit()
  610. {
  611.     DbConnectInf    = NULL;
  612.     Contact         = NULL;
  613.  
  614.     // Create the main frame window
  615.     DemoFrame = new DatabaseDemoFrame(NULL, wxT("wxWindows Database Demo"), wxPoint(50, 50), wxSize(537, 480));
  616.  
  617.     // Give it an icon
  618.     DemoFrame->SetIcon(wxICON(db));
  619.  
  620.     // Make a menubar
  621.     wxMenu *file_menu = new wxMenu;
  622.     file_menu->Append(FILE_CREATE, wxT("&Create CONTACT table"));
  623.     file_menu->Append(FILE_RECREATE_TABLE, wxT("&Recreate CONTACT table"));
  624.     file_menu->Append(FILE_RECREATE_INDEXES, wxT("&Recreate CONTACT indexes"));
  625. #if wxUSE_NEW_GRID
  626.     file_menu->Append(FILE_DBGRID_TABLE,  wxT("&Open DB Grid example"));
  627. #endif
  628.     file_menu->Append(FILE_EXIT, wxT("E&xit"));
  629.  
  630.     wxMenu *edit_menu = new wxMenu;
  631.     edit_menu->Append(EDIT_PARAMETERS, wxT("&Parameters..."));
  632.  
  633.     wxMenu *help_menu = new wxMenu;
  634.     help_menu->Append(HELP_ABOUT, wxT("&About"));
  635.  
  636.     wxMenuBar *menu_bar = new wxMenuBar;
  637.     menu_bar->Append(file_menu, wxT("&File"));
  638.     menu_bar->Append(edit_menu, wxT("&Edit"));
  639.     menu_bar->Append(help_menu, wxT("&Help"));
  640.     DemoFrame->SetMenuBar(menu_bar);
  641.  
  642.     params.ODBCSource[0] = 0;
  643.     params.UserName[0]   = 0;
  644.     params.Password[0]   = 0;
  645.     params.DirPath[0]    = 0;
  646.  
  647.     // Show the frame
  648.     DemoFrame->Show(TRUE);
  649.  
  650.     // Passing NULL for the SQL environment handle causes
  651.     // the wxDbConnectInf constructor to obtain a handle
  652.     // for you.
  653.     //
  654.     // WARNING: Be certain that you do not free this handle
  655.     //          directly with SQLFreeEnv().  Use either the
  656.     //          method ::FreeHenv() or delete the DbConnectInf.
  657.     DbConnectInf = new wxDbConnectInf(NULL, params.ODBCSource, params.UserName, 
  658.                                       params.Password, params.DirPath);
  659.  
  660.     if (!DbConnectInf || !DbConnectInf->GetHenv())
  661.     {
  662.         wxMessageBox(wxT("Unable to define data source connection info."), wxT("DB CONNECTION ERROR..."),wxOK | wxICON_EXCLAMATION);
  663.         wxDELETE(DbConnectInf);
  664.     }
  665.  
  666.     if (!ReadParamFile(params))
  667.         DemoFrame->BuildParameterDialog(NULL);
  668.  
  669.     if (!wxStrlen(params.ODBCSource))
  670.     {
  671.         wxDELETE(DbConnectInf);
  672.         return(FALSE);
  673.     }
  674.  
  675.     DbConnectInf->SetDsn(params.ODBCSource);
  676.     DbConnectInf->SetUserID(params.UserName);
  677.     DbConnectInf->SetPassword(params.Password);
  678.     DbConnectInf->SetDefaultDir(params.DirPath);
  679.  
  680.     READONLY_DB = wxDbGetConnection(DbConnectInf);
  681.     if (READONLY_DB == 0)
  682.     {
  683.         wxMessageBox(wxT("Unable to connect to the data source.\n\nCheck the name of your data source to verify it has been correctly entered/spelled.\n\nWith some databases, the user name and password must\nbe created with full rights to the CONTACT table prior to making a connection\n(using tools provided by the database manufacturer)"), wxT("DB CONNECTION ERROR..."),wxOK | wxICON_EXCLAMATION);
  684.         DemoFrame->BuildParameterDialog(NULL);
  685.         wxDELETE(DbConnectInf);
  686.         wxMessageBox(wxT("Now exiting program.\n\nRestart program to try any new settings."),wxT("Notice..."),wxOK | wxICON_INFORMATION);
  687.         return(FALSE);
  688.     }
  689.  
  690.     DemoFrame->BuildEditorDialog();
  691.  
  692.     // Show the frame
  693.     DemoFrame->Refresh();
  694.  
  695.     return TRUE;
  696. }  // DatabaseDemoApp::OnInit()
  697.  
  698.  
  699. /*
  700. * Remove CR or CR/LF from a character string.
  701. */
  702. char* wxRemoveLineTerminator(char* aString)
  703. {
  704.     int len = strlen(aString);
  705.     while (len > 0 && (aString[len-1] == '\r' || aString[len-1] == '\n')) {
  706.         aString[len-1] = '\0';
  707.         len--;
  708.     }
  709.     return aString;
  710. }
  711.  
  712.  
  713. bool DatabaseDemoApp::ReadParamFile(Cparameters ¶ms)
  714. {
  715.     FILE *paramFile;
  716.     if ((paramFile = fopen(PARAM_FILENAME, wxT("r"))) == NULL)
  717.     {
  718.         wxString tStr;
  719.         tStr.Printf(wxT("Unable to open the parameter file '%s' for reading.\n\nYou must specify the data source, user name, and\npassword that will be used and save those settings."),PARAM_FILENAME);
  720.         wxMessageBox(tStr,wxT("File I/O Error..."),wxOK | wxICON_EXCLAMATION);
  721.  
  722.         return FALSE;
  723.     }
  724.  
  725.     wxChar buffer[1000+1];
  726.     fgets(buffer, sizeof(params.ODBCSource), paramFile);
  727.     wxRemoveLineTerminator(buffer);
  728.     wxStrcpy(params.ODBCSource,buffer);
  729.  
  730.     fgets(buffer, sizeof(params.UserName), paramFile);
  731.     wxRemoveLineTerminator(buffer);
  732.     wxStrcpy(params.UserName,buffer);
  733.  
  734.     fgets(buffer, sizeof(params.Password), paramFile);
  735.     wxRemoveLineTerminator(buffer);
  736.     wxStrcpy(params.Password,buffer);
  737.  
  738.     fgets(buffer, sizeof(params.DirPath), paramFile);
  739.     wxRemoveLineTerminator(buffer);
  740.     wxStrcpy(params.DirPath,buffer);
  741.  
  742.     fclose(paramFile);
  743.  
  744.     return TRUE;
  745. }  // DatabaseDemoApp::ReadParamFile()
  746.  
  747.  
  748. bool DatabaseDemoApp::WriteParamFile(Cparameters ¶ms)
  749. {
  750.     FILE *paramFile;
  751.     if ((paramFile = fopen(PARAM_FILENAME, wxT("wt"))) == NULL)
  752.     {
  753.         wxString tStr;
  754.         tStr.Printf(wxT("Unable to write/overwrite '%s'."),PARAM_FILENAME);
  755.         wxMessageBox(tStr,wxT("File I/O Error..."),wxOK | wxICON_EXCLAMATION);
  756.         return FALSE;
  757.     }
  758.  
  759.     fputs(wxGetApp().params.ODBCSource, paramFile);
  760.     fputc(wxT('\n'), paramFile);
  761.     fputs(wxGetApp().params.UserName, paramFile);
  762.     fputc(wxT('\n'), paramFile);
  763.     fputs(wxGetApp().params.Password, paramFile);
  764.     fputc(wxT('\n'), paramFile);
  765.     fputs(wxGetApp().params.DirPath, paramFile);
  766.     fputc(wxT('\n'), paramFile);
  767.     fclose(paramFile);
  768.  
  769.     return TRUE;
  770. }  // DatabaseDemoApp::WriteParamFile()
  771.  
  772.  
  773. void DatabaseDemoApp::CreateDataTable(bool recreate)
  774. {
  775.     bool Ok = TRUE;
  776.     if (recreate)
  777.        Ok = (wxMessageBox(wxT("Any data currently residing in the table will be erased.\n\nAre you sure?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
  778.  
  779.     if (!Ok)
  780.         return;
  781.  
  782.     wxBeginBusyCursor();
  783.  
  784.     bool success = TRUE;
  785.  
  786.     Contact->GetDb()->RollbackTrans();  // Make sure the current cursor is in a known/stable state
  787.  
  788.     if (!Contact->CreateTable(recreate))
  789.     {
  790.         wxEndBusyCursor();
  791.         wxString tStr;
  792.         tStr = wxT("Error creating CONTACTS table.\nTable was not created.\n\n");
  793.         wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),Contact->GetDb(),__FILE__,__LINE__),
  794.                      wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
  795.  
  796.         success = FALSE;
  797.     }
  798.     else
  799.     {
  800.         if (!Contact->CreateIndexes(recreate))
  801.         {
  802.             wxEndBusyCursor();
  803.             wxString tStr;
  804.             tStr = wxT("Error creating CONTACTS indexes.\nIndexes will be unavailable.\n\n");
  805.             wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),Contact->GetDb(),__FILE__,__LINE__),
  806.                          wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
  807.  
  808.             success = FALSE;
  809.         }
  810.     }
  811.     while (wxIsBusy())
  812.         wxEndBusyCursor();
  813.  
  814.     if (success)
  815.         wxMessageBox(wxT("Table and index(es) were successfully created."),wxT("Notice..."),wxOK | wxICON_INFORMATION);
  816. }  // DatabaseDemoApp::CreateDataTable()
  817.  
  818.  
  819. BEGIN_EVENT_TABLE(DatabaseDemoFrame, wxFrame)
  820.     EVT_MENU(FILE_CREATE, DatabaseDemoFrame::OnCreate)
  821.     EVT_MENU(FILE_RECREATE_TABLE, DatabaseDemoFrame::OnRecreateTable)
  822.     EVT_MENU(FILE_RECREATE_INDEXES, DatabaseDemoFrame::OnRecreateIndexes)
  823. #if wxUSE_NEW_GRID
  824.     EVT_MENU(FILE_DBGRID_TABLE, DatabaseDemoFrame::OnDbGridTable)
  825. #endif
  826.     EVT_MENU(FILE_EXIT, DatabaseDemoFrame::OnExit)
  827.     EVT_MENU(EDIT_PARAMETERS, DatabaseDemoFrame::OnEditParameters)
  828.     EVT_MENU(HELP_ABOUT, DatabaseDemoFrame::OnAbout)
  829.     EVT_CLOSE(DatabaseDemoFrame::OnCloseWindow)
  830. END_EVENT_TABLE()
  831.  
  832.  
  833. // DatabaseDemoFrame constructor
  834. DatabaseDemoFrame::DatabaseDemoFrame(wxFrame *frame, const wxString& title,
  835.                                      const wxPoint& pos, const wxSize& size):
  836.                                         wxFrame(frame, -1, title, pos, size)
  837. {
  838.     // Put any code in necessary for initializing the main frame here
  839.     pEditorDlg = NULL;
  840.     pParamDlg  = NULL;
  841.  
  842.     delete wxLog::SetActiveTarget(new wxLogStderr);
  843.  
  844. }  // DatabaseDemoFrame constructor
  845.  
  846. DatabaseDemoFrame::~DatabaseDemoFrame()
  847. {
  848.     delete wxLog::SetActiveTarget(NULL);
  849. }  // DatabaseDemoFrame destructor
  850.  
  851.  
  852. void DatabaseDemoFrame::OnCreate(wxCommandEvent& event)
  853. {
  854.     wxGetApp().CreateDataTable(FALSE);
  855. }  // DatabaseDemoFrame::OnCreate()
  856.  
  857.  
  858. void DatabaseDemoFrame::OnRecreateTable(wxCommandEvent& event)
  859. {
  860.     wxGetApp().CreateDataTable(TRUE);
  861. }  // DatabaseDemoFrame::OnRecreate()
  862.  
  863.  
  864. void DatabaseDemoFrame::OnRecreateIndexes(wxCommandEvent& event)
  865. {
  866.     wxGetApp().Contact->GetDb()->RollbackTrans();  // Make sure the current cursor is in a known/stable state
  867.  
  868.     if (!wxGetApp().Contact->CreateIndexes(TRUE))
  869.     {
  870.         while (wxIsBusy())
  871.             wxEndBusyCursor();
  872.         wxString tStr;
  873.         tStr = wxT("Error creating CONTACTS indexes.\nNew indexes will be unavailable.\n\n");
  874.         wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),wxGetApp().Contact->GetDb(),__FILE__,__LINE__),
  875.                      wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
  876.  
  877.     }
  878.      else
  879.         wxMessageBox(wxT("Index(es) were successfully recreated."),wxT("Notice..."),wxOK | wxICON_INFORMATION);
  880.  
  881. }  // DatabaseDemoFrame::OnRecreateIndexes()
  882.  
  883.  
  884. #if wxUSE_NEW_GRID
  885. void DatabaseDemoFrame::OnDbGridTable(wxCommandEvent& )
  886. {
  887.     DbGridFrame *frame = new DbGridFrame(this);
  888.     if (frame->Initialize())
  889.     {
  890.         frame->Show();
  891.     }
  892. }
  893. #endif
  894.  
  895. void DatabaseDemoFrame::OnExit(wxCommandEvent& event)
  896. {
  897.     Close();
  898. }  // DatabaseDemoFrame::OnExit()
  899.  
  900.  
  901. void DatabaseDemoFrame::OnEditParameters(wxCommandEvent& event)
  902. {
  903.     if ((pEditorDlg->mode != mCreate) && (pEditorDlg->mode != mEdit))
  904.         BuildParameterDialog(this);
  905.     else
  906.         wxMessageBox(wxT("Cannot change database parameters while creating or editing a record"),wxT("Notice..."),wxOK | wxICON_INFORMATION);
  907. }  // DatabaseDemoFrame::OnEditParameters()
  908.  
  909.  
  910. void DatabaseDemoFrame::OnAbout(wxCommandEvent& event)
  911. {
  912.     wxMessageBox(wxT("wxWindows sample program for database classes\n\nContributed on 27 July 1998"),wxT("About..."),wxOK | wxICON_INFORMATION);
  913. }  // DatabaseDemoFrame::OnAbout()
  914.  
  915.  
  916. // Put any additional checking necessary to make certain it is alright
  917. // to close the program here that is not done elsewhere
  918. void DatabaseDemoFrame::OnCloseWindow(wxCloseEvent& event)
  919. {
  920.     // Clean up time
  921.     if (pEditorDlg && pEditorDlg->Close())
  922.         pEditorDlg = NULL;
  923.     else
  924.     {
  925.         if (pEditorDlg)
  926.         {
  927.             event.Veto();
  928.             return;
  929.         }
  930.     }
  931.  
  932.     wxDELETE(wxGetApp().Contact);
  933.  
  934.     // This function will close all the connections to the database that have been
  935.     // previously cached.
  936.     wxDbCloseConnections();
  937.  
  938.     // Deletion of the wxDbConnectInf instance must be the LAST thing done that
  939.     // has anything to do with the database.  Deleting this before disconnecting,
  940.     // freeing/closing connections, etc will result in a crash!
  941.     wxDELETE(wxGetApp().DbConnectInf);
  942.  
  943.     this->Destroy();
  944.  
  945. }  // DatabaseDemoFrame::OnCloseWindow()
  946.  
  947.  
  948. void DatabaseDemoFrame::BuildEditorDialog()
  949. {
  950.     pEditorDlg = NULL;
  951.     pEditorDlg = new CeditorDlg(this);
  952.     if (pEditorDlg)
  953.     {
  954.         pEditorDlg->Initialize();
  955.         if (!pEditorDlg->initialized)
  956.         {
  957.             pEditorDlg->Close();
  958.             pEditorDlg = NULL;
  959.             wxMessageBox(wxT("Unable to initialize the editor dialog for some reason"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
  960.             Close();
  961.         }
  962.     } 
  963.     else
  964.     {
  965.         wxMessageBox(wxT("Unable to create the editor dialog for some reason"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
  966.         Close();
  967.     }
  968. }  // DatabaseDemoFrame::BuildEditorDialog()
  969.  
  970.  
  971. void DatabaseDemoFrame::BuildParameterDialog(wxWindow *parent)
  972. {
  973.     pParamDlg = new CparameterDlg(parent);
  974.  
  975.     if (!pParamDlg)
  976.         wxMessageBox(wxT("Unable to create the parameter dialog for some reason"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
  977. }  // DatabaseDemoFrame::BuildParameterDialog()
  978.  
  979.  
  980. /*
  981.  * Constructor note: If no wxDb object is passed in, a new connection to the database
  982.  *     is created for this instance of Ccontact.  This can be a slow process depending
  983.  *     on the database engine being used, and some database engines have a limit on the
  984.  *     number of connections (either hard limits, or license restricted) so care should 
  985.  *     be used to use as few connections as is necessary.  
  986.  *
  987.  * IMPORTANT: Objects which share a wxDb pointer are ALL acted upon whenever a member 
  988.  *     function of pDb is called (i.e. CommitTrans() or RollbackTrans(), so if modifying 
  989.  *     or creating a table objects which use the same pDb, know that all the objects
  990.  *     will be committed or rolled back when any of the objects has this function call made.
  991.  */
  992. Ccontact::Ccontact (wxDb *pwxDb) : wxDbTable(pwxDb ? pwxDb : wxDbGetConnection(wxGetApp().DbConnectInf),
  993.                                              CONTACT_TABLE_NAME, CONTACT_NO_COLS, wxT(""),
  994.                                              !wxDB_QUERY_ONLY, wxGetApp().DbConnectInf->GetDefaultDir())
  995. {
  996.     // This is used to represent whether the database connection should be released
  997.     // when this instance of the object is deleted.  If using the same connection
  998.     // for multiple instance of database objects, then the connection should only be 
  999.     // released when the last database instance using the connection is deleted
  1000.     freeDbConn = !pwxDb;
  1001.     
  1002.     if (GetDb())
  1003.         GetDb()->SetSqlLogging(sqlLogON);
  1004.  
  1005.     SetupColumns();
  1006.  
  1007. }  // Ccontact Constructor
  1008.  
  1009.  
  1010. void Ccontact::Initialize()
  1011. {
  1012.     Name[0]            = 0;
  1013.     Addr1[0]           = 0;
  1014.     Addr2[0]           = 0;
  1015.     City[0]            = 0;
  1016.     State[0]           = 0;
  1017.     PostalCode[0]      = 0;
  1018.     Country[0]         = 0;
  1019.     JoinDate.year      = 1980;
  1020.     JoinDate.month     = 1;
  1021.     JoinDate.day       = 1;
  1022.     JoinDate.hour      = 0;
  1023.     JoinDate.minute    = 0;
  1024.     JoinDate.second    = 0;
  1025.     JoinDate.fraction  = 0;
  1026.     NativeLanguage     = langENGLISH;
  1027.     IsDeveloper        = FALSE;
  1028.     Contributions      = 0;
  1029.     LinesOfCode        = 0L;
  1030. }  // Ccontact::Initialize
  1031.  
  1032.  
  1033. Ccontact::~Ccontact()
  1034. {
  1035.     if (freeDbConn)
  1036.     {
  1037.         if (!wxDbFreeConnection(GetDb()))
  1038.         {
  1039.             wxString tStr;
  1040.             tStr = wxT("Unable to Free the Ccontact data table handle\n\n");
  1041.  
  1042.             wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),wxGetApp().Contact->GetDb(),__FILE__,__LINE__),
  1043.                          wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
  1044.         }
  1045.     }
  1046. }  // Ccontract destructor
  1047.  
  1048.  
  1049. /*
  1050.  * Handles setting up all the connections for the interface from the wxDbTable
  1051.  * functions to interface to the data structure used to store records in 
  1052.  * memory, and for all the column definitions that define the table structure
  1053.  */
  1054. void Ccontact::SetupColumns()
  1055. {
  1056.     // NOTE: Columns now are 8 character names, as that is all dBase can support.  Longer
  1057.     //       names can be used for other database engines
  1058.     SetColDefs ( 0,wxT("NAME"),       DB_DATA_TYPE_VARCHAR,     Name,           SQL_C_CHAR,                 sizeof(Name),           TRUE, TRUE);  // Primary index
  1059.     SetColDefs ( 1,wxT("ADDRESS1"),   DB_DATA_TYPE_VARCHAR,     Addr1,          SQL_C_CHAR,                 sizeof(Addr1),          FALSE,TRUE);
  1060.     SetColDefs ( 2,wxT("ADDRESS2"),   DB_DATA_TYPE_VARCHAR,     Addr2,          SQL_C_CHAR,                 sizeof(Addr2),          FALSE,TRUE);
  1061.     SetColDefs ( 3,wxT("CITY"),       DB_DATA_TYPE_VARCHAR,     City,           SQL_C_CHAR,                 sizeof(City),           FALSE,TRUE);
  1062.     SetColDefs ( 4,wxT("STATE"),      DB_DATA_TYPE_VARCHAR,     State,          SQL_C_CHAR,                 sizeof(State),          FALSE,TRUE);
  1063.     SetColDefs ( 5,wxT("POSTCODE"),   DB_DATA_TYPE_VARCHAR,     PostalCode,     SQL_C_CHAR,                 sizeof(PostalCode),     FALSE,TRUE);
  1064.     SetColDefs ( 6,wxT("COUNTRY"),    DB_DATA_TYPE_VARCHAR,     Country,        SQL_C_CHAR,                 sizeof(Country),        FALSE,TRUE);
  1065.     SetColDefs ( 7,wxT("JOINDATE"),   DB_DATA_TYPE_DATE,       &JoinDate,       SQL_C_TIMESTAMP,            sizeof(JoinDate),       FALSE,TRUE);
  1066.     SetColDefs ( 8,wxT("IS_DEV"),     DB_DATA_TYPE_INTEGER,    &IsDeveloper,    SQL_C_BOOLEAN(IsDeveloper), sizeof(IsDeveloper),    FALSE,TRUE);
  1067.     SetColDefs ( 9,wxT("CONTRIBS"),   DB_DATA_TYPE_INTEGER,    &Contributions,  SQL_C_UTINYINT,             sizeof(Contributions),  FALSE,TRUE);
  1068.     SetColDefs (10,wxT("LINE_CNT"),   DB_DATA_TYPE_INTEGER,    &LinesOfCode,    SQL_C_ULONG,                sizeof(LinesOfCode),    FALSE,TRUE);
  1069.     SetColDefs (11,wxT("LANGUAGE"),   DB_DATA_TYPE_INTEGER,    &NativeLanguage, SQL_C_ENUM,                 sizeof(NativeLanguage), FALSE,TRUE);
  1070. #if wxODBC_BLOB_EXPERIMENT > 0
  1071.     SetColDefs (12,wxT("PICTURE"),    DB_DATA_TYPE_BLOB,        Picture,        SQL_LONGVARBINARY,          sizeof(Picture),        FALSE,TRUE);
  1072. #endif
  1073. }  // Ccontact::SetupColumns
  1074.  
  1075.  
  1076. bool Ccontact::CreateIndexes(bool recreate)
  1077. {
  1078.     // This index could easily be accomplished with an "orderBy" clause, 
  1079.     // but is done to show how to construct a non-primary index.
  1080.     wxString    indexName;
  1081.     wxDbIdxDef  idxDef[2];
  1082.  
  1083.     bool        Ok = TRUE;
  1084.  
  1085.     wxStrcpy(idxDef[0].ColName, "IS_DEV");
  1086.     idxDef[0].Ascending = TRUE;
  1087.  
  1088.     wxStrcpy(idxDef[1].ColName, "NAME");
  1089.     idxDef[1].Ascending = TRUE;
  1090.  
  1091.     indexName = GetTableName();
  1092.     indexName += "_IDX1";
  1093.     Ok = CreateIndex(indexName.c_str(), TRUE, 2, idxDef, recreate);
  1094.  
  1095.     return Ok;
  1096. }  // Ccontact::CreateIndexes()
  1097.  
  1098.  
  1099. /*
  1100.  * Having a function to do a query on the primary key (and possibly others) is
  1101.  * very efficient and tighter coding so that it is available where ever the object
  1102.  * is.  Great for use with multiple tables when not using views or outer joins
  1103.  */
  1104. bool Ccontact::FetchByName(const wxString &name)
  1105. {
  1106.     whereStr.Printf(wxT("NAME = '%s'"),name.c_str());
  1107.     SetWhereClause(whereStr.c_str());
  1108.     SetOrderByClause(wxT(""));
  1109.  
  1110.     if (!Query())
  1111.         return(FALSE);
  1112.  
  1113.     // Fetch the record
  1114.     return(GetNext());
  1115.  
  1116. }  // Ccontact::FetchByName()
  1117.  
  1118.  
  1119. /*
  1120.  *
  1121.  *  ************* DIALOGS ***************
  1122.  *
  1123.  */
  1124.  
  1125.  
  1126. /* CeditorDlg constructor
  1127.  *
  1128.  * Creates the dialog used for creating/editing/deleting/copying a Ccontact object.
  1129.  * This dialog actually is drawn in the main frame of the program
  1130.  *
  1131.  * An instance of Ccontact is created - "Contact" - which is used to hold the Ccontact
  1132.  * object that is currently being worked with.
  1133.  */
  1134.  
  1135. BEGIN_EVENT_TABLE(CeditorDlg, wxPanel)
  1136.     EVT_BUTTON(-1,  CeditorDlg::OnButton)
  1137.     EVT_CLOSE(CeditorDlg::OnCloseWindow)
  1138. END_EVENT_TABLE()
  1139.  
  1140. CeditorDlg::CeditorDlg(wxWindow *parent) : wxPanel (parent, 0, 0, 537, 480)
  1141. {
  1142.     // Since the ::OnCommand() function is overridden, this prevents the widget
  1143.     // detection in ::OnCommand() until all widgets have been initialized to prevent
  1144.     // uninitialized pointers from crashing the program
  1145.     widgetPtrsSet = FALSE;
  1146.  
  1147.     initialized = FALSE;
  1148.  
  1149.     SetMode(mView);
  1150.  
  1151.     Show(FALSE);
  1152. }  // CeditorDlg constructor
  1153.  
  1154.  
  1155. void CeditorDlg::OnCloseWindow(wxCloseEvent& event)
  1156. {
  1157.     // Clean up time
  1158.     if ((mode != mCreate) && (mode != mEdit))
  1159.     {
  1160.         this->Destroy();
  1161.     }
  1162.     else
  1163.     {
  1164.         wxMessageBox(wxT("Must finish processing the current record being created/modified before exiting"),wxT("Notice..."),wxOK | wxICON_INFORMATION);
  1165.         event.Veto();
  1166.     }
  1167. }  // CeditorDlg::OnCloseWindow()
  1168.  
  1169.  
  1170. void CeditorDlg::OnButton(wxCommandEvent &event)
  1171. {
  1172.     wxWindow *win = (wxWindow*) event.GetEventObject();
  1173.     OnCommand( *win, event );
  1174. }  // CeditorDlg::OnButton()
  1175.  
  1176.  
  1177. void CeditorDlg::OnCommand(wxWindow& win, wxCommandEvent& event)
  1178. {
  1179.     wxString widgetName;
  1180.     
  1181.     widgetName = win.GetName();
  1182.  
  1183.     if (!widgetPtrsSet)
  1184.         return;
  1185.  
  1186.     if (widgetName == pCreateBtn->GetName())
  1187.     {
  1188.         wxGetApp().Contact->Initialize();
  1189.         PutData();
  1190.         SetMode( mCreate );
  1191.         pNameTxt->SetValue(wxT(""));
  1192.         pNameTxt->SetFocus();
  1193.         return;
  1194.     }
  1195.  
  1196.     if (widgetName == pEditBtn->GetName())
  1197.     {
  1198.         saveName = wxGetApp().Contact->Name;
  1199.         SetMode( mEdit );
  1200.         pNameTxt->SetFocus();
  1201.         return;
  1202.     }
  1203.  
  1204.     if (widgetName == pCopyBtn->GetName())
  1205.     {
  1206.         SetMode(mCreate);
  1207.         pNameTxt->SetValue(wxT(""));
  1208.         pNameTxt->SetFocus();
  1209.         return;
  1210.     }
  1211.  
  1212.     if (widgetName == pDeleteBtn->GetName())
  1213.     {
  1214.         bool Ok = (wxMessageBox(wxT("Are you sure?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
  1215.  
  1216.         if (!Ok)
  1217.             return;
  1218.  
  1219.         if (Ok && wxGetApp().Contact->Delete())
  1220.         {
  1221.             // NOTE: Deletions are not finalized until a CommitTrans() is performed.  
  1222.             //       If the commit were not performed, the program will continue to 
  1223.             //       show the table contents as if they were deleted until this instance
  1224.             //       of Ccontact is deleted.  If the Commit wasn't performed, the 
  1225.             //       database will automatically Rollback the changes when the database
  1226.             //       connection is terminated
  1227.             wxGetApp().Contact->GetDb()->CommitTrans();
  1228.  
  1229.             // Try to get the row that followed the just deleted row in the orderBy sequence
  1230.             if (!GetNextRec())
  1231.             {
  1232.                 // There was now row (in sequence) after the just deleted row, so get the
  1233.                 // row which preceded the just deleted row
  1234.                 if (!GetPrevRec())
  1235.                 {
  1236.                     // There are now no rows remaining, so clear the dialog widgets
  1237.                     wxGetApp().Contact->Initialize();
  1238.                     PutData();
  1239.                 }
  1240.             }
  1241.             SetMode(mode);    // force reset of button enable/disable
  1242.         }
  1243.         else
  1244.             // Delete failed
  1245.             wxGetApp().Contact->GetDb()->RollbackTrans();
  1246.  
  1247.         SetMode(mView);
  1248.         return;
  1249.     }
  1250.  
  1251.     if (widgetName == pSaveBtn->GetName())
  1252.     {
  1253.         Save();
  1254.         return;
  1255.     }
  1256.  
  1257.     if (widgetName == pCancelBtn->GetName())
  1258.     {
  1259.         bool Ok = (wxMessageBox(wxT("Are you sure?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
  1260.  
  1261.         if (!Ok)
  1262.             return;
  1263.  
  1264.         if (saveName.IsEmpty())
  1265.         {
  1266.             wxGetApp().Contact->Initialize();
  1267.             PutData();
  1268.             SetMode(mView);
  1269.             return;
  1270.         }
  1271.         else
  1272.         {
  1273.             // Requery previous record
  1274.             if (wxGetApp().Contact->FetchByName(saveName))
  1275.             {
  1276.                 PutData();
  1277.                 SetMode(mView);
  1278.                 return;
  1279.             }
  1280.         }
  1281.  
  1282.         // Previous record not available, retrieve first record in table
  1283.         if (wxGetApp().Contact->GetDb()->Dbms() != dbmsPOSTGRES &&
  1284.             wxGetApp().Contact->GetDb()->Dbms() != dbmsMY_SQL)
  1285.         {
  1286.             wxGetApp().Contact->whereStr  = wxT("NAME = (SELECT MIN(NAME) FROM ");
  1287.             wxGetApp().Contact->whereStr += wxGetApp().Contact->GetTableName();
  1288.             wxGetApp().Contact->whereStr += wxT(")");
  1289.             wxGetApp().Contact->SetWhereClause(wxGetApp().Contact->whereStr.c_str());
  1290.         }
  1291.         else
  1292.             wxGetApp().Contact->SetWhereClause(wxT(""));
  1293.  
  1294.         if (!wxGetApp().Contact->Query())
  1295.         {
  1296.             wxString tStr;
  1297.             tStr = wxT("ODBC error during Query()\n\n");
  1298.             wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),wxGetApp().Contact->GetDb(),__FILE__,__LINE__),
  1299.                          wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
  1300.             
  1301.             SetMode(mView);
  1302.             return;
  1303.         }
  1304.         if (wxGetApp().Contact->GetNext())  // Successfully read first record
  1305.         {
  1306.             PutData();
  1307.             SetMode(mView);
  1308.             return;
  1309.         }
  1310.         // No contacts are available, clear dialog
  1311.         wxGetApp().Contact->Initialize();
  1312.         PutData();
  1313.         SetMode(mView);
  1314.         return;
  1315.     }  // Cancel Button
  1316.  
  1317.     if (widgetName == pPrevBtn->GetName())
  1318.     {
  1319.         if (!GetPrevRec())
  1320.             wxBell();
  1321.         return;
  1322.     }  // Prev Button
  1323.  
  1324.     if (widgetName == pNextBtn->GetName())
  1325.     {
  1326.         if (!GetNextRec())
  1327.             wxBell();
  1328.         return;
  1329.     }  // Next Button
  1330.  
  1331.     if (widgetName == pQueryBtn->GetName())
  1332.     {
  1333.         // Display the query dialog box
  1334.         wxChar qryWhere[DB_MAX_WHERE_CLAUSE_LEN+1];
  1335.         wxStrcpy(qryWhere, (const wxChar*) wxGetApp().Contact->qryWhereStr);
  1336.         wxChar *tblName[] = {(wxChar *)CONTACT_TABLE_NAME, 0};
  1337.         new CqueryDlg(GetParent(), wxGetApp().Contact->GetDb(), tblName, qryWhere);
  1338.  
  1339.         // Query the first record in the new record set and
  1340.         // display it, if the query string has changed.
  1341.         if (wxStrcmp(qryWhere, (const wxChar*) wxGetApp().Contact->qryWhereStr))
  1342.         {
  1343.             wxGetApp().Contact->whereStr.Empty();
  1344.             wxGetApp().Contact->SetOrderByClause("NAME");
  1345.  
  1346.             if (wxGetApp().Contact->GetDb()->Dbms() != dbmsPOSTGRES &&
  1347.                 wxGetApp().Contact->GetDb()->Dbms() != dbmsMY_SQL)
  1348.             {
  1349.                 wxGetApp().Contact->whereStr  = wxT("NAME = (SELECT MIN(NAME) FROM ");
  1350.                 wxGetApp().Contact->whereStr += CONTACT_TABLE_NAME;
  1351.             }
  1352.             
  1353.             // Append the query where string (if there is one)
  1354.             wxGetApp().Contact->qryWhereStr  = qryWhere;
  1355.             if (wxStrlen(qryWhere))
  1356.             {
  1357.                 wxGetApp().Contact->whereStr += wxT(" WHERE ");
  1358.                 wxGetApp().Contact->whereStr += wxGetApp().Contact->qryWhereStr;
  1359.             }
  1360.             // Close the expression with a right paren
  1361.             wxGetApp().Contact->whereStr += wxT(")");
  1362.             // Requery the table
  1363.             wxGetApp().Contact->SetWhereClause(wxGetApp().Contact->whereStr.c_str());
  1364.             if (!wxGetApp().Contact->Query())
  1365.             {
  1366.                 wxString tStr;
  1367.                 tStr = wxT("ODBC error during Query()\n\n");
  1368.                 wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),wxGetApp().Contact->GetDb(),__FILE__,__LINE__),
  1369.                              wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
  1370.  
  1371.                 return;
  1372.             }
  1373.             // Display the first record from the query set
  1374.             if (!wxGetApp().Contact->GetNext())
  1375.                 wxGetApp().Contact->Initialize();
  1376.             PutData();
  1377.         }
  1378.  
  1379.         // Enable/Disable the reset button
  1380.         pResetBtn->Enable(!wxGetApp().Contact->qryWhereStr.IsEmpty());
  1381.  
  1382.         return;
  1383.     }  // Query button
  1384.  
  1385.  
  1386.     if (widgetName == pResetBtn->GetName())
  1387.     {
  1388.         // Clear the additional where criteria established by the query feature
  1389.         wxGetApp().Contact->qryWhereStr = wxT("");
  1390.         wxGetApp().Contact->SetOrderByClause(wxT("NAME"));
  1391.  
  1392.         if (wxGetApp().Contact->GetDb()->Dbms() != dbmsPOSTGRES &&
  1393.             wxGetApp().Contact->GetDb()->Dbms() != dbmsMY_SQL)
  1394.         {
  1395.             wxGetApp().Contact->whereStr  = wxT("NAME = (SELECT MIN(NAME) FROM ");
  1396.             wxGetApp().Contact->whereStr += CONTACT_TABLE_NAME;
  1397.             wxGetApp().Contact->whereStr += wxT(")");
  1398.         }
  1399.  
  1400.         wxGetApp().Contact->SetWhereClause(wxGetApp().Contact->whereStr.c_str());
  1401.         if (!wxGetApp().Contact->Query())
  1402.         {
  1403.             wxString tStr;
  1404.             tStr = wxT("ODBC error during Query()\n\n");
  1405.             wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),wxGetApp().Contact->GetDb(),__FILE__,__LINE__),
  1406.                          wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
  1407.             return;
  1408.         }
  1409.         if (!wxGetApp().Contact->GetNext())
  1410.             wxGetApp().Contact->Initialize();
  1411.         PutData();
  1412.         pResetBtn->Enable(FALSE);
  1413.  
  1414.         return;
  1415.     }  // Reset button
  1416.  
  1417.  
  1418.     if (widgetName == pNameListBtn->GetName())
  1419.     {
  1420.         new ClookUpDlg(/* wxWindow    *parent        */ this,
  1421.                        /* wxChar      *windowTitle   */ wxT("Select contact name"),
  1422.                        /* wxChar      *tableName     */ (wxChar *) CONTACT_TABLE_NAME,
  1423.                        /* wxChar      *dispCol1      */ wxT("NAME"),
  1424.                        /* wxChar      *dispCol2      */ wxT("JOINDATE"),
  1425.                        /* wxChar      *where         */ wxT(""),
  1426.                        /* wxChar      *orderBy       */ wxT("NAME"),
  1427.                        /* wxDb        *pDb           */ wxGetApp().READONLY_DB,
  1428.                        /* const wxString &defDir     */ wxGetApp().DbConnectInf->GetDefaultDir(),
  1429.                        /* bool        distinctValues */ TRUE);
  1430.  
  1431.         if (ListDB_Selection && wxStrlen(ListDB_Selection))
  1432.         {
  1433.             wxString w = wxT("NAME = '");
  1434.             w += ListDB_Selection;
  1435.             w += wxT("'");
  1436.             GetRec(w);
  1437.         }
  1438.  
  1439.         return;
  1440.     }
  1441.  
  1442.     if (widgetName == pDataTypesBtn->GetName())
  1443.     {
  1444.         CheckSupportForAllDataTypes(wxGetApp().READONLY_DB);
  1445.         wxMessageBox("Support datatypes was dumped to stdout.");
  1446.         return;
  1447.     }  // Data types Button
  1448.  
  1449.     if (widgetName == pDbDiagsBtn->GetName())
  1450.     {
  1451.         DisplayDbDiagnostics(wxGetApp().READONLY_DB);
  1452.         wxMessageBox("Diagnostics info was dumped to stdout.");
  1453.         return;
  1454.     }
  1455.  
  1456.     if (widgetName == pCatalogBtn->GetName())
  1457.     {
  1458.         if (wxGetApp().Contact->GetDb()->Catalog("","catalog.txt"))
  1459.             wxMessageBox("The file 'catalog.txt' was created.");
  1460.         else
  1461.             wxMessageBox("Creation of the file 'catalog.txt' was failed.");
  1462.         return;
  1463.     }
  1464.  
  1465. }  // CeditorDlg::OnCommand()
  1466.  
  1467.  
  1468. bool CeditorDlg::Initialize()
  1469. {
  1470.     // Create the data structure and a new database connection.  
  1471.     // (As there is not a pDb being passed in the constructor, a new database
  1472.     // connection is created)
  1473.     wxGetApp().Contact = new Ccontact();
  1474.  
  1475.     if (!wxGetApp().Contact)
  1476.     {
  1477.         wxMessageBox(wxT("Unable to instantiate an instance of Ccontact"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
  1478.         return FALSE;
  1479.     }
  1480.  
  1481.     // Check if the table exists or not.  If it doesn't, ask the user if they want to 
  1482.     // create the table.  Continue trying to create the table until it exists, or user aborts
  1483.     while (!wxGetApp().Contact->GetDb()->TableExists((wxChar *)CONTACT_TABLE_NAME, 
  1484.                                           wxGetApp().DbConnectInf->GetUserID(), 
  1485.                                           wxGetApp().DbConnectInf->GetDefaultDir()))
  1486.     {
  1487.         wxString tStr;
  1488.         tStr.Printf(wxT("Unable to open the table '%s'.  The table may\nneed to be created.\n\nDo you wish to try to create/clear the table?\n\n"),CONTACT_TABLE_NAME);
  1489.         bool createTable = (wxMessageBox(tStr.c_str(),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
  1490.  
  1491.         if (!createTable)
  1492.         {
  1493. //            Close();
  1494.             return FALSE;
  1495.         }
  1496.         else
  1497.             wxGetApp().CreateDataTable(FALSE);
  1498.     }
  1499.  
  1500.     // Tables must be "opened" before anything other than creating/deleting table can be done
  1501.     if (!wxGetApp().Contact->Open())
  1502.     {
  1503.         // Table does exist, or there was some problem opening it.  Currently this should
  1504.         // never fail, except in the case of the table not exisiting or the current
  1505.         // user has insufficent privileges to access the table
  1506. #if 1
  1507. // This code is experimenting with a new function that will hopefully be available
  1508. // in the 2.4 release.  This check will determine whether the open failing was due
  1509. // to the table not existing, or the users privileges being insufficient to
  1510. // open the table.
  1511.         if (!wxGetApp().Contact->GetDb()->TablePrivileges(CONTACT_TABLE_NAME, wxT("SELECT"),
  1512.                                                 wxGetApp().Contact->GetDb()->GetUsername(),
  1513.                                                 wxGetApp().Contact->GetDb()->GetUsername(),
  1514.                                                 wxGetApp().DbConnectInf->GetDefaultDir()))
  1515.         {
  1516.             wxString tStr;
  1517.             tStr.Printf(wxT("Unable to open the table '%s' (likely due to\ninsufficient privileges of the logged in user).\n\n"),CONTACT_TABLE_NAME);
  1518.  
  1519.             wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),wxGetApp().Contact->GetDb(),__FILE__,__LINE__),
  1520.                          wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
  1521.         }
  1522.         else 
  1523. #endif
  1524.         if (!wxGetApp().Contact->GetDb()->TableExists(CONTACT_TABLE_NAME,
  1525.                                            wxGetApp().Contact->GetDb()->GetUsername(),
  1526.                                            wxGetApp().DbConnectInf->GetDefaultDir()))
  1527.         {
  1528.             wxString tStr;
  1529.             tStr.Printf(wxT("Unable to open the table '%s' as the table\ndoes not appear to exist in the tablespace available\nto the currently logged in user.\n\n"),CONTACT_TABLE_NAME);
  1530.             wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),wxGetApp().Contact->GetDb(),__FILE__,__LINE__),
  1531.                          wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
  1532.         }
  1533.  
  1534.         return FALSE;
  1535.     }
  1536.  
  1537.     // Build the dialog
  1538.  
  1539.     (void)new wxStaticBox(this, EDITOR_DIALOG_FN_GROUP, wxT(""),  wxPoint(15, 1), wxSize(497,  69), 0, wxT("FunctionGrp"));
  1540.     (void)new wxStaticBox(this, EDITOR_DIALOG_SEARCH_GROUP, wxT(""), wxPoint(417, 1), wxSize(95, 242), 0, wxT("SearchGrp"));
  1541.  
  1542.     pCreateBtn      = new wxButton(this, EDITOR_DIALOG_CREATE,           wxT("&Create"),     wxPoint( 25,  21), wxSize( 70,  35), 0, wxDefaultValidator, wxT("CreateBtn"));
  1543.     pEditBtn        = new wxButton(this, EDITOR_DIALOG_EDIT,             wxT("&Edit"),       wxPoint(102,  21), wxSize( 70,  35), 0, wxDefaultValidator, wxT("EditBtn"));
  1544.     pDeleteBtn      = new wxButton(this, EDITOR_DIALOG_DELETE,           wxT("&Delete"),     wxPoint(179,  21), wxSize( 70,  35), 0, wxDefaultValidator, wxT("DeleteBtn"));
  1545.     pCopyBtn        = new wxButton(this, EDITOR_DIALOG_COPY,             wxT("Cop&y"),       wxPoint(256,  21), wxSize( 70,  35), 0, wxDefaultValidator, wxT("CopyBtn"));
  1546.     pSaveBtn        = new wxButton(this, EDITOR_DIALOG_SAVE,             wxT("&Save"),       wxPoint(333,  21), wxSize( 70,  35), 0, wxDefaultValidator, wxT("SaveBtn"));
  1547.     pCancelBtn      = new wxButton(this, EDITOR_DIALOG_CANCEL,           wxT("C&ancel"),     wxPoint(430,  21), wxSize( 70,  35), 0, wxDefaultValidator, wxT("CancelBtn"));
  1548.     pPrevBtn        = new wxButton(this, EDITOR_DIALOG_PREV,             wxT("<< &Prev"),    wxPoint(430,  81), wxSize( 70,  35), 0, wxDefaultValidator, wxT("PrevBtn"));
  1549.     pNextBtn        = new wxButton(this, EDITOR_DIALOG_NEXT,             wxT("&Next >>"),    wxPoint(430, 121), wxSize( 70,  35), 0, wxDefaultValidator, wxT("NextBtn"));
  1550.     pQueryBtn       = new wxButton(this, EDITOR_DIALOG_QUERY,            wxT("&Query"),      wxPoint(430, 161), wxSize( 70,  35), 0, wxDefaultValidator, wxT("QueryBtn"));
  1551.     pResetBtn       = new wxButton(this, EDITOR_DIALOG_RESET,            wxT("&Reset"),      wxPoint(430, 200), wxSize( 70,  35), 0, wxDefaultValidator, wxT("ResetBtn"));
  1552.     pNameMsg        = new wxStaticText(this, EDITOR_DIALOG_NAME_MSG,     wxT("Name:"),       wxPoint( 17,  80), wxSize( -1,  -1), 0, wxT("NameMsg"));
  1553.     pNameTxt        = new wxTextCtrl(this, EDITOR_DIALOG_NAME_TEXT,      wxT(""),            wxPoint( 17,  97), wxSize(308,  25), 0, wxDefaultValidator, wxT("NameTxt"));
  1554.     pNameListBtn    = new wxButton(this, EDITOR_DIALOG_LOOKUP,           wxT("&Lookup"),     wxPoint(333,  97), wxSize( 70,  24), 0, wxDefaultValidator, wxT("LookupBtn"));
  1555.     pAddress1Msg    = new wxStaticText(this, EDITOR_DIALOG_ADDRESS1_MSG, wxT("Address:"),    wxPoint( 17, 130), wxSize( -1,  -1), 0, wxT("Address1Msg"));
  1556.     pAddress1Txt    = new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT,  wxT(""),            wxPoint( 17, 147), wxSize(308,  25), 0, wxDefaultValidator, wxT("Address1Txt"));
  1557.     pAddress2Msg    = new wxStaticText(this, EDITOR_DIALOG_ADDRESS2_MSG, wxT("Address:"),    wxPoint( 17, 180), wxSize( -1,  -1), 0, wxT("Address2Msg"));
  1558.     pAddress2Txt    = new wxTextCtrl(this, EDITOR_DIALOG_ADDRESS2_TEXT,  wxT(""),            wxPoint( 17, 197), wxSize(308,  25), 0, wxDefaultValidator, wxT("Address2Txt"));
  1559.     pCityMsg        = new wxStaticText(this, EDITOR_DIALOG_CITY_MSG,     wxT("City:"),       wxPoint( 17, 230), wxSize( -1,  -1), 0, wxT("CityMsg"));
  1560.     pCityTxt        = new wxTextCtrl(this, EDITOR_DIALOG_CITY_TEXT,      wxT(""),            wxPoint( 17, 247), wxSize(225,  25), 0, wxDefaultValidator, wxT("CityTxt"));
  1561.     pStateMsg       = new wxStaticText(this, EDITOR_DIALOG_STATE_MSG,    wxT("State:"),      wxPoint(250, 230), wxSize( -1,  -1), 0, wxT("StateMsg"));
  1562.     pStateTxt       = new wxTextCtrl(this, EDITOR_DIALOG_STATE_TEXT,     wxT(""),            wxPoint(250, 247), wxSize(153,  25), 0, wxDefaultValidator, wxT("StateTxt"));
  1563.     pCountryMsg     = new wxStaticText(this, EDITOR_DIALOG_COUNTRY_MSG,  wxT("Country:"),    wxPoint( 17, 280), wxSize( -1,  -1), 0, wxT("CountryMsg"));
  1564.     pCountryTxt     = new wxTextCtrl(this, EDITOR_DIALOG_COUNTRY_TEXT,   wxT(""),            wxPoint( 17, 297), wxSize(225,  25), 0, wxDefaultValidator, wxT("CountryTxt"));
  1565.     pPostalCodeMsg  = new wxStaticText(this, EDITOR_DIALOG_POSTAL_MSG,   wxT("Postal Code:"),wxPoint(250, 280), wxSize( -1,  -1), 0, wxT("PostalCodeMsg"));
  1566.     pPostalCodeTxt  = new wxTextCtrl(this, EDITOR_DIALOG_POSTAL_TEXT,    wxT(""),            wxPoint(250, 297), wxSize(153,  25), 0, wxDefaultValidator, wxT("PostalCodeTxt"));
  1567.  
  1568.     wxString choice_strings[5];
  1569.     choice_strings[0] = wxT("English");
  1570.     choice_strings[1] = wxT("French");
  1571.     choice_strings[2] = wxT("German");
  1572.     choice_strings[3] = wxT("Spanish");
  1573.     choice_strings[4] = wxT("Other");
  1574.  
  1575.     pNativeLangChoice = new wxChoice(this, EDITOR_DIALOG_LANG_CHOICE,                             wxPoint( 17, 346), wxSize(277,  -1), 5, choice_strings);
  1576.     pNativeLangMsg    = new wxStaticText(this, EDITOR_DIALOG_LANG_MSG,   wxT("Native language:"), wxPoint( 17, 330), wxSize( -1,  -1), 0, wxT("NativeLangMsg"));
  1577.  
  1578.     wxString radio_strings[2];
  1579.     radio_strings[0]  = wxT("No");
  1580.     radio_strings[1]  = wxT("Yes");
  1581.     pDeveloperRadio   = new wxRadioBox(this,EDITOR_DIALOG_DEVELOPER,     wxT("Developer:"),       wxPoint(303, 330), wxSize( -1,  -1), 2, radio_strings, 2, wxHORIZONTAL);
  1582.     pJoinDateMsg      = new wxStaticText(this, EDITOR_DIALOG_JOIN_MSG,   wxT("Date joined:"),     wxPoint( 17, 380), wxSize( -1,  -1), 0, wxT("JoinDateMsg"));
  1583.     pJoinDateTxt      = new wxTextCtrl(this, EDITOR_DIALOG_JOIN_TEXT,    wxT(""),                 wxPoint( 17, 397), wxSize(150,  25), 0, wxDefaultValidator, wxT("JoinDateTxt"));
  1584.     pContribMsg       = new wxStaticText(this, EDITOR_DIALOG_CONTRIB_MSG,wxT("Contributions:"),   wxPoint(175, 380), wxSize( -1,  -1), 0, wxT("ContribMsg"));
  1585.     pContribTxt       = new wxTextCtrl(this, EDITOR_DIALOG_CONTRIB_TEXT, wxT(""),                 wxPoint(175, 397), wxSize(120,  25), 0, wxDefaultValidator, wxT("ContribTxt"));
  1586.     pLinesMsg         = new wxStaticText(this, EDITOR_DIALOG_LINES_MSG,  wxT("Lines of code:"),   wxPoint(303, 380), wxSize( -1,  -1), 0, wxT("LinesMsg"));
  1587.     pLinesTxt         = new wxTextCtrl(this, EDITOR_DIALOG_LINES_TEXT,   wxT(""),                 wxPoint(303, 397), wxSize(100,  25), 0, wxDefaultValidator, wxT("LinesTxt"));
  1588.  
  1589.     pCatalogBtn       = new wxButton(this, EDITOR_DIALOG_CATALOG,        wxT("Catalo&g"),         wxPoint(430, 287), wxSize( 70,  35), 0, wxDefaultValidator, wxT("CatalogBtn"));
  1590.     pDataTypesBtn     = new wxButton(this, EDITOR_DIALOG_DATATYPES,      wxT("Data&types"),       wxPoint(430, 337), wxSize( 70,  35), 0, wxDefaultValidator, wxT("DataTypesBtn"));
  1591.     pDbDiagsBtn       = new wxButton(this, EDITOR_DIALOG_DB_DIAGS,       wxT("DB Dia&gs"),        wxPoint(430, 387), wxSize( 70,  35), 0, wxDefaultValidator, wxT("DbDiagsBtn"));
  1592.  
  1593.     // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to 
  1594.     // handle all widget processing
  1595.     widgetPtrsSet = TRUE;
  1596.  
  1597.     // Setup the orderBy and where clauses to return back a single record as the result set, 
  1598.     // as there will only be one record being shown on the dialog at a time, this optimizes
  1599.     // network traffic by only returning a one row result
  1600.     
  1601.     wxGetApp().Contact->SetOrderByClause(wxT("NAME"));  // field name to sort by
  1602.  
  1603.     // The wxString "whereStr" is not a member of the wxDbTable object, it is a member variable
  1604.     // specifically in the Ccontact class.  It is used here for simpler construction of a varying
  1605.     // length string, and then after the string is built, the wxDbTable member variable "where" is
  1606.     // assigned the pointer to the constructed string.
  1607.     //
  1608.     // The constructed where clause below has a sub-query within it "SELECT MIN(NAME) FROM %s" 
  1609.     // to achieve a single row (in this case the first name in alphabetical order).
  1610.     
  1611.     if (wxGetApp().Contact->GetDb()->Dbms() != dbmsPOSTGRES &&
  1612.         wxGetApp().Contact->GetDb()->Dbms() != dbmsMY_SQL)
  1613.     {
  1614.         wxGetApp().Contact->whereStr.Printf(wxT("NAME = (SELECT MIN(NAME) FROM %s)"),
  1615.                                             wxGetApp().Contact->GetTableName().c_str());
  1616.         // NOTE: (const wxChar*) returns a pointer which may not be valid later, so this is short term use only
  1617.         wxGetApp().Contact->SetWhereClause(wxGetApp().Contact->whereStr);
  1618.     }
  1619.     else
  1620.        wxGetApp().Contact->SetWhereClause(wxT(""));
  1621.  
  1622.     // Perform the Query to get the result set.  
  1623.     // NOTE: If there are no rows returned, that is a valid result, so Query() would return TRUE.  
  1624.     //       Only if there is a database error will Query() come back as FALSE
  1625.     if (!wxGetApp().Contact->Query())
  1626.     {
  1627.         wxString tStr;
  1628.         tStr = wxT("ODBC error during Query()\n\n");
  1629.         wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),wxGetApp().Contact->GetDb(),__FILE__,__LINE__),
  1630.                      wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
  1631.         return FALSE;
  1632.     }
  1633.  
  1634.     // Since Query succeeded, now get the row that was returned
  1635.     if (!wxGetApp().Contact->GetNext())
  1636.         // If the GetNext() failed at this point, then there are no rows to retrieve, 
  1637.         // so clear the values in the members of "Contact" so that PutData() blanks the 
  1638.         // widgets on the dialog
  1639.         wxGetApp().Contact->Initialize();
  1640. /*
  1641.     wxGetApp().Contact->GetDb()->RollbackTrans();
  1642. */
  1643.     SetMode(mView);
  1644.     PutData();
  1645.  
  1646.     Show(TRUE);
  1647.  
  1648.     initialized = TRUE;
  1649.     return TRUE;
  1650. }  // CeditorDlg::Initialize()
  1651.  
  1652.  
  1653. void CeditorDlg::FieldsEditable()
  1654. {
  1655.     if (!widgetPtrsSet)
  1656.         return;
  1657.  
  1658.     pNameTxt->Enable((mode == mCreate) || (mode == mEdit));
  1659.     pAddress1Txt->Enable((mode == mCreate) || (mode == mEdit));
  1660.     pAddress2Txt->Enable((mode == mCreate) || (mode == mEdit));
  1661.     pCityTxt->Enable((mode == mCreate) || (mode == mEdit));
  1662.     pStateTxt->Enable((mode == mCreate) || (mode == mEdit));
  1663.     pPostalCodeTxt->Enable((mode == mCreate) || (mode == mEdit));
  1664.     pCountryTxt->Enable((mode == mCreate) || (mode == mEdit));
  1665.  
  1666.     pJoinDateTxt->Enable((mode == mCreate) || (mode == mEdit));
  1667.     pContribTxt->Enable((mode == mCreate) || (mode == mEdit));
  1668.     pLinesTxt->Enable((mode == mCreate) || (mode == mEdit));
  1669.     pNativeLangChoice->Enable((mode == mCreate) || (mode == mEdit));
  1670.     pDeveloperRadio->Enable((mode == mCreate) || (mode == mEdit));
  1671.  
  1672. }  // CeditorDlg::FieldsEditable()
  1673.  
  1674.  
  1675. void CeditorDlg::SetMode(enum DialogModes m)
  1676. {
  1677.     bool edit = FALSE;
  1678.  
  1679.     mode = m;
  1680.     switch (mode)
  1681.     {
  1682.         case mCreate:
  1683.         case mEdit:
  1684.             edit = TRUE;
  1685.             break;
  1686.         case mView:
  1687.         case mSearch:
  1688.             edit = FALSE;
  1689.             break;
  1690.         default:
  1691.                 break;
  1692.     };
  1693.  
  1694.     if (widgetPtrsSet)
  1695.     {
  1696.         pCreateBtn->Enable( !edit );
  1697.         pEditBtn->Enable( !edit && (wxStrcmp(wxGetApp().Contact->Name,wxT(""))!=0) );
  1698.         pDeleteBtn->Enable( !edit && (wxStrcmp(wxGetApp().Contact->Name,wxT(""))!=0) );
  1699.         pCopyBtn->Enable( !edit && (wxStrcmp(wxGetApp().Contact->Name,wxT(""))!=0) );
  1700.         pSaveBtn->Enable( edit );
  1701.         pCancelBtn->Enable( edit );
  1702.         pPrevBtn->Enable( !edit );
  1703.         pNextBtn->Enable( !edit );
  1704.         pQueryBtn->Enable( !edit );
  1705.         pResetBtn->Enable( !edit && !wxGetApp().Contact->qryWhereStr.IsEmpty() );
  1706.         pNameListBtn->Enable( !edit );
  1707.     }
  1708.  
  1709.     FieldsEditable();
  1710. }  // CeditorDlg::SetMode()
  1711.  
  1712.  
  1713. bool CeditorDlg::PutData()
  1714. {
  1715.     wxString tStr;
  1716.  
  1717.     pNameTxt->SetValue(wxGetApp().Contact->Name);
  1718.     pAddress1Txt->SetValue(wxGetApp().Contact->Addr1);
  1719.     pAddress2Txt->SetValue(wxGetApp().Contact->Addr2);
  1720.     pCityTxt->SetValue(wxGetApp().Contact->City);
  1721.     pStateTxt->SetValue(wxGetApp().Contact->State);
  1722.     pCountryTxt->SetValue(wxGetApp().Contact->Country);
  1723.     pPostalCodeTxt->SetValue(wxGetApp().Contact->PostalCode);
  1724.  
  1725.     tStr.Printf(wxT("%d/%d/%d"),wxGetApp().Contact->JoinDate.month,wxGetApp().Contact->JoinDate.day,wxGetApp().Contact->JoinDate.year);
  1726.     pJoinDateTxt->SetValue(tStr);
  1727.  
  1728.     tStr.Printf(wxT("%d"),wxGetApp().Contact->Contributions);
  1729.     pContribTxt->SetValue(tStr);
  1730.  
  1731.     tStr.Printf(wxT("%lu"),wxGetApp().Contact->LinesOfCode);
  1732.     pLinesTxt->SetValue(tStr);
  1733.  
  1734.     pNativeLangChoice->SetSelection(wxGetApp().Contact->NativeLanguage);
  1735.  
  1736.     pDeveloperRadio->SetSelection(wxGetApp().Contact->IsDeveloper);
  1737.  
  1738.     return TRUE;
  1739. }  // Ceditor::PutData()
  1740.  
  1741.  
  1742. /*
  1743.  * Reads the data out of all the widgets on the dialog.  Some data evaluation is done
  1744.  * to ensure that there is a name entered and that the date field is valid.
  1745.  *
  1746.  * A return value of TRUE means that valid data was retrieved from the dialog, otherwise
  1747.  * invalid data was found (and a message was displayed telling the user what to fix), and
  1748.  * the data was not placed into the appropraite fields of Ccontact
  1749.  */
  1750. bool CeditorDlg::GetData()
  1751. {
  1752.     // Validate that the data currently entered into the widgets is valid data
  1753.  
  1754.     wxString tStr;
  1755.     tStr = pNameTxt->GetValue();
  1756.     if (!wxStrcmp((const wxChar*) tStr,wxT("")))
  1757.     {
  1758.         wxMessageBox(wxT("A name is required for entry into the contact table"),wxT("Notice..."),wxOK | wxICON_INFORMATION);
  1759.         return FALSE;
  1760.     }
  1761.  
  1762.     bool   invalid = FALSE;
  1763.     int    mm = 1,dd = 1,yyyy = 2001;
  1764.     int    first, second;
  1765.  
  1766.     tStr = pJoinDateTxt->GetValue();
  1767.     if (tStr.Freq(wxT('/')) != 2)
  1768.         invalid = TRUE;
  1769.  
  1770.     // Find the month, day, and year tokens
  1771.     if (!invalid)
  1772.     {
  1773.         first   = tStr.First(wxT('/'));
  1774.         second  = tStr.Last(wxT('/'));
  1775.  
  1776.         mm      = atoi(tStr.SubString(0,first));
  1777.         dd      = atoi(tStr.SubString(first+1,second));
  1778.         yyyy    = atoi(tStr.SubString(second+1,tStr.Length()-1));
  1779.  
  1780.         invalid = !(mm && dd && yyyy);
  1781.     }
  1782.  
  1783.     // Force Year 2000 compliance
  1784.     if (!invalid && (yyyy < 1000))
  1785.         invalid = TRUE;
  1786.  
  1787.     // Check the token ranges for validity
  1788.     if (!invalid)
  1789.     {
  1790.         if (yyyy > 9999)
  1791.             invalid = TRUE;
  1792.         else if ((mm < 1) || (mm > 12))
  1793.             invalid = TRUE;
  1794.         else
  1795.         {
  1796.             if (dd < 1)
  1797.                 invalid = TRUE;
  1798.             else
  1799.             {
  1800.                 int days[12] = {31,28,31,30,31,30,
  1801.                                 31,31,30,31,30,31};
  1802.                 if (dd > days[mm-1])
  1803.                 {
  1804.                     invalid = TRUE;
  1805.                     if ((dd == 29) && (mm == 2))
  1806.                     {
  1807.                         if (((yyyy % 4) == 0) && (((yyyy % 100) != 0) || ((yyyy % 400) == 0)))
  1808.                             invalid = FALSE;
  1809.                     }
  1810.                 }
  1811.             }
  1812.         }
  1813.     }
  1814.  
  1815.     if (!invalid)
  1816.     {
  1817.         wxGetApp().Contact->JoinDate.month = mm;
  1818.         wxGetApp().Contact->JoinDate.day   = dd;
  1819.         wxGetApp().Contact->JoinDate.year  = yyyy;
  1820.     }
  1821.     else
  1822.     {
  1823.         wxMessageBox(wxT("Improper date format.  Please check the date\nspecified and try again.\n\nNOTE: Dates are in american format (MM/DD/YYYY)"),wxT("Notice..."),wxOK | wxICON_INFORMATION);
  1824.         return FALSE;
  1825.     }
  1826.  
  1827.     tStr = pNameTxt->GetValue();
  1828.     wxStrcpy(wxGetApp().Contact->Name,(const wxChar*) tStr);
  1829.     wxStrcpy(wxGetApp().Contact->Addr1,pAddress1Txt->GetValue());
  1830.     wxStrcpy(wxGetApp().Contact->Addr2,pAddress2Txt->GetValue());
  1831.     wxStrcpy(wxGetApp().Contact->City,pCityTxt->GetValue());
  1832.     wxStrcpy(wxGetApp().Contact->State,pStateTxt->GetValue());
  1833.     wxStrcpy(wxGetApp().Contact->Country,pCountryTxt->GetValue());
  1834.     wxStrcpy(wxGetApp().Contact->PostalCode,pPostalCodeTxt->GetValue());
  1835.  
  1836.     wxGetApp().Contact->Contributions = atoi(pContribTxt->GetValue());
  1837.     wxGetApp().Contact->LinesOfCode = atol(pLinesTxt->GetValue());
  1838.  
  1839.     wxGetApp().Contact->NativeLanguage = (enum Language) pNativeLangChoice->GetSelection();
  1840.     wxGetApp().Contact->IsDeveloper = pDeveloperRadio->GetSelection() > 0;
  1841.  
  1842.     return TRUE;
  1843. }  // CeditorDlg::GetData()
  1844.  
  1845.  
  1846. /*
  1847.  * Retrieve data from the dialog, verify the validity of the data, and if it is valid,
  1848.  * try to insert/update the data to the table based on the current 'mode' the dialog
  1849.  * is set to.
  1850.  *
  1851.  * A return value of TRUE means the insert/update was completed successfully, a return
  1852.  * value of FALSE means that Save() failed.  If returning FALSE, then this function
  1853.  * has displayed a detailed error message for the user.
  1854.  */
  1855. bool CeditorDlg::Save()
  1856. {
  1857.     bool failed = FALSE;
  1858.  
  1859.     // Read the data in the widgets of the dialog to get the user's data
  1860.     if (!GetData())
  1861.         failed = TRUE;
  1862.  
  1863.     // Perform any other required validations necessary before saving
  1864.     if (!failed)
  1865.     {
  1866.         wxBeginBusyCursor();
  1867.  
  1868.         if (mode == mCreate)
  1869.         {
  1870.             RETCODE result = wxGetApp().Contact->Insert();
  1871.  
  1872.             failed = (result != DB_SUCCESS);
  1873.             if (failed)
  1874.             {
  1875.                 // Some errors may be expected, like a duplicate key, so handle those instances with
  1876.                 // specific error messages.
  1877.                 if (result == DB_ERR_INTEGRITY_CONSTRAINT_VIOL)
  1878.                 {
  1879.                     wxString tStr;
  1880.                     tStr = wxT("A duplicate key value already exists in the table.\nUnable to save record\n\n");
  1881.                     wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),wxGetApp().Contact->GetDb(),__FILE__,__LINE__),
  1882.                                  wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
  1883.                 }
  1884.                 else
  1885.                 {
  1886.                     // Some other unexpected error occurred
  1887.                     wxString tStr;
  1888.                     tStr = wxT("Database insert failed\n\n");
  1889.                     wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),wxGetApp().Contact->GetDb(),__FILE__,__LINE__),
  1890.                                  wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
  1891.                 }
  1892.             }
  1893.         }
  1894.         else  // mode == mEdit
  1895.         {
  1896.             wxGetApp().Contact->GetDb()->RollbackTrans();
  1897.             wxGetApp().Contact->whereStr.Printf("NAME = '%s'",saveName.c_str());
  1898.             if (!wxGetApp().Contact->UpdateWhere(wxGetApp().Contact->whereStr))
  1899.             {
  1900.                 wxString tStr;
  1901.                 tStr = wxT("Database update failed\n\n");
  1902.                 wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),wxGetApp().Contact->GetDb(),__FILE__,__LINE__),
  1903.                              wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
  1904.                 failed = TRUE;
  1905.             }
  1906.         }
  1907.  
  1908.         if (!failed)
  1909.         {
  1910.             wxGetApp().Contact->GetDb()->CommitTrans();
  1911.             SetMode(mView);  // Sets the dialog mode back to viewing after save is successful
  1912.         }
  1913.         else
  1914.             wxGetApp().Contact->GetDb()->RollbackTrans();
  1915.  
  1916.         wxEndBusyCursor();
  1917.     }
  1918.  
  1919.     return !failed;
  1920. }  // CeditorDlg::Save()
  1921.  
  1922.  
  1923. /*
  1924.  * Where this program is only showing a single row at a time in the dialog,
  1925.  * a special where clause must be built to find just the single row which,
  1926.  * in sequence, would follow the currently displayed row.
  1927.  */
  1928. bool CeditorDlg::GetNextRec()
  1929. {
  1930.     wxString w;
  1931.  
  1932.     if (wxGetApp().Contact->GetDb()->Dbms() != dbmsPOSTGRES &&
  1933.         wxGetApp().Contact->GetDb()->Dbms() != dbmsMY_SQL)
  1934.     {
  1935.         w  = wxT("NAME = (SELECT MIN(NAME) FROM ");
  1936.         w += wxGetApp().Contact->GetTableName();
  1937.         w += wxT(" WHERE NAME > '");
  1938.     }
  1939.     else
  1940.         w = wxT("(NAME > '");
  1941.  
  1942.     w += wxGetApp().Contact->Name;
  1943.     w += wxT("'");
  1944.  
  1945.     // If a query where string is currently set, append that criteria
  1946.     if (!wxGetApp().Contact->qryWhereStr.IsEmpty())
  1947.     {
  1948.         w += wxT(" AND (");
  1949.         w += wxGetApp().Contact->qryWhereStr;
  1950.         w += wxT(")");
  1951.     }
  1952.  
  1953.     w += wxT(")");
  1954.     return(GetRec(w));
  1955.  
  1956. }  // CeditorDlg::GetNextRec()
  1957.  
  1958.  
  1959. /*
  1960.  * Where this program is only showing a single row at a time in the dialog,
  1961.  * a special where clause must be built to find just the single row which,
  1962.  * in sequence, would precede the currently displayed row.
  1963.  */
  1964. bool CeditorDlg::GetPrevRec()
  1965. {
  1966.     wxString w;
  1967.  
  1968.     if (wxGetApp().Contact->GetDb()->Dbms() != dbmsPOSTGRES &&
  1969.         wxGetApp().Contact->GetDb()->Dbms() != dbmsMY_SQL)
  1970.     {
  1971.         w  = wxT("NAME = (SELECT MAX(NAME) FROM ");
  1972.         w += wxGetApp().Contact->GetTableName();
  1973.         w += wxT(" WHERE NAME < '");
  1974.     }
  1975.     else
  1976.         w = wxT("(NAME < '");
  1977.  
  1978.     w += wxGetApp().Contact->Name;
  1979.     w += wxT("'");
  1980.  
  1981.     // If a query where string is currently set, append that criteria
  1982.     if (!wxGetApp().Contact->qryWhereStr.IsEmpty())
  1983.     {
  1984.         w += wxT(" AND (");
  1985.         w += wxGetApp().Contact->qryWhereStr;
  1986.         w += wxT(")");
  1987.     }
  1988.  
  1989.     w += wxT(")");
  1990.  
  1991.     return(GetRec(w));
  1992.  
  1993. }  // CeditorDlg::GetPrevRec()
  1994.  
  1995.  
  1996. /*
  1997.  * This function is here to avoid duplicating this same code in both the
  1998.  * GetPrevRec() and GetNextRec() functions
  1999.  */
  2000. bool CeditorDlg::GetRec(const wxString &whereStr)
  2001. {
  2002.     wxGetApp().Contact->SetWhereClause(whereStr);
  2003.     wxGetApp().Contact->SetOrderByClause(wxT("NAME"));
  2004.  
  2005.     if (!wxGetApp().Contact->Query())
  2006.     {
  2007.         wxString tStr;
  2008.         tStr = wxT("ODBC error during Query()\n\n");
  2009.         wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),wxGetApp().Contact->GetDb(),__FILE__,__LINE__),
  2010.                      wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
  2011.  
  2012.         return(FALSE);
  2013.     }
  2014.  
  2015.     if (wxGetApp().Contact->GetNext())
  2016.     {
  2017.         PutData();
  2018.         return(TRUE);
  2019.     }
  2020.     else
  2021.         return(FALSE);
  2022. }  // CeditorDlg::GetRec()
  2023.  
  2024.  
  2025.  
  2026. /*
  2027.  * CparameterDlg constructor
  2028.  */
  2029.  
  2030. BEGIN_EVENT_TABLE(CparameterDlg, wxDialog)
  2031.     EVT_BUTTON(PARAMETER_DIALOG_SAVE,  CparameterDlg::OnButton)
  2032.     EVT_BUTTON(PARAMETER_DIALOG_CANCEL,  CparameterDlg::OnButton)
  2033.     EVT_CLOSE(CparameterDlg::OnCloseWindow)
  2034. END_EVENT_TABLE()
  2035.  
  2036. CparameterDlg::CparameterDlg(wxWindow *parent) : wxDialog (parent, PARAMETER_DIALOG, wxT("ODBC parameter settings"), wxPoint(-1, -1), wxSize(400, 325))
  2037. {
  2038.     // Since the ::OnCommand() function is overridden, this prevents the widget
  2039.     // detection in ::OnCommand() until all widgets have been initialized to prevent
  2040.     // uninitialized pointers from crashing the program
  2041.     widgetPtrsSet = FALSE;
  2042.  
  2043.     pParamODBCSourceMsg  = new wxStaticText(this, PARAMETER_DIALOG_SOURCE_MSG,   wxT("ODBC data sources:"),   wxPoint( 10, 10),    wxSize( -1,  -1), 0, wxT("ParamODBCSourceMsg"));
  2044.     pParamODBCSourceList = new wxListBox(this, PARAMETER_DIALOG_SOURCE_LISTBOX,                          wxPoint( 10, 29),    wxSize(285, 150), 0, 0, wxLB_SINGLE|wxLB_ALWAYS_SB, wxDefaultValidator, wxT("ParamODBCSourceList"));
  2045.     pParamUserNameMsg    = new wxStaticText(this, PARAMETER_DIALOG_NAME_MSG,     wxT("Database user name:"),  wxPoint( 10, 193),   wxSize( -1,  -1), 0, wxT("ParamUserNameMsg"));
  2046.     pParamUserNameTxt    = new wxTextCtrl(this, PARAMETER_DIALOG_NAME_TEXT,      wxT(""), wxPoint(10, 209),   wxSize( 140, 25),    0, wxDefaultValidator, wxT("ParamUserNameTxt"));
  2047.     pParamPasswordMsg    = new wxStaticText(this, PARAMETER_DIALOG_PASSWORD_MSG, wxT("Password:"),            wxPoint(156, 193),   wxSize( -1,  -1), 0, wxT("ParamPasswordMsg"));
  2048.     pParamPasswordTxt    = new wxTextCtrl(this, PARAMETER_DIALOG_PASSWORD_TEXT,  wxT(""), wxPoint(156, 209),  wxSize( 140,  25),   0, wxDefaultValidator, wxT("ParamPasswordTxt"));
  2049.     pParamDirPathMsg     = new wxStaticText(this, PARAMETER_DIALOG_DIRPATH_MSG,  wxT("Directory:"),           wxPoint( 10, 243),   wxSize( -1,  -1), 0, wxT("ParamDirPathMsg"));
  2050.     pParamDirPathTxt     = new wxTextCtrl(this, PARAMETER_DIALOG_DIRPATH_TEXT,   wxT(""),                     wxPoint( 10, 259),   wxSize(140,  25), 0, wxDefaultValidator, wxT("ParamDirPathTxt"));
  2051.     pParamSaveBtn        = new wxButton(this, PARAMETER_DIALOG_SAVE,             wxT("&Save"),                wxPoint(310,  21),   wxSize( 70,  35), 0, wxDefaultValidator, wxT("ParamSaveBtn"));
  2052.     pParamCancelBtn      = new wxButton(this, PARAMETER_DIALOG_CANCEL,           wxT("C&ancel"),              wxPoint(310,  66),   wxSize( 70,  35), 0, wxDefaultValidator, wxT("ParamCancelBtn"));
  2053.  
  2054.     // Now that all the widgets on the panel are created, its safe to allow ::OnCommand() to 
  2055.     // handle all widget processing
  2056.     widgetPtrsSet = TRUE;
  2057.  
  2058.     saved = FALSE;
  2059.     savedParamSettings = wxGetApp().params;
  2060.  
  2061.     Centre(wxBOTH);
  2062.     PutData();
  2063.     ShowModal();
  2064. }  // CparameterDlg constructor
  2065.  
  2066.  
  2067. void CparameterDlg::OnCloseWindow(wxCloseEvent& event)
  2068. {
  2069.     // Put any additional checking necessary to make certain it is alright
  2070.     // to close the program here that is not done elsewhere
  2071.     if (!saved)
  2072.     {
  2073.         bool Ok = (wxMessageBox(wxT("No changes have been saved.\n\nAre you sure you wish exit the parameter screen?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
  2074.         
  2075.         if (!Ok)
  2076.         {
  2077.             event.Veto();
  2078.             return;
  2079.         }
  2080.         
  2081.         wxGetApp().params = savedParamSettings;
  2082.     }
  2083.  
  2084.     if (GetParent() != NULL)
  2085.         GetParent()->SetFocus();
  2086.  
  2087.     while (wxIsBusy())
  2088.         wxEndBusyCursor();
  2089.  
  2090.     Show(FALSE);
  2091.     SetReturnCode(0);  // added so BoundsChecker would not report use of uninitialized variable
  2092.  
  2093.     this->Destroy();
  2094. }  // CparameterDlg::OnCloseWindow()
  2095.  
  2096.  
  2097. void CparameterDlg::OnButton( wxCommandEvent &event )
  2098. {
  2099.     wxWindow *win = (wxWindow*) event.GetEventObject();
  2100.     OnCommand( *win, event );
  2101. }
  2102.  
  2103.  
  2104. void CparameterDlg::OnCommand(wxWindow& win, wxCommandEvent& event)
  2105. {
  2106.     wxString widgetName;
  2107.     
  2108.     widgetName = win.GetName();
  2109.  
  2110.     if (!widgetPtrsSet)
  2111.         return;
  2112.  
  2113.     if (widgetName == pParamSaveBtn->GetName())
  2114.     {
  2115.         if (Save())
  2116.         {
  2117.             wxString tStr;
  2118.             tStr = wxT("Database parameters have been saved.");
  2119.             if (GetParent() != NULL)  // The parameter dialog was not called during startup due to a missing cfg file
  2120.                 tStr += wxT("\nNew parameters will take effect the next time the program is started.");
  2121.             wxMessageBox(tStr,wxT("Notice..."),wxOK | wxICON_INFORMATION);
  2122.             saved = TRUE;
  2123.             Close();
  2124.         }
  2125.         return;
  2126.     }
  2127.  
  2128.     if (widgetName == pParamCancelBtn->GetName())
  2129.     {
  2130.         Close();
  2131.         return;
  2132.     }
  2133. }  // CparameterDlg::OnCommand()
  2134.  
  2135.  
  2136. bool CparameterDlg::PutData()
  2137. {
  2138.     // Fill the data source list box
  2139.     FillDataSourceList();
  2140.  
  2141.     // Fill in the fields from the params object
  2142.     if (wxGetApp().params.ODBCSource && wxStrlen(wxGetApp().params.ODBCSource))
  2143.     {
  2144.         int index = pParamODBCSourceList->FindString(wxGetApp().params.ODBCSource);
  2145.         if (index != -1)
  2146.             pParamODBCSourceList->SetSelection(index);
  2147.     }
  2148.     pParamUserNameTxt->SetValue(wxGetApp().params.UserName);
  2149.     pParamPasswordTxt->SetValue(wxGetApp().params.Password);
  2150.     pParamDirPathTxt->SetValue(wxGetApp().params.DirPath);
  2151.     return TRUE;
  2152. }  // CparameterDlg::PutData()
  2153.  
  2154.  
  2155. bool CparameterDlg::GetData()
  2156. {
  2157.     wxString tStr;
  2158.     if (pParamODBCSourceList->GetStringSelection() != wxT(""))
  2159.     {
  2160.         tStr = pParamODBCSourceList->GetStringSelection();
  2161.         if (tStr.Length() > (sizeof(wxGetApp().params.ODBCSource)-1))
  2162.         {
  2163.             wxString errmsg;
  2164.             errmsg.Printf(wxT("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());
  2165.             wxMessageBox(errmsg,wxT("Internal program error..."),wxOK | wxICON_EXCLAMATION);
  2166.             return FALSE;
  2167.         }
  2168.         wxStrcpy(wxGetApp().params.ODBCSource, tStr);
  2169.     }
  2170.     else
  2171.         return FALSE;
  2172.     
  2173.     tStr = pParamUserNameTxt->GetValue();
  2174.     if (tStr.Length() > (sizeof(wxGetApp().params.UserName)-1))
  2175.     {
  2176.         wxString errmsg;
  2177.         errmsg.Printf(wxT("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());
  2178.         wxMessageBox(errmsg,wxT("Internal program error..."),wxOK | wxICON_EXCLAMATION);
  2179.         return FALSE;
  2180.     }
  2181.     wxStrcpy(wxGetApp().params.UserName, tStr);
  2182.  
  2183.     tStr = pParamPasswordTxt->GetValue();
  2184.     if (tStr.Length() > (sizeof(wxGetApp().params.Password)-1))
  2185.     {
  2186.         wxString errmsg;
  2187.         errmsg.Printf(wxT("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());
  2188.         wxMessageBox(errmsg,wxT("Internal program error..."),wxOK | wxICON_EXCLAMATION);
  2189.         return FALSE;
  2190.     }
  2191.     wxStrcpy(wxGetApp().params.Password,tStr);
  2192.  
  2193.     tStr = pParamDirPathTxt->GetValue();
  2194.     tStr.Replace(wxT("\\"),wxT("/"));
  2195.     if (tStr.Length() > (sizeof(wxGetApp().params.DirPath)-1))
  2196.     {
  2197.         wxString errmsg;
  2198.         errmsg.Printf(wxT("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());
  2199.         wxMessageBox(errmsg,wxT("Internal program error..."),wxOK | wxICON_EXCLAMATION);
  2200.         return FALSE;
  2201.     }
  2202.     wxStrcpy(wxGetApp().params.DirPath,tStr);
  2203.     return TRUE;
  2204. }  // CparameterDlg::GetData()
  2205.  
  2206.  
  2207. bool CparameterDlg::Save()
  2208. {
  2209.     // Copy the current params in case user cancels changing
  2210.     // the params, so that we can reset them.
  2211.     if (!GetData())
  2212.     {
  2213.         wxGetApp().params = savedParamSettings;
  2214.         return FALSE;
  2215.     }
  2216.  
  2217.     wxGetApp().WriteParamFile(wxGetApp().params);
  2218.  
  2219.     return TRUE;
  2220. }  // CparameterDlg::Save()
  2221.  
  2222.  
  2223. void CparameterDlg::FillDataSourceList()
  2224. {
  2225.     wxChar Dsn[SQL_MAX_DSN_LENGTH + 1];
  2226.     wxChar DsDesc[255];
  2227.     wxStringList strList;
  2228.  
  2229.     while (wxDbGetDataSource(wxGetApp().DbConnectInf->GetHenv(), Dsn,
  2230.                              SQL_MAX_DSN_LENGTH+1, DsDesc, 255))
  2231.         strList.Add(Dsn);
  2232.  
  2233.     strList.Sort();
  2234.     strList.Add(wxT(""));
  2235.     wxChar **p = strList.ListToArray();
  2236.  
  2237.     int i;
  2238.     for (i = 0; wxStrlen(p[i]); i++)
  2239.         pParamODBCSourceList->Append(p[i]);
  2240.  
  2241.     wxDELETEA(p);
  2242. }  // CparameterDlg::FillDataSourceList()
  2243.  
  2244.  
  2245. BEGIN_EVENT_TABLE(CqueryDlg, wxDialog)
  2246.     EVT_BUTTON(-1,  CqueryDlg::OnButton)
  2247.     EVT_CLOSE(CqueryDlg::OnCloseWindow)
  2248. END_EVENT_TABLE()
  2249.  
  2250.  
  2251. // CqueryDlg() constructor
  2252. CqueryDlg::CqueryDlg(wxWindow *parent, wxDb *pDb, wxChar *tblName[], 
  2253.                      const wxString &pWhereArg) :
  2254.     wxDialog (parent, QUERY_DIALOG, wxT("Query"), wxPoint(-1, -1), wxSize(480, 360))
  2255. {
  2256.     wxBeginBusyCursor();
  2257.  
  2258.     colInf = 0;
  2259.     dbTable = 0;
  2260.     masterTableName = tblName[0];
  2261.     widgetPtrsSet = FALSE;
  2262.     pDB = pDb;
  2263.  
  2264.     // Initialize the WHERE clause from the string passed in
  2265.     pWhere = pWhereArg;                                           // Save a pointer to the output buffer
  2266.     if (pWhere.Length() > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN)  // Check the length of the buffer passed in
  2267.     {
  2268.         wxString s;
  2269.         s.Printf(wxT("Maximum where clause length exceeded.\nLength must be less than %d"), DB_MAX_WHERE_CLAUSE_LEN+1);
  2270.         wxMessageBox(s,wxT("Error..."),wxOK | wxICON_EXCLAMATION);
  2271.         Close();
  2272.         return;
  2273.     }
  2274.  
  2275.     pQueryCol1Msg           = new wxStaticText(this, QUERY_DIALOG_COL_MSG,    wxT("Column 1:"),   wxPoint( 10,  10), wxSize( 69,  16), 0, wxT("QueryCol1Msg"));
  2276.     pQueryCol1Choice        = new wxChoice(this, QUERY_DIALOG_COL_CHOICE,                    wxPoint( 10,  27), wxSize(250,  27), 0, 0, 0, wxDefaultValidator, wxT("QueryCol1Choice"));
  2277.     pQueryNotMsg            = new wxStaticText(this, QUERY_DIALOG_NOT_MSG,    wxT("NOT"),         wxPoint(268,  10), wxSize( -1,  -1), 0, wxT("QueryNotMsg"));
  2278.     pQueryNotCheck          = new wxCheckBox(this, QUERY_DIALOG_NOT_CHECKBOX, wxT(""),            wxPoint(275,  37), wxSize( 20,  20), 0, wxDefaultValidator, wxT("QueryNotCheck"));
  2279.  
  2280.     wxString choice_strings[9];
  2281.     choice_strings[0] = wxT("=");
  2282.     choice_strings[1] = wxT("<");
  2283.     choice_strings[2] = wxT(">");
  2284.     choice_strings[3] = wxT("<=");
  2285.     choice_strings[4] = wxT(">=");
  2286.     choice_strings[5] = wxT("Begins");
  2287.     choice_strings[6] = wxT("Contains");
  2288.     choice_strings[7] = wxT("Like");
  2289.     choice_strings[8] = wxT("Between");
  2290.  
  2291.     pQueryOperatorMsg       = new wxStaticText(this, QUERY_DIALOG_OP_MSG,       wxT("Operator:"),         wxPoint(305,  10), wxSize( -1,  -1), 0, wxT("QueryOperatorMsg"));
  2292.     pQueryOperatorChoice    = new wxChoice(this, QUERY_DIALOG_OP_CHOICE,                                  wxPoint(305,  27), wxSize( 80,  27), 9, choice_strings, 0, wxDefaultValidator, wxT("QueryOperatorChoice"));
  2293.     pQueryCol2Msg           = new wxStaticText(this, QUERY_DIALOG_COL2_MSG,     wxT("Column 2:"),         wxPoint( 10,  65), wxSize( 69,  16), 0, wxT("QueryCol2Msg"));
  2294.     pQueryCol2Choice        = new wxChoice(this, QUERY_DIALOG_COL2_CHOICE,                                wxPoint( 10,  82), wxSize(250,  27), 0, 0, 0, wxDefaultValidator, wxT("QueryCol2Choice"));
  2295.     pQuerySqlWhereMsg       = new wxStaticText(this, QUERY_DIALOG_WHERE_MSG,    wxT("SQL where clause:"), wxPoint( 10, 141), wxSize( -1,  -1), 0, wxT("QuerySqlWhereMsg"));
  2296.     pQuerySqlWhereMtxt      = new wxTextCtrl(this, QUERY_DIALOG_WHERE_TEXT,     wxT(""),                  wxPoint( 10, 159), wxSize(377, 134), wxTE_MULTILINE, wxDefaultValidator, wxT("QuerySqlWhereMtxt"));
  2297.     pQueryAddBtn            = new wxButton(this, QUERY_DIALOG_ADD,              wxT("&Add"),              wxPoint(406,  24), wxSize( 56,  26), 0, wxDefaultValidator, wxT("QueryAddBtn"));
  2298.     pQueryAndBtn            = new wxButton(this, QUERY_DIALOG_AND,              wxT("A&nd"),              wxPoint(406,  58), wxSize( 56,  26), 0, wxDefaultValidator, wxT("QueryAndBtn"));
  2299.     pQueryOrBtn             = new wxButton(this, QUERY_DIALOG_OR,               wxT("&Or"),               wxPoint(406,  92), wxSize( 56,  26), 0, wxDefaultValidator, wxT("QueryOrBtn"));
  2300.     pQueryLParenBtn         = new wxButton(this, QUERY_DIALOG_LPAREN,           wxT("("),                 wxPoint(406, 126), wxSize( 26,  26), 0, wxDefaultValidator, wxT("QueryLParenBtn"));
  2301.     pQueryRParenBtn         = new wxButton(this, QUERY_DIALOG_RPAREN,           wxT(")"),                 wxPoint(436, 126), wxSize( 26,  26), 0, wxDefaultValidator, wxT("QueryRParenBtn"));
  2302.     pQueryDoneBtn           = new wxButton(this, QUERY_DIALOG_DONE,             wxT("&Done"),             wxPoint(406, 185), wxSize( 56,  26), 0, wxDefaultValidator, wxT("QueryDoneBtn"));
  2303.     pQueryClearBtn          = new wxButton(this, QUERY_DIALOG_CLEAR,            wxT("C&lear"),            wxPoint(406, 218), wxSize( 56,  26), 0, wxDefaultValidator, wxT("QueryClearBtn"));
  2304.     pQueryCountBtn          = new wxButton(this, QUERY_DIALOG_COUNT,            wxT("&Count"),            wxPoint(406, 252), wxSize( 56,  26), 0, wxDefaultValidator, wxT("QueryCountBtn"));
  2305.     pQueryValue1Msg         = new wxStaticText(this, QUERY_DIALOG_VALUE1_MSG,   wxT("Value:"),            wxPoint(277,  66), wxSize( -1,  -1), 0, wxT("QueryValue1Msg"));
  2306.     pQueryValue1Txt         = new wxTextCtrl(this, QUERY_DIALOG_VALUE1_TEXT,    wxT(""),                  wxPoint(277,  83), wxSize(108,  25), 0, wxDefaultValidator, wxT("QueryValue1Txt"));
  2307.     pQueryValue2Msg         = new wxStaticText(this, QUERY_DIALOG_VALUE2_MSG,   wxT("AND"),               wxPoint(238, 126), wxSize( -1,  -1), 0, wxT("QueryValue2Msg"));
  2308.     pQueryValue2Txt         = new wxTextCtrl(this, QUERY_DIALOG_VALUE2_TEXT,    wxT(""),                  wxPoint(277, 120), wxSize(108,  25), 0, wxDefaultValidator, wxT("QueryValue2Txt"));
  2309.     pQueryHintGrp           = new wxStaticBox(this, QUERY_DIALOG_HINT_GROUP,    wxT(""),                  wxPoint( 10, 291), wxSize(377,  40), 0, wxT("QueryHintGrp"));
  2310.     pQueryHintMsg           = new wxStaticText(this, QUERY_DIALOG_HINT_MSG,     wxT(""),                  wxPoint( 16, 306), wxSize( -1,  -1), 0, wxT("QueryHintMsg"));
  2311.  
  2312.     widgetPtrsSet = TRUE;
  2313.     // Initialize the dialog
  2314.     wxString qualName;
  2315.     pQueryCol2Choice->Append(wxT("VALUE -->"));
  2316.     colInf = pDB->GetColumns(tblName);
  2317.  
  2318.     if (!colInf)
  2319.     {
  2320.         wxEndBusyCursor();
  2321.         wxString tStr;
  2322.         tStr = wxT("ODBC error during GetColumns()\n\n");
  2323.         wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),wxGetApp().Contact->GetDb(),__FILE__,__LINE__),
  2324.                      wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
  2325.         return;
  2326.     }
  2327.  
  2328.     int i;
  2329.     for (i = 0; colInf[i].colName && wxStrlen(colInf[i].colName); i++)
  2330.     {
  2331.         // If there is more than one table being queried, qualify
  2332.         // the column names with the table name prefix.
  2333.         if (tblName[1] && wxStrlen(tblName[1]))
  2334.         {
  2335.             qualName.Printf(wxT("%s.%s"), colInf[i].tableName, colInf[i].colName);
  2336.             pQueryCol1Choice->Append(qualName);
  2337.             pQueryCol2Choice->Append(qualName);
  2338.         }
  2339.         else  // Single table query, append just the column names
  2340.         {
  2341.             pQueryCol1Choice->Append(colInf[i].colName);
  2342.             pQueryCol2Choice->Append(colInf[i].colName);
  2343.         }
  2344.     }
  2345.  
  2346.     pQueryCol1Choice->SetSelection(0);
  2347.     pQueryCol2Choice->SetSelection(0);
  2348.     pQueryOperatorChoice->SetSelection(0);
  2349.  
  2350.     pQueryValue2Msg->Show(FALSE);
  2351.     pQueryValue2Txt->Show(FALSE);
  2352.  
  2353.     pQueryHintMsg->SetLabel(langQRY_EQ);
  2354.  
  2355.     pQuerySqlWhereMtxt->SetValue(pWhere.c_str());
  2356.  
  2357.     wxEndBusyCursor();
  2358.  
  2359.     // Display the dialog window
  2360.     Centre(wxBOTH);
  2361.     ShowModal();
  2362. }  // CqueryDlg() constructor
  2363.  
  2364.  
  2365. CqueryDlg::~CqueryDlg()
  2366. {
  2367. }  // CqueryDlg::~CqueryDlg() destructor
  2368.  
  2369.  
  2370. void CqueryDlg::OnButton(wxCommandEvent &event)
  2371. {
  2372.   wxWindow *win = (wxWindow*) event.GetEventObject();
  2373.   OnCommand( *win, event );
  2374. }  // CqueryDlg::OnButton()
  2375.  
  2376.  
  2377. void CqueryDlg::OnCommand(wxWindow& win, wxCommandEvent& event)
  2378. {
  2379.     // Widget pointers won't be set when the dialog is constructed.
  2380.     // Control is passed through this function once for each widget on
  2381.     // a dialog as the dialog is constructed.
  2382.     if (!widgetPtrsSet)
  2383.         return;
  2384.  
  2385.     wxString widgetName = win.GetName();
  2386.  
  2387.     // Operator choice box
  2388.     if (widgetName == pQueryOperatorChoice->GetName())
  2389.     {
  2390.         // Set the help text
  2391.         switch((qryOp) pQueryOperatorChoice->GetSelection())
  2392.         {
  2393.             case qryOpEQ:
  2394.                 pQueryHintMsg->SetLabel(langQRY_EQ);
  2395.                 break;
  2396.             case qryOpLT:
  2397.                 pQueryHintMsg->SetLabel(langQRY_LT);
  2398.                 break;
  2399.             case qryOpGT:
  2400.                 pQueryHintMsg->SetLabel(langQRY_GT);
  2401.                 break;
  2402.             case qryOpLE:
  2403.                 pQueryHintMsg->SetLabel(langQRY_LE);
  2404.                 break;
  2405.             case qryOpGE:
  2406.                 pQueryHintMsg->SetLabel(langQRY_GE);
  2407.                 break;
  2408.             case qryOpBEGINS:
  2409.                 pQueryHintMsg->SetLabel(langQRY_BEGINS);
  2410.                 break;
  2411.             case qryOpCONTAINS:
  2412.                 pQueryHintMsg->SetLabel(langQRY_CONTAINS);
  2413.                 break;
  2414.             case qryOpLIKE:
  2415.                 pQueryHintMsg->SetLabel(langQRY_LIKE);
  2416.                 break;
  2417.             case qryOpBETWEEN:
  2418.                 pQueryHintMsg->SetLabel(langQRY_BETWEEN);
  2419.                 break;
  2420.         }
  2421.  
  2422.         // Hide the value2 widget
  2423.         pQueryValue2Msg->Show(FALSE);  // BETWEEN will show this widget
  2424.         pQueryValue2Txt->Show(FALSE);  // BETWEEN will show this widget
  2425.  
  2426.         // Disable the NOT operator for <, <=, >, >=
  2427.         switch((qryOp) pQueryOperatorChoice->GetSelection())
  2428.         {
  2429.             case qryOpLT:
  2430.             case qryOpGT:
  2431.             case qryOpLE:
  2432.             case qryOpGE:
  2433.                 pQueryNotCheck->SetValue(0);
  2434.                 pQueryNotCheck->Enable(FALSE);
  2435.                 break;
  2436.             default:
  2437.                 pQueryNotCheck->Enable(TRUE);
  2438.                 break;
  2439.         }
  2440.  
  2441.         // Manipulate the dialog to handle the selected operator
  2442.         switch((qryOp) pQueryOperatorChoice->GetSelection())
  2443.         {
  2444.             case qryOpEQ:
  2445.             case qryOpLT:
  2446.             case qryOpGT:
  2447.             case qryOpLE:
  2448.             case qryOpGE:
  2449.                 pQueryCol2Choice->Enable(TRUE);
  2450.                 if (pQueryCol2Choice->GetSelection())    // Column name is highlighted
  2451.                 {
  2452.                     pQueryValue1Msg->Show(FALSE);
  2453.                     pQueryValue1Txt->Show(FALSE);
  2454.                 }
  2455.                 else                                                // "Value" is highlighted
  2456.                 {
  2457.                     pQueryValue1Msg->Show(TRUE);
  2458.                     pQueryValue1Txt->Show(TRUE);
  2459.                     pQueryValue1Txt->SetFocus();
  2460.                 }
  2461.                 break;
  2462.             case qryOpBEGINS:
  2463.             case qryOpCONTAINS:
  2464.             case qryOpLIKE:
  2465.                 pQueryCol2Choice->SetSelection(0);
  2466.                 pQueryCol2Choice->Enable(FALSE);
  2467.                 pQueryValue1Msg->Show(TRUE);
  2468.                 pQueryValue1Txt->Show(TRUE);
  2469.                 pQueryValue1Txt->SetFocus();
  2470.                 break;
  2471.             case qryOpBETWEEN:
  2472.                 pQueryCol2Choice->SetSelection(0);
  2473.                 pQueryCol2Choice->Enable(FALSE);
  2474.                 pQueryValue2Msg->Show(TRUE);
  2475.                 pQueryValue2Txt->Show(TRUE);
  2476.                 pQueryValue1Msg->Show(TRUE);
  2477.                 pQueryValue1Txt->Show(TRUE);
  2478.                 pQueryValue1Txt->SetFocus();
  2479.                 break;
  2480.         }
  2481.  
  2482.         return;
  2483.  
  2484.     }  // Operator choice box
  2485.  
  2486.     // Column 2 choice
  2487.     if (widgetName == pQueryCol2Choice->GetName())
  2488.     {
  2489.         if (pQueryCol2Choice->GetSelection())    // Column name is highlighted
  2490.         {
  2491.             pQueryValue1Msg->Show(FALSE);
  2492.             pQueryValue1Txt->Show(FALSE);
  2493.         }
  2494.         else                                                // "Value" is highlighted
  2495.         {
  2496.             pQueryValue1Msg->Show(TRUE);
  2497.             pQueryValue1Txt->Show(TRUE);
  2498.             pQueryValue1Txt->SetFocus();
  2499.         }
  2500.         return;
  2501.     }  // Column 2 choice
  2502.  
  2503.     // Add button
  2504.     if (widgetName == pQueryAddBtn->GetName())
  2505.     {
  2506.         ProcessAddBtn();
  2507.         return;
  2508.     }  // Add button
  2509.  
  2510.     // And button
  2511.     if (widgetName == pQueryAndBtn->GetName())
  2512.     {
  2513.         AppendToWhere(wxT(" AND\n"));
  2514.         return;
  2515.     }  // And button
  2516.  
  2517.     // Or button
  2518.     if (widgetName == pQueryOrBtn->GetName())
  2519.     {
  2520.         AppendToWhere(wxT(" OR\n"));
  2521.         return;
  2522.     }  // Or button
  2523.  
  2524.     // Left Paren button
  2525.     if (widgetName == pQueryLParenBtn->GetName())
  2526.     {
  2527.         AppendToWhere(wxT("("));
  2528.         return;
  2529.     }  // Left Paren button
  2530.  
  2531.     // Right paren button
  2532.     if (widgetName == pQueryRParenBtn->GetName())
  2533.     {
  2534.         AppendToWhere(wxT(")"));
  2535.         return;
  2536.     }  // Right Paren button
  2537.  
  2538.     // Done button
  2539.     if (widgetName == pQueryDoneBtn->GetName())
  2540.     {
  2541.         // Be sure the where clause will not overflow the output buffer
  2542.         if (wxStrlen(pQuerySqlWhereMtxt->GetValue()) > (unsigned int)DB_MAX_WHERE_CLAUSE_LEN)
  2543.         {
  2544.             wxString s;
  2545.             s.Printf(wxT("Maximum where clause length exceeded.\nLength must be less than %d"), DB_MAX_WHERE_CLAUSE_LEN+1);
  2546.             wxMessageBox(s,wxT("Error..."),wxOK | wxICON_EXCLAMATION);
  2547.             return;
  2548.         }
  2549.         // Validate the where clause for things such as matching parens
  2550.         if (!ValidateWhereClause())
  2551.             return;
  2552.         // Copy the where clause to the output buffer and exit
  2553.         pWhere = pQuerySqlWhereMtxt->GetValue();
  2554.         Close();
  2555.         return;
  2556.     }  // Done button
  2557.  
  2558.     // Clear button
  2559.     if (widgetName == pQueryClearBtn->GetName())
  2560.     {
  2561.         bool Ok = (wxMessageBox(wxT("Are you sure you wish to clear the Query?"),wxT("Confirm"),wxYES_NO|wxICON_QUESTION) == wxYES);
  2562.  
  2563.         if (Ok)
  2564.             pQuerySqlWhereMtxt->SetValue(wxT(""));
  2565.         return;
  2566.     }  // Clear button
  2567.  
  2568.     // Count button
  2569.     if (widgetName == pQueryCountBtn->GetName())
  2570.     {
  2571.         wxBeginBusyCursor();
  2572.         ProcessCountBtn();
  2573.         wxEndBusyCursor();
  2574.         return;
  2575.     }  // Count button
  2576.  
  2577. }  // CqueryDlg::OnCommand
  2578.  
  2579.  
  2580. void CqueryDlg::OnCloseWindow(wxCloseEvent& event)
  2581. {
  2582.     // Clean up
  2583.     wxDELETEA(colInf);
  2584.  
  2585.     wxDELETE(dbTable);
  2586.  
  2587.     GetParent()->SetFocus();
  2588.     while (wxIsBusy())
  2589.         wxEndBusyCursor();
  2590.  
  2591.     Show(FALSE);
  2592.     SetReturnCode(1);  // added so BoundsChecker would not report use of uninitialized variable
  2593.  
  2594.     this->Destroy();
  2595. }  // CqueryDlg::OnCloseWindow()
  2596.  
  2597.  
  2598. void CqueryDlg::AppendToWhere(wxChar *s)
  2599. {
  2600.     wxString whereStr = pQuerySqlWhereMtxt->GetValue();
  2601.     whereStr += s;
  2602.     pQuerySqlWhereMtxt->SetValue(whereStr);
  2603. }  // CqueryDlg::AppendToWhere()
  2604.  
  2605.  
  2606. void CqueryDlg::ProcessAddBtn()
  2607. {
  2608.     qryOp oper = (qryOp) pQueryOperatorChoice->GetSelection();
  2609.  
  2610.     // Verify that eveything is filled in correctly
  2611.     if (pQueryCol2Choice->GetSelection() == 0)            // "Value" is selected
  2612.     {
  2613.         // Verify that value 1 is filled in
  2614.         if (wxStrlen(pQueryValue1Txt->GetValue()) == 0)
  2615.         {
  2616.             wxBell();
  2617.             pQueryValue1Txt->SetFocus();
  2618.             return;
  2619.         }
  2620.         // For the BETWEEN operator, value 2 must be filled in as well
  2621.         if (oper == qryOpBETWEEN &&
  2622.              wxStrlen(pQueryValue2Txt->GetValue()) == 0)
  2623.         {
  2624.             wxBell();
  2625.             pQueryValue2Txt->SetFocus();
  2626.             return;
  2627.         }
  2628.     }
  2629.  
  2630.     // Build the expression and append it to the where clause window
  2631.     wxString s = pQueryCol1Choice->GetStringSelection();
  2632.     
  2633.     if (pQueryNotCheck->GetValue() && (oper != qryOpEQ))
  2634.         s += wxT(" NOT");
  2635.     
  2636.     switch(oper)
  2637.     {
  2638.     case qryOpEQ:
  2639.         if (pQueryNotCheck->GetValue())    // NOT box is checked
  2640.             s += wxT(" <>");
  2641.         else
  2642.             s += wxT(" =");
  2643.         break;
  2644.     case qryOpLT:
  2645.         s += wxT(" <");
  2646.         break;
  2647.     case qryOpGT:
  2648.         s += wxT(" >");
  2649.         break;
  2650.     case qryOpLE:
  2651.         s += wxT(" <=");
  2652.         break;
  2653.     case qryOpGE:
  2654.         s += wxT(" >=");
  2655.         break;
  2656.     case qryOpBEGINS:
  2657.     case qryOpCONTAINS:
  2658.     case qryOpLIKE:
  2659.         s += wxT(" LIKE");
  2660.         break;
  2661.     case qryOpBETWEEN:
  2662.         s += wxT(" BETWEEN");
  2663.         break;
  2664.     }
  2665.  
  2666.     s += wxT(" ");
  2667.  
  2668.     int col1Idx = pQueryCol1Choice->GetSelection();
  2669.  
  2670.     bool quote = FALSE;
  2671.     if (colInf[col1Idx].sqlDataType == SQL_VARCHAR  ||
  2672.         oper == qryOpBEGINS                         ||
  2673.         oper == qryOpCONTAINS                       ||
  2674.         oper == qryOpLIKE)
  2675.         quote = TRUE;
  2676.  
  2677.     if (pQueryCol2Choice->GetSelection())    // Column name
  2678.         s += pQueryCol2Choice->GetStringSelection();
  2679.     else  // Column 2 is a "value"
  2680.     {
  2681.         if (quote)
  2682.             s += wxT("'");
  2683.         if (oper == qryOpCONTAINS)
  2684.             s += wxT("%");
  2685.         s += pQueryValue1Txt->GetValue();
  2686.         if (oper == qryOpCONTAINS || oper == qryOpBEGINS)
  2687.             s += wxT("%");
  2688.         if (quote)
  2689.             s += wxT("'");
  2690.     }
  2691.  
  2692.     if (oper == qryOpBETWEEN)
  2693.     {
  2694.         s += wxT(" AND ");
  2695.         if (quote)
  2696.             s += wxT("'");
  2697.         s += pQueryValue2Txt->GetValue();
  2698.         if (quote)
  2699.             s += wxT("'");
  2700.     }
  2701.  
  2702.     AppendToWhere((wxChar*) (const wxChar*) s);
  2703.  
  2704. }  // CqueryDlg::ProcessAddBtn()
  2705.  
  2706.  
  2707. void CqueryDlg::ProcessCountBtn()
  2708. {
  2709.     if (!ValidateWhereClause())
  2710.         return;
  2711.  
  2712.     if (!dbTable)  // wxDbTable object needs to be created and opened
  2713.     {
  2714.         dbTable = new wxDbTable(pDB, masterTableName, 0, wxT(""),
  2715.                                 !wxDB_QUERY_ONLY, 
  2716.                                 wxGetApp().DbConnectInf->GetDefaultDir());
  2717.         if (!dbTable)
  2718.         {
  2719.             wxMessageBox(wxT("Memory allocation failed creating a wxDbTable object."),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
  2720.             return;
  2721.         }
  2722.         if (!dbTable->Open())
  2723.         {
  2724.             wxString tStr;
  2725.             tStr = wxT("ODBC error during Open()\n\n");
  2726.             wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),wxGetApp().Contact->GetDb(),__FILE__,__LINE__),
  2727.                          wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
  2728.             return;
  2729.         }
  2730.     }
  2731.  
  2732.     // Count() with WHERE clause
  2733.     wxString whereStr;
  2734.  
  2735.     whereStr = pQuerySqlWhereMtxt->GetValue();
  2736.     dbTable->SetWhereClause(whereStr.c_str());
  2737.  
  2738.     ULONG whereCnt = dbTable->Count();
  2739.  
  2740.     // Count() of all records in the table
  2741.     dbTable->SetWhereClause(wxT(""));
  2742.     ULONG totalCnt = dbTable->Count();
  2743.  
  2744.     if (whereCnt > 0 || totalCnt == 0)
  2745.     {
  2746.         wxString tStr;
  2747.         tStr.Printf(wxT("%lu of %lu records match the query criteria."),whereCnt,totalCnt);
  2748.         wxMessageBox(tStr,wxT("Notice..."),wxOK | wxICON_INFORMATION);
  2749.     }
  2750.     else
  2751.     {
  2752.         wxString tStr;
  2753.         tStr.Printf(wxT("%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);
  2754.         wxMessageBox(tStr,wxT("Notice..."),wxOK | wxICON_INFORMATION);
  2755.     }
  2756.  
  2757.     // After a wxMessageBox, the focus does not necessarily return to the
  2758.     // window which was the focus when the message box popped up, so return
  2759.     // focus to the Query dialog for certain
  2760.     SetFocus();
  2761.  
  2762. }  // CqueryDlg::ProcessCountBtn()
  2763.  
  2764.  
  2765. bool CqueryDlg::ValidateWhereClause()
  2766. {
  2767.     wxString where = pQuerySqlWhereMtxt->GetValue();
  2768.  
  2769.     if (where.Freq(wxT('(')) != where.Freq(wxT(')')))
  2770.     {
  2771.         wxMessageBox(wxT("There are mismatched parenthesis in the constructed where clause"),wxT("Error..."),wxOK | wxICON_EXCLAMATION);
  2772.         return(FALSE);
  2773.     }
  2774.     // After a wxMessageBox, the focus does not necessarily return to the
  2775.     // window which was the focus when the message box popped up, so return
  2776.     // focus to the Query dialog for certain
  2777.     SetFocus();
  2778.  
  2779.     return(TRUE);
  2780.  
  2781. }  // CqueryDlg::ValidateWhereClause()
  2782.  
  2783.  
  2784.  
  2785. void DisplayDbDiagnostics(wxDb *pDb)
  2786. {
  2787.     wxString s, t;
  2788.     bool comma = FALSE;
  2789.  
  2790.     s = langDBINF_DB_NAME;
  2791.     s += pDb->dbInf.dbmsName;
  2792.     s += "\n";
  2793.  
  2794.     s += langDBINF_DB_VER;
  2795.     s += pDb->dbInf.dbmsVer;
  2796.     s += "\n";
  2797.  
  2798.     s += langDBINF_DRIVER_NAME;
  2799.     s += pDb->dbInf.driverName;
  2800.     s += "\n";
  2801.  
  2802.     s += langDBINF_DRIVER_ODBC_VER;
  2803.     s += pDb->dbInf.odbcVer;
  2804.     s += "\n";
  2805.  
  2806.     s += langDBINF_DRIVER_MGR_ODBC_VER;
  2807.     s += pDb->dbInf.drvMgrOdbcVer;
  2808.     s += "\n";
  2809.  
  2810.     s += langDBINF_DRIVER_VER;
  2811.     s += pDb->dbInf.driverVer;
  2812.     s += "\n";
  2813.  
  2814.     s += langDBINF_SERVER_NAME;
  2815.     s += pDb->dbInf.serverName;
  2816.     s += "\n";
  2817.  
  2818.     s += langDBINF_FILENAME;
  2819.     s += pDb->dbInf.databaseName;
  2820.     s += "\n";
  2821.  
  2822.     s += langDBINF_OUTER_JOINS;
  2823.     s += pDb->dbInf.outerJoins;
  2824.     s += "\n";
  2825.  
  2826.     s += langDBINF_STORED_PROC;
  2827.     s += pDb->dbInf.procedureSupport;
  2828.     s += "\n";
  2829.  
  2830.     if (pDb->dbInf.maxConnections)
  2831.         t.sprintf("%s%d\n", langDBINF_MAX_HDBC, pDb->dbInf.maxConnections);
  2832.     else
  2833.         t.sprintf("%s%s\n", langDBINF_MAX_HDBC, langDBINF_UNLIMITED);
  2834.     s += t;
  2835.  
  2836.     if (pDb->dbInf.maxStmts)
  2837.         t.sprintf("%s%d\n", langDBINF_MAX_HSTMT, pDb->dbInf.maxStmts);
  2838.     else
  2839.         t.sprintf("%s%s\n", langDBINF_MAX_HSTMT, langDBINF_UNLIMITED);
  2840.     s += t;
  2841.  
  2842.     s += langDBINF_API_LVL;
  2843.     switch(pDb->dbInf.apiConfLvl)
  2844.     {
  2845.         case SQL_OAC_NONE:  s += langDBINF_NONE;        break;
  2846.         case SQL_OAC_LEVEL1:    s += langDBINF_LEVEL1;  break;
  2847.         case SQL_OAC_LEVEL2:    s += langDBINF_LEVEL2;  break;
  2848.     }
  2849.     s += "\n";
  2850.  
  2851.     s += langDBINF_CLI_LVL;
  2852.     switch(pDb->dbInf.cliConfLvl)
  2853.     {
  2854.         case SQL_OSCC_NOT_COMPLIANT:    s += langDBINF_NOT_COMPLIANT;   break;
  2855.         case SQL_OSCC_COMPLIANT:        s += langDBINF_COMPLIANT;           break;
  2856.     }
  2857.     s += "\n";
  2858.  
  2859.     s += langDBINF_SQL_LVL;
  2860.     switch(pDb->dbInf.sqlConfLvl)
  2861.     {
  2862.         case SQL_OSC_MINIMUM:   s += langDBINF_MIN_GRAMMAR; break;
  2863.         case SQL_OSC_CORE:      s += langDBINF_CORE_GRAMMAR;    break;
  2864.         case SQL_OSC_EXTENDED:  s += langDBINF_EXT_GRAMMAR; break;
  2865.     }
  2866.     s += "\n";
  2867.  
  2868.     s += langDBINF_COMMIT_BEHAVIOR;
  2869.     switch(pDb->dbInf.cursorCommitBehavior)
  2870.     {
  2871.         case SQL_CB_DELETE:     s += langDBINF_DELETE_CURSORS;  break;
  2872.         case SQL_CB_CLOSE:      s += langDBINF_CLOSE_CURSORS;       break;
  2873.         case SQL_CB_PRESERVE:   s += langDBINF_PRESERVE_CURSORS;    break;
  2874.     }
  2875.     s += "\n";
  2876.  
  2877.     s += langDBINF_ROLLBACK_BEHAVIOR;
  2878.     switch(pDb->dbInf.cursorRollbackBehavior)
  2879.     {
  2880.         case SQL_CB_DELETE:     s += langDBINF_DELETE_CURSORS;  break;
  2881.         case SQL_CB_CLOSE:      s += langDBINF_CLOSE_CURSORS;       break;
  2882.         case SQL_CB_PRESERVE:   s += langDBINF_PRESERVE_CURSORS;    break;
  2883.     }
  2884.     s += "\n";
  2885.  
  2886.     s += langDBINF_SUPP_NOT_NULL;
  2887.     switch(pDb->dbInf.supportNotNullClause)
  2888.     {
  2889.         case SQL_NNC_NULL:      s += langNO;    break;
  2890.         case SQL_NNC_NON_NULL:  s += langYES;   break;
  2891.     }
  2892.     s += "\n";
  2893.  
  2894.     s += langDBINF_SUPP_IEF;
  2895.     s += pDb->dbInf.supportIEF;
  2896.     s += "\n";
  2897.  
  2898.     // DEFAULT setting for "Transaction Isolation Level"
  2899.     s += langDBINF_TXN_ISOLATION;
  2900.     switch(pDb->dbInf.txnIsolation)
  2901.     {
  2902.         case SQL_TXN_READ_UNCOMMITTED:  s += langDBINF_READ_UNCOMMITTED;    break;
  2903.         case SQL_TXN_READ_COMMITTED:        s += langDBINF_READ_COMMITTED;  break;
  2904.         case SQL_TXN_REPEATABLE_READ:       s += langDBINF_REPEATABLE_READ; break;
  2905.         case SQL_TXN_SERIALIZABLE:          s += langDBINF_SERIALIZABLE;        break;
  2906. #ifdef ODBC_V20
  2907.         case SQL_TXN_VERSIONING:            s += langDBINF_VERSIONING;          break;
  2908. #endif
  2909.     }
  2910.     s += "\n";
  2911.  
  2912.     // CURRENT setting for "Transaction Isolation Level"
  2913.     long txnIsoLvl;
  2914.     s += langDBINF_TXN_ISOLATION_CURR;
  2915.     if (SQLGetConnectOption(pDb->GetHDBC(),SQL_TXN_ISOLATION,&txnIsoLvl) == SQL_SUCCESS)
  2916.     {
  2917.         switch(txnIsoLvl)
  2918.         {
  2919.             case SQL_TXN_READ_UNCOMMITTED:  s += langDBINF_READ_UNCOMMITTED;    break;
  2920.             case SQL_TXN_READ_COMMITTED:        s += langDBINF_READ_COMMITTED;  break;
  2921.             case SQL_TXN_REPEATABLE_READ:       s += langDBINF_REPEATABLE_READ; break;
  2922.             case SQL_TXN_SERIALIZABLE:          s += langDBINF_SERIALIZABLE;        break;
  2923. #ifdef ODBC_V20
  2924.             case SQL_TXN_VERSIONING:            s += langDBINF_VERSIONING;          break;
  2925. #endif
  2926.         }
  2927.     }
  2928.     s += "\n";
  2929.  
  2930. #ifdef __VMS__
  2931. #pragma message disable incboodep
  2932. #endif
  2933.     comma = FALSE;
  2934.     s += langDBINF_TXN_ISOLATION_OPTS;
  2935.     if (pDb->dbInf.txnIsolationOptions & SQL_TXN_READ_UNCOMMITTED)
  2936.         {s += langDBINF_READ_UNCOMMITTED; comma++;}
  2937.     if (pDb->dbInf.txnIsolationOptions & SQL_TXN_READ_COMMITTED)
  2938.         {if (comma++) s += ", "; s += langDBINF_READ_COMMITTED;}
  2939.     if (pDb->dbInf.txnIsolationOptions & SQL_TXN_REPEATABLE_READ)
  2940.         {if (comma++) s += ", "; s += langDBINF_REPEATABLE_READ;}
  2941.     if (pDb->dbInf.txnIsolationOptions & SQL_TXN_SERIALIZABLE)
  2942.         {if (comma++) s += ", "; s += langDBINF_SERIALIZABLE;}
  2943. #ifdef ODBC_V20
  2944.     if (pDb->dbInf.txnIsolationOptions & SQL_TXN_VERSIONING)
  2945.         {if (comma++) s += ", "; s += langDBINF_VERSIONING;}
  2946. #endif
  2947.     s += "\n";
  2948.  
  2949.     comma = FALSE;
  2950.     s += langDBINF_FETCH_DIRS;
  2951.     if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_NEXT)
  2952.         {s += langDBINF_NEXT; comma++;}
  2953.     if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_PRIOR)
  2954.         {if (comma++) s += ", "; s += langDBINF_PREV;}
  2955.     if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_FIRST)
  2956.         {if (comma++) s += ", "; s += langDBINF_FIRST;}
  2957.     if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_LAST)
  2958.         {if (comma++) s += ", "; s += langDBINF_LAST;}
  2959.     if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_ABSOLUTE)
  2960.         {if (comma++) s += ", "; s += langDBINF_ABSOLUTE;}
  2961.     if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_RELATIVE)
  2962.         {if (comma++) s += ", "; s += langDBINF_RELATIVE;}
  2963. #ifdef ODBC_V20
  2964.     if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_RESUME)
  2965.         {if (comma++) s += ", "; s += langDBINF_RESUME;}
  2966. #endif
  2967.     if (pDb->dbInf.fetchDirections & SQL_FD_FETCH_BOOKMARK)
  2968.         {if (comma++) s += ", "; s += langDBINF_BOOKMARK;}
  2969.     s += "\n";
  2970.  
  2971.     comma = FALSE;
  2972.     s += langDBINF_LOCK_TYPES;
  2973.     if (pDb->dbInf.lockTypes & SQL_LCK_NO_CHANGE)
  2974.         {s += langDBINF_NO_CHANGE; comma++;}
  2975.     if (pDb->dbInf.lockTypes & SQL_LCK_EXCLUSIVE)
  2976.         {if (comma++) s += ", "; s += langDBINF_EXCLUSIVE;}
  2977.     if (pDb->dbInf.lockTypes & SQL_LCK_UNLOCK)
  2978.         {if (comma++) s += ", "; s += langDBINF_UNLOCK;}
  2979.     s += "\n";
  2980.  
  2981.     comma = FALSE;
  2982.     s += langDBINF_POS_OPERS;
  2983.     if (pDb->dbInf.posOperations & SQL_POS_POSITION)
  2984.         {s += langDBINF_POSITION; comma++;}
  2985.     if (pDb->dbInf.posOperations & SQL_POS_REFRESH)
  2986.         {if (comma++) s += ", "; s += langDBINF_REFRESH;}
  2987.     if (pDb->dbInf.posOperations & SQL_POS_UPDATE)
  2988.         {if (comma++) s += ", "; s += langDBINF_UPD;}
  2989.     if (pDb->dbInf.posOperations & SQL_POS_DELETE)
  2990.         {if (comma++) s += ", "; s += langDBINF_DEL;}
  2991.     if (pDb->dbInf.posOperations & SQL_POS_ADD)
  2992.         {if (comma++) s += ", "; s += langDBINF_ADD;}
  2993.     s += "\n";
  2994.  
  2995.     comma = FALSE;
  2996.     s += langDBINF_POS_STMTS;
  2997.     if (pDb->dbInf.posStmts & SQL_PS_POSITIONED_DELETE)
  2998.         {s += langDBINF_POS_DEL; comma++;}
  2999.     if (pDb->dbInf.posStmts & SQL_PS_POSITIONED_UPDATE)
  3000.         {if (comma++) s += ", "; s += langDBINF_POS_UPD;}
  3001.     if (pDb->dbInf.posStmts & SQL_PS_SELECT_FOR_UPDATE)
  3002.         {if (comma++) s += ", "; s += langDBINF_SELECT_FOR_UPD;}
  3003.     s += "\n";
  3004.  
  3005.     comma = FALSE;
  3006.     s += langDBINF_SCROLL_CONCURR;
  3007.     if (pDb->dbInf.scrollConcurrency & SQL_SCCO_READ_ONLY)
  3008.         {s += langDBINF_READ_ONLY; comma++;}
  3009.     if (pDb->dbInf.scrollConcurrency & SQL_SCCO_LOCK)
  3010.         {if (comma++) s += ", "; s += langDBINF_LOCK;}
  3011.     if (pDb->dbInf.scrollConcurrency & SQL_SCCO_OPT_ROWVER)
  3012.         {if (comma++) s += ", "; s += langDBINF_OPT_ROWVER;}
  3013.     if (pDb->dbInf.scrollConcurrency & SQL_SCCO_OPT_VALUES)
  3014.         {if (comma++) s += ", "; s += langDBINF_OPT_VALUES;}
  3015.     s += "\n";
  3016.  
  3017.     comma = FALSE;
  3018.     s += langDBINF_SCROLL_OPTS;
  3019.     if (pDb->dbInf.scrollOptions & SQL_SO_FORWARD_ONLY)
  3020.         {s += langDBINF_FWD_ONLY; comma++;}
  3021.     if (pDb->dbInf.scrollOptions & SQL_SO_STATIC)
  3022.         {if (comma++) s += ", "; s += langDBINF_STATIC;}
  3023.     if (pDb->dbInf.scrollOptions & SQL_SO_KEYSET_DRIVEN)
  3024.         {if (comma++) s += ", "; s += langDBINF_KEYSET_DRIVEN;}
  3025.     if (pDb->dbInf.scrollOptions & SQL_SO_DYNAMIC)
  3026.         {if (comma++) s += ", "; s += langDBINF_DYNAMIC;}
  3027.     if (pDb->dbInf.scrollOptions & SQL_SO_MIXED)
  3028.         {if (comma++) s += ", "; s += langDBINF_MIXED;}
  3029.     s += "\n";
  3030.  
  3031.     comma = FALSE;
  3032.     s += langDBINF_STATIC_SENS;
  3033.     if (pDb->dbInf.staticSensitivity & SQL_SS_ADDITIONS)
  3034.         {s += langDBINF_ADDITIONS; comma++;}
  3035.     if (pDb->dbInf.staticSensitivity & SQL_SS_DELETIONS)
  3036.         {if (comma++) s += ", "; s += langDBINF_DELETIONS;}
  3037.     if (pDb->dbInf.staticSensitivity & SQL_SS_UPDATES)
  3038.         {if (comma++) s += ", "; s += langDBINF_UPDATES;}
  3039.     s += "\n";
  3040. #ifdef __VMS__
  3041. #pragma message enable incboodep
  3042. #endif
  3043.  
  3044.  
  3045.     s += langDBINF_TXN_CAPABLE;
  3046.     switch(pDb->dbInf.txnCapable)
  3047.     {
  3048.         case SQL_TC_NONE:           s += langNO;                        break;
  3049.         case SQL_TC_DML:            s += langDBINF_DML_ONLY;        break;
  3050.         case SQL_TC_DDL_COMMIT: s += langDBINF_DDL_COMMIT;      break;
  3051.         case SQL_TC_DDL_IGNORE: s += langDBINF_DDL_IGNORE;      break;
  3052.         case SQL_TC_ALL:            s += langDBINF_DDL_AND_DML; break;
  3053.     }
  3054.     s += "\n";
  3055.  
  3056.     t.sprintf("%s%d\n", langDBINF_LOGIN_TIMEOUT, pDb->dbInf.loginTimeout);
  3057.     s += t;
  3058.  
  3059.     // Oracle specific information
  3060.     if (pDb->Dbms() == dbmsORACLE)
  3061.     {
  3062.         s += "\n";
  3063.         s += langDBINF_ORACLE_BANNER;
  3064.         s += "\n";
  3065.  
  3066.         // Oracle cache hit ratio
  3067.         SDWORD cb;
  3068.         ULONG dbBlockGets;
  3069.         pDb->ExecSql("SELECT VALUE FROM V$SYSSTAT WHERE NAME = 'db block gets'");
  3070.         pDb->GetNext();
  3071.         if (pDb->GetData(1, SQL_C_ULONG, &dbBlockGets, 0, &cb))
  3072.         {
  3073.             t.sprintf("%s: %lu\n", langDBINF_DB_BLOCK_GETS, dbBlockGets);
  3074.             s += t;
  3075.         }
  3076.  
  3077.         ULONG consistentGets;
  3078.         pDb->ExecSql("SELECT VALUE FROM V$SYSSTAT WHERE NAME = 'consistent gets'");
  3079.         pDb->GetNext();
  3080.         if (pDb->GetData(1, SQL_C_ULONG, &consistentGets, 0, &cb))
  3081.         {
  3082.             t.sprintf("%s: %lu\n", langDBINF_CONSISTENT_GETS, consistentGets);
  3083.             s += t;
  3084.         }
  3085.  
  3086.         ULONG physReads;
  3087.         pDb->ExecSql("SELECT VALUE FROM V$SYSSTAT WHERE NAME = 'physical reads'");
  3088.         pDb->GetNext();
  3089.         if (pDb->GetData(1, SQL_C_ULONG, &physReads, 0, &cb))
  3090.         {
  3091.             t.sprintf("%s: %lu\n", langDBINF_PHYSICAL_READS, physReads);
  3092.             s += t;
  3093.         }
  3094.  
  3095.         ULONG hitRatio = (ULONG)((1.00 - ((float)physReads / (float)(dbBlockGets + consistentGets))) * 100.00);
  3096.         t.sprintf("*** %s: %lu%%\n", langDBINF_CACHE_HIT_RATIO, hitRatio);
  3097.         s += t;
  3098.  
  3099.         // Tablespace information
  3100.         s += "\n";
  3101.         s += langDBINF_TABLESPACE_IO;
  3102.         s += "\n";
  3103.         ULONG physWrites;
  3104.         char tablespaceName[257];
  3105.         pDb->ExecSql("SELECT NAME,PHYRDS,PHYWRTS FROM V$DATAFILE, V$FILESTAT WHERE V$DATAFILE.FILE# = V$FILESTAT.FILE#");
  3106.         while (pDb->GetNext())
  3107.         {
  3108.             pDb->GetData(1, SQL_C_CHAR,  tablespaceName, 257, &cb);
  3109.             pDb->GetData(2, SQL_C_ULONG, &physReads,     0,   &cb);
  3110.             pDb->GetData(3, SQL_C_ULONG, &physWrites,    0,   &cb);
  3111.             t.sprintf("%s\n\t%s: %lu\t%s: %lu\n", tablespaceName,
  3112.                 langDBINF_PHYSICAL_READS, physReads, langDBINF_PHYSICAL_WRITES, physWrites);
  3113.             s += t;
  3114.         }
  3115.  
  3116.         s += "\n";
  3117.     }
  3118.  
  3119.     wxLogMessage(s);
  3120.  
  3121. }  // DisplayDbDiagnostics()
  3122.  
  3123. #if wxUSE_NEW_GRID
  3124.  
  3125. BEGIN_EVENT_TABLE(DbGridFrame, wxFrame)
  3126.  //   EVT_CLOSE(DbGridFrame::OnCloseWindow)
  3127. END_EVENT_TABLE()
  3128.  
  3129.  
  3130. DbGridFrame::DbGridFrame(wxWindow *parent)
  3131.     : wxFrame (parent, -1, wxT("Database Table"),
  3132.                wxDefaultPosition, wxSize(400, 325))
  3133. {
  3134.     initialized = FALSE;
  3135. }
  3136.  
  3137.  
  3138. void DbGridFrame::OnCloseWindow(wxCloseEvent& event)
  3139. {
  3140.     this->Destroy();
  3141. }
  3142.  
  3143.  
  3144. bool DbGridFrame::Initialize()
  3145. {
  3146.     wxGrid *grid = new wxGrid(this, -1, wxDefaultPosition);
  3147.  
  3148.     grid->RegisterDataType(wxGRID_VALUE_DATETIME,
  3149.                              new wxGridCellDateTimeRenderer(_T("%d %b %Y")),
  3150.                              new wxGridCellTextEditor);
  3151. #ifdef CHOICEINT
  3152.     grid->RegisterDataType(wxGRID_VALUE_CHOICEINT,
  3153.                              new wxGridCellEnumRenderer,
  3154.                              new wxGridCellEnumEditor);
  3155.                              
  3156.     wxString NativeLangChoice( wxString::Format("%s:%s,%s,%s,%s,%s",wxGRID_VALUE_CHOICEINT, 
  3157.                             wxT("English"),
  3158.                             wxT("French"),
  3159.                             wxT("German"),
  3160.                             wxT("Spanish"),
  3161.                             wxT("Other") )); 
  3162. #endif
  3163.  
  3164.     // Columns must match the sequence specified in SetColDef() calls
  3165.     wxDbGridColInfo* cols =
  3166.         new wxDbGridColInfo( 0,wxGRID_VALUE_STRING,wxT("Name"),
  3167.         new wxDbGridColInfo( 1,wxGRID_VALUE_STRING,wxT("Address 1"),
  3168.         new wxDbGridColInfo( 2,wxGRID_VALUE_STRING,wxT("Address 2"),
  3169.         new wxDbGridColInfo( 3,wxGRID_VALUE_STRING,wxT("City"),
  3170.         new wxDbGridColInfo( 4,wxGRID_VALUE_STRING,wxT("State"),
  3171.         new wxDbGridColInfo( 5,wxGRID_VALUE_STRING,wxT("PostCode"),
  3172.         new wxDbGridColInfo( 6,wxGRID_VALUE_STRING,wxT("Country"),
  3173.         new wxDbGridColInfo( 7,wxGRID_VALUE_DBAUTO,wxT("Join Date"),
  3174.         new wxDbGridColInfo( 8,wxGRID_VALUE_BOOL,  wxT("Developer"),
  3175.         new wxDbGridColInfo( 9,wxGRID_VALUE_NUMBER,wxT("Contributions"),
  3176.         new wxDbGridColInfo(10,wxGRID_VALUE_NUMBER,wxT("Lines Of Code"),
  3177. #ifdef CHOICEINT
  3178.         new wxDbGridColInfo(11,NativeLangChoice,   wxT("Native Language"),NULL))))))))))));
  3179. #else        
  3180.         new wxDbGridColInfo(11,wxGRID_VALUE_NUMBER,wxT("Native Language"),NULL))))))))))));
  3181. #endif
  3182.  
  3183.     Ccontact *Contact = new Ccontact();
  3184.     //wxGetApp().Contact
  3185.  
  3186.     if (!Contact)
  3187.     {
  3188.         wxMessageBox(wxT("Unable to instantiate an instance of Ccontact"), wxT("Error..."), wxOK | wxICON_EXCLAMATION);
  3189.         return FALSE;
  3190.     }
  3191.  
  3192.     if (!Contact->Open())
  3193.     {
  3194.         if (Contact->GetDb()->TableExists(CONTACT_TABLE_NAME, Contact->GetDb()->GetUsername(),
  3195.                                           wxGetApp().DbConnectInf->GetDefaultDir()))
  3196.         {
  3197.             wxString tStr;
  3198.             tStr.Printf(wxT("Unable to open the table '%s'.\n\n"),CONTACT_TABLE_NAME);
  3199.             wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),wxGetApp().Contact->GetDb(),__FILE__,__LINE__),
  3200.                          wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
  3201.         }
  3202.  
  3203.         return FALSE;
  3204.     }
  3205.  
  3206.     // Execute the following query using the cursor designated
  3207.     // for full table query
  3208.     Contact->SetRowMode(wxDbTable::WX_ROW_MODE_QUERY);
  3209.  
  3210.     if (!Contact->Query())
  3211.     {
  3212.         wxString tStr;
  3213.         tStr = wxT("ODBC error during Query()\n\n");
  3214.         wxMessageBox(wxDbLogExtendedErrorMsg(tStr.c_str(),wxGetApp().Contact->GetDb(),__FILE__,__LINE__),
  3215.                      wxT("ODBC Error..."),wxOK | wxICON_EXCLAMATION);
  3216.         return FALSE;
  3217.     }
  3218.  
  3219.     // No data has been read in from the database yet, so
  3220.     // we need to initialize the data members to valid values
  3221.     // so Fit() can correctly size the grid
  3222.     Contact->Initialize();
  3223.  
  3224.     wxDbGridTableBase* db = new wxDbGridTableBase(Contact, cols, wxUSE_QUERY, TRUE);
  3225.  
  3226.     delete cols;
  3227.  
  3228.     grid->SetTable(db,TRUE);
  3229.     grid->SetMargins(0, 0);
  3230.  
  3231.     grid->Fit();
  3232.     wxSize size = grid->GetSize();
  3233.     size.x += 10;
  3234.     size.y += 10;
  3235.     SetClientSize(size);
  3236.     initialized = TRUE;
  3237.     return TRUE;
  3238. }  // DbGridFrame::Initialize()
  3239.  
  3240. #endif // #if wxUSE_NEW_GRID
  3241.  
  3242. /*
  3243.     TEST CODE FOR TESTING THE wxDbCreateDataSource() FUNCTION
  3244.  
  3245.         int result = 0;
  3246.         result = wxDbCreateDataSource(wxT("Microsoft Access Driver (*.mdb)"),wxT("GLT-TEST2"),wxT("GLT-Descrip"),FALSE,wxT(""),this);
  3247.         if (!result)
  3248.         {
  3249.             // check for errors caused by ConfigDSN based functions
  3250.             DWORD retcode = 0;
  3251.             WORD cb;
  3252.             wxChar errMsg[500+1];
  3253.             errMsg[0] = wxT('\0');
  3254.  
  3255.             SQLInstallerError(1,&retcode,errMsg,500,&cb);
  3256.  
  3257.             wxMessageBox(wxT("FAILED creating data source"),wxT("FAILED"));
  3258.         }
  3259.         else
  3260.             wxMessageBox(wxT("SUCCEEDED creating data source"),wxT("SUCCESS"));
  3261. */
  3262.  
  3263.  
  3264.