home *** CD-ROM | disk | FTP | other *** search
/ Mastering MFC Development / MMD.ISO / labs / c10 / lab01 / ex01 / dataview.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-20  |  12.4 KB  |  466 lines

  1. // DataView.cpp : implementation file
  2. //
  3.  
  4. #include "stdafx.h"
  5. #include "Browser.h"
  6. #include "DataView.h"
  7. #include "BrowserDoc.h"
  8. #include "Mainfrm.h"
  9. #include "ChildFrm.h"
  10. #include "VarDecoder.h"
  11. #include "FindDlg.h"
  12. #include "QueryDlg.h"
  13.  
  14. #ifdef _DEBUG
  15. #define new DEBUG_NEW
  16. #undef THIS_FILE
  17. static char THIS_FILE[] = __FILE__;
  18. #endif
  19.  
  20. #define USERMSG_HEADCLICK WM_USER + 1     //To solve problem with LVN_COLUMNCLICK
  21.  
  22. /////////////////////////////////////////////////////////////////////////////
  23. // CDataView
  24.  
  25. IMPLEMENT_DYNCREATE(CDataView, CListView)
  26.  
  27. CDataView::CDataView()
  28.     : m_pDB( NULL ), m_pQuery( NULL ), 
  29.     m_pRecordset( NULL ), m_pTable( NULL )
  30.  
  31. {
  32. }
  33.  
  34. CDataView::~CDataView()
  35. {
  36.     try
  37.     {
  38.         if ( m_pRecordset )           //No check for dirty records
  39.             m_pRecordset->Close( );    //This is just a browser
  40.         if ( m_pQuery )
  41.             m_pQuery->Close( );
  42.         if ( m_pTable )
  43.             m_pTable->Close( );
  44.     }
  45.     catch ( CException* ex )
  46.     {
  47.         ex->ReportError( );
  48.         ex->Delete( );
  49.     }
  50.     delete m_pRecordset;   //Release the memory regardless 
  51.     delete m_pQuery;        //of other problems
  52.     delete m_pTable;
  53. }
  54.  
  55.  
  56. BEGIN_MESSAGE_MAP(CDataView, CListView)
  57.     //{{AFX_MSG_MAP(CDataView)
  58.     ON_COMMAND(ID_PAGE_DOWN, OnPageDown)
  59.     ON_COMMAND(ID_PAGE_FIRST, OnPageFirst)
  60.     ON_COMMAND(ID_PAGE_LAST, OnPageLast)
  61.     ON_COMMAND(ID_PAGE_UP, OnPageUp)
  62.     ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnclick)
  63.     //}}AFX_MSG_MAP
  64.     ON_MESSAGE( USERMSG_HEADCLICK, OnHeadClick )
  65. END_MESSAGE_MAP()
  66.  
  67. /////////////////////////////////////////////////////////////////////////////
  68. // CDataView drawing
  69.  
  70. void CDataView::OnDraw(CDC* pDC)
  71. {
  72.     CDocument* pDoc = GetDocument();
  73.     // TODO: add draw code here
  74. }
  75.  
  76. /////////////////////////////////////////////////////////////////////////////
  77. // CDataView diagnostics
  78.  
  79. #ifdef _DEBUG
  80. void CDataView::AssertValid() const
  81. {
  82.     CListView::AssertValid();
  83. }
  84.  
  85. void CDataView::Dump(CDumpContext& dc) const
  86. {
  87.     CListView::Dump(dc);
  88. }
  89. #endif //_DEBUG
  90.  
  91. /////////////////////////////////////////////////////////////////////////////
  92. // CDataView message handlers
  93.  
  94. BOOL CDataView::PreCreateWindow(CREATESTRUCT& cs) 
  95. {
  96.     // TODO: Add your specialized code here and/or call the base class
  97.  
  98.     return CListView::PreCreateWindow(cs);
  99. }
  100.  
  101. //Function receives a pointer to the CDaoDatabase object, table or query name
  102. //and whether it is a table or a query.  If a query, it calls a function to
  103. //get any parameters.  Then it opens recordset.  
  104. BOOL CDataView::SetData( CDaoDatabase * pDB, const CString & name, const int nType )
  105. {     
  106.     //In place for exercise 1
  107.     if ( TRUE /*exercise 1*/ ) return FALSE;//remove for exercise 2
  108.  
  109.     //Set database and table names as title bar
  110.     CString str = GetDocument( )->GetTitle( );
  111.     ( ( CChildFrame * ) GetParentFrame( ) )
  112.         ->m_strCaption = str + ": " + name;     //Store database: tablename
  113.   
  114.     m_pDB = pDB;  //Store database pointer in view CDataView::m_pDB
  115.  
  116.     try
  117.     {
  118.         //Code for exercise 2 goes here
  119.     }    //End try block
  120.     catch ( CException * ex )
  121.     {
  122.         ex->ReportError( );
  123.         ex->Delete( );
  124.         delete m_pTable;  //Clean up mess
  125.         delete m_pRecordset;
  126.         delete m_pQuery;
  127.         m_pTable = NULL;  
  128.         m_pRecordset = NULL;
  129.         m_pQuery = NULL;
  130.  
  131.         return FALSE;
  132.     }
  133.  
  134.     LoadHeaders( ); //Fill in the view's column headers
  135.     LoadData( );    //Load the report view rows
  136.  
  137.     return TRUE;
  138. }
  139.  
  140. CBrowserDoc  * CDataView::GetDocument( )
  141. {
  142.     return ( CBrowserDoc * ) m_pDocument; //Cast to correct pointer type
  143. }
  144.  
  145. void CDataView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView) 
  146. {
  147.     // TODO: Add your specialized code here and/or call the base class
  148.  
  149.     CMainFrame * pFrame = ( CMainFrame * ) AfxGetMainWnd( );
  150.     
  151.     if ( bActivate )      //This view is activated so we load its toolbar
  152.         pFrame->m_wndToolBar.LoadToolBar(IDR_DATATYPE);
  153.     else if ( pFrame == ( CMainFrame * ) pActivateView ) //Load mainframe toolbar
  154.         pFrame->m_wndToolBar.LoadToolBar(IDR_MAINFRAME); //if mainframe activates
  155.     pFrame->RecalcLayout( );  //Compute client area
  156.  
  157.     CListView::OnActivateView(bActivate, pActivateView, pDeactiveView);
  158. }
  159.  
  160. void CDataView::LoadHeaders( )
  161. {
  162.     CListCtrl & lstctrl = GetListCtrl( );  //Get view's list control
  163.     
  164.     lstctrl.DeleteAllItems( );  //Clean it out
  165.  
  166.     //Make the column headers
  167.     
  168.     lstctrl.CWnd::ModifyStyle( NULL, LVS_REPORT ); //Set for report view
  169.     
  170.     try
  171.     {
  172.         int width;    //Width of fieldname text
  173.         int align;    //Alignment style (left, center, right)
  174.         CDaoFieldInfo fInfo;   //Structure of field information
  175.         
  176.         int columns = m_pRecordset->GetFieldCount( );  //How many fields
  177.         for ( int i = 0 ; i < columns ; i ++ )
  178.         {
  179.             m_pRecordset->GetFieldInfo( i, fInfo );    
  180.             //Align text and memo fields to the left, others to the right
  181.             align =        
  182.                 dbText == fInfo.m_nType || dbMemo == fInfo.m_nType
  183.                 ? LVCFMT_LEFT : LVCFMT_RIGHT;
  184.             width = lstctrl.GetStringWidth( fInfo.m_strName );
  185.             //Make the column twice the label width
  186.             lstctrl.InsertColumn( i, fInfo.m_strName, align, 2 * width );
  187.         }
  188.     }
  189.     catch( CException * ex )
  190.     {
  191.         ex->ReportError( );
  192.         ex->Delete( );
  193.     }
  194. }
  195.  
  196.  
  197. //Fill list view with data.  If a non-null pointer is passed to the
  198. //function, use CDaoRecordset::FindNext to locate data, otherwise use
  199. //CDaoRecordset::MoveNext
  200.  
  201. void CDataView::LoadData( CString * pstrCriteria )
  202. {
  203.     CListCtrl & lstctrl = GetListCtrl( );  //The view's list control
  204.     lstctrl.DeleteAllItems( );  //Clean it out
  205.     
  206.     int rows = lstctrl.GetCountPerPage( ); //How many rows can fit on the page
  207.  
  208.     try
  209.     {
  210.         //Code for exercise 3 goes here
  211.     }
  212.     catch( CException* ex )
  213.     {
  214.         ex->ReportError( );
  215.         ex->Delete( );
  216.     }
  217. }
  218.  
  219. void CDataView::OnPageDown() 
  220. {
  221.     // TODO: Add your command handler code here
  222.     try 
  223.     {
  224.         if ( m_pRecordset->IsBOF( ) )  //If past the top on a previous move
  225.             m_pRecordset->MoveFirst( );    //move to the first record
  226.         LoadData( );  //Start loading from current position
  227.     }
  228.     catch ( CException * ex )
  229.     {
  230.         ex->ReportError( );
  231.         ex->Delete( );
  232.     }
  233. }
  234.  
  235. void CDataView::OnPageFirst() 
  236. {
  237.     // TODO: Add your command handler code here
  238.     try 
  239.     {
  240.         m_pRecordset->MoveFirst( );
  241.         LoadData( ) ;
  242.     }
  243.     catch ( CException * ex )
  244.     {
  245.         ex->ReportError( );
  246.         ex->Delete( );
  247.     }
  248. }
  249.  
  250. void CDataView::OnPageLast() 
  251. {
  252.     // TODO: Add your command handler code here
  253.     
  254.     CListCtrl & lstctrl = GetListCtrl( );  //The view's list control
  255.     int rows = lstctrl.GetCountPerPage( ); //How many rows can fit on the page
  256.     
  257.     try 
  258.     {
  259.         m_pRecordset->MoveLast( );
  260.         m_pRecordset->Move( 1 - rows );     //Show a full page
  261.         if ( m_pRecordset->IsBOF( ) )      //Small table
  262.             m_pRecordset->MoveFirst( );
  263.         LoadData( ) ;
  264.     }
  265.     catch ( CException * ex )
  266.     {
  267.         ex->ReportError( );
  268.         ex->Delete( );
  269.     }
  270. }
  271.  
  272. void CDataView::OnPageUp()                                 
  273. {
  274.     // TODO: Add your command handler code here
  275.  
  276.     CListCtrl & lstctrl = GetListCtrl( );    //The view's list control
  277.     int rows = lstctrl.GetCountPerPage( );    //How many rows in list
  278.     int items = lstctrl.GetItemCount( );    //Items actually displayed
  279.  
  280.     try 
  281.     {    //From bottom of current page to top of previous page
  282.         m_pRecordset->MoveNext( );
  283.         if ( m_pRecordset->IsEOF( ) ) //Show last page if at EOF
  284.             m_pRecordset->Move( - rows - items );
  285.         else  //Go past current page to top of preceeding page
  286.             m_pRecordset->Move( - 2 * rows );
  287.         
  288.         if ( m_pRecordset->IsBOF( ) )  //Easy to do on small table
  289.             m_pRecordset->MoveFirst( );
  290.     
  291.         LoadData( ) ;
  292.     }
  293.     catch ( CException * ex )
  294.     {
  295.         ex->ReportError( );
  296.         ex->Delete( );
  297.     }    
  298. }
  299.  
  300. void CDataView::OnColumnclick(NMHDR* pNMHDR, LRESULT* pResult) 
  301. {
  302.     NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
  303.     // TODO: Add your control notification handler code here
  304.     
  305.     //The listview tries to read the dialog's first message, so we
  306.     //post a message to give the listview time to finish its
  307.     //processing.  This is a work-around.
  308.     PostMessage( USERMSG_HEADCLICK, (UINT) pNMHDR );
  309.     
  310.     * pResult = 0;
  311. }
  312.  
  313. //Message handler to get message sent by CDataView::OnColumnclick
  314. long CDataView::OnHeadClick( UINT uP, long )
  315.  
  316. {
  317.     NM_LISTVIEW * pNMListView = ( NM_LISTVIEW * ) uP;
  318.  
  319.     CListCtrl & lstctrl = GetListCtrl( );  //View's list control
  320.     char caFieldName[100];    //Buffer to hold field name
  321.  
  322.     LV_COLUMN lc;            //List view column information structure                 
  323.     lc.mask = LVCF_TEXT;    //We're after the text data member
  324.     lc.pszText = caFieldName;  //Tell the structure about the buffer
  325.     lc.cchTextMax = sizeof caFieldName;    //Tell the structure the size
  326.  
  327.     int column = pNMListView->iSubItem;    //Find out which column was clicked
  328.  
  329.     if ( ! lstctrl.GetColumn( column, & lc ) )    //Ask for the information
  330.     {
  331.         MessageBox( "Cannot execute find" ); 
  332.         return FALSE;
  333.     }
  334.  
  335.      CString strField = _T( lc.pszText ); //Field name from column structure
  336.                         //_T casts negotiates ANSI and Unicode differences
  337.     try
  338.     {                                                
  339.         CFindDlg dlg;
  340.         CDaoFieldInfo fInfo;
  341.  
  342.         m_pRecordset->GetFieldInfo( column, fInfo );
  343.         BOOL bTextType =           //Is the field a text or memo type?
  344.             dbText == fInfo.m_nType || dbMemo == fInfo.m_nType;
  345.         if ( bTextType ) //If a text or memo field set the radio button to Like
  346.             dlg.m_nMatchType = CFindDlg::LIKE;  
  347.         else
  348.             dlg.m_nMatchType = CFindDlg::EXACT; //Must be numeric, use Exact
  349.  
  350.         //If the user doesn't enter a string, 
  351.         //we reset the list to all records
  352.         if ( IDOK == dlg.DoModal( ) )
  353.         {
  354.             if ( "" == dlg.m_strFind )    //Set the filter, and requery
  355.             {
  356.                 m_pRecordset->m_strFilter = "TRUE = TRUE"; //Every record
  357.                 m_pRecordset->Requery( );
  358.                 LoadData( );
  359.                 return TRUE;
  360.             } //End empty string criteria
  361.  
  362.             //Build a query string from the dialog information
  363.             //Enclose field names in brackets [Field Name], use
  364.             //wildcards to get LIKE and contains behavior
  365.             //Use quotes for text criteria "Text criteria"
  366.             //Exact:    [Field Name] = "Text criteria"
  367.             //Like:        [Field Name] LIKE "Text criteria*"
  368.             //Contains:    [Field Name] LIKE "*Text criteria*"
  369.             //Numeric:    [Field Name] = 12345
  370.  
  371.             CString strQuery;    
  372.             switch ( dlg.m_nMatchType )
  373.             {
  374.             case CFindDlg::EXACT :
  375.                 if ( bTextType ) //Text needs quote delimiters
  376.                     strQuery.Format( "[%s] = \"%s\" ", strField, dlg.m_strFind );
  377.                 else   //Numeric entries don't use quotes
  378.                      strQuery.Format( "[%s] = %s ", strField, dlg.m_strFind ); 
  379.                 break;
  380.             case CFindDlg::LIKE :  //Append an * to the search string
  381.                     strQuery.Format( "[%s] LIKE \"%s*\" ", strField, dlg.m_strFind );
  382.                 break;
  383.             case CFindDlg::CONTAINS :  //Prepend and append asterisks to the search string
  384.                     strQuery.Format( "[%s] LIKE \"*%s*\" ", strField, dlg.m_strFind );
  385.                 break;
  386.             }
  387.  
  388.             if ( m_pQuery )  //We use find method to load data
  389.             {
  390.                 FindQueryData( strQuery ); //Tries to bookmark current position
  391.             }
  392.             else  //Use the filter string we created and requery
  393.             {
  394.                 m_pRecordset->m_strFilter = strQuery; 
  395.                 m_pRecordset->Requery( );
  396.                 LoadData( );
  397.             }
  398.         
  399.             return TRUE;
  400.         }  //End if IDOK 
  401.     }
  402.     catch ( CException * ex )
  403.     {
  404.         ex->ReportError( );
  405.         ex->Delete( );
  406.     }
  407.     return FALSE;
  408. }
  409.  
  410. //Determine whether the select query requires any parameters.  If so,
  411. //determine the parameter names and types, and get them from user
  412. void CDataView::SetParams( CDaoQueryDef * pQDef )
  413. {
  414.     try
  415.     {
  416.         int paramCount = pQDef->GetParameterCount( );
  417.         if ( 0 == paramCount )
  418.             return;   //Nothing to do
  419.         
  420.         CDaoParameterInfo daoInfo;  //Information structure
  421.         CQueryDlg dlg;   //Dialog to fetch parameter values
  422.  
  423.         for ( int i = 0 ; i < paramCount; i ++ ) //Get the params
  424.         {
  425.             pQDef->GetParameterInfo( i, daoInfo );
  426.             dlg.m_strParamName = daoInfo.m_strName;  //Show the param name in the dialog
  427.             //In this section we create variants from the user's entry
  428.             if ( IDOK == dlg.DoModal( ) )  //Show the dialog
  429.             {
  430.                 if ( dbDate == daoInfo.m_nType ) //If a date parameter
  431.                 {
  432.                     COleVariant var ( dlg.m_strParamValue ); //Create a variant
  433.                     COleDateTime dt ( var );        //Convert variant to COleDateTime
  434.                     pQDef->SetParamValue( i, dt );    //Set date param
  435.                 }
  436.                 else    
  437.                 {        //See article Q140599 regarding the casts
  438.                     COleVariant var ( _T( dlg.m_strParamValue ), VT_BSTRT );
  439.                     pQDef->SetParamValue( i, var );
  440.                 }
  441.             }
  442.         }
  443.     }
  444.     catch ( CException * ex )
  445.     {
  446.         ex->ReportError( );
  447.         ex->Delete( );
  448.     }    
  449. }
  450.  
  451. void CDataView::FindQueryData( CString & strCriteria )
  452. {
  453.     CListCtrl & lstctrl = GetListCtrl( );  //The view's list control
  454.     
  455.     try
  456.     {
  457.     //Code for exercise 4 goes in this block
  458.  
  459.     }
  460.     catch ( CException * ex )
  461.     {
  462.         ex->ReportError( );
  463.         ex->Delete( );
  464.     }    
  465. }
  466.