home *** CD-ROM | disk | FTP | other *** search
- // DataView.cpp : implementation file
- //
-
- #include "stdafx.h"
- #include "Browser.h"
- #include "DataView.h"
- #include "BrowserDoc.h"
- #include "Mainfrm.h"
- #include "ChildFrm.h"
- #include "VarDecoder.h"
- #include "FindDlg.h"
- #include "QueryDlg.h"
-
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
-
- #define USERMSG_HEADCLICK WM_USER + 1 //To solve problem with LVN_COLUMNCLICK
-
- /////////////////////////////////////////////////////////////////////////////
- // CDataView
-
- IMPLEMENT_DYNCREATE(CDataView, CListView)
-
- CDataView::CDataView()
- : m_pDB( NULL ), m_pQuery( NULL ),
- m_pRecordset( NULL ), m_pTable( NULL )
-
- {
- }
-
- CDataView::~CDataView()
- {
- try
- {
- if ( m_pRecordset ) //No check for dirty records
- m_pRecordset->Close( ); //This is just a browser
- if ( m_pQuery )
- m_pQuery->Close( );
- if ( m_pTable )
- m_pTable->Close( );
- }
- catch ( CException* ex )
- {
- ex->ReportError( );
- ex->Delete( );
- }
- delete m_pRecordset; //Release the memory regardless
- delete m_pQuery; //of other problems
- delete m_pTable;
- }
-
-
- BEGIN_MESSAGE_MAP(CDataView, CListView)
- //{{AFX_MSG_MAP(CDataView)
- ON_COMMAND(ID_PAGE_DOWN, OnPageDown)
- ON_COMMAND(ID_PAGE_FIRST, OnPageFirst)
- ON_COMMAND(ID_PAGE_LAST, OnPageLast)
- ON_COMMAND(ID_PAGE_UP, OnPageUp)
- ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnclick)
- //}}AFX_MSG_MAP
- ON_MESSAGE( USERMSG_HEADCLICK, OnHeadClick )
- END_MESSAGE_MAP()
-
- /////////////////////////////////////////////////////////////////////////////
- // CDataView drawing
-
- void CDataView::OnDraw(CDC* pDC)
- {
- CDocument* pDoc = GetDocument();
- // TODO: add draw code here
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CDataView diagnostics
-
- #ifdef _DEBUG
- void CDataView::AssertValid() const
- {
- CListView::AssertValid();
- }
-
- void CDataView::Dump(CDumpContext& dc) const
- {
- CListView::Dump(dc);
- }
- #endif //_DEBUG
-
- /////////////////////////////////////////////////////////////////////////////
- // CDataView message handlers
-
- BOOL CDataView::PreCreateWindow(CREATESTRUCT& cs)
- {
- // TODO: Add your specialized code here and/or call the base class
-
- return CListView::PreCreateWindow(cs);
- }
-
- //Function receives a pointer to the CDaoDatabase object, table or query name
- //and whether it is a table or a query. If a query, it calls a function to
- //get any parameters. Then it opens recordset.
- BOOL CDataView::SetData( CDaoDatabase * pDB, const CString & name, const int nType )
- {
- //In place for exercise 1
- //return FALSE; //remove for exercise 2
-
- //Set database and table names as title bar
- CString str = GetDocument( )->GetTitle( );
- ( ( CChildFrame * ) GetParentFrame( ) )
- ->m_strCaption = str + ": " + name; //Store database: tablename
-
- m_pDB = pDB; //Store database pointer in view CDataView::m_pDB
-
- try
- {
- if ( TABLE == nType )
- {
- m_pRecordset = new CDaoRecordset( m_pDB );
- CString sql = "Select * from [" + name + "]";
- m_pRecordset->Open( dbOpenDynaset, sql );
- }
-
- else if ( QUERY == nType )
- {
- m_pQuery = new CDaoQueryDef( m_pDB );
- m_pQuery->Open( name );
- if ( dbQSelect == m_pQuery->GetType( ) )
- {
- SetParams( m_pQuery );
- m_pRecordset = new CDaoRecordset( m_pDB );
- m_pRecordset->Open( m_pQuery );
- } //End if Select-Query
- else
- {
- AfxMessageBox( "Not a Select Query" );
- return FALSE;
- }
- } //End Query-type
- } //End try block
- catch ( CException * ex )
- {
- ex->ReportError( );
- ex->Delete( );
- delete m_pTable; //Clean up mess
- delete m_pRecordset;
- delete m_pQuery;
- m_pTable = NULL;
- m_pRecordset = NULL;
- m_pQuery = NULL;
-
- return FALSE;
- }
-
- LoadHeaders( ); //Fill in the view's column headers
- LoadData( ); //Load the report view rows
-
- return TRUE;
- }
-
- CBrowserDoc * CDataView::GetDocument( )
- {
- return ( CBrowserDoc * ) m_pDocument; //Cast to correct pointer type
- }
-
- void CDataView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView)
- {
- // TODO: Add your specialized code here and/or call the base class
-
- CMainFrame * pFrame = ( CMainFrame * ) AfxGetMainWnd( );
-
- if ( bActivate ) //This view is activated so we load its toolbar
- pFrame->m_wndToolBar.LoadToolBar(IDR_DATATYPE);
- else if ( pFrame == ( CMainFrame * ) pActivateView ) //Load mainframe toolbar
- pFrame->m_wndToolBar.LoadToolBar(IDR_MAINFRAME); //if mainframe activates
- pFrame->RecalcLayout( ); //Compute client area
-
- CListView::OnActivateView(bActivate, pActivateView, pDeactiveView);
- }
-
- void CDataView::LoadHeaders()
- {
- CListCtrl & lstctrl = GetListCtrl( ); //Get view's list control
-
- lstctrl.DeleteAllItems( ); //Clean it out
-
- //Make the column headers
-
- lstctrl.CWnd::ModifyStyle( NULL, LVS_REPORT ); //Set for report view
-
- try
- {
- int width; //Width of fieldname text
- int align; //Alignment style (left, center, right)
- CDaoFieldInfo fInfo; //Structure of field information
-
- int columns = m_pRecordset->GetFieldCount( ); //How many fields
- for ( int i = 0 ; i < columns ; i ++ )
- {
- m_pRecordset->GetFieldInfo( i, fInfo );
- //Align text and memo fields to the left, others to the right
- align =
- dbText == fInfo.m_nType || dbMemo == fInfo.m_nType
- ? LVCFMT_LEFT : LVCFMT_RIGHT;
- width = lstctrl.GetStringWidth( fInfo.m_strName );
- //Make the column twice the label width
- lstctrl.InsertColumn( i, fInfo.m_strName, align, 2 * width );
- }
- }
- catch( CException * ex )
- {
- ex->ReportError( );
- ex->Delete( );
- }
- }
-
-
- //Fill list view with data. If a non-null pointer is passed to the
- //function, use CDaoRecordset::FindNext to locate data, otherwise use
- //CDaoRecordset::MoveNext
-
- void CDataView::LoadData( CString * pstrCriteria )
- {
- CListCtrl & lstctrl = GetListCtrl( ); //The view's list control
- lstctrl.DeleteAllItems( ); //Clean it out
-
- int rows = lstctrl.GetCountPerPage( ); //How many rows can fit on the page
-
- try
- {
- COleVariant var;
- CString str;
-
- int columns = m_pRecordset->GetFieldCount( ); //How many fields
-
- // Move through records
- for ( int r = 0 ; r < rows && ! m_pRecordset->IsEOF( ) ; r ++ )
- {
- for ( int c = 0; c < columns ; c ++ ) //Move across fields
- {
- m_pRecordset->GetFieldValue( c, var );
-
- //Converter function from VarDecoder.cpp (not an MFC file)
- str = ::strVARIANT( var );
-
- // Add field value to list control
- if (0 == c ) //First item in row so we need to use InsertItem
- lstctrl.InsertItem( r, ( LPCTSTR ) str );
- else //row exists, so we use SetItemText
- lstctrl.SetItemText( r, c, ( LPCTSTR ) str );
- } //End this record
-
- if ( pstrCriteria ) //We're passed a criteria string
- {
- //Try to find another record, if not found then
- if ( ! m_pRecordset->FindNext( ( LPCTSTR ) * pstrCriteria ) )
- break; //stop the looping on rows of data
- }
- else //No criteria, so we just take the next record
- m_pRecordset->MoveNext( );
- }
- if ( m_pRecordset->IsEOF( ) )
- m_pRecordset->MoveLast( ); //Leave cursor on a record
- }
- catch( CException* ex )
- {
- ex->ReportError( );
- ex->Delete( );
- }
- }
-
- void CDataView::OnPageDown()
- {
- // TODO: Add your command handler code here
- try
- {
- if ( m_pRecordset->IsBOF( ) ) //If past the top on a previous move
- m_pRecordset->MoveFirst( ); //move to the first record
- LoadData( ); //Start loading from current position
- }
- catch ( CException * ex )
- {
- ex->ReportError( );
- ex->Delete( );
- }
- }
-
- void CDataView::OnPageFirst()
- {
- // TODO: Add your command handler code here
- try
- {
- m_pRecordset->MoveFirst( );
- LoadData( ) ;
- }
- catch ( CException * ex )
- {
- ex->ReportError( );
- ex->Delete( );
- }
- }
-
- void CDataView::OnPageLast()
- {
- // TODO: Add your command handler code here
-
- CListCtrl & lstctrl = GetListCtrl( ); //The view's list control
- int rows = lstctrl.GetCountPerPage( ); //How many rows can fit on the page
-
- try
- {
- m_pRecordset->MoveLast( );
- m_pRecordset->Move( 1 - rows ); //Show a full page
- if ( m_pRecordset->IsBOF( ) ) //Small table
- m_pRecordset->MoveFirst( );
- LoadData( ) ;
- }
- catch ( CException * ex )
- {
- ex->ReportError( );
- ex->Delete( );
- }
- }
-
- void CDataView::OnPageUp()
- {
- // TODO: Add your command handler code here
-
- CListCtrl & lstctrl = GetListCtrl( ); //The view's list control
- int rows = lstctrl.GetCountPerPage( ); //How many rows in list
- int items = lstctrl.GetItemCount( ); //Items actually displayed
-
- try
- { //From bottom of current page to top of previous page
- m_pRecordset->MoveNext( );
- if ( m_pRecordset->IsEOF( ) ) //Show last page if at EOF
- m_pRecordset->Move( - rows - items );
- else //Go past current page to top of preceeding page
- m_pRecordset->Move( - 2 * rows );
-
- if ( m_pRecordset->IsBOF( ) ) //Easy to do on small table
- m_pRecordset->MoveFirst( );
-
- LoadData( ) ;
- }
- catch ( CException * ex )
- {
- ex->ReportError( );
- ex->Delete( );
- }
- }
-
- void CDataView::OnColumnclick(NMHDR* pNMHDR, LRESULT* pResult)
- {
- NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
- // TODO: Add your control notification handler code here
-
- //The listview tries to read the dialog's first message, so we
- //post a message to give the listview time to finish its
- //processing. This is a work-around.
- PostMessage( USERMSG_HEADCLICK, (UINT) pNMHDR );
-
- * pResult = 0;
- }
-
- //Message handler to get message sent by CDataView::OnColumnclick
- long CDataView::OnHeadClick( UINT uP, long )
-
- {
- NM_LISTVIEW * pNMListView = ( NM_LISTVIEW * ) uP;
-
- CListCtrl & lstctrl = GetListCtrl( ); //View's list control
- char caFieldName[100]; //Buffer to hold field name
-
- LV_COLUMN lc; //List view column information structure
- lc.mask = LVCF_TEXT; //We're after the text data member
- lc.pszText = caFieldName; //Tell the structure about the buffer
- lc.cchTextMax = sizeof caFieldName; //Tell the structure the size
-
- int column = pNMListView->iSubItem; //Find out which column was clicked
-
- if ( ! lstctrl.GetColumn( column, & lc ) ) //Ask for the information
- {
- MessageBox( "Cannot execute find" );
- return FALSE;
- }
-
- CString strField = _T( lc.pszText ); //Field name from column structure
- //_T casts negotiates ANSI and Unicode differences
- try
- {
- CFindDlg dlg;
- CDaoFieldInfo fInfo;
-
- m_pRecordset->GetFieldInfo( column, fInfo );
- BOOL bTextType = //Is the field a text or memo type?
- dbText == fInfo.m_nType || dbMemo == fInfo.m_nType;
- if ( bTextType ) //If a text or memo field set the radio button to Like
- dlg.m_nMatchType = CFindDlg::LIKE;
- else
- dlg.m_nMatchType = CFindDlg::EXACT; //Must be numeric, use Exact
-
- //If the user doesn't enter a string,
- //we reset the list to all records
- if ( IDOK == dlg.DoModal( ) )
- {
- if ( "" == dlg.m_strFind ) //Set the filter, and requery
- {
- m_pRecordset->m_strFilter = "TRUE = TRUE"; //Every record
- m_pRecordset->Requery( );
- LoadData( );
- return TRUE;
- } //End empty string criteria
-
- //Build a query string from the dialog information
- //Enclose field names in brackets [Field Name], use
- //wildcards to get LIKE and contains behavior
- //Use quotes for text criteria "Text criteria"
- //Exact: [Field Name] = "Text criteria"
- //Like: [Field Name] LIKE "Text criteria*"
- //Contains: [Field Name] LIKE "*Text criteria*"
- //Numeric: [Field Name] = 12345
-
- CString strQuery;
- switch ( dlg.m_nMatchType )
- {
- case CFindDlg::EXACT :
- if ( bTextType ) //Text needs quote delimiters
- strQuery.Format( "[%s] = \"%s\" ", strField, dlg.m_strFind );
- else //Numeric entries don't use quotes
- strQuery.Format( "[%s] = %s ", strField, dlg.m_strFind );
- break;
- case CFindDlg::LIKE : //Append an * to the search string
- strQuery.Format( "[%s] LIKE \"%s*\" ", strField, dlg.m_strFind );
- break;
- case CFindDlg::CONTAINS : //Prepend and append asterisks to the search string
- strQuery.Format( "[%s] LIKE \"*%s*\" ", strField, dlg.m_strFind );
- break;
- }
-
- if ( m_pQuery ) //We use find method to load data
- {
- FindQueryData( strQuery ); //Tries to bookmark current position
- }
- else //Use the filter string we created and requery
- {
- m_pRecordset->m_strFilter = strQuery;
- m_pRecordset->Requery( );
- LoadData( );
- }
-
- return TRUE;
- } //End if IDOK
- }
- catch ( CException * ex )
- {
- ex->ReportError( );
- ex->Delete( );
- }
- return FALSE;
- }
-
- //Determine whether the select query requires any parameters. If so,
- //determine the parameter names and types, and get them from user
- void CDataView::SetParams( CDaoQueryDef * pQDef )
- {
- try
- {
- int paramCount = pQDef->GetParameterCount( );
- if ( 0 == paramCount )
- return; //Nothing to do
-
- CDaoParameterInfo daoInfo; //Information structure
- CQueryDlg dlg; //Dialog to fetch parameter values
-
- for ( int i = 0 ; i < paramCount; i ++ ) //Get the params
- {
- pQDef->GetParameterInfo( i, daoInfo );
- dlg.m_strParamName = daoInfo.m_strName; //Show the param name in the dialog
- //In this section we create variants from the user's entry
- if ( IDOK == dlg.DoModal( ) ) //Show the dialog
- {
- if ( dbDate == daoInfo.m_nType ) //If a date parameter
- {
- COleVariant var ( dlg.m_strParamValue ); //Create a variant
- COleDateTime dt ( var ); //Convert variant to COleDateTime
- pQDef->SetParamValue( i, dt ); //Set date param
- }
- else
- { //See article Q140599 regarding the casts
- COleVariant var ( _T( dlg.m_strParamValue ), VT_BSTRT );
- pQDef->SetParamValue( i, var );
- }
- }
- }
- }
- catch ( CException * ex )
- {
- ex->ReportError( );
- ex->Delete( );
- }
- }
-
- void CDataView::FindQueryData( CString & strCriteria )
- {
- CListCtrl & lstctrl = GetListCtrl( ); //The view's list control
- try
- {
- COleVariant varBookmark;
-
- int rows = lstctrl.GetItemCount( ); //How many items in list
- if ( m_pRecordset->CanBookmark( ) ) //If we can, we get a bookmark
- {
- m_pRecordset->Move( - rows ); //Move to top item in list
- if ( m_pRecordset->IsBOF( ) ) //Too far for a bookmark?
- m_pRecordset->MoveFirst( );
- varBookmark = m_pRecordset->GetBookmark( );
- m_pRecordset->Move( rows ); //Start search from original location
- }
- if ( m_pRecordset->FindNext( strCriteria ) ) //Found it!
- LoadData( & strCriteria ); //Load a page of found items
- else //we didn't find a record
- {
- if ( m_pRecordset->CanBookmark( ) ) //We have a mark
- m_pRecordset->SetBookmark( varBookmark ); //so we go to start
- else
- m_pRecordset->MoveFirst( ); //If no mark, go to the top
-
- MessageBox( "Record not found" );
- LoadData( ); //Bookmark or no, fill the list
- }
- }
- catch ( CException * ex )
- {
- ex->ReportError( );
- ex->Delete( );
- }
- }
-