|
|
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];
1.1.1.2 ! root 292:
1.1 root 293: rc = dc->StartDoc( "Phone Book" );
1.1.1.2 ! root 294:
1.1 root 295: if ( rc < 0 )
296: {
297: sprintf( szError, "Unable to Begin printing - Error[%d]", rc );
298: MessageBox( szError, NULL,MB_OK );
299: return;
300: }
301:
302: int x, y;
303: CPerson* pCurrent;
304: int nPerson=0;
305: CString szDisplay;
306: int nStart, nEnd;
307:
308: // Get Height and Width of large character
309: CSize extentChar = dc->GetTextExtent( "M", 1 );
310: int nCharHeight = extentChar.cy;
311: int nCharWidth = extentChar.cx;
312:
313: // Get Page size in # of full lines
314: int nExtPage = ( dc->GetDeviceCaps(VERTRES) - nCharHeight )
315: / nCharHeight;
316:
317: CString szTitle;
318: szTitle = CString( "Phone Book - " ) + m_people.GetName();
319:
320: while ( nPerson != m_people.GetCount() )
321: {
322: // Print a Page Header
323: dc->StartPage();
324: dc->SetTextAlign ( TA_LEFT | TA_TOP );
325: dc->TextOut( 0, 0, szTitle, szTitle.GetLength() );
326: dc->MoveTo( 0, nCharHeight );
327: dc->LineTo(
328: dc->GetTextExtent( szTitle, szTitle.GetLength() ).cx,
329: nCharHeight );
330:
331: // Print People from start to last person or page size minus
332: // 2 ( header size )
333: nEnd = min( m_people.GetCount() - nPerson, nExtPage-2 );
334: for ( nStart = 0; nStart < nEnd; nStart++, nPerson++ )
335: {
336: x = 0;
337: y = nCharHeight * ( nStart+2 );
338:
339: pCurrent = m_people.GetPerson( nPerson );
340: szDisplay = " " + pCurrent->GetLastName() + ", " +
341: pCurrent->GetFirstName();
342: dc->SetTextAlign( TA_LEFT | TA_TOP );
343: dc->TextOut( x, y, szDisplay, szDisplay.GetLength() );
344:
345: szDisplay = pCurrent->GetPhoneNumber();
346: dc->SetTextAlign( TA_RIGHT | TA_TOP );
347: dc->TextOut( x + SIZENAME * nCharWidth, y, szDisplay,
348: szDisplay.GetLength() );
349:
350: szDisplay = pCurrent->GetModTime().Format( "%m/%d/%y %H:%M" );
351: dc->TextOut( x + ( SIZENAME + SIZEPHONE ) * nCharWidth, y,
352: szDisplay, szDisplay.GetLength() );
353: }
354: dc->EndPage();
355: }
356: dc->EndDoc();
357: dc->DeleteDC();
358: SetCursor( AfxGetApp()->LoadStandardCursor( IDC_ARROW ) );
359: }
360: }
361:
362: //////////////////////////////////////////////////
363: // CMainWindow::OnExit
364: //
365: void CMainWindow::OnExit()
366: {
367: OnClose();
368: }
369:
370: //////////////////////////////////////////////////
371: // CMainWindow::OnAdd
372: // Using the EditDialog fill in a new person object. If the user
373: // selects OK then add the person, call OnSize to resize the scroll
374: // region, and invalidate the screen so it will be redrawn with the
375: // new person in the correct order.
376: //
377: void CMainWindow::OnAdd()
378: {
379: CPerson* person=new CPerson();
380:
381: CEditDialog dlgAdd( person, this );
382: if ( dlgAdd.DoModal() == IDOK )
383: {
384: m_people.AddPerson( person );
385: OnSize( 0, m_cxClient, m_cyClient );
386: }
387: else
388: delete person;
389: }
390:
391: //////////////////////////////////////////////////
392: // CMainWindow::OnDelete
393: // Deletes the current selection. Check to see if the selection is
394: // now past then end of the list. Also call OnSize since the list
395: // length has now changed.
396: //
397: void CMainWindow::OnDelete()
398: {
399: if ( m_nSelectLine == -1 )
400: {
401: MessageBox( "Select a person to delete first" );
402: return;
403: }
404: m_people.DeletePerson( m_nSelectLine );
405: if ( m_nSelectLine >= (int)m_people.GetCount() )
406: m_nSelectLine--;
407: OnSize( 0, m_cxClient, m_cyClient );
408: }
409:
410: ////////////////////////////////////////////////////
411: // CMainWindow::OnFind
412: // Gets information from the CFindDialog modal dialog box, then searches for
413: // matching people. Note the Add and Delete menu items are disabled after
414: // a find is made. Find All is enabled.
415: //
416: void CMainWindow::OnFind()
417: {
418: CFindDialog dlgFind( this );
419: if ( dlgFind.DoModal() == IDOK &&
420: dlgFind.GetFindString().GetLength() != 0 )
421: {
422: if ( m_people.DoFind( dlgFind.GetFindString() ) )
423: {
424: m_nSelectLine = -1;
425: CString tmp;
426: tmp = m_people.GetTitle() + " Found: "
427: + dlgFind.GetFindString();
428: SetWindowText( tmp );
429: CMenu* pMenu = GetMenu();
430: pMenu->EnableMenuItem( IDM_FINDALL, MF_ENABLED );
431: pMenu->EnableMenuItem( IDM_FIND, MF_GRAYED );
432: pMenu->EnableMenuItem( IDM_DELETE, MF_GRAYED );
433: pMenu->EnableMenuItem( IDM_ADD, MF_GRAYED );
434: OnSize( 0, m_cxClient, m_cyClient );
435: }
436: else
437: MessageBox( "No match found in list." );
438: }
439: }
440:
441: ////////////////////////////////////////////////////
442: // CMainWindow::OnFindAll
443: // Returns to view the whole database. Add, Delete are re-enabled, and
444: // Find All is again disabled. OnSize is called because the list
445: // has changed length.
446: //
447: void CMainWindow::OnFindAll()
448: {
449: m_people.DoFind();
450: SetWindowText( m_people.GetTitle() );
451: CMenu* pMenu = GetMenu();
452: pMenu->EnableMenuItem( IDM_FINDALL, MF_GRAYED );
453: pMenu->EnableMenuItem( IDM_FIND, MF_ENABLED );
454: pMenu->EnableMenuItem( IDM_DELETE, MF_ENABLED );
455: pMenu->EnableMenuItem( IDM_ADD, MF_ENABLED );
456: OnSize( 0, m_cxClient, m_cyClient );
457: }
458:
459: ////////////////////////////////////////////////////
460: // CMainWindow::OnEdit
461: // Using the member variable m_nSelectLine a CEditDialog is created
462: // and filled with the selected person. If the dialog OK button is
463: // used the dialog saves the changes into the object.
464: // over any old information.
465: //
466: void CMainWindow::OnEdit()
467: {
468: if ( m_nSelectLine == -1 )
469: {
470: MessageBox( "Select a person to edit first" );
471: return;
472: }
473:
474: // Get a pointer to the person in the list.
475: CPerson* pPerson = m_people.GetPerson( m_nSelectLine );
476: CPerson tmpPerson = *pPerson;
477:
478: //Edit the data.
479: CEditDialog dlgEdit( &tmpPerson, this );
480:
481: //if the ok button is pressed redraw the screen
482: if ( dlgEdit.DoModal() == IDOK )
483: {
484: m_people.ReplacePerson( pPerson, tmpPerson );
485: InvalidateLine();
486: }
487: }
488:
489: //////////////////////////////////////////////////
490: // CMainWindow::OnHelp
491: //
492: void CMainWindow::OnHelp()
493: {
494: if ( !m_people.IsPresent() )
495: {
496: CModalDialog dlgHelp( "NoData", this );
497: dlgHelp.DoModal();
498: return;
499: }
500:
501: if ( !m_people.IsNamed() )
502: {
503: CModalDialog dlgHelp( "NoName", this );
504: if ( dlgHelp.DoModal() == IDCANCEL )
505: return;
506: }
507:
508: CModalDialog dlgHelp( "Enter", this );
509: dlgHelp.DoModal();
510: }
511:
512: //////////////////////////////////////////////////
513: // CMainWindow::OnAbout
514: //
515: void CMainWindow::OnAbout()
516: {
517: CModalDialog dlgAbout( "AboutBox", this );
518: dlgAbout.DoModal();
519: }
520:
521: /////////////////////////////////////////////////////////////////////////////
522: // The Following are WINDOW messages
523:
524: //////////////////////////////////////////////////
525: // CMainWindow::OnCreate
526: // Queries the current text metrics to determine char size.
527: //
528: int CMainWindow::OnCreate( LPCREATESTRUCT )
529: {
530: TEXTMETRIC tm;
531:
532: // Get the text metrics.
533: CDC* dc = GetDC();
534: dc->GetTextMetrics( &tm );
535: ReleaseDC( dc );
536:
537: // Decide the statistics on how many rows, etc., we can display.
538: m_cxChar = tm.tmAveCharWidth;
539: m_cxCaps = ( (tm.tmPitchAndFamily & 1 )? 3 : 2 ) * m_cxChar / 2;
540: m_cyChar = tm.tmHeight + tm.tmExternalLeading;
541: m_nMaxWidth = ( SIZENAME + SIZEPHONE + 1 ) * m_cxCaps;
542: m_nVscrollPos = m_nHscrollPos = 0;
543:
544: return 0;
545: }
546:
547: //////////////////////////////////////////////////
548: // CMainWindow::OnClose
549: // Check to see if the current file needs to be saved. Terminate
550: // the database and destory the window.
551: //
552: void CMainWindow::OnClose()
553: {
554: if ( !CheckForSave( "File Exit", "Save file before exit?" ) )
555: return;
556: m_people.Terminate();
557: DestroyWindow();
558: }
559:
560: //////////////////////////////////////////////////
561: // CMainWindow::OnSize
562: // When resized, we need to recalculate our scrollbar ranges based on what
563: // part of the database is visible.
564: //
565: void CMainWindow::OnSize( UINT, int x, int y )
566: {
567: m_cxClient = x;
568: m_cyClient = y;
569:
570: m_nVscrollMax = max( 0,
571: (int)( m_people.GetCount() ) - m_cyClient / m_cyChar );
572: m_nVscrollPos = min( m_nVscrollPos, m_nVscrollMax );
573:
574: SetScrollRange( SB_VERT, 0, m_nVscrollMax, FALSE );
575: SetScrollPos( SB_VERT, m_nVscrollPos, TRUE );
576:
577: m_nHscrollMax = max( 0, ( m_nMaxWidth - m_cxClient ) / m_cxChar );
578: m_nHscrollPos = min( m_nHscrollPos, m_nHscrollMax );
579:
580: SetScrollRange( SB_HORZ, 0, m_nHscrollMax, FALSE );
581: SetScrollPos( SB_HORZ, m_nHscrollPos, TRUE );
582: Invalidate( TRUE );
583: }
584:
585: //////////////////////////////////////////////////
586: // CMainWindow::OnVScroll
587: // Translate scroll messages into Scroll increments and then
588: // checks the current position to determine if scrolling is possible
589: //
590: void CMainWindow::OnVScroll( UINT wParam, UINT pos, CScrollBar* )
591: {
592: short nScrollInc;
593:
594: switch ( wParam )
595: {
596: case SB_TOP:
597: nScrollInc = -m_nVscrollPos;
598: break;
599:
600: case SB_BOTTOM:
601: nScrollInc = m_nVscrollMax - m_nVscrollPos;
602: break;
603:
604: case SB_LINEUP:
605: nScrollInc = -1;
606: break;
607:
608: case SB_LINEDOWN:
609: nScrollInc = 1;
610: break;
611:
612: case SB_PAGEUP:
613: nScrollInc = min( -1, -m_cyClient / m_cyChar );
614: break;
615:
616: case SB_PAGEDOWN:
617: nScrollInc = max( 1, m_cyClient / m_cyChar );
618: break;
619:
620: case SB_THUMBTRACK:
621: nScrollInc = pos - m_nVscrollPos;
622: break;
623:
624: default:
625: nScrollInc = 0;
626: }
627:
628: if ( nScrollInc = max( -m_nVscrollPos,
629: min( nScrollInc, m_nVscrollMax - m_nVscrollPos ) ) )
630: {
631: m_nVscrollPos += nScrollInc;
632: ScrollWindow( 0, -m_cyChar * nScrollInc );
633: SetScrollPos( SB_VERT, m_nVscrollPos );
634: UpdateWindow();
635: }
636: }
637:
638: //////////////////////////////////////////////////
639: // CMainWindow::OnHScroll
640: // Translate scroll messages into Scroll increments and then
641: // checks the current position to determine if scrolling is possible
642: //
643: void CMainWindow::OnHScroll( UINT wParam, UINT pos, CScrollBar* )
644: {
645: int nScrollInc;
646: switch ( wParam )
647: {
648: case SB_LINEUP:
649: nScrollInc = -1;
650: break;
651:
652: case SB_LINEDOWN:
653: nScrollInc = 1;
654: break;
655:
656: case SB_PAGEUP:
657: nScrollInc = -PAGESIZE;
658: break;
659:
660: case SB_PAGEDOWN:
661: nScrollInc = PAGESIZE;
662: break;
663:
664: case SB_THUMBPOSITION:
665: nScrollInc = pos - m_nHscrollPos;
666: break;
667:
668: default:
669: nScrollInc = 0;
670: }
671:
672: if ( nScrollInc = max( -m_nHscrollPos,
673: min( nScrollInc, m_nHscrollMax - m_nHscrollPos ) ) )
674: {
675: m_nHscrollPos += nScrollInc;
676: ScrollWindow( -m_cxChar * nScrollInc, 0 );
677: SetScrollPos( SB_HORZ, m_nHscrollPos );
678: UpdateWindow();
679: }
680: }
681:
682: //////////////////////////////////////////////////
683: // CMainWindow::OnUp
684: // Uses Accelerator tables to link the up arrow key to this
685: // routine. Decrements the select line with checking for scrolling
686: // and wrapping off the top of the list.
687: //
688: //
689: void CMainWindow::OnUp()
690: {
691: InvalidateLine();
692:
693: if ( m_nSelectLine <= 0 )
694: {
695: m_nSelectLine = m_people.GetCount() - 1;
696: m_nVscrollPos = max( 0, m_nSelectLine + 1 - ( m_cyClient / m_cyChar ) );
697: Invalidate( TRUE );
698: }
699: else
700: {
701: m_nSelectLine--;
702: if ( m_nSelectLine - m_nVscrollPos < 0 )
703: OnVScroll( SB_LINEUP, 0, NULL );
704:
705: // Selection is off the screen
706: if ( m_nSelectLine - m_nVscrollPos > ( m_cyClient / m_cyChar ) )
707: {
708: m_nVscrollPos = m_nSelectLine + 1 - ( m_cyClient / m_cyChar );
709: SetScrollPos( SB_VERT, m_nVscrollPos, TRUE );
710: Invalidate( TRUE );
711: }
712: if ( m_nSelectLine - m_nVscrollPos < 0 )
713: {
714: m_nVscrollPos = m_nSelectLine;
715: SetScrollPos( SB_VERT, m_nVscrollPos, TRUE );
716: Invalidate( TRUE );
717: }
718: }
719:
720: InvalidateLine();
721: }
722:
723: //////////////////////////////////////////////////
724: // CMainWindow::OnDown
725: // Uses Accelerator tables to link the down arrow key to this
726: // routine. Inc the select line with checking for scrolling
727: // and wrapping off the bottom of the list.
728: //
729: void CMainWindow::OnDown()
730: {
731: InvalidateLine();
732:
733: if ( m_nSelectLine == (int)( m_people.GetCount() - 1 )
734: || m_nSelectLine == -1 )
735: {
736: m_nSelectLine = 0;
737: m_nVscrollPos = 0;
738: Invalidate( TRUE );
739: }
740: else
741: {
742: m_nSelectLine++;
743: if ( ( m_nSelectLine - m_nVscrollPos + 1 ) > ( m_cyClient / m_cyChar ) )
744: OnVScroll( SB_LINEDOWN, 0, NULL );
745:
746: // Selection is off the screen
747: if ( ( m_nSelectLine - m_nVscrollPos ) > ( m_cyClient / m_cyChar ) )
748: {
749: m_nVscrollPos = m_nSelectLine + 1 - ( m_cyClient / m_cyChar );
750: SetScrollPos( SB_VERT, m_nVscrollPos, TRUE );
751: Invalidate( TRUE );
752: }
753: if ( ( m_nSelectLine - m_nVscrollPos ) < 0 )
754: {
755: m_nVscrollPos = m_nSelectLine;
756: SetScrollPos( SB_VERT, m_nVscrollPos, TRUE );
757: Invalidate( TRUE );
758: }
759: }
760:
761: InvalidateLine();
762: }
763:
764: //////////////////////////////////////////////////
765: // CMainWindow::OnLButtonDown
766: // Turns the location of the mouse pointer into a line number
767: // and stores that information in m_nSelectLine. Uses
768: // InvalidateLine to cause OnPaint to change the screen.
769: //
770: void CMainWindow::OnLButtonDown( UINT, CPoint location )
771: {
772: InvalidateLine();
773:
774: int pos = m_nVscrollPos + location.y / m_cyChar;
775:
776: if ( ( m_nSelectLine != pos ) && ( pos < (int)m_people.GetCount() ) )
777: {
778: m_nSelectLine = pos;
779: InvalidateLine();
780: }
781: else
782: m_nSelectLine = -1;
783: }
784:
785: //////////////////////////////////////////////////
786: // CMainWindow::OnLButtonDblClk
787: // Translates mouse left button double click into edit person.
788: //
789: void CMainWindow::OnLButtonDblClk( UINT wParam, CPoint location )
790: {
791: if ( m_nSelectLine == -1 )
792: OnLButtonDown( wParam, location );
793: OnEdit();
794: }
795:
796: //////////////////////////////////////////////////
797: // CMainWindow::OnKeyDown
798: // Translates keyboard input into scroll messages
799: //
800: void CMainWindow::OnKeyDown( UINT wParam, UINT, UINT )
801: {
802: switch ( wParam )
803: {
804: case VK_HOME:
805: OnVScroll( SB_TOP, 0, NULL );
806: break;
807: case VK_END:
808: OnVScroll( SB_BOTTOM, 0, NULL );
809: break;
810: case VK_PRIOR:
811: OnVScroll( SB_PAGEUP, 0, NULL );
812: break;
813: case VK_NEXT:
814: OnVScroll( SB_PAGEDOWN, 0, NULL );
815: break;
816: case VK_LEFT:
817: OnHScroll( SB_PAGEUP, 0, NULL );
818: break;
819: case VK_RIGHT:
820: OnHScroll( SB_PAGEDOWN, 0, NULL );
821: break;
822: }
823: }
824:
825: //////////////////////////////////////////////////
826: // CMainWindow::OnPaint
827: // This routine does all the painting for the screen.
828: //
829: void CMainWindow::OnPaint()
830: {
831:
832: CPaintDC dc( this );
833:
834: // Set the Text and background colors for the DC also create a Brush
835: CBrush bBack;
836: dc.SetTextColor( GetSysColor( COLOR_WINDOWTEXT ) );
837: dc.SetBkColor( GetSysColor( COLOR_WINDOW ) );
838: bBack.CreateSolidBrush( GetSysColor( COLOR_WINDOW ) );
839:
840: // Compute the lines that need to be redrawn
841: int nStart = max( 0, m_nVscrollPos + dc.m_ps.rcPaint.top / m_cyChar - 1 );
842: int nEnd = min( (int)m_people.GetCount(),
843: m_nVscrollPos + ( dc.m_ps.rcPaint.bottom / m_cyChar+1 ) );
844:
845: // Create a rect the width of the display.
846: CRect area( 0, 0, m_cxClient, 0 );
847:
848: CString szDisplay;
849: CPerson* pCurrent;
850: int x,y;
851: for ( ;nStart < nEnd; nStart++ )
852: {
853: // if the current line is the select line then change the
854: // colors to the highlight text colors.
855: if ( m_nSelectLine == nStart )
856: {
857: bBack.DeleteObject();
858: bBack.CreateSolidBrush( GetSysColor( COLOR_HIGHLIGHT ) );
859: dc.SetTextColor( GetSysColor( COLOR_HIGHLIGHTTEXT ) );
860: dc.SetBkColor( GetSysColor( COLOR_HIGHLIGHT ) );
861: }
862:
863: // x is the number of characters horz scrolled * the width of
864: // char. y is the current line no. - number of lines scrolled
865: // times the height of a line.
866: x = m_cxChar * ( -m_nHscrollPos );
867: y = m_cyChar * ( nStart - m_nVscrollPos );
868:
869: // Set the rect to y and y + the height of the line. Fill the
870: // rect with the background color.
871: area.top = y;
872: area.bottom = y+ m_cyChar;
873: dc.FillRect( area, &bBack );
874:
875: // Get the person and build a string with his name.
876: pCurrent = m_people.GetPerson( nStart );
877: szDisplay = " " + pCurrent->GetLastName() + ", " +
878: pCurrent->GetFirstName();
879:
880: // Set the dc to write using the point as the left top of the
881: // character. Write the name.
882: dc.SetTextAlign( TA_LEFT | TA_TOP );
883: dc.TextOut ( x, y,szDisplay, szDisplay.GetLength() );
884:
885: // Write the phone number right aligned.
886: szDisplay = pCurrent->GetPhoneNumber();
887: dc.SetTextAlign ( TA_RIGHT | TA_TOP );
888: dc.TextOut ( x + SIZENAME * m_cxCaps, y, szDisplay,
889: szDisplay.GetLength() );
890:
891: // Write the time.
892: szDisplay = pCurrent->GetModTime().Format( "%m/%d/%y %H:%M" );
893: dc.TextOut ( x + ( SIZENAME + SIZEPHONE ) * m_cxCaps, y,
894: szDisplay, szDisplay.GetLength() );
895:
896: // If this is the select line then we need to reset the dc
897: // colors back to the original colors.
898: if ( m_nSelectLine == nStart )
899: {
900: bBack.DeleteObject();
901: bBack.CreateSolidBrush( GetSysColor( COLOR_WINDOW ) );
902: dc.SetTextColor( GetSysColor( COLOR_WINDOWTEXT ) );
903: dc.SetBkColor( GetSysColor( COLOR_WINDOW ) );
904: }
905: }
906: }
907:
908: /////////////////////////////////////////////////////////////////////////////
909: // The following are utility routines
910:
911:
912: //////////////////////////////////////////////////
913: // CMainWindow::FileDlg
914: // Call the commdlg routine to display File Open or File Save As
915: // dialogs. The setup is the same for either. If bOpen is TRUE
916: // then File Open is display otherwise File Save As is displayed.
917: // The File Name and File Title are stored at the string pointer
918: // passed in.
919: //
920: BOOL CMainWindow::FileDlg( BOOL bOpen, int nMaxFile, LPSTR szFile,
921: int nMaxFileTitle, LPSTR szFileTitle )
922: {
923:
924: OPENFILENAME of;
925:
926: char szDirName[SIZESTRING];
927: char szFilter[] = "Phone Book Files (*.pb)\0"
928: "*.pb\0"
929: "\0";
930:
931: szDirName[0] = '.';
932:
933: of.lStructSize = sizeof( OPENFILENAME );
934: of.hwndOwner = m_hWnd;
935: of.lpstrFilter = szFilter;
936: of.lpstrCustomFilter = NULL;
937: of.nMaxCustFilter = 0L;
938: of.nFilterIndex = 1L;
939: of.lpstrFile=szFile;
940: of.nMaxFile=nMaxFile;
941: of.lpstrFileTitle = szFileTitle;
942: of.nMaxFileTitle = nMaxFileTitle;
943: of.lpstrInitialDir = szDirName;
944: of.lpstrTitle = NULL;
945: of.nFileOffset = 0;
946: of.nFileExtension = 0;
947: of.lpstrDefExt = "pb";
948: if ( bOpen )
949: {
950: of.Flags = OFN_HIDEREADONLY;
951: return GetOpenFileName( &of );
952: }
953: else
954: {
955: of.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
956: return GetSaveFileName( &of );
957: }
958: }
959:
960: //////////////////////////////////////////////////
961: // CMainWindow::Save
962: // Handles any time a file needs to be saved to the disk.
963: // Passing in FALSE for name brings up the file save as dialog
964: // whether or not the database had a name before.
965: //
966: BOOL CMainWindow::Save( BOOL bIsNamed /* = FALSE */ )
967: {
968: CString szFileName, szFileTitle;
969: TRY
970: {
971: if ( bIsNamed )
972: m_people.DoSave();
973: else
974: {
975: szFileName = m_people.GetName();
976: if ( FileDlg( FALSE, SIZESTRING,
977: szFileName.GetBuffer( SIZESTRING ), SIZESTRING,
978: szFileTitle.GetBuffer( SIZESTRING ) ) )
979: {
980: szFileName.ReleaseBuffer();
981: m_people.DoSave( szFileName );
982: m_people.SetTitle( szFileTitle );
983: SetWindowText( m_people.GetTitle() );
984: }
985: else
986: return FALSE;
987: }
988: }
989: CATCH( CFileException, e )
990: {
991: char ErrorMsg[SIZESTRING];
992: sprintf( ErrorMsg,"Saving %s returned a 0x%lx.",
993: (const char*)szFileTitle, e->m_lOsError );
994: MessageBox( ErrorMsg, "File Open Error" );
995: }
996: AND_CATCH( CArchiveException, e )
997: {
998: char ErrorMsg[SIZESTRING];
999: sprintf( ErrorMsg,"Reading the %s archive failed.",
1000: (const char*)szFileTitle );
1001: MessageBox( ErrorMsg, "File Open Error" );
1002: }
1003: END_CATCH
1004: return TRUE;
1005: }
1006:
1007: //////////////////////////////////////////////////
1008: // CMainWindow::CheckForSave
1009: // Whenever a new file is opened this routine will determine if
1010: // there are unsaved changes in the current database. If so it
1011: // will query the user and determine save or not as appropriate.
1012: //
1013: BOOL CMainWindow::CheckForSave( const char* pszTitle, const char* pszMessage )
1014: {
1015: if ( m_people.IsDirty() )
1016: {
1017: UINT nButton = MessageBox( pszMessage, pszTitle, MB_YESNOCANCEL );
1018: if ( nButton == IDYES )
1019: {
1020: if ( !Save( m_people.IsNamed() ) )
1021: return FALSE;
1022: }
1023: else if ( nButton == IDCANCEL )
1024: return FALSE;
1025: }
1026: return TRUE;
1027: }
1028:
1029:
1030: //////////////////////////////////////////////////
1031: // CMainWindow::SetMenu
1032: // Whenever the existance of the DataBase is changed this
1033: // routine will reset the menus so only the possible commands
1034: // are accessible.
1035: //
1036: void CMainWindow::SetMenu()
1037: {
1038: CMenu* pMenu = GetMenu();
1039: if ( m_people.IsPresent() )
1040: {
1041: if ( m_people.IsNamed() )
1042: pMenu->EnableMenuItem( IDM_SAVE, MF_ENABLED );
1043: else
1044: pMenu->EnableMenuItem( IDM_SAVE, MF_GRAYED );
1045: pMenu->EnableMenuItem( IDM_SAVEAS, MF_ENABLED );
1046: pMenu->EnableMenuItem( IDM_CLOSE, MF_ENABLED );
1047: pMenu->EnableMenuItem( IDM_PRINT, MF_ENABLED );
1048: pMenu->EnableMenuItem( IDM_ADD, MF_ENABLED );
1049: pMenu->EnableMenuItem( IDM_DELETE, MF_ENABLED );
1050: pMenu->EnableMenuItem( IDM_FIND, MF_ENABLED );
1051: pMenu->EnableMenuItem( IDM_EDIT, MF_ENABLED );
1052: }
1053: else
1054: {
1055: pMenu->EnableMenuItem( IDM_SAVE, MF_GRAYED );
1056: pMenu->EnableMenuItem( IDM_SAVEAS, MF_GRAYED );
1057: pMenu->EnableMenuItem( IDM_CLOSE, MF_GRAYED );
1058: pMenu->EnableMenuItem( IDM_PRINT, MF_GRAYED );
1059: pMenu->EnableMenuItem( IDM_ADD, MF_GRAYED );
1060: pMenu->EnableMenuItem( IDM_DELETE, MF_GRAYED );
1061: pMenu->EnableMenuItem( IDM_FIND, MF_GRAYED );
1062: pMenu->EnableMenuItem( IDM_FINDALL, MF_GRAYED );
1063: pMenu->EnableMenuItem( IDM_EDIT, MF_GRAYED );
1064: }
1065: }
1066:
1067: //////////////////////////////////////////////////
1068: // CMainWindow::InvalidateLine
1069: // Marks the screen area of the currently selected person as
1070: // invalid causing windows to call OnPaint to redraw the area.
1071: // This is normally used when the selected line is being changed.
1072: //
1073: void CMainWindow::InvalidateLine()
1074: {
1075: CRect area( 0, ( m_nSelectLine - m_nVscrollPos ) * m_cyChar, m_cxClient,
1076: ( m_nSelectLine + 1 - m_nVscrollPos ) * m_cyChar );
1077: InvalidateRect( area );
1078: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.