// This is a part of the Microsoft Foundation Classes C++ library. // Copyright (C) 1992-1998 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Microsoft Foundation Classes Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Microsoft Foundation Classes product. #include "stdafx.h" #ifdef AFX_DB_SEG #pragma code_seg(AFX_DB_SEG) #endif #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define new DEBUG_NEW ///////////////////////////////////////////////////////////////////////////// BEGIN_MESSAGE_MAP(CRecordView, CFormView) //{{AFX_MSG_MAP(CRecordView) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_MSG_MAP ON_COMMAND_EX(ID_RECORD_FIRST, OnMove) ON_UPDATE_COMMAND_UI(ID_RECORD_FIRST, OnUpdateRecordFirst) ON_COMMAND_EX(ID_RECORD_PREV, OnMove) ON_UPDATE_COMMAND_UI(ID_RECORD_PREV, OnUpdateRecordPrev) ON_COMMAND_EX(ID_RECORD_NEXT, OnMove) ON_UPDATE_COMMAND_UI(ID_RECORD_NEXT, OnUpdateRecordNext) ON_COMMAND_EX(ID_RECORD_LAST, OnMove) ON_UPDATE_COMMAND_UI(ID_RECORD_LAST, OnUpdateRecordLast) END_MESSAGE_MAP() CRecordView::CRecordView(LPCTSTR lpszTemplateName) : CFormView(lpszTemplateName) { } CRecordView::CRecordView(UINT nIDTemplate) : CFormView(nIDTemplate) { } CRecordView::~CRecordView() { } void CRecordView::OnInitialUpdate() { CRecordset* pRecordset = OnGetRecordset(); // recordset must be allocated already ASSERT(pRecordset != NULL); if (!pRecordset->IsOpen()) { CWaitCursor wait; pRecordset->Open(); } CFormView::OnInitialUpdate(); } BOOL CRecordView::IsOnFirstRecord() { ASSERT_VALID(this); CRecordsetStatus status; OnGetRecordset()->GetStatus(status); return status.m_lCurrentRecord == 0; } BOOL CRecordView::IsOnLastRecord() { ASSERT_VALID(this); CRecordset* pRecordset = OnGetRecordset(); CRecordsetStatus status; pRecordset->GetStatus(status); if (!status.m_bRecordCountFinal) return FALSE; return ((status.m_lCurrentRecord+1 == pRecordset->GetRecordCount())); } BOOL CRecordView::OnMove(UINT nIDMoveCommand) { CRecordset* pSet = OnGetRecordset(); if (pSet->CanUpdate() && !pSet->IsDeleted()) { pSet->Edit(); if (!UpdateData()) return TRUE; pSet->Update(); } switch (nIDMoveCommand) { case ID_RECORD_PREV: pSet->MovePrev(); if (!pSet->IsBOF()) break; case ID_RECORD_FIRST: pSet->MoveFirst(); break; case ID_RECORD_NEXT: pSet->MoveNext(); if (!pSet->IsEOF()) break; if (!pSet->CanScroll()) { // clear out screen since we're sitting on EOF pSet->SetFieldNull(NULL); break; } case ID_RECORD_LAST: pSet->MoveLast(); break; default: // Unexpected case value ASSERT(FALSE); } // Show results of move operation UpdateData(FALSE); return TRUE; } void CRecordView::OnUpdateRecordFirst(CCmdUI* pCmdUI) { CRecordset* prs = OnGetRecordset(); // enable if opened, can scroll backwards, pCmdUI->Enable(prs->IsOpen() && prs->CanScroll() && // >= 1 records present and not already on first record !(prs->IsEOF() && prs->IsBOF()) && !IsOnFirstRecord()); } void CRecordView::OnUpdateRecordPrev(CCmdUI* pCmdUI) { CRecordView::OnUpdateRecordFirst(pCmdUI); } void CRecordView::OnUpdateRecordNext(CCmdUI* pCmdUI) { CRecordset* prs = OnGetRecordset(); // enable if opened and >= 1 records present pCmdUI->Enable(prs->IsOpen() && !(prs->IsEOF() && prs->IsBOF()) // and not already on last record && !IsOnLastRecord()); } void CRecordView::OnUpdateRecordLast(CCmdUI* pCmdUI) { CRecordset* prs = OnGetRecordset(); // enable if opened, can scroll, pCmdUI->Enable(prs->IsOpen() && prs->CanScroll() && // >= 1 records present and not already on last record !(prs->IsEOF() && prs->IsBOF()) && !IsOnLastRecord()); } ///////////////////////////////////////////////////////////////////////////// // DDX Cover functions for use with fields of a recordset ///////////////////////////////////////////////////////////////////////////// // Simple field formatting to text item BOOL AFXAPI AfxFieldText(CDataExchange* pDX, int nIDC, void* pv, CRecordset* pRecordset) { ASSERT_VALID(pRecordset); HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC); TCHAR szT[2]; if (pDX->m_bSaveAndValidate) { ::GetWindowText(hWndCtrl, szT, _countof(szT)); if (szT[0] == '\0') { if (pRecordset->IsFieldNullable(pv)) { pRecordset->SetFieldNull(pv); return TRUE; } } else pRecordset->SetFieldNull(pv, FALSE); } else { if (!pRecordset->IsOpen() || pRecordset->IsFieldNull(pv)) { szT[0] = '\0'; AfxSetWindowText(hWndCtrl, szT); return TRUE; } else if (pRecordset->IsDeleted()) { CString strDeleted(MAKEINTRESOURCE(AFX_IDS_DELETED)); AfxSetWindowText(hWndCtrl, strDeleted); return TRUE; } } return FALSE; } void AFXAPI DDX_FieldText(CDataExchange* pDX, int nIDC, int& value, CRecordset* pRecordset) { if (!AfxFieldText(pDX, nIDC, &value, pRecordset)) DDX_Text(pDX, nIDC, value); } void AFXAPI DDX_FieldText(CDataExchange* pDX, int nIDC, BYTE& value, CRecordset* pRecordset) { if (!AfxFieldText(pDX, nIDC, &value, pRecordset)) DDX_Text(pDX, nIDC, value); } void AFXAPI DDX_FieldText(CDataExchange* pDX, int nIDC, UINT& value, CRecordset* pRecordset) { if (!AfxFieldText(pDX, nIDC, &value, pRecordset)) DDX_Text(pDX, nIDC, value); } void AFXAPI DDX_FieldText(CDataExchange* pDX, int nIDC, long& value, CRecordset* pRecordset) { if (!AfxFieldText(pDX, nIDC, &value, pRecordset)) DDX_Text(pDX, nIDC, value); } void AFXAPI DDX_FieldText(CDataExchange* pDX, int nIDC, DWORD& value, CRecordset* pRecordset) { if (!AfxFieldText(pDX, nIDC, &value, pRecordset)) DDX_Text(pDX, nIDC, value); } void AFXAPI DDX_FieldText(CDataExchange* pDX, int nIDC, CString& value, CRecordset* pRecordset) { ASSERT_VALID(pRecordset); HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC); if (pDX->m_bSaveAndValidate) { // check if length is too long (this is complicated by Windows NT/J) int nLen = ::GetWindowTextLength(hWndCtrl); if (nLen > value.GetAllocLength()) { if (!_afxDBCS) AfxFailMaxChars(pDX, value.GetAllocLength()); CString strTemp; ::GetWindowText(hWndCtrl, strTemp.GetBuffer(nLen), nLen+1); strTemp.ReleaseBuffer(); nLen = strTemp.GetLength(); if (nLen > value.GetAllocLength()) AfxFailMaxChars(pDX, value.GetAllocLength()); } // get known length ::GetWindowText(hWndCtrl, value.GetBuffer(0), nLen+1); value.ReleaseBuffer(); if (nLen == 0) { if (pRecordset->IsFieldNullable(&value)) pRecordset->SetFieldNull(&value, TRUE); } else { pRecordset->SetFieldNull(&value, FALSE); } } else if (pRecordset->IsDeleted()) { CString strDeleted(MAKEINTRESOURCE(AFX_IDS_DELETED)); AfxSetWindowText(hWndCtrl, strDeleted); } else { AfxSetWindowText(hWndCtrl, value); } } void AFXAPI DDX_FieldText(CDataExchange* pDX, int nIDC, LPTSTR pstrValue, int nMaxLength, CRecordset* pRecordset) { ASSERT_VALID(pRecordset); HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC); if (pDX->m_bSaveAndValidate) { int nLen = ::GetWindowText(hWndCtrl, pstrValue, nMaxLength); if (nLen == 0) { if (pRecordset->IsFieldNullable(pstrValue)) pRecordset->SetFieldNull(pstrValue, TRUE); } else pRecordset->SetFieldNull(pstrValue, FALSE); } else if (pRecordset->IsDeleted()) { CString strDeleted(MAKEINTRESOURCE(AFX_IDS_DELETED)); AfxSetWindowText(hWndCtrl, strDeleted); } else AfxSetWindowText(hWndCtrl, pstrValue); } void AFXAPI DDX_FieldLBString(CDataExchange* pDX, int nIDC, CString& value, CRecordset* pRecordset) { ASSERT_VALID(pRecordset); HWND hWndCtrl = pDX->PrepareCtrl(nIDC); if (pDX->m_bSaveAndValidate) { int nIndex = (int)::SendMessage(hWndCtrl, LB_GETCURSEL, 0, 0L); if (nIndex != -1) { int nLen = (int)::SendMessage(hWndCtrl, LB_GETTEXTLEN, nIndex, 0L); if (nLen > value.GetAllocLength()) AfxFailMaxChars(pDX, value.GetAllocLength()); ::SendMessage(hWndCtrl, LB_GETTEXT, nIndex, (LPARAM)(LPSTR)value.GetBuffer(0)); if (nLen == 0) { if (pRecordset->IsFieldNullable(&value)) pRecordset->SetFieldNull(&value, TRUE); } else { pRecordset->SetFieldNull(&value, FALSE); } value.ReleaseBuffer(); } else { // no selection value.GetBufferSetLength(0); if (pRecordset->IsFieldNullable(&value)) pRecordset->SetFieldNull(&value); } } else { if (!pRecordset->IsOpen() || pRecordset->IsFieldNull(&value)) { SendMessage(hWndCtrl, LB_SETCURSEL, (WPARAM)-1, 0L); } else { // set current selection based on data string if (::SendMessage(hWndCtrl, LB_SELECTSTRING, (WPARAM)-1, (LPARAM)(LPCTSTR)value) == LB_ERR) { // no selection match TRACE0("Warning: no listbox item selected.\n"); } } } } void AFXAPI DDX_FieldLBStringExact(CDataExchange* pDX, int nIDC, CString& value, CRecordset* pRecordset) { ASSERT_VALID(pRecordset); HWND hWndCtrl = pDX->PrepareCtrl(nIDC); if (pDX->m_bSaveAndValidate) { DDX_FieldLBString(pDX, nIDC, value, pRecordset); } else { if (!pRecordset->IsOpen() || pRecordset->IsFieldNull(&value)) { SendMessage(hWndCtrl, LB_SETCURSEL, (WPARAM)-1, 0L); } else { // set current selection based on data string int i = (int)::SendMessage(hWndCtrl, LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCTSTR)value); if (i < 0) { // no selection match TRACE0("Warning: no listbox item selected.\n"); } else { // select it SendMessage(hWndCtrl, LB_SETCURSEL, i, 0L); } } } } void AFXAPI DDX_FieldLBIndex(CDataExchange* pDX, int nIDC, int& index, CRecordset* pRecordset) { ASSERT_VALID(pRecordset); if (!pDX->m_bSaveAndValidate && (!pRecordset->IsOpen() || pRecordset->IsFieldNull(&index))) { int nIndex = 0; DDX_LBIndex(pDX, nIDC, nIndex); } else DDX_LBIndex(pDX, nIDC, index); } void AFXAPI DDX_FieldCBString(CDataExchange* pDX, int nIDC, CString& value, CRecordset* pRecordset) { ASSERT_VALID(pRecordset); HWND hWndCtrl = pDX->PrepareCtrl(nIDC); if (pDX->m_bSaveAndValidate) { // just get current edit item text (or drop list static) int nLen = ::GetWindowTextLength(hWndCtrl); if (nLen != -1) { CString strTemp; ::GetWindowText(hWndCtrl, strTemp.GetBuffer(nLen), nLen+1); strTemp.ReleaseBuffer(); nLen = strTemp.GetLength(); if (nLen > value.GetAllocLength()) AfxFailMaxChars(pDX, value.GetAllocLength()); // get known length ::GetWindowText(hWndCtrl, value.GetBuffer(0), nLen+1); } else { // for drop lists GetWindowTextLength does not work - assume // preallocated length ::GetWindowText(hWndCtrl, value.GetBuffer(0), value.GetAllocLength()+1); } value.ReleaseBuffer(); if (value.GetLength() == 0) { if (pRecordset->IsFieldNullable(&value)) pRecordset->SetFieldNull(&value, TRUE); } else { pRecordset->SetFieldNull(&value, FALSE); } } else { if (!pRecordset->IsOpen() || pRecordset->IsFieldNull(&value)) { SendMessage(hWndCtrl, CB_SETCURSEL, (WPARAM)-1, 0L); } else { // set current selection based on model string if (::SendMessage(hWndCtrl, CB_SELECTSTRING, (WPARAM)-1, (LPARAM)(LPCTSTR)value) == CB_ERR) { // just set the edit text (will be ignored if DROPDOWNLIST) AfxSetWindowText(hWndCtrl, value); } } } } void AFXAPI DDX_FieldCBStringExact(CDataExchange* pDX, int nIDC, CString& value, CRecordset* pRecordset) { ASSERT_VALID(pRecordset); HWND hWndCtrl = pDX->PrepareCtrl(nIDC); if (pDX->m_bSaveAndValidate) { DDX_FieldCBString(pDX, nIDC, value, pRecordset); } else { if (!pRecordset->IsOpen() || pRecordset->IsFieldNull(&value)) { SendMessage(hWndCtrl, CB_SETCURSEL, (WPARAM)-1, 0L); } else { // set current selection based on data string int i = (int)::SendMessage(hWndCtrl, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCTSTR)value); if (i < 0) { // no selection match TRACE0("Warning: no combobox item selected.\n"); } else { // select it SendMessage(hWndCtrl, CB_SETCURSEL, i, 0L); } } } } void AFXAPI DDX_FieldCBIndex(CDataExchange* pDX, int nIDC, int& index, CRecordset* pRecordset) { ASSERT_VALID(pRecordset); if (!pDX->m_bSaveAndValidate && (!pRecordset->IsOpen() || pRecordset->IsFieldNull(&index))) { int nIndex = 0; DDX_CBIndex(pDX, nIDC, nIndex); } else DDX_CBIndex(pDX, nIDC, index); } void AFXAPI DDX_FieldScroll(CDataExchange* pDX, int nIDC, int& value, CRecordset* pRecordset) { ASSERT_VALID(pRecordset); if (!pDX->m_bSaveAndValidate && (!pRecordset->IsOpen() || pRecordset->IsFieldNull(&value))) { int nValue = 0; DDX_Scroll(pDX, nIDC, nValue); } else DDX_Scroll(pDX, nIDC, value); } ///////////////////////////////////////////////////////////////////////////// // Data exchange for special controls void AFXAPI DDX_FieldCheck(CDataExchange* pDX, int nIDC, int& value, CRecordset* pRecordset) { ASSERT_VALID(pRecordset); HWND hWndCtrl = pDX->PrepareCtrl(nIDC); if (pDX->m_bSaveAndValidate) { value = (int)::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L); ASSERT(value >= 0 && value <= 2); if (value == 2) { if (pRecordset->IsFieldNullable(&value)) pRecordset->SetFieldNull(&value); else { TRACE0("Warning: checkbox value indeterminate and field can't be NULL.\n"); // Default to unchecked value = 0; } } } else { if (!pRecordset->IsOpen() || pRecordset->IsFieldNull(&value)) { int style = ((int)::GetWindowLong(hWndCtrl, GWL_STYLE) & 0xf); if ((style == BS_3STATE || style == BS_AUTO3STATE)) value = 2; else { TRACE0("Warning: field NULL and checkbox can't be indeterminate.\n"); // Default to unchecked value = 0; } } if (value < 0 || value > 2) { value = 0; // default to off TRACE1("Warning: dialog data checkbox value (%d) out of range.\n", value); } ::SendMessage(hWndCtrl, BM_SETCHECK, (WPARAM)value, 0L); } } void AFXAPI DDX_FieldRadio(CDataExchange* pDX, int nIDC, int& value, CRecordset* pRecordset) { ASSERT_VALID(pRecordset); if (!pDX->m_bSaveAndValidate && (!pRecordset->IsOpen() || pRecordset->IsFieldNull(&value))) value = -1; DDX_Radio(pDX, nIDC, value); if (pDX->m_bSaveAndValidate) { if (value == -1 && !pRecordset->IsFieldNullable(&value)) { AfxFailRadio(pDX); } else { pRecordset->SetFieldNull(&value, (value == -1)); } } } ///////////////////////////////////////////////////////////////////////////// #ifdef _DEBUG void CRecordView::AssertValid() const { CFormView::AssertValid(); } void CRecordView::Dump(CDumpContext& dc) const { CFormView::Dump(dc); dc << "m_bOnFirstRecord = " << m_bOnFirstRecord; dc << "\nm_bOnLastRecord = " << m_bOnLastRecord; dc << "\n"; } #endif ////////////////////////////////////////////////////////////////////////////// // Inline function declarations expanded out-of-line #ifndef _AFX_ENABLE_INLINES static char _szAfxDbInl[] = "afxdb.inl"; #undef THIS_FILE #define THIS_FILE _szAfxDbInl #define _AFXDBVIEW_INLINE #include "afxdb.inl" #endif #ifdef AFX_INIT_SEG #pragma code_seg(AFX_INIT_SEG) #endif IMPLEMENT_DYNAMIC(CRecordView, CFormView) /////////////////////////////////////////////////////////////////////////////