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