"Fossies" - the Fresh Open Source Software Archive

Member "erltools/pub/cplusplu/test/toto" (25 Jul 1999, 33992 Bytes) of package /linux/misc/old/erltools-4.0.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 // view.cpp : Defines the behaviors for the application and frame window.   
    2 //   
    3 // This is a part of the Microsoft Foundation Classes C++ library.   
    4 // Copyright (C) 1992 Microsoft Corporation   
    5 // All rights reserved.   
    6 //   
    7 // This source code is only intended as a supplement to the   
    8 // Microsoft Foundation Classes Reference and Microsoft   
    9 // QuickHelp documentation provided with the library.   
   10 // See these sources for detailed information regarding the   
   11 // Microsoft Foundation Classes product.   
   12 #include <afxwin.h>
   13 #include "resource.h"
   14 #include "database.h"
   15 #include "view.h"
   16 #include <commdlg.h>
   17 
   18 #define SIZESTRING 256
   19 #define SIZENAME 30
   20 #define SIZEPHONE 26
   21 #define PAGESIZE 8
   22 
   23 // a simple way to reduce size of C runtimes   
   24 // disables the use of getenv and argv/argc   
   25 extern "C" 
   26 
   27 void _setargv () {}
   28 
   29 extern "C" 
   30 
   31 void _setenvp () {}
   32 
   33 /////////////////////////////////////////////////////////////////////////////   
   34 // Create the single global instance of the database viewer app.   
   35 CTheApp PersonApp ;
   36 
   37 /////////////////////////////////////////////////////////////////////////////   
   38 // CTheApp   
   39 //////////////////////////////////////////////////   
   40 //  CtheApp::InitInstance   
   41 //  Override InitInstance function to create a CMainWindow object   
   42 //  and display it on the screen   
   43 //   
   44 
   45 BOOL CTheApp::InitInstance ()
   46 {
   47     m_pMainWnd = new CMainWindow ;
   48     m_pMainWnd -> ShowWindow(m_nCmdShow);
   49     m_pMainWnd -> UpdateWindow();
   50     return TRUE ;
   51 }
   52 
   53 /////////////////////////////////////////////////////////////////////////////   
   54 // CFindDialog   
   55 //////////////////////////////////////////////////   
   56 //  CFindDialog::OnOK   
   57 //  When the user hits OK get the data entered and store it in this   
   58 //  object.  Then end the dialog.   
   59 //   
   60 
   61 void CFindDialog::OnOK ()
   62 {
   63     GetDlgItemText(IDC_DATA, m_szFindName.GetBuffer(SIZESTRING), SIZESTRING);
   64     m_szFindName.ReleaseBuffer();
   65     EndDialog(IDOK);
   66 }
   67 
   68 /////////////////////////////////////////////////////////////////////////////   
   69 // CEditPerson   
   70 //////////////////////////////////////////////////   
   71 //  CEditDialog::OnInitDialog   
   72 //  Fill in the fields witht the data placed in this object   
   73 //  when it was created.   
   74 //   
   75 
   76 BOOL CEditDialog::OnInitDialog ()
   77 {
   78     SetDlgItemText(IDC_LASTNAME, m_pData -> GetLastName());
   79     SetDlgItemText(IDC_FIRSTNAME, m_pData -> GetFirstName());
   80     SetDlgItemText(IDC_PHONE, m_pData -> GetPhoneNumber());
   81     SetDlgItemText(IDC_MOD
   82                     , m_pData -> GetModTime().Format("%m/%d/%y %H:%M"));
   83     SendDlgItemMessage(IDC_LASTNAME, EM_SETSEL);
   84     return TRUE ;
   85 }
   86 
   87 //////////////////////////////////////////////////   
   88 //  CEditDialog::OnOK   
   89 //  When OK is pressed set the data to what the user has entered.   
   90 //   
   91 
   92 void CEditDialog::OnOK ()
   93 {
   94     char    szTmp [SIZESTRING];
   95     
   96     GetDlgItemText(IDC_LASTNAME, szTmp, sizeof(((szTmp))));
   97     m_pData -> SetLastName(szTmp);
   98     GetDlgItemText(IDC_FIRSTNAME, szTmp, sizeof(((szTmp))));
   99     m_pData -> SetFirstName(szTmp);
  100     GetDlgItemText(IDC_PHONE, szTmp, sizeof(((szTmp))));
  101     m_pData -> SetPhoneNumber(szTmp);
  102     EndDialog(IDOK);
  103 }
  104 
  105 /////////////////////////////////////////////////////////////////////////////   
  106 // CMainWindow   
  107 BEGIN_MESSAGE_MAP(CMainWindow, CFrameWnd)
  108     
  109     // File menu commands:   
  110     ON_COMMAND(IDM_NEW, OnNew)
  111     ON_COMMAND(IDM_OPEN, OnOpen)
  112     ON_COMMAND(IDM_SAVE, OnSave)
  113     ON_COMMAND(IDM_SAVEAS, OnSaveAs)
  114     ON_COMMAND(IDM_CLOSE, OnDBClose)
  115     ON_COMMAND(IDM_PRINT, OnPrint)
  116     ON_COMMAND(IDM_EXIT, OnExit)
  117     
  118     // Person menu commands:   
  119     ON_COMMAND(IDM_ADD, OnAdd)
  120     ON_COMMAND(IDM_DELETE, OnDelete)
  121     ON_COMMAND(IDM_EDIT, OnEdit)
  122     ON_COMMAND(IDM_FIND, OnFind)
  123     ON_COMMAND(IDM_FINDALL, OnFindAll)
  124     
  125     // Help menu commands:   
  126     ON_COMMAND(IDM_HELP, OnHelp)
  127     ON_COMMAND(IDM_ABOUT, OnAbout)
  128     
  129     // Selection accelerators:   
  130     ON_COMMAND(VK_UP, OnUp)
  131     ON_COMMAND(VK_DOWN, OnDown)
  132     
  133     // Other Windows messages:   
  134     ON_WM_CREATE()
  135     ON_WM_CLOSE()
  136     ON_WM_SIZE()
  137     ON_WM_VSCROLL()
  138     ON_WM_HSCROLL()
  139     ON_WM_LBUTTONDOWN()
  140     ON_WM_LBUTTONDBLCLK()
  141     ON_WM_KEYDOWN()
  142     ON_WM_PAINT()
  143 END_MESSAGE_MAP()
  144 
  145 //////////////////////////////////////////////////   
  146 //  CMainWindow::CMainWindow   
  147 //  Constructs and initializes a CMainWindow object   
  148 //   
  149 
  150 CMainWindow::CMainWindow ()
  151 {
  152     VERIFY(LoadAccelTable("MainAccelTable"));
  153     VERIFY(Create(NULL, "Phone Book", WS_OVERLAPPEDWINDOW, rectDefault
  154                     , NULL, "MainMenu"));
  155     m_nSelectLine =  - 1 ;
  156 }
  157 
  158 /////////////////////////////////////////////////////////////////////////////   
  159 //  The Following are CMainWindow Menu Items   
  160 //////////////////////////////////////////////////   
  161 //  CMainWindow::OnNew   
  162 //  After checking to see if current data needs to be stored, call   
  163 //  database New and resize/repaint the window.   
  164 //   
  165 
  166 void CMainWindow::OnNew ()
  167 {
  168     if ( !CheckForSave("File New", "Save file before New?")) 
  169         return ;
  170     m_people.New();
  171     SetMenu();
  172     SetWindowText(m_people.GetTitle());
  173     OnSize(0, m_cxClient, m_cyClient);
  174 }
  175 
  176 //////////////////////////////////////////////////   
  177 //  CMainWindow::OnOpen   
  178 //   
  179 
  180 void CMainWindow::OnOpen ()
  181 {
  182     if ( !CheckForSave("File Open", "Save file before Open?")) 
  183         return ;
  184     
  185     // Attempt to open a database file and read it.   
  186     // If a file or archive exception occurs, catch it and   
  187     // present an error message box.   
  188     CString szFileName, szFileTitle ;
  189     
  190     TRY 
  191     {
  192         
  193         // Use CommDlg to get the file name and then call DoOpen.   
  194         // Set the Window title and menus.  Resize/Repaint.   
  195         if ( FileDlg(TRUE, SIZESTRING, szFileName.GetBuffer(SIZESTRING)
  196                         , SIZESTRING, szFileTitle.GetBuffer(SIZESTRING))) {
  197             szFileName.ReleaseBuffer();
  198             szFileTitle.ReleaseBuffer();
  199             m_people.DoOpen(szFileName);
  200             m_people.SetTitle(szFileTitle);
  201             SetWindowText(m_people.GetTitle());
  202             SetMenu();
  203             OnSize(0, m_cxClient, m_cyClient);
  204         }
  205     }
  206     CATCH(CFileException, e)
  207     {
  208         char    ErrorMsg [SIZESTRING];
  209         sprintf(ErrorMsg, "Opening %s returned a 0x%lx."
  210                     , (const char *)szFileTitle, e -> m_lOsError);
  211         MessageBox(ErrorMsg, "File Open Error");
  212     }
  213     AND_CATCH(CArchiveException, e)
  214     {
  215         char    ErrorMsg [SIZESTRING];
  216         sprintf(ErrorMsg, "Reading the %s archive failed."
  217                     , (const char *)szFileTitle);
  218         MessageBox(ErrorMsg, "File Open Error");
  219     }
  220     END_CATCH
  221 }
  222 
  223 //////////////////////////////////////////////////   
  224 //  CMainWindow::OnSave   
  225 //   
  226 
  227 void CMainWindow::OnSave ()
  228 {
  229     Save(m_people.IsNamed());
  230 }
  231 
  232 //////////////////////////////////////////////////   
  233 //  CMainWindow::OnSaveAs   
  234 //   
  235 
  236 void CMainWindow::OnSaveAs ()
  237 {
  238     Save();
  239 }
  240 
  241 //////////////////////////////////////////////////   
  242 //  CMainWindow::OnDBClose   
  243 //  Closes the current database, checking to see if it should be   
  244 //  saved first.  Reset the window title and the scroll regions.   
  245 //  Invalidating the entire screen causes OnPaint to repaint but   
  246 //  this time without any data.   
  247 //   
  248 
  249 void CMainWindow::OnDBClose ()
  250 {
  251     if ( !CheckForSave("File Close", "Save file before closing?")) 
  252         return ;
  253     m_people.Terminate();
  254     SetWindowText("Phone Book");
  255     SetMenu();
  256     OnSize(0, m_cxClient, m_cyClient);
  257 }
  258 
  259 //////////////////////////////////////////////////   
  260 //  CMainWindow::OnPrint   
  261 //  Uses the commdlg print dialog to create a printer dc   
  262 //  Then it uses code almost identical to the OnPaint code   
  263 //  to write the data to the printer.   
  264 //   
  265 
  266 void CMainWindow::OnPrint ()
  267 {
  268     PRINTDLG    pd ;
  269     
  270     pd.lStructSize = sizeof(((PRINTDLG)));
  271     pd.hwndOwner = m_hWnd ;
  272     pd.hDevMode = (HANDLE)NULL ;
  273     pd.hDevNames = (HANDLE)NULL ;
  274     pd.Flags = PD_RETURNDC | PD_NOSELECTION | PD_NOPAGENUMS ;
  275     pd.nFromPage = 0 ;
  276     pd.nToPage = 0 ;
  277     pd.nMinPage = 0 ;
  278     pd.nMaxPage = 0 ;
  279     pd.nCopies = 1 ;
  280     pd.hInstance = (HINSTANCE)NULL ;
  281     if ( PrintDlg(&pd) != 0 ) {
  282         
  283         // CommDlg returned a DC so create a CDC object from it.   
  284         ASSERT(pd.hDC != 0);
  285         CDC *dc ;
  286         dc = CDC::FromHandle(pd.hDC);
  287         
  288         // Change to hour glass while printing   
  289         SetCursor(AfxGetApp() -> LoadStandardCursor(IDC_WAIT));
  290         
  291         // Begin printing the document.   
  292         int rc ;
  293         char    szError [SIZESTRING];
  294         rc = dc -> StartDoc("Phone Book");
  295         if ( rc < 0 ) {
  296             sprintf(szError, "Unable to Begin printing - Error[%d]", rc);
  297             MessageBox(szError, NULL, MB_OK);
  298             return ;
  299         }
  300         int x, y ;
  301         CPerson *pCurrent ;
  302         int nPerson = 0 ;
  303         CString szDisplay ;
  304         int nStart, nEnd ;
  305         
  306         // Get Height and Width of large character   
  307         CSize   extentChar = dc -> GetTextExtent("M", 1);
  308         int nCharHeight = extentChar.cy ;
  309         int nCharWidth = extentChar.cx ;
  310         
  311         // Get Page size in # of full lines   
  312         int nExtPage
  313                  = (dc -> GetDeviceCaps(VERTRES) - nCharHeight)
  314                      / nCharHeight ;
  315         CString szTitle ;
  316         szTitle = CString("Phone Book - ") + m_people.GetName();
  317         while ( nPerson != m_people.GetCount()) {
  318             
  319             // Print a Page Header   
  320             dc -> StartPage();
  321             dc -> SetTextAlign(TA_LEFT | TA_TOP);
  322             dc -> TextOut(0, 0, szTitle, szTitle.GetLength());
  323             dc -> MoveTo(0, nCharHeight);
  324             dc -> LineTo(dc -> GetTextExtent(szTitle, szTitle.GetLength())
  325                                 .cx
  326                             , nCharHeight);
  327             
  328             // Print People from start to last person or page size minus   
  329             // 2 ( header size )   
  330             nEnd = min(m_people.GetCount() - nPerson, nExtPage - 2);
  331             for ( nStart = 0 ; nStart < nEnd ; nStart++, nPerson++ ) {
  332                 x = 0 ;
  333                 y = nCharHeight * (nStart + 2);
  334                 pCurrent = m_people.GetPerson(nPerson);
  335                 szDisplay = " " + pCurrent -> GetLastName() + ", "
  336                      + pCurrent -> GetFirstName();
  337                 dc -> SetTextAlign(TA_LEFT | TA_TOP);
  338                 dc -> TextOut(x, y, szDisplay, szDisplay.GetLength());
  339                 szDisplay = pCurrent -> GetPhoneNumber();
  340                 dc -> SetTextAlign(TA_RIGHT | TA_TOP);
  341                 dc -> TextOut(x + SIZENAME * nCharWidth, y, szDisplay
  342                                 , szDisplay.GetLength());
  343                 szDisplay = pCurrent -> GetModTime().Format("%m/%d/%y %H:%M");
  344                 dc -> TextOut(x + (SIZENAME + SIZEPHONE) * nCharWidth, y
  345                                 , szDisplay, szDisplay.GetLength());
  346             }
  347             dc -> EndPage();
  348         }
  349         dc -> EndDoc();
  350         dc -> DeleteDC();
  351         SetCursor(AfxGetApp() -> LoadStandardCursor(IDC_ARROW));
  352     }
  353 }
  354 
  355 //////////////////////////////////////////////////   
  356 //  CMainWindow::OnExit   
  357 //   
  358 
  359 void CMainWindow::OnExit ()
  360 {
  361     OnClose();
  362 }
  363 
  364 //////////////////////////////////////////////////   
  365 //  CMainWindow::OnAdd   
  366 //  Using the EditDialog fill in a new person object.  If the user   
  367 //  selects OK then add the person, call OnSize to resize the scroll   
  368 //  region, and invalidate the screen so it will be redrawn with the   
  369 //  new person in the correct order.   
  370 //   
  371 
  372 void CMainWindow::OnAdd ()
  373 {
  374     CPerson *person = new CPerson ;
  375     CEditDialog dlgAdd (person, this) ;
  376     
  377     if ( dlgAdd.DoModal() == IDOK ) {
  378         m_people.AddPerson(person);
  379         OnSize(0, m_cxClient, m_cyClient);
  380     } else 
  381         delete person ;
  382 }
  383 
  384 //////////////////////////////////////////////////   
  385 //  CMainWindow::OnDelete   
  386 //  Deletes the current selection.  Check to see if the selection is   
  387 //  now past then end of the list.  Also call OnSize since the list   
  388 //  length has now changed.   
  389 //   
  390 
  391 void CMainWindow::OnDelete ()
  392 {
  393     if ( m_nSelectLine ==  - 1 ) {
  394         MessageBox("Select a person to delete first");
  395         return ;
  396     }
  397     m_people.DeletePerson(m_nSelectLine);
  398     if ( m_nSelectLine >= (int)m_people.GetCount()) 
  399         m_nSelectLine-- ;
  400     OnSize(0, m_cxClient, m_cyClient);
  401 }
  402 
  403 ////////////////////////////////////////////////////   
  404 //  CMainWindow::OnFind   
  405 //  Gets information from the CFindDialog modal dialog box, then searches for   
  406 //  matching people.  Note the Add and Delete menu items are disabled after   
  407 //  a find is made.  Find All is enabled.   
  408 //   
  409 
  410 void CMainWindow::OnFind ()
  411 {
  412     CFindDialog dlgFind (this) ;
  413     
  414     if ( dlgFind.DoModal() == IDOK
  415              && dlgFind.GetFindString().GetLength() != 0 ) {
  416         if ( m_people.DoFind(dlgFind.GetFindString())) {
  417             m_nSelectLine =  - 1 ;
  418             CString tmp ;
  419             tmp = m_people.GetTitle() + " Found: "
  420                  + dlgFind.GetFindString();
  421             SetWindowText(tmp);
  422             CMenu   *pMenu = GetMenu();
  423             pMenu -> EnableMenuItem(IDM_FINDALL, MF_ENABLED);
  424             pMenu -> EnableMenuItem(IDM_FIND, MF_GRAYED);
  425             pMenu -> EnableMenuItem(IDM_DELETE, MF_GRAYED);
  426             pMenu -> EnableMenuItem(IDM_ADD, MF_GRAYED);
  427             OnSize(0, m_cxClient, m_cyClient);
  428         } else 
  429             MessageBox("No match found in list.");
  430     }
  431 }
  432 
  433 ////////////////////////////////////////////////////   
  434 //  CMainWindow::OnFindAll   
  435 //  Returns to view the whole database.  Add, Delete are re-enabled, and   
  436 //  Find All is again disabled.  OnSize is called because the list   
  437 //  has changed length.   
  438 //   
  439 
  440 void CMainWindow::OnFindAll ()
  441 {
  442     m_people.DoFind();
  443     SetWindowText(m_people.GetTitle());
  444     
  445     CMenu   *pMenu = GetMenu();
  446     
  447     pMenu -> EnableMenuItem(IDM_FINDALL, MF_GRAYED);
  448     pMenu -> EnableMenuItem(IDM_FIND, MF_ENABLED);
  449     pMenu -> EnableMenuItem(IDM_DELETE, MF_ENABLED);
  450     pMenu -> EnableMenuItem(IDM_ADD, MF_ENABLED);
  451     OnSize(0, m_cxClient, m_cyClient);
  452 }
  453 
  454 ////////////////////////////////////////////////////   
  455 //  CMainWindow::OnEdit   
  456 //  Using the member variable m_nSelectLine a CEditDialog is created   
  457 //  and filled with the selected person.  If the dialog OK button is   
  458 //  used the dialog saves the changes into the object.   
  459 //  over any old information.   
  460 //   
  461 
  462 void CMainWindow::OnEdit ()
  463 {
  464     if ( m_nSelectLine ==  - 1 ) {
  465         MessageBox("Select a person to edit first");
  466         return ;
  467     }
  468     
  469     // Get a pointer to the person in the list.   
  470     CPerson *pPerson = m_people.GetPerson(m_nSelectLine);
  471     CPerson tmpPerson = *pPerson ;
  472     //Edit the data.   
  473     CEditDialog dlgEdit(&tmpPerson, this);
  474     
  475     //if the ok button is pressed redraw the screen   
  476     if ( dlgEdit.DoModal() == IDOK ) {
  477         m_people.ReplacePerson(pPerson, tmpPerson);
  478         InvalidateLine();
  479     }
  480 }
  481 
  482 //////////////////////////////////////////////////   
  483 //  CMainWindow::OnHelp   
  484 //   
  485 
  486 void CMainWindow::OnHelp ()
  487 {
  488     if ( !m_people.IsPresent()) {
  489         CModalDialog    dlgHelp("NoData", this);
  490         dlgHelp.DoModal();
  491         return ;
  492     }
  493     if ( !m_people.IsNamed()) {
  494         CModalDialog    dlgHelp("NoName", this);
  495         if ( dlgHelp.DoModal() == IDCANCEL ) 
  496             return ;
  497     }
  498     
  499     CModalDialog    dlgHelp("Enter", this);
  500     
  501     dlgHelp.DoModal();
  502 }
  503 
  504 //////////////////////////////////////////////////   
  505 //  CMainWindow::OnAbout   
  506 //   
  507 
  508 void CMainWindow::OnAbout ()
  509 {
  510     CModalDialog    dlgAbout("AboutBox", this);
  511     
  512     dlgAbout.DoModal();
  513 }
  514 
  515 /////////////////////////////////////////////////////////////////////////////   
  516 //  The Following are WINDOW messages   
  517 //////////////////////////////////////////////////   
  518 //  CMainWindow::OnCreate   
  519 //  Queries the current text metrics to determine char size.   
  520 //   
  521 
  522 int CMainWindow::OnCreate ( LPCREATESTRUCT )
  523 {
  524     TEXTMETRIC  tm ;
  525     
  526     // Get the text metrics.   
  527     CDC *dc = GetDC();
  528     
  529     dc -> GetTextMetrics(&tm);
  530     ReleaseDC(dc);
  531     
  532     // Decide the statistics on how many rows, etc., we can display.   
  533     m_cxChar = tm.tmAveCharWidth ;
  534     m_cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * m_cxChar / 2 ;
  535     m_cyChar = tm.tmHeight + tm.tmExternalLeading ;
  536     m_nMaxWidth = (SIZENAME + SIZEPHONE + 1) * m_cxCaps ;
  537     m_nVscrollPos = m_nHscrollPos = 0 ;
  538     return 0 ;
  539 }
  540 
  541 //////////////////////////////////////////////////   
  542 //  CMainWindow::OnClose   
  543 //  Check to see if the current file needs to be saved.  Terminate   
  544 //  the database and destory the window.   
  545 //   
  546 
  547 void CMainWindow::OnClose ()
  548 {
  549     if ( !CheckForSave("File Exit", "Save file before exit?")) 
  550         return ;
  551     m_people.Terminate();
  552     DestroyWindow();
  553 }
  554 
  555 //////////////////////////////////////////////////   
  556 //  CMainWindow::OnSize   
  557 //  When resized, we need to recalculate our scrollbar ranges based on what   
  558 //  part of the database is visible.   
  559 //   
  560 
  561 void CMainWindow::OnSize ( UINT, int x, int y )
  562 {
  563     m_cxClient = x ;
  564     m_cyClient = y ;
  565     m_nVscrollMax = max(0, (int)(m_people.GetCount())
  566                              - m_cyClient / m_cyChar);
  567     m_nVscrollPos = min(m_nVscrollPos, m_nVscrollMax);
  568     SetScrollRange(SB_VERT, 0, m_nVscrollMax, FALSE);
  569     SetScrollPos(SB_VERT, m_nVscrollPos, TRUE);
  570     m_nHscrollMax = max(0, (m_nMaxWidth - m_cxClient) / m_cxChar);
  571     m_nHscrollPos = min(m_nHscrollPos, m_nHscrollMax);
  572     SetScrollRange(SB_HORZ, 0, m_nHscrollMax, FALSE);
  573     SetScrollPos(SB_HORZ, m_nHscrollPos, TRUE);
  574     Invalidate(TRUE);
  575 }
  576 
  577 //////////////////////////////////////////////////   
  578 //  CMainWindow::OnVScroll   
  579 //  Translate scroll messages into Scroll increments and then   
  580 //  checks the current position to determine if scrolling is possible   
  581 //   
  582 
  583 void CMainWindow::OnVScroll ( UINT wParam, UINT pos, CScrollBar *)
  584 {
  585     short   nScrollInc ;
  586     
  587     switch ( wParam ) {
  588         case SB_TOP : 
  589             nScrollInc =  - m_nVscrollPos ;
  590             break ;
  591         case SB_BOTTOM : 
  592             nScrollInc = m_nVscrollMax - m_nVscrollPos ;
  593             break ;
  594         case SB_LINEUP : 
  595             nScrollInc =  - 1 ;
  596             break ;
  597         case SB_LINEDOWN : 
  598             nScrollInc = 1 ;
  599             break ;
  600         case SB_PAGEUP : 
  601             nScrollInc = min( - 1,  - m_cyClient / m_cyChar);
  602             break ;
  603         case SB_PAGEDOWN : 
  604             nScrollInc = max(1, m_cyClient / m_cyChar);
  605             break ;
  606         case SB_THUMBTRACK : 
  607             nScrollInc = pos - m_nVscrollPos ;
  608             break ;
  609         default : nScrollInc = 0 ;
  610     } 
  611     if ( nScrollInc = max( - m_nVscrollPos
  612                             , min(nScrollInc, m_nVscrollMax - m_nVscrollPos))) {
  613         m_nVscrollPos += nScrollInc ;
  614         ScrollWindow(0,  - m_cyChar * nScrollInc);
  615         SetScrollPos(SB_VERT, m_nVscrollPos);
  616         UpdateWindow();
  617     }
  618 }
  619 
  620 //////////////////////////////////////////////////   
  621 //  CMainWindow::OnHScroll   
  622 //  Translate scroll messages into Scroll increments and then   
  623 //  checks the current position to determine if scrolling is possible   
  624 //   
  625 
  626 void CMainWindow::OnHScroll ( UINT wParam, UINT pos, CScrollBar *)
  627 {
  628     int nScrollInc ;
  629     
  630     switch ( wParam ) {
  631         case SB_LINEUP : 
  632             nScrollInc =  - 1 ;
  633             break ;
  634         case SB_LINEDOWN : 
  635             nScrollInc = 1 ;
  636             break ;
  637         case SB_PAGEUP : 
  638             nScrollInc =  - PAGESIZE ;
  639             break ;
  640         case SB_PAGEDOWN : 
  641             nScrollInc = PAGESIZE ;
  642             break ;
  643         case SB_THUMBPOSITION : 
  644             nScrollInc = pos - m_nHscrollPos ;
  645             break ;
  646         default : nScrollInc = 0 ;
  647     } 
  648     if ( nScrollInc = max( - m_nHscrollPos
  649                             , min(nScrollInc, m_nHscrollMax - m_nHscrollPos))) {
  650         m_nHscrollPos += nScrollInc ;
  651         ScrollWindow( - m_cxChar * nScrollInc, 0);
  652         SetScrollPos(SB_HORZ, m_nHscrollPos);
  653         UpdateWindow();
  654     }
  655 }
  656 
  657 //////////////////////////////////////////////////   
  658 //  CMainWindow::OnUp   
  659 //  Uses Accelerator tables to link the up arrow key to this   
  660 //  routine.  Decrements the select line with checking for scrolling   
  661 //  and wrapping off the top of the list.   
  662 //   
  663 //   
  664 
  665 void CMainWindow::OnUp ()
  666 {
  667     InvalidateLine();
  668     if ( m_nSelectLine <= 0 ) {
  669         m_nSelectLine = m_people.GetCount() - 1 ;
  670         m_nVscrollPos = max(0, m_nSelectLine + 1 - m_cyClient / m_cyChar);
  671         Invalidate(TRUE);
  672     } else {
  673         m_nSelectLine-- ;
  674         if ( m_nSelectLine - m_nVscrollPos < 0 ) 
  675             OnVScroll(SB_LINEUP, 0, NULL);
  676         
  677         // Selection is off the screen   
  678         if ( m_nSelectLine - m_nVscrollPos > m_cyClient / m_cyChar ) {
  679             m_nVscrollPos = m_nSelectLine + 1 - m_cyClient / m_cyChar ;
  680             SetScrollPos(SB_VERT, m_nVscrollPos, TRUE);
  681             Invalidate(TRUE);
  682         }
  683         if ( m_nSelectLine - m_nVscrollPos < 0 ) {
  684             m_nVscrollPos = m_nSelectLine ;
  685             SetScrollPos(SB_VERT, m_nVscrollPos, TRUE);
  686             Invalidate(TRUE);
  687         }
  688     }
  689     InvalidateLine();
  690 }
  691 
  692 //////////////////////////////////////////////////   
  693 //  CMainWindow::OnDown   
  694 //  Uses Accelerator tables to link the down arrow key to this   
  695 //  routine.  Inc the select line with checking for scrolling   
  696 //  and wrapping off the bottom of the list.   
  697 //   
  698 
  699 void CMainWindow::OnDown ()
  700 {
  701     InvalidateLine();
  702     if ( m_nSelectLine == (int)(m_people.GetCount() - 1)
  703              || m_nSelectLine ==  - 1 ) {
  704         m_nSelectLine = 0 ;
  705         m_nVscrollPos = 0 ;
  706         Invalidate(TRUE);
  707     } else {
  708         m_nSelectLine++ ;
  709         if ( m_nSelectLine - m_nVscrollPos + 1 > m_cyClient / m_cyChar ) 
  710             OnVScroll(SB_LINEDOWN, 0, NULL);
  711         
  712         // Selection is off the screen   
  713         if ( m_nSelectLine - m_nVscrollPos > m_cyClient / m_cyChar ) {
  714             m_nVscrollPos = m_nSelectLine + 1 - m_cyClient / m_cyChar ;
  715             SetScrollPos(SB_VERT, m_nVscrollPos, TRUE);
  716             Invalidate(TRUE);
  717         }
  718         if ( m_nSelectLine - m_nVscrollPos < 0 ) {
  719             m_nVscrollPos = m_nSelectLine ;
  720             SetScrollPos(SB_VERT, m_nVscrollPos, TRUE);
  721             Invalidate(TRUE);
  722         }
  723     }
  724     InvalidateLine();
  725 }
  726 
  727 //////////////////////////////////////////////////   
  728 //  CMainWindow::OnLButtonDown   
  729 //  Turns the location of the mouse pointer into a line number   
  730 //  and stores that information in m_nSelectLine.  Uses   
  731 //  InvalidateLine to cause OnPaint to change the screen.   
  732 //   
  733 
  734 void CMainWindow::OnLButtonDown ( UINT, CPoint location )
  735 {
  736     InvalidateLine();
  737     
  738     int pos = m_nVscrollPos + location.y / m_cyChar ;
  739     
  740     if ( m_nSelectLine != pos && pos < (int)m_people.GetCount()) {
  741         m_nSelectLine = pos ;
  742         InvalidateLine();
  743     } else 
  744         m_nSelectLine =  - 1 ;
  745 }
  746 
  747 //////////////////////////////////////////////////   
  748 //  CMainWindow::OnLButtonDblClk   
  749 //  Translates mouse left button double click into edit person.   
  750 //   
  751 
  752 void CMainWindow::OnLButtonDblClk ( UINT wParam, CPoint location )
  753 {
  754     if ( m_nSelectLine ==  - 1 ) 
  755         OnLButtonDown(wParam, location);
  756     OnEdit();
  757 }
  758 
  759 //////////////////////////////////////////////////   
  760 //  CMainWindow::OnKeyDown   
  761 //  Translates keyboard input into scroll messages   
  762 //   
  763 
  764 void CMainWindow::OnKeyDown ( UINT wParam, UINT, UINT )
  765 {
  766     switch ( wParam ) {
  767         case VK_HOME : 
  768             OnVScroll(SB_TOP, 0, NULL);
  769             break ;
  770         case VK_END : 
  771             OnVScroll(SB_BOTTOM, 0, NULL);
  772             break ;
  773         case VK_PRIOR : 
  774             OnVScroll(SB_PAGEUP, 0, NULL);
  775             break ;
  776         case VK_NEXT : 
  777             OnVScroll(SB_PAGEDOWN, 0, NULL);
  778             break ;
  779         case VK_LEFT : 
  780             OnHScroll(SB_PAGEUP, 0, NULL);
  781             break ;
  782         case VK_RIGHT : 
  783             OnHScroll(SB_PAGEDOWN, 0, NULL);
  784             break ;
  785     } 
  786 }
  787 
  788 //////////////////////////////////////////////////   
  789 //  CMainWindow::OnPaint   
  790 //  This routine does all the painting for the screen.   
  791 //   
  792 
  793 void CMainWindow::OnPaint ()
  794 {
  795     CPaintDC    dc (this) ;
  796     
  797     // Set the Text and background colors for the DC also create a Brush   
  798     CBrush  bBack ;
  799     
  800     dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
  801     dc.SetBkColor(GetSysColor(COLOR_WINDOW));
  802     bBack.CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  803     
  804     // Compute the lines that need to be redrawn   
  805     int nStart = max(0, m_nVscrollPos + dc.m_ps.rcPaint.top / m_cyChar - 1);
  806     int nEnd = min((int)m_people.GetCount()
  807                     , m_nVscrollPos
  808                          + (dc.m_ps.rcPaint.bottom / m_cyChar + 1));
  809     
  810     // Create a rect the width of the display.   
  811     CRect   area(0, 0, m_cxClient, 0);
  812     CString szDisplay ;
  813     CPerson *pCurrent ;
  814     int x, y ;
  815     
  816     for (; nStart < nEnd ; nStart++ ) {
  817         
  818         // if the current line is the select line then change the   
  819         // colors to the highlight text colors.   
  820         if ( m_nSelectLine == nStart ) {
  821             bBack.DeleteObject();
  822             bBack.CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
  823             dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT));
  824             dc.SetBkColor(GetSysColor(COLOR_HIGHLIGHT));
  825         }
  826         
  827         // x is the number of characters horz scrolled * the width of   
  828         // char.  y is the current line no. - number of lines scrolled   
  829         // times the height of a line.   
  830         x = m_cxChar *  - m_nHscrollPos ;
  831         y = m_cyChar * (nStart - m_nVscrollPos);
  832         
  833         // Set the rect to y and y + the height of the line.  Fill the   
  834         // rect with the background color.   
  835         area.top = y ;
  836         area.bottom = y + m_cyChar ;
  837         dc.FillRect(area, &bBack);
  838         
  839         // Get the person and build a string with his name.   
  840         pCurrent = m_people.GetPerson(nStart);
  841         szDisplay = " " + pCurrent -> GetLastName() + ", "
  842              + pCurrent -> GetFirstName();
  843         
  844         // Set the dc to write using the point as the left top of the   
  845         // character.  Write the name.   
  846         dc.SetTextAlign(TA_LEFT | TA_TOP);
  847         dc.TextOut(x, y, szDisplay, szDisplay.GetLength());
  848         
  849         // Write the phone number right aligned.   
  850         szDisplay = pCurrent -> GetPhoneNumber();
  851         dc.SetTextAlign(TA_RIGHT | TA_TOP);
  852         dc.TextOut(x + SIZENAME * m_cxCaps, y, szDisplay
  853                     , szDisplay.GetLength());
  854         
  855         // Write the time.   
  856         szDisplay = pCurrent -> GetModTime().Format("%m/%d/%y %H:%M");
  857         dc.TextOut(x + (SIZENAME + SIZEPHONE) * m_cxCaps, y, szDisplay
  858                     , szDisplay.GetLength());
  859         
  860         // If this is the select line then we need to reset the dc   
  861         // colors back to the original colors.   
  862         if ( m_nSelectLine == nStart ) {
  863             bBack.DeleteObject();
  864             bBack.CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  865             dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
  866             dc.SetBkColor(GetSysColor(COLOR_WINDOW));
  867         }
  868     }
  869 }
  870 
  871 /////////////////////////////////////////////////////////////////////////////   
  872 //  The following are utility routines   
  873 //////////////////////////////////////////////////   
  874 //  CMainWindow::FileDlg   
  875 //  Call the commdlg routine to display File Open or File Save As   
  876 //  dialogs.  The setup is the same for either.  If bOpen is TRUE   
  877 //  then File Open is display otherwise File Save As is displayed.   
  878 //  The File Name and File Title are stored at the string pointer   
  879 //  passed in.   
  880 //   
  881 
  882 BOOL CMainWindow::FileDlg ( BOOL bOpen, int nMaxFile, LPSTR szFile
  883         , int nMaxFileTitle, LPSTR szFileTitle )
  884 {
  885     OPENFILENAME    of ;
  886     char    szDirName [SIZESTRING];
  887     char    szFilter [] = "Phone Book Files (*.pb)\0";
  888     
  889     szDirName [0] = '.';
  890     of.lStructSize = sizeof(((OPENFILENAME)));
  891     of.hwndOwner = m_hWnd ;
  892     of.lpstrFilter = szFilter ;
  893     of.lpstrCustomFilter = NULL ;
  894     of.nMaxCustFilter = 0L ;
  895     of.nFilterIndex = 1L ;
  896     of.lpstrFile = szFile ;
  897     of.nMaxFile = nMaxFile ;
  898     of.lpstrFileTitle = szFileTitle ;
  899     of.nMaxFileTitle = nMaxFileTitle ;
  900     of.lpstrInitialDir = szDirName ;
  901     of.lpstrTitle = NULL ;
  902     of.nFileOffset = 0 ;
  903     of.nFileExtension = 0 ;
  904     of.lpstrDefExt = "pb";
  905     if ( bOpen ) {
  906         of.Flags = OFN_HIDEREADONLY ;
  907         return GetOpenFileName(&of);
  908     } else {
  909         of.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT ;
  910         return GetSaveFileName(&of);
  911     }
  912 }
  913 
  914 //////////////////////////////////////////////////   
  915 //  CMainWindow::Save   
  916 //  Handles any time a file needs to be saved to the disk.   
  917 //  Passing in FALSE for name brings up the file save as dialog   
  918 //  whether or not the database had a name before.   
  919 //   
  920 
  921 BOOL CMainWindow::Save ( BOOL bIsNamed/* = FALSE */ )
  922 {
  923     CString szFileName, szFileTitle ;
  924     
  925     TRY 
  926     {
  927         if ( bIsNamed ) 
  928             m_people.DoSave();
  929         else {
  930             szFileName = m_people.GetName();
  931             if ( FileDlg(FALSE, SIZESTRING
  932                             , szFileName.GetBuffer(SIZESTRING), SIZESTRING
  933                             , szFileTitle.GetBuffer(SIZESTRING))) {
  934                 szFileName.ReleaseBuffer();
  935                 m_people.DoSave(szFileName);
  936                 m_people.SetTitle(szFileTitle);
  937                 SetWindowText(m_people.GetTitle());
  938             } else 
  939                 return FALSE ;
  940         }
  941     }
  942     CATCH(CFileException, e)
  943     {
  944         char    ErrorMsg [SIZESTRING];
  945         sprintf(ErrorMsg, "Saving %s returned a 0x%lx."
  946                     , (const char *)szFileTitle, e -> m_lOsError);
  947         MessageBox(ErrorMsg, "File Open Error");
  948     }
  949     AND_CATCH(CArchiveException, e)
  950     {
  951         char    ErrorMsg [SIZESTRING];
  952         sprintf(ErrorMsg, "Reading the %s archive failed."
  953                     , (const char *)szFileTitle);
  954         MessageBox(ErrorMsg, "File Open Error");
  955     }
  956     END_CATCH
  957     
  958     return TRUE ;
  959 }
  960 
  961 //////////////////////////////////////////////////   
  962 //  CMainWindow::CheckForSave   
  963 //  Whenever a new file is opened this routine will determine if   
  964 //  there are unsaved changes in the current database.  If so it   
  965 //  will query the user and determine save or not as appropriate.   
  966 //   
  967 
  968 BOOL CMainWindow::CheckForSave ( const char *pszTitle
  969         , const char *pszMessage )
  970 {
  971     if ( m_people.IsDirty()) {
  972         UINT    nButton = MessageBox(pszMessage, pszTitle, MB_YESNOCANCEL);
  973         if ( nButton == IDYES ) {
  974             if ( !Save(m_people.IsNamed())) 
  975                 return FALSE ;
  976         } else if ( nButton == IDCANCEL ) 
  977             return FALSE ;
  978     }
  979     return TRUE ;
  980 }
  981 
  982 //////////////////////////////////////////////////   
  983 //  CMainWindow::SetMenu   
  984 //  Whenever the existance of the DataBase is changed this   
  985 //  routine will reset the menus so only the possible commands   
  986 //  are accessible.   
  987 //   
  988 
  989 void CMainWindow::SetMenu ()
  990 {
  991     CMenu   *pMenu = GetMenu();
  992     
  993     if ( m_people.IsPresent()) {
  994         if ( m_people.IsNamed()) 
  995             pMenu -> EnableMenuItem(IDM_SAVE, MF_ENABLED);
  996         else 
  997             pMenu -> EnableMenuItem(IDM_SAVE, MF_GRAYED);
  998         pMenu -> EnableMenuItem(IDM_SAVEAS, MF_ENABLED);
  999         pMenu -> EnableMenuItem(IDM_CLOSE, MF_ENABLED);
 1000         pMenu -> EnableMenuItem(IDM_PRINT, MF_ENABLED);
 1001         pMenu -> EnableMenuItem(IDM_ADD, MF_ENABLED);
 1002         pMenu -> EnableMenuItem(IDM_DELETE, MF_ENABLED);
 1003         pMenu -> EnableMenuItem(IDM_FIND, MF_ENABLED);
 1004         pMenu -> EnableMenuItem(IDM_EDIT, MF_ENABLED);
 1005     } else {
 1006         pMenu -> EnableMenuItem(IDM_SAVE, MF_GRAYED);
 1007         pMenu -> EnableMenuItem(IDM_SAVEAS, MF_GRAYED);
 1008         pMenu -> EnableMenuItem(IDM_CLOSE, MF_GRAYED);
 1009         pMenu -> EnableMenuItem(IDM_PRINT, MF_GRAYED);
 1010         pMenu -> EnableMenuItem(IDM_ADD, MF_GRAYED);
 1011         pMenu -> EnableMenuItem(IDM_DELETE, MF_GRAYED);
 1012         pMenu -> EnableMenuItem(IDM_FIND, MF_GRAYED);
 1013         pMenu -> EnableMenuItem(IDM_FINDALL, MF_GRAYED);
 1014         pMenu -> EnableMenuItem(IDM_EDIT, MF_GRAYED);
 1015     }
 1016 }
 1017 
 1018 //////////////////////////////////////////////////   
 1019 //  CMainWindow::InvalidateLine   
 1020 //  Marks the screen area of the currently selected person as   
 1021 //  invalid causing windows to call OnPaint to redraw the area.   
 1022 //  This is normally used when the selected line is being changed.   
 1023 //   
 1024 
 1025 void CMainWindow::InvalidateLine ()
 1026 {
 1027     CRect   area(0, (m_nSelectLine - m_nVscrollPos) * m_cyChar, m_cxClient
 1028                     , (m_nSelectLine + 1 - m_nVscrollPos) * m_cyChar);
 1029     
 1030     InvalidateRect(area);
 1031 }