home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / daoview.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  18KB  |  765 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFX_DB_SEG
  14. #pragma code_seg(AFX_DB_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. #define new DEBUG_NEW
  23.  
  24. /////////////////////////////////////////////////////////////////////////////
  25.  
  26. IMPLEMENT_DYNAMIC(CDaoRecordView, CFormView)
  27.  
  28. BEGIN_MESSAGE_MAP(CDaoRecordView, CFormView)
  29.     //{{AFX_MSG_MAP(CDaoRecordView)
  30.         // NOTE - the ClassWizard will add and remove mapping macros here.
  31.     //}}AFX_MSG_MAP
  32.     ON_COMMAND_EX(ID_RECORD_FIRST, OnMove)
  33.     ON_UPDATE_COMMAND_UI(ID_RECORD_FIRST, OnUpdateRecordFirst)
  34.     ON_COMMAND_EX(ID_RECORD_PREV, OnMove)
  35.     ON_UPDATE_COMMAND_UI(ID_RECORD_PREV, OnUpdateRecordPrev)
  36.     ON_COMMAND_EX(ID_RECORD_NEXT, OnMove)
  37.     ON_UPDATE_COMMAND_UI(ID_RECORD_NEXT, OnUpdateRecordNext)
  38.     ON_COMMAND_EX(ID_RECORD_LAST, OnMove)
  39.     ON_UPDATE_COMMAND_UI(ID_RECORD_LAST, OnUpdateRecordLast)
  40. END_MESSAGE_MAP()
  41.  
  42. CDaoRecordView::CDaoRecordView(LPCTSTR lpszTemplateName)
  43.     : CFormView(lpszTemplateName)
  44. {
  45.     m_nStatus = 0;
  46.  
  47.     // Setup dummy bookmarks
  48.     m_varBookmarkCurrent = 1L;
  49.     m_varBookmarkFirst = m_varBookmarkLast = 0L;
  50. }
  51.  
  52. CDaoRecordView::CDaoRecordView(UINT nIDTemplate)
  53.     : CFormView(nIDTemplate)
  54. {
  55.     m_nStatus = 0;
  56.  
  57.     // Setup dummy bookmarks
  58.     m_varBookmarkCurrent = 1L;
  59.     m_varBookmarkFirst = m_varBookmarkLast = 0L;
  60. }
  61.  
  62. CDaoRecordView::~CDaoRecordView()
  63. {
  64. }
  65.  
  66. void CDaoRecordView::OnInitialUpdate()
  67. {
  68.     ASSERT_VALID(this);
  69.  
  70.     CDaoRecordset* pRecordset = OnGetRecordset();
  71.     // recordset must be allocated already
  72.     ASSERT(pRecordset != NULL);
  73.  
  74.     if (!pRecordset->IsOpen())
  75.     {
  76.         CWaitCursor wait;
  77.         pRecordset->Open();
  78.     }
  79.  
  80.     if (!pRecordset->IsEOF())
  81.     {
  82.         // Determine recordset properties for move button enabling
  83.         if (pRecordset->CanBookmark())
  84.         {
  85.             // Get the bookmark of the first record
  86.             m_varBookmarkCurrent = pRecordset->GetBookmark();
  87.             m_varBookmarkFirst = m_varBookmarkCurrent;
  88.         }
  89.  
  90.         // Enable forward scrolling buttons
  91.         m_nStatus |= AFX_DAOVIEW_SCROLL_NEXT;
  92.  
  93.         // Enable backward scrolling buttons if possible
  94.         if (pRecordset->CanScroll())
  95.         {
  96.             m_nStatus |= AFX_DAOVIEW_SCROLL_LAST;
  97.             m_nStatus |= AFX_DAOVIEW_SCROLL_BACKWARD;
  98.         }
  99.         else
  100.         {
  101.             m_nStatus &= ~AFX_DAOVIEW_SCROLL_LAST;
  102.             m_nStatus &= ~AFX_DAOVIEW_SCROLL_BACKWARD;
  103.         }
  104.     }
  105.     else
  106.     {
  107.         // Disable scrolling
  108.         m_nStatus &= ~AFX_DAOVIEW_SCROLL_NEXT;
  109.         m_nStatus &= ~AFX_DAOVIEW_SCROLL_LAST;
  110.         m_nStatus &= ~AFX_DAOVIEW_SCROLL_BACKWARD;
  111.     }
  112.  
  113.     CFormView::OnInitialUpdate();
  114. }
  115.  
  116. BOOL CDaoRecordView::OnMove(UINT nIDMoveCommand)
  117. {
  118.     ASSERT_VALID(this);
  119.  
  120.     CDaoRecordset* pSet = OnGetRecordset();
  121.     if (pSet->CanUpdate())
  122.     {
  123.         pSet->Edit();
  124.         if (!UpdateData())
  125.             return TRUE;
  126.  
  127.         if (pSet->IsFieldDirty(NULL))
  128.             pSet->Update();
  129.         else
  130.             pSet->CancelUpdate();
  131.     }
  132.  
  133.     BOOL bBookmarkable = pSet->CanBookmark();
  134.     BOOL bScrollable = pSet->CanScroll();
  135.  
  136.     switch (nIDMoveCommand)
  137.     {
  138.         case ID_RECORD_PREV:
  139.             pSet->MovePrev();
  140.  
  141.             if (!pSet->IsBOF())
  142.             {
  143.                 if (bBookmarkable)
  144.                     m_varBookmarkCurrent = pSet->GetBookmark();
  145.  
  146.                 // Enable forward scrolling
  147.                 m_nStatus |= AFX_DAOVIEW_SCROLL_NEXT;
  148.  
  149.                 if (bScrollable)
  150.                 {
  151.                     m_nStatus |= AFX_DAOVIEW_SCROLL_LAST;
  152.  
  153.                     if (IsOnFirstRecord())
  154.                         // Disable backward scrolling
  155.                         m_nStatus &= ~AFX_DAOVIEW_SCROLL_BACKWARD;
  156.                     else
  157.                         m_nStatus |= AFX_DAOVIEW_SCROLL_BACKWARD;
  158.                 }
  159.                 else
  160.                 {
  161.                     m_nStatus &= ~AFX_DAOVIEW_SCROLL_LAST;
  162.                     m_nStatus &= ~AFX_DAOVIEW_SCROLL_BACKWARD;
  163.                 }
  164.  
  165.  
  166.                 break;
  167.             }
  168.             // Fall through to reset to first record
  169.  
  170.         case ID_RECORD_FIRST:
  171.             pSet->MoveFirst();
  172.  
  173.             // backward scrolling never allowed after movefirst
  174.             m_nStatus &= ~AFX_DAOVIEW_SCROLL_BACKWARD;
  175.  
  176.             if (pSet->IsEOF())
  177.             {
  178.                 // Empty recordset, disable forward too
  179.                 m_nStatus &= ~AFX_DAOVIEW_SCROLL_NEXT;
  180.                 m_nStatus &= ~AFX_DAOVIEW_SCROLL_LAST;
  181.             }
  182.             else
  183.             {
  184.                 if (bBookmarkable)
  185.                 {
  186.                     m_varBookmarkCurrent = pSet->GetBookmark();
  187.                     m_varBookmarkFirst = m_varBookmarkCurrent;
  188.                 }
  189.  
  190.                 // Enable forward scrolling
  191.                 m_nStatus |= AFX_DAOVIEW_SCROLL_NEXT;
  192.  
  193.                 if (bScrollable)
  194.                     m_nStatus |= AFX_DAOVIEW_SCROLL_LAST;
  195.                 else
  196.                     m_nStatus &= ~AFX_DAOVIEW_SCROLL_LAST;
  197.             }
  198.  
  199.             break;
  200.  
  201.         case ID_RECORD_NEXT:
  202.             pSet->MoveNext();
  203.  
  204.             if (!pSet->IsEOF())
  205.             {
  206.                 if (bBookmarkable)
  207.                     m_varBookmarkCurrent = pSet->GetBookmark();
  208.  
  209.                 if (IsOnLastRecord())
  210.                 {
  211.                     // Disable forward scrolling
  212.                     m_nStatus &= ~AFX_DAOVIEW_SCROLL_NEXT;
  213.                     m_nStatus &= ~AFX_DAOVIEW_SCROLL_LAST;
  214.                 }
  215.                 else
  216.                 {
  217.                     m_nStatus |= AFX_DAOVIEW_SCROLL_NEXT;
  218.                     m_nStatus |= AFX_DAOVIEW_SCROLL_LAST;
  219.                 }
  220.  
  221.                 if (bScrollable)
  222.                     m_nStatus |= AFX_DAOVIEW_SCROLL_BACKWARD;
  223.                 else
  224.                 {
  225.                     m_nStatus &= ~AFX_DAOVIEW_SCROLL_LAST;
  226.                     m_nStatus &= ~AFX_DAOVIEW_SCROLL_BACKWARD;
  227.                 }
  228.  
  229.                 break;
  230.             }
  231.  
  232.             // Can't fall through to move last
  233.             if (!bScrollable)
  234.             {
  235.                 // At the end of forward only recordset
  236.                 m_nStatus &= ~AFX_DAOVIEW_SCROLL_NEXT;
  237.                 m_nStatus &= ~AFX_DAOVIEW_SCROLL_LAST;
  238.                 m_nStatus &= ~AFX_DAOVIEW_SCROLL_BACKWARD;
  239.                 break;
  240.             }
  241.  
  242.             // Fall through to reset to last record
  243.  
  244.         case ID_RECORD_LAST:
  245.             pSet->MoveLast();
  246.  
  247.             // forward scrolling never allowed after movelast
  248.             m_nStatus &= ~AFX_DAOVIEW_SCROLL_NEXT;
  249.             m_nStatus &= ~AFX_DAOVIEW_SCROLL_LAST;
  250.  
  251.             if (pSet->IsBOF())
  252.             {
  253.                 // Empty recordset, disable backward too
  254.                 m_nStatus &= ~AFX_DAOVIEW_SCROLL_BACKWARD;
  255.             }
  256.             else
  257.             {
  258.                 if (bBookmarkable)
  259.                 {
  260.                     m_varBookmarkCurrent = pSet->GetBookmark();
  261.                     m_varBookmarkLast = m_varBookmarkCurrent;
  262.                 }
  263.  
  264.                 // Enable backward scrolling
  265.                 if (bBookmarkable)
  266.                     m_nStatus |= AFX_DAOVIEW_SCROLL_BACKWARD;
  267.                 else
  268.                     m_nStatus &= ~AFX_DAOVIEW_SCROLL_BACKWARD;
  269.             }
  270.  
  271.             break;
  272.  
  273.         default:
  274.             // Unexpected case value
  275.             ASSERT(FALSE);
  276.     }
  277.  
  278.     // Show results of move operation
  279.     UpdateData(FALSE);
  280.     return TRUE;
  281. }
  282.  
  283. BOOL CDaoRecordView::IsOnFirstRecord()
  284. {
  285.     ASSERT_VALID(this);
  286.     return (m_varBookmarkCurrent == m_varBookmarkFirst);
  287. }
  288.  
  289. BOOL CDaoRecordView::IsOnLastRecord()
  290. {
  291.     ASSERT_VALID(this);
  292.     return (m_varBookmarkCurrent == m_varBookmarkLast);
  293. }
  294.  
  295. /////////////////////////////////////////////////////////////////////////////
  296. // DDX Cover functions for use with fields of a recordset
  297.  
  298. /////////////////////////////////////////////////////////////////////////////
  299. // Simple field formatting to text item
  300.  
  301. BOOL AFXAPI AfxFieldText(CDataExchange* pDX, int nIDC, void* pv,
  302.     CDaoRecordset* pRecordset)
  303. {
  304.     ASSERT_VALID(pRecordset);
  305.  
  306.     HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);
  307.     TCHAR szT[2];
  308.     if (pDX->m_bSaveAndValidate)
  309.     {
  310.         ::GetWindowText(hWndCtrl, szT, _countof(szT));
  311.         if (szT[0] == '\0')
  312.         {
  313.             // If edit buffer not NULL prior to update, set it dirty
  314.             // to catch case of setting field value from PSEUDO NULL to NULL.
  315.             if (!pRecordset->IsFieldNull(pv))
  316.                 pRecordset->SetFieldDirty(pv, TRUE);
  317.             pRecordset->SetFieldNull(pv);
  318.             return TRUE;
  319.         }
  320.         else
  321.         {
  322.             // If edit buffer NULL prior to update, set it dirty
  323.             // to catch case of setting field value to PSEUDO NULL.
  324.             if (pRecordset->IsFieldNull(pv))
  325.                 pRecordset->SetFieldDirty(pv, TRUE);
  326.             pRecordset->SetFieldNull(pv, FALSE);
  327.         }
  328.     }
  329.     else
  330.     {
  331.         if (!pRecordset->IsOpen() || pRecordset->IsFieldNull(pv))
  332.         {
  333.             szT[0] = '\0';
  334.             AfxSetWindowText(hWndCtrl, szT);
  335.             return TRUE;
  336.         }
  337.     }
  338.     return FALSE;
  339. }
  340.  
  341. void AFXAPI DDX_FieldText(CDataExchange* pDX, int nIDC, BOOL& value,
  342.     CDaoRecordset* pRecordset)
  343. {
  344.     if (!AfxFieldText(pDX, nIDC, &value, pRecordset))
  345.         DDX_Text(pDX, nIDC, value);
  346. }
  347.  
  348. void AFXAPI DDX_FieldText(CDataExchange* pDX, int nIDC, BYTE& value,
  349.     CDaoRecordset* pRecordset)
  350. {
  351.     if (!AfxFieldText(pDX, nIDC, &value, pRecordset))
  352.         DDX_Text(pDX, nIDC, value);
  353. }
  354.  
  355. void AFXAPI DDX_FieldText(CDataExchange* pDX, int nIDC, short& value,
  356.     CDaoRecordset* pRecordset)
  357. {
  358.     if (!AfxFieldText(pDX, nIDC, &value, pRecordset))
  359.         DDX_Text(pDX, nIDC, value);
  360. }
  361.  
  362. void AFXAPI DDX_FieldText(CDataExchange* pDX, int nIDC, long& value,
  363.     CDaoRecordset* pRecordset)
  364. {
  365.     if (!AfxFieldText(pDX, nIDC, &value, pRecordset))
  366.         DDX_Text(pDX, nIDC, value);
  367. }
  368.  
  369. void AFXAPI DDX_FieldText(CDataExchange* pDX, int nIDC, DWORD& value,
  370.     CDaoRecordset* pRecordset)
  371. {
  372.     if (!AfxFieldText(pDX, nIDC, &value, pRecordset))
  373.         DDX_Text(pDX, nIDC, value);
  374. }
  375.  
  376. void AFXAPI DDX_FieldText(CDataExchange* pDX, int nIDC, COleCurrency& value,
  377.     CDaoRecordset* pRecordset)
  378. {
  379.     if (!AfxFieldText(pDX, nIDC, &value, pRecordset))
  380.         DDX_Text(pDX, nIDC, value);
  381. }
  382.  
  383. void AFXAPI DDX_FieldText(CDataExchange* pDX, int nIDC, float& value,
  384.     CDaoRecordset* pRecordset)
  385. {
  386.     if (!AfxFieldText(pDX, nIDC, &value, pRecordset))
  387.         DDX_Text(pDX, nIDC, value);
  388. }
  389.  
  390. void AFXAPI DDX_FieldText(CDataExchange* pDX, int nIDC, double& value,
  391.     CDaoRecordset* pRecordset)
  392. {
  393.     if (!AfxFieldText(pDX, nIDC, &value, pRecordset))
  394.         DDX_Text(pDX, nIDC, value);
  395. }
  396.  
  397. void AFXAPI DDX_FieldText(CDataExchange* pDX, int nIDC, COleDateTime& value,
  398.     CDaoRecordset* pRecordset)
  399. {
  400.     if (!AfxFieldText(pDX, nIDC, &value, pRecordset))
  401.         DDX_Text(pDX, nIDC, value);
  402. }
  403.  
  404. void AFXAPI DDX_FieldText(CDataExchange* pDX, int nIDC, CString &value,
  405.     CDaoRecordset* pRecordset)
  406. {
  407.     if (!AfxFieldText(pDX, nIDC, &value, pRecordset))
  408.         DDX_Text(pDX, nIDC, value);
  409. }
  410.  
  411. void AFXAPI DDX_FieldText(CDataExchange* pDX, int nIDC, LPTSTR pstrValue,
  412.     int nMaxLen, CDaoRecordset* pRecordset)
  413. {
  414.     if (!AfxFieldText(pDX, nIDC, &pstrValue, pRecordset))
  415.         DDX_Text(pDX, nIDC, pstrValue, nMaxLen);
  416. }
  417.  
  418. void AFXAPI DDX_FieldLBString(CDataExchange* pDX, int nIDC, CString& value,
  419.     CDaoRecordset* pRecordset)
  420. {
  421.     ASSERT_VALID(pRecordset);
  422.  
  423.     HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
  424.     if (pDX->m_bSaveAndValidate)
  425.     {
  426.         int nIndex = (int)::SendMessage(hWndCtrl, LB_GETCURSEL, 0, 0L);
  427.         if (nIndex != -1)
  428.         {
  429.             int nLen = (int)::SendMessage(hWndCtrl, LB_GETTEXTLEN, nIndex, 0L);
  430.             ::SendMessage(hWndCtrl, LB_GETTEXT, nIndex,
  431.                     (LPARAM)(LPSTR)value.GetBuffer(nLen));
  432.             if (nLen == 0)
  433.             {
  434.                 if (pRecordset->IsFieldNullable(&value))
  435.                     pRecordset->SetFieldNull(&value, TRUE);
  436.             }
  437.             else
  438.             {
  439.                 pRecordset->SetFieldNull(&value, FALSE);
  440.             }
  441.             value.ReleaseBuffer();
  442.         }
  443.         else
  444.         {
  445.             // no selection
  446.             value.GetBufferSetLength(0);
  447.             if (pRecordset->IsFieldNullable(&value))
  448.                 pRecordset->SetFieldNull(&value);
  449.         }
  450.     }
  451.     else
  452.     {
  453.         if (!pRecordset->IsOpen() || pRecordset->IsFieldNull(&value))
  454.         {
  455.             SendMessage(hWndCtrl, LB_SETCURSEL, (WPARAM)-1, 0L);
  456.         }
  457.         else
  458.         {
  459.             // set current selection based on data string
  460.             if (::SendMessage(hWndCtrl, LB_SELECTSTRING, (WPARAM)-1,
  461.               (LPARAM)(LPCTSTR)value) == LB_ERR)
  462.             {
  463.                 // no selection match
  464.                 TRACE0("Warning: no listbox item selected.\n");
  465.             }
  466.         }
  467.     }
  468. }
  469.  
  470. void AFXAPI DDX_FieldLBStringExact(CDataExchange* pDX, int nIDC, CString& value,
  471.     CDaoRecordset* pRecordset)
  472. {
  473.     ASSERT_VALID(pRecordset);
  474.  
  475.     HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
  476.     if (pDX->m_bSaveAndValidate)
  477.     {
  478.         DDX_FieldLBString(pDX, nIDC, value, pRecordset);
  479.     }
  480.     else
  481.     {
  482.         if (!pRecordset->IsOpen() || pRecordset->IsFieldNull(&value))
  483.         {
  484.             SendMessage(hWndCtrl, LB_SETCURSEL, (WPARAM)-1, 0L);
  485.         }
  486.         else
  487.         {
  488.             // set current selection based on data string
  489.             int i = (int)::SendMessage(hWndCtrl, LB_FINDSTRINGEXACT, (WPARAM)-1,
  490.               (LPARAM)(LPCTSTR)value);
  491.             if (i < 0)
  492.             {
  493.                 // no selection match
  494.                 TRACE0("Warning: no listbox item selected.\n");
  495.             }
  496.             else
  497.             {
  498.                 // select it
  499.                 SendMessage(hWndCtrl, LB_SETCURSEL, i, 0L);
  500.             }
  501.         }
  502.     }
  503. }
  504.  
  505. void AFXAPI DDX_FieldCBString(CDataExchange* pDX, int nIDC, CString& value,
  506.     CDaoRecordset* pRecordset)
  507. {
  508.     ASSERT_VALID(pRecordset);
  509.  
  510.     HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
  511.     if (pDX->m_bSaveAndValidate)
  512.     {
  513.         // just get current edit item text (or drop list static)
  514.         int nLen = ::GetWindowTextLength(hWndCtrl);
  515.         if (nLen != -1)
  516.         {
  517.             // get known length
  518.             ::GetWindowText(hWndCtrl, value.GetBuffer(nLen), nLen+1);
  519.         }
  520.         else
  521.         {
  522.             // for drop lists GetWindowTextLength does not work - assume
  523.             //  preallocated length (or 256, whichever is larger)
  524.             nLen = value.GetAllocLength();
  525.             if (nLen < 256)
  526.                 nLen = 256;
  527.             ::GetWindowText(hWndCtrl, value.GetBuffer(nLen-1), nLen);
  528.         }
  529.         value.ReleaseBuffer();
  530.         if (value.GetLength() == 0)
  531.         {
  532.             if (pRecordset->IsFieldNullable(&value))
  533.                 pRecordset->SetFieldNull(&value, TRUE);
  534.         }
  535.         else
  536.         {
  537.             pRecordset->SetFieldNull(&value, FALSE);
  538.         }
  539.     }
  540.     else
  541.     {
  542.         if (!pRecordset->IsOpen() || pRecordset->IsFieldNull(&value))
  543.         {
  544.             SendMessage(hWndCtrl, CB_SETCURSEL, (WPARAM)-1, 0L);
  545.         }
  546.         else
  547.         {
  548.             // set current selection based on model string
  549.             if (::SendMessage(hWndCtrl, CB_SELECTSTRING, (WPARAM)-1,
  550.                 (LPARAM)(LPCTSTR)value) == CB_ERR)
  551.             {
  552.                 // just set the edit text (will be ignored if DROPDOWNLIST)
  553.                 AfxSetWindowText(hWndCtrl, value);
  554.             }
  555.         }
  556.     }
  557. }
  558.  
  559. void AFXAPI DDX_FieldCBStringExact(CDataExchange* pDX, int nIDC, CString& value,
  560.     CDaoRecordset* pRecordset)
  561. {
  562.     ASSERT_VALID(pRecordset);
  563.  
  564.     HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
  565.     if (pDX->m_bSaveAndValidate)
  566.     {
  567.         DDX_FieldCBString(pDX, nIDC, value, pRecordset);
  568.     }
  569.     else
  570.     {
  571.         if (!pRecordset->IsOpen() || pRecordset->IsFieldNull(&value))
  572.         {
  573.             SendMessage(hWndCtrl, CB_SETCURSEL, (WPARAM)-1, 0L);
  574.         }
  575.         else
  576.         {
  577.             // set current selection based on data string
  578.             int i = (int)::SendMessage(hWndCtrl, CB_FINDSTRINGEXACT, (WPARAM)-1,
  579.               (LPARAM)(LPCTSTR)value);
  580.             if (i < 0)
  581.             {
  582.                 // no selection match
  583.                 TRACE0("Warning: no combobox item selected.\n");
  584.             }
  585.             else
  586.             {
  587.                 // select it
  588.                 SendMessage(hWndCtrl, CB_SETCURSEL, i, 0L);
  589.             }
  590.         }
  591.     }
  592. }
  593.  
  594. void AFXAPI DDX_FieldLBIndex(CDataExchange* pDX, int nIDC, int& index,
  595.     CDaoRecordset* pRecordset)
  596. {
  597.     ASSERT_VALID(pRecordset);
  598.  
  599.     if (!pDX->m_bSaveAndValidate &&
  600.         (!pRecordset->IsOpen() || pRecordset->IsFieldNull(&index)))
  601.     {
  602.         int nIndex = 0;
  603.         DDX_LBIndex(pDX, nIDC, nIndex);
  604.     }
  605.     else
  606.         DDX_LBIndex(pDX, nIDC, index);
  607. }
  608.  
  609. void AFXAPI DDX_FieldCBIndex(CDataExchange* pDX, int nIDC, int& index,
  610.     CDaoRecordset* pRecordset)
  611. {
  612.     ASSERT_VALID(pRecordset);
  613.  
  614.     if (!pDX->m_bSaveAndValidate &&
  615.         (!pRecordset->IsOpen() || pRecordset->IsFieldNull(&index)))
  616.     {
  617.         int nIndex = 0;
  618.         DDX_CBIndex(pDX, nIDC, nIndex);
  619.     }
  620.     else
  621.         DDX_CBIndex(pDX, nIDC, index);
  622. }
  623.  
  624. void AFXAPI DDX_FieldScroll(CDataExchange* pDX, int nIDC, int& value,
  625.     CDaoRecordset* pRecordset)
  626. {
  627.     ASSERT_VALID(pRecordset);
  628.  
  629.     if (!pDX->m_bSaveAndValidate &&
  630.         (!pRecordset->IsOpen() || pRecordset->IsFieldNull(&value)))
  631.     {
  632.         int nValue = 0;
  633.         DDX_Scroll(pDX, nIDC, nValue);
  634.     }
  635.     else
  636.         DDX_Scroll(pDX, nIDC, value);
  637. }
  638.  
  639. void AFXAPI DDX_FieldSlider(CDataExchange* pDX, int nIDC, int& value,
  640.     CDaoRecordset* pRecordset)
  641. {
  642.     ASSERT_VALID(pRecordset);
  643.  
  644.     if (!pDX->m_bSaveAndValidate &&
  645.         (!pRecordset->IsOpen() || pRecordset->IsFieldNull(&value)))
  646.     {
  647.         int nValue = 0;
  648.         DDX_Slider(pDX, nIDC, nValue);
  649.     }
  650.     else
  651.         DDX_Slider(pDX, nIDC, value);
  652. }
  653.  
  654. /////////////////////////////////////////////////////////////////////////////
  655. // Data exchange for special controls
  656.  
  657. void AFXAPI DDX_FieldCheck(CDataExchange* pDX, int nIDC, int& value, CDaoRecordset* pRecordset)
  658. {
  659.     ASSERT_VALID(pRecordset);
  660.  
  661.     HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
  662.     if (pDX->m_bSaveAndValidate)
  663.     {
  664.         value = (int)::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L);
  665.         ASSERT(value >= 0 && value <= 2);
  666.         if (value == 2)
  667.         {
  668.             if (pRecordset->IsFieldNullable(&value))
  669.                 pRecordset->SetFieldNull(&value);
  670.             else
  671.             {
  672.                 TRACE0("Warning: can't set field NULL for checkbox value.\n");
  673.                 // Default to unchecked
  674.                 value = 0;
  675.             }
  676.         }
  677.     }
  678.     else
  679.     {
  680.         if (!pRecordset->IsOpen() || pRecordset->IsFieldNull(&value))
  681.         {
  682.             int style = ((int)::GetWindowLong(hWndCtrl, GWL_STYLE) & 0xf);
  683.             if ((style == BS_3STATE || style == BS_AUTO3STATE))
  684.                 value = 2;
  685.             else
  686.             {
  687.                 TRACE0("Warning: can't set checkbox value for NULL field.\n");
  688.                 // Default to unchecked
  689.                 value = 0;
  690.             }
  691.         }
  692.         if (value < 0 || value > 2)
  693.         {
  694.             value = 0;      // default to off
  695.             TRACE1("Warning: dialog data checkbox value (%d) out of range.\n",
  696.                 value);
  697.         }
  698.         ::SendMessage(hWndCtrl, BM_SETCHECK, (WPARAM)value, 0L);
  699.     }
  700. }
  701.  
  702. void AFXAPI DDX_FieldRadio(CDataExchange* pDX, int nIDC, int& value,
  703.     CDaoRecordset* pRecordset)
  704. {
  705.     ASSERT_VALID(pRecordset);
  706.  
  707.     if (!pDX->m_bSaveAndValidate &&
  708.         (!pRecordset->IsOpen() || pRecordset->IsFieldNull(&value)))
  709.         value = -1;
  710.     DDX_Radio(pDX, nIDC, value);
  711.     if (pDX->m_bSaveAndValidate)
  712.     {
  713.         if (value == -1 && !pRecordset->IsFieldNullable(&value))
  714.         {
  715.             AfxFailRadio(pDX);
  716.         }
  717.         else
  718.         {
  719.             pRecordset->SetFieldNull(&value, (value == -1));
  720.         }
  721.     }
  722. }
  723.  
  724. /////////////////////////////////////////////////////////////////////////////
  725.  
  726. #ifdef _DEBUG
  727. void CDaoRecordView::AssertValid() const
  728. {
  729.     CFormView::AssertValid();
  730. }
  731.  
  732. void CDaoRecordView::Dump(CDumpContext& dc) const
  733. {
  734.     ASSERT_VALID(this);
  735.  
  736.     CFormView::Dump(dc);
  737.  
  738.     dc << "m_nStatus =" << m_nStatus;
  739.     dc << "m_varBookmarkCurrent =" << m_varBookmarkCurrent;
  740.     dc << "m_varBookmarkFirst =" << m_varBookmarkFirst;
  741.     dc << "m_varBookmarkLast =" << m_varBookmarkLast;
  742.  
  743.     dc << "\n";
  744. }
  745. #endif
  746.  
  747. //////////////////////////////////////////////////////////////////////////////
  748. // Inline function declarations expanded out-of-line
  749.  
  750. #ifndef _AFX_ENABLE_INLINES
  751.  
  752. static char _szAfxDaoInl[] = "afxdao.inl";
  753. #undef THIS_FILE
  754. #define THIS_FILE _szAfxDaoInl
  755. #define _AFXDAOVIEW_INLINE
  756. #include "afxdao.inl"
  757.  
  758. #endif
  759.  
  760. #ifdef AFX_INIT_SEG
  761. #pragma code_seg(AFX_INIT_SEG)
  762. #endif
  763.  
  764. /////////////////////////////////////////////////////////////////////////////
  765.