|
|
Microsoft Windows NT Build 511 (SDK Final Release) 07-24-1993
// view.cpp : Defines the behaviors for the application and frame window.
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and Microsoft
// QuickHelp documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include <afxwin.h>
#include "resource.h"
#include "database.h"
#include "view.h"
#include <commdlg.h>
#define SIZESTRING 256
#define SIZENAME 30
#define SIZEPHONE 26
#define PAGESIZE 8
// a simple way to reduce size of C runtimes
// disables the use of getenv and argv/argc
extern "C" void _setargv() { }
extern "C" void _setenvp() { }
/////////////////////////////////////////////////////////////////////////////
// Create the single global instance of the database viewer app.
CTheApp PersonApp;
/////////////////////////////////////////////////////////////////////////////
// CTheApp
//////////////////////////////////////////////////
// CtheApp::InitInstance
// Override InitInstance function to create a CMainWindow object
// and display it on the screen
//
BOOL CTheApp::InitInstance()
{
m_pMainWnd = new CMainWindow();
m_pMainWnd->ShowWindow( m_nCmdShow );
m_pMainWnd->UpdateWindow();
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CFindDialog
//////////////////////////////////////////////////
// CFindDialog::OnOK
// When the user hits OK get the data entered and store it in this
// object. Then end the dialog.
//
void CFindDialog::OnOK()
{
GetDlgItemText( IDC_DATA, m_szFindName.GetBuffer( SIZESTRING ), SIZESTRING );
m_szFindName.ReleaseBuffer();
EndDialog( IDOK );
}
/////////////////////////////////////////////////////////////////////////////
// CEditPerson
//////////////////////////////////////////////////
// CEditDialog::OnInitDialog
// Fill in the fields witht the data placed in this object
// when it was created.
//
BOOL CEditDialog::OnInitDialog()
{
SetDlgItemText( IDC_LASTNAME, m_pData->GetLastName() );
SetDlgItemText( IDC_FIRSTNAME, m_pData->GetFirstName() );
SetDlgItemText( IDC_PHONE, m_pData->GetPhoneNumber() );
SetDlgItemText( IDC_MOD, m_pData->GetModTime().Format("%m/%d/%y %H:%M" ) );
SendDlgItemMessage( IDC_LASTNAME, EM_SETSEL );
return TRUE;
}
//////////////////////////////////////////////////
// CEditDialog::OnOK
// When OK is pressed set the data to what the user has entered.
//
void CEditDialog::OnOK()
{
char szTmp[SIZESTRING];
GetDlgItemText( IDC_LASTNAME, szTmp, sizeof ( szTmp ) );
m_pData->SetLastName( szTmp );
GetDlgItemText( IDC_FIRSTNAME, szTmp, sizeof ( szTmp ) );
m_pData->SetFirstName( szTmp );
GetDlgItemText( IDC_PHONE, szTmp, sizeof ( szTmp ) );
m_pData->SetPhoneNumber( szTmp );
EndDialog( IDOK );
}
/////////////////////////////////////////////////////////////////////////////
// CMainWindow
BEGIN_MESSAGE_MAP( CMainWindow, CFrameWnd )
// File menu commands:
ON_COMMAND( IDM_NEW, OnNew )
ON_COMMAND( IDM_OPEN, OnOpen )
ON_COMMAND( IDM_SAVE, OnSave )
ON_COMMAND( IDM_SAVEAS, OnSaveAs )
ON_COMMAND( IDM_CLOSE, OnDBClose )
ON_COMMAND( IDM_PRINT, OnPrint )
ON_COMMAND( IDM_EXIT, OnExit )
// Person menu commands:
ON_COMMAND( IDM_ADD, OnAdd )
ON_COMMAND( IDM_DELETE, OnDelete )
ON_COMMAND( IDM_EDIT, OnEdit )
ON_COMMAND( IDM_FIND, OnFind )
ON_COMMAND( IDM_FINDALL, OnFindAll )
// Help menu commands:
ON_COMMAND( IDM_HELP, OnHelp )
ON_COMMAND( IDM_ABOUT, OnAbout )
// Selection accelerators:
ON_COMMAND( VK_UP, OnUp )
ON_COMMAND( VK_DOWN, OnDown )
// Other Windows messages:
ON_WM_CREATE()
ON_WM_CLOSE()
ON_WM_SIZE()
ON_WM_VSCROLL()
ON_WM_HSCROLL()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONDBLCLK()
ON_WM_KEYDOWN()
ON_WM_PAINT()
END_MESSAGE_MAP()
//////////////////////////////////////////////////
// CMainWindow::CMainWindow
// Constructs and initializes a CMainWindow object
//
CMainWindow::CMainWindow()
{
VERIFY( LoadAccelTable( "MainAccelTable" ) );
VERIFY( Create( NULL, "Phone Book",
WS_OVERLAPPEDWINDOW, rectDefault, NULL, "MainMenu" ) );
m_nSelectLine = -1;
}
/////////////////////////////////////////////////////////////////////////////
// The Following are CMainWindow Menu Items
//////////////////////////////////////////////////
// CMainWindow::OnNew
// After checking to see if current data needs to be stored, call
// database New and resize/repaint the window.
//
void CMainWindow::OnNew()
{
if ( !CheckForSave( "File New", "Save file before New?" ) )
return;
m_people.New();
SetMenu();
SetWindowText( m_people.GetTitle() );
OnSize( 0, m_cxClient, m_cyClient );
}
//////////////////////////////////////////////////
// CMainWindow::OnOpen
//
void CMainWindow::OnOpen()
{
if ( !CheckForSave( "File Open", "Save file before Open?" ) )
return;
// Attempt to open a database file and read it.
// If a file or archive exception occurs, catch it and
// present an error message box.
CString szFileName, szFileTitle;
TRY
{
// Use CommDlg to get the file name and then call DoOpen.
// Set the Window title and menus. Resize/Repaint.
if ( FileDlg( TRUE, SIZESTRING, szFileName.GetBuffer( SIZESTRING ),
SIZESTRING, szFileTitle.GetBuffer( SIZESTRING ) ) )
{
szFileName.ReleaseBuffer();
szFileTitle.ReleaseBuffer();
m_people.DoOpen( szFileName );
m_people.SetTitle( szFileTitle );
SetWindowText( m_people.GetTitle() );
SetMenu();
OnSize( 0, m_cxClient, m_cyClient );
}
}
CATCH( CFileException, e )
{
char ErrorMsg[SIZESTRING];
sprintf( ErrorMsg,"Opening %s returned a 0x%lx.",
(const char*)szFileTitle, e->m_lOsError );
MessageBox( ErrorMsg, "File Open Error" );
}
AND_CATCH( CArchiveException, e )
{
char ErrorMsg[SIZESTRING];
sprintf( ErrorMsg,"Reading the %s archive failed.",
(const char*)szFileTitle );
MessageBox( ErrorMsg, "File Open Error" );
}
END_CATCH
}
//////////////////////////////////////////////////
// CMainWindow::OnSave
//
void CMainWindow::OnSave()
{
Save( m_people.IsNamed() );
}
//////////////////////////////////////////////////
// CMainWindow::OnSaveAs
//
void CMainWindow::OnSaveAs()
{
Save();
}
//////////////////////////////////////////////////
// CMainWindow::OnDBClose
// Closes the current database, checking to see if it should be
// saved first. Reset the window title and the scroll regions.
// Invalidating the entire screen causes OnPaint to repaint but
// this time without any data.
//
void CMainWindow::OnDBClose()
{
if ( !CheckForSave( "File Close", "Save file before closing?" ) )
return;
m_people.Terminate();
SetWindowText( "Phone Book" );
SetMenu();
OnSize( 0, m_cxClient, m_cyClient );
}
//////////////////////////////////////////////////
// CMainWindow::OnPrint
// Uses the commdlg print dialog to create a printer dc
// Then it uses code almost identical to the OnPaint code
// to write the data to the printer.
//
void CMainWindow::OnPrint()
{
PRINTDLG pd;
pd.lStructSize = sizeof( PRINTDLG );
pd.hwndOwner=m_hWnd;
pd.hDevMode=(HANDLE)NULL;
pd.hDevNames=(HANDLE)NULL;
pd.Flags=PD_RETURNDC | PD_NOSELECTION | PD_NOPAGENUMS;
pd.nFromPage=0;
pd.nToPage=0;
pd.nMinPage=0;
pd.nMaxPage=0;
pd.nCopies=1;
pd.hInstance=(HINSTANCE)NULL;
if ( PrintDlg( &pd ) != 0 )
{
// CommDlg returned a DC so create a CDC object from it.
ASSERT( pd.hDC != 0 );
CDC * dc;
dc = CDC::FromHandle( pd.hDC );
// Change to hour glass while printing
SetCursor( AfxGetApp()->LoadStandardCursor( IDC_WAIT ) );
// Begin printing the document.
int rc;
char szError[SIZESTRING];
rc = dc->StartDoc( "Phone Book" );
if ( rc < 0 )
{
sprintf( szError, "Unable to Begin printing - Error[%d]", rc );
MessageBox( szError, NULL,MB_OK );
return;
}
int x, y;
CPerson* pCurrent;
int nPerson=0;
CString szDisplay;
int nStart, nEnd;
// Get Height and Width of large character
CSize extentChar = dc->GetTextExtent( "M", 1 );
int nCharHeight = extentChar.cy;
int nCharWidth = extentChar.cx;
// Get Page size in # of full lines
int nExtPage = ( dc->GetDeviceCaps(VERTRES) - nCharHeight )
/ nCharHeight;
CString szTitle;
szTitle = CString( "Phone Book - " ) + m_people.GetName();
while ( nPerson != m_people.GetCount() )
{
// Print a Page Header
dc->StartPage();
dc->SetTextAlign ( TA_LEFT | TA_TOP );
dc->TextOut( 0, 0, szTitle, szTitle.GetLength() );
dc->MoveTo( 0, nCharHeight );
dc->LineTo(
dc->GetTextExtent( szTitle, szTitle.GetLength() ).cx,
nCharHeight );
// Print People from start to last person or page size minus
// 2 ( header size )
nEnd = min( m_people.GetCount() - nPerson, nExtPage-2 );
for ( nStart = 0; nStart < nEnd; nStart++, nPerson++ )
{
x = 0;
y = nCharHeight * ( nStart+2 );
pCurrent = m_people.GetPerson( nPerson );
szDisplay = " " + pCurrent->GetLastName() + ", " +
pCurrent->GetFirstName();
dc->SetTextAlign( TA_LEFT | TA_TOP );
dc->TextOut( x, y, szDisplay, szDisplay.GetLength() );
szDisplay = pCurrent->GetPhoneNumber();
dc->SetTextAlign( TA_RIGHT | TA_TOP );
dc->TextOut( x + SIZENAME * nCharWidth, y, szDisplay,
szDisplay.GetLength() );
szDisplay = pCurrent->GetModTime().Format( "%m/%d/%y %H:%M" );
dc->TextOut( x + ( SIZENAME + SIZEPHONE ) * nCharWidth, y,
szDisplay, szDisplay.GetLength() );
}
dc->EndPage();
}
dc->EndDoc();
dc->DeleteDC();
SetCursor( AfxGetApp()->LoadStandardCursor( IDC_ARROW ) );
}
}
//////////////////////////////////////////////////
// CMainWindow::OnExit
//
void CMainWindow::OnExit()
{
OnClose();
}
//////////////////////////////////////////////////
// CMainWindow::OnAdd
// Using the EditDialog fill in a new person object. If the user
// selects OK then add the person, call OnSize to resize the scroll
// region, and invalidate the screen so it will be redrawn with the
// new person in the correct order.
//
void CMainWindow::OnAdd()
{
CPerson* person=new CPerson();
CEditDialog dlgAdd( person, this );
if ( dlgAdd.DoModal() == IDOK )
{
m_people.AddPerson( person );
OnSize( 0, m_cxClient, m_cyClient );
}
else
delete person;
}
//////////////////////////////////////////////////
// CMainWindow::OnDelete
// Deletes the current selection. Check to see if the selection is
// now past then end of the list. Also call OnSize since the list
// length has now changed.
//
void CMainWindow::OnDelete()
{
if ( m_nSelectLine == -1 )
{
MessageBox( "Select a person to delete first" );
return;
}
m_people.DeletePerson( m_nSelectLine );
if ( m_nSelectLine >= (int)m_people.GetCount() )
m_nSelectLine--;
OnSize( 0, m_cxClient, m_cyClient );
}
////////////////////////////////////////////////////
// CMainWindow::OnFind
// Gets information from the CFindDialog modal dialog box, then searches for
// matching people. Note the Add and Delete menu items are disabled after
// a find is made. Find All is enabled.
//
void CMainWindow::OnFind()
{
CFindDialog dlgFind( this );
if ( dlgFind.DoModal() == IDOK &&
dlgFind.GetFindString().GetLength() != 0 )
{
if ( m_people.DoFind( dlgFind.GetFindString() ) )
{
m_nSelectLine = -1;
CString tmp;
tmp = m_people.GetTitle() + " Found: "
+ dlgFind.GetFindString();
SetWindowText( tmp );
CMenu* pMenu = GetMenu();
pMenu->EnableMenuItem( IDM_FINDALL, MF_ENABLED );
pMenu->EnableMenuItem( IDM_FIND, MF_GRAYED );
pMenu->EnableMenuItem( IDM_DELETE, MF_GRAYED );
pMenu->EnableMenuItem( IDM_ADD, MF_GRAYED );
OnSize( 0, m_cxClient, m_cyClient );
}
else
MessageBox( "No match found in list." );
}
}
////////////////////////////////////////////////////
// CMainWindow::OnFindAll
// Returns to view the whole database. Add, Delete are re-enabled, and
// Find All is again disabled. OnSize is called because the list
// has changed length.
//
void CMainWindow::OnFindAll()
{
m_people.DoFind();
SetWindowText( m_people.GetTitle() );
CMenu* pMenu = GetMenu();
pMenu->EnableMenuItem( IDM_FINDALL, MF_GRAYED );
pMenu->EnableMenuItem( IDM_FIND, MF_ENABLED );
pMenu->EnableMenuItem( IDM_DELETE, MF_ENABLED );
pMenu->EnableMenuItem( IDM_ADD, MF_ENABLED );
OnSize( 0, m_cxClient, m_cyClient );
}
////////////////////////////////////////////////////
// CMainWindow::OnEdit
// Using the member variable m_nSelectLine a CEditDialog is created
// and filled with the selected person. If the dialog OK button is
// used the dialog saves the changes into the object.
// over any old information.
//
void CMainWindow::OnEdit()
{
if ( m_nSelectLine == -1 )
{
MessageBox( "Select a person to edit first" );
return;
}
// Get a pointer to the person in the list.
CPerson* pPerson = m_people.GetPerson( m_nSelectLine );
CPerson tmpPerson = *pPerson;
//Edit the data.
CEditDialog dlgEdit( &tmpPerson, this );
//if the ok button is pressed redraw the screen
if ( dlgEdit.DoModal() == IDOK )
{
m_people.ReplacePerson( pPerson, tmpPerson );
InvalidateLine();
}
}
//////////////////////////////////////////////////
// CMainWindow::OnHelp
//
void CMainWindow::OnHelp()
{
if ( !m_people.IsPresent() )
{
CModalDialog dlgHelp( "NoData", this );
dlgHelp.DoModal();
return;
}
if ( !m_people.IsNamed() )
{
CModalDialog dlgHelp( "NoName", this );
if ( dlgHelp.DoModal() == IDCANCEL )
return;
}
CModalDialog dlgHelp( "Enter", this );
dlgHelp.DoModal();
}
//////////////////////////////////////////////////
// CMainWindow::OnAbout
//
void CMainWindow::OnAbout()
{
CModalDialog dlgAbout( "AboutBox", this );
dlgAbout.DoModal();
}
/////////////////////////////////////////////////////////////////////////////
// The Following are WINDOW messages
//////////////////////////////////////////////////
// CMainWindow::OnCreate
// Queries the current text metrics to determine char size.
//
int CMainWindow::OnCreate( LPCREATESTRUCT )
{
TEXTMETRIC tm;
// Get the text metrics.
CDC* dc = GetDC();
dc->GetTextMetrics( &tm );
ReleaseDC( dc );
// Decide the statistics on how many rows, etc., we can display.
m_cxChar = tm.tmAveCharWidth;
m_cxCaps = ( (tm.tmPitchAndFamily & 1 )? 3 : 2 ) * m_cxChar / 2;
m_cyChar = tm.tmHeight + tm.tmExternalLeading;
m_nMaxWidth = ( SIZENAME + SIZEPHONE + 1 ) * m_cxCaps;
m_nVscrollPos = m_nHscrollPos = 0;
return 0;
}
//////////////////////////////////////////////////
// CMainWindow::OnClose
// Check to see if the current file needs to be saved. Terminate
// the database and destory the window.
//
void CMainWindow::OnClose()
{
if ( !CheckForSave( "File Exit", "Save file before exit?" ) )
return;
m_people.Terminate();
DestroyWindow();
}
//////////////////////////////////////////////////
// CMainWindow::OnSize
// When resized, we need to recalculate our scrollbar ranges based on what
// part of the database is visible.
//
void CMainWindow::OnSize( UINT, int x, int y )
{
m_cxClient = x;
m_cyClient = y;
m_nVscrollMax = max( 0,
(int)( m_people.GetCount() ) - m_cyClient / m_cyChar );
m_nVscrollPos = min( m_nVscrollPos, m_nVscrollMax );
SetScrollRange( SB_VERT, 0, m_nVscrollMax, FALSE );
SetScrollPos( SB_VERT, m_nVscrollPos, TRUE );
m_nHscrollMax = max( 0, ( m_nMaxWidth - m_cxClient ) / m_cxChar );
m_nHscrollPos = min( m_nHscrollPos, m_nHscrollMax );
SetScrollRange( SB_HORZ, 0, m_nHscrollMax, FALSE );
SetScrollPos( SB_HORZ, m_nHscrollPos, TRUE );
Invalidate( TRUE );
}
//////////////////////////////////////////////////
// CMainWindow::OnVScroll
// Translate scroll messages into Scroll increments and then
// checks the current position to determine if scrolling is possible
//
void CMainWindow::OnVScroll( UINT wParam, UINT pos, CScrollBar* )
{
short nScrollInc;
switch ( wParam )
{
case SB_TOP:
nScrollInc = -m_nVscrollPos;
break;
case SB_BOTTOM:
nScrollInc = m_nVscrollMax - m_nVscrollPos;
break;
case SB_LINEUP:
nScrollInc = -1;
break;
case SB_LINEDOWN:
nScrollInc = 1;
break;
case SB_PAGEUP:
nScrollInc = min( -1, -m_cyClient / m_cyChar );
break;
case SB_PAGEDOWN:
nScrollInc = max( 1, m_cyClient / m_cyChar );
break;
case SB_THUMBTRACK:
nScrollInc = pos - m_nVscrollPos;
break;
default:
nScrollInc = 0;
}
if ( nScrollInc = max( -m_nVscrollPos,
min( nScrollInc, m_nVscrollMax - m_nVscrollPos ) ) )
{
m_nVscrollPos += nScrollInc;
ScrollWindow( 0, -m_cyChar * nScrollInc );
SetScrollPos( SB_VERT, m_nVscrollPos );
UpdateWindow();
}
}
//////////////////////////////////////////////////
// CMainWindow::OnHScroll
// Translate scroll messages into Scroll increments and then
// checks the current position to determine if scrolling is possible
//
void CMainWindow::OnHScroll( UINT wParam, UINT pos, CScrollBar* )
{
int nScrollInc;
switch ( wParam )
{
case SB_LINEUP:
nScrollInc = -1;
break;
case SB_LINEDOWN:
nScrollInc = 1;
break;
case SB_PAGEUP:
nScrollInc = -PAGESIZE;
break;
case SB_PAGEDOWN:
nScrollInc = PAGESIZE;
break;
case SB_THUMBPOSITION:
nScrollInc = pos - m_nHscrollPos;
break;
default:
nScrollInc = 0;
}
if ( nScrollInc = max( -m_nHscrollPos,
min( nScrollInc, m_nHscrollMax - m_nHscrollPos ) ) )
{
m_nHscrollPos += nScrollInc;
ScrollWindow( -m_cxChar * nScrollInc, 0 );
SetScrollPos( SB_HORZ, m_nHscrollPos );
UpdateWindow();
}
}
//////////////////////////////////////////////////
// CMainWindow::OnUp
// Uses Accelerator tables to link the up arrow key to this
// routine. Decrements the select line with checking for scrolling
// and wrapping off the top of the list.
//
//
void CMainWindow::OnUp()
{
InvalidateLine();
if ( m_nSelectLine <= 0 )
{
m_nSelectLine = m_people.GetCount() - 1;
m_nVscrollPos = max( 0, m_nSelectLine + 1 - ( m_cyClient / m_cyChar ) );
Invalidate( TRUE );
}
else
{
m_nSelectLine--;
if ( m_nSelectLine - m_nVscrollPos < 0 )
OnVScroll( SB_LINEUP, 0, NULL );
// Selection is off the screen
if ( m_nSelectLine - m_nVscrollPos > ( m_cyClient / m_cyChar ) )
{
m_nVscrollPos = m_nSelectLine + 1 - ( m_cyClient / m_cyChar );
SetScrollPos( SB_VERT, m_nVscrollPos, TRUE );
Invalidate( TRUE );
}
if ( m_nSelectLine - m_nVscrollPos < 0 )
{
m_nVscrollPos = m_nSelectLine;
SetScrollPos( SB_VERT, m_nVscrollPos, TRUE );
Invalidate( TRUE );
}
}
InvalidateLine();
}
//////////////////////////////////////////////////
// CMainWindow::OnDown
// Uses Accelerator tables to link the down arrow key to this
// routine. Inc the select line with checking for scrolling
// and wrapping off the bottom of the list.
//
void CMainWindow::OnDown()
{
InvalidateLine();
if ( m_nSelectLine == (int)( m_people.GetCount() - 1 )
|| m_nSelectLine == -1 )
{
m_nSelectLine = 0;
m_nVscrollPos = 0;
Invalidate( TRUE );
}
else
{
m_nSelectLine++;
if ( ( m_nSelectLine - m_nVscrollPos + 1 ) > ( m_cyClient / m_cyChar ) )
OnVScroll( SB_LINEDOWN, 0, NULL );
// Selection is off the screen
if ( ( m_nSelectLine - m_nVscrollPos ) > ( m_cyClient / m_cyChar ) )
{
m_nVscrollPos = m_nSelectLine + 1 - ( m_cyClient / m_cyChar );
SetScrollPos( SB_VERT, m_nVscrollPos, TRUE );
Invalidate( TRUE );
}
if ( ( m_nSelectLine - m_nVscrollPos ) < 0 )
{
m_nVscrollPos = m_nSelectLine;
SetScrollPos( SB_VERT, m_nVscrollPos, TRUE );
Invalidate( TRUE );
}
}
InvalidateLine();
}
//////////////////////////////////////////////////
// CMainWindow::OnLButtonDown
// Turns the location of the mouse pointer into a line number
// and stores that information in m_nSelectLine. Uses
// InvalidateLine to cause OnPaint to change the screen.
//
void CMainWindow::OnLButtonDown( UINT, CPoint location )
{
InvalidateLine();
int pos = m_nVscrollPos + location.y / m_cyChar;
if ( ( m_nSelectLine != pos ) && ( pos < (int)m_people.GetCount() ) )
{
m_nSelectLine = pos;
InvalidateLine();
}
else
m_nSelectLine = -1;
}
//////////////////////////////////////////////////
// CMainWindow::OnLButtonDblClk
// Translates mouse left button double click into edit person.
//
void CMainWindow::OnLButtonDblClk( UINT wParam, CPoint location )
{
if ( m_nSelectLine == -1 )
OnLButtonDown( wParam, location );
OnEdit();
}
//////////////////////////////////////////////////
// CMainWindow::OnKeyDown
// Translates keyboard input into scroll messages
//
void CMainWindow::OnKeyDown( UINT wParam, UINT, UINT )
{
switch ( wParam )
{
case VK_HOME:
OnVScroll( SB_TOP, 0, NULL );
break;
case VK_END:
OnVScroll( SB_BOTTOM, 0, NULL );
break;
case VK_PRIOR:
OnVScroll( SB_PAGEUP, 0, NULL );
break;
case VK_NEXT:
OnVScroll( SB_PAGEDOWN, 0, NULL );
break;
case VK_LEFT:
OnHScroll( SB_PAGEUP, 0, NULL );
break;
case VK_RIGHT:
OnHScroll( SB_PAGEDOWN, 0, NULL );
break;
}
}
//////////////////////////////////////////////////
// CMainWindow::OnPaint
// This routine does all the painting for the screen.
//
void CMainWindow::OnPaint()
{
CPaintDC dc( this );
// Set the Text and background colors for the DC also create a Brush
CBrush bBack;
dc.SetTextColor( GetSysColor( COLOR_WINDOWTEXT ) );
dc.SetBkColor( GetSysColor( COLOR_WINDOW ) );
bBack.CreateSolidBrush( GetSysColor( COLOR_WINDOW ) );
// Compute the lines that need to be redrawn
int nStart = max( 0, m_nVscrollPos + dc.m_ps.rcPaint.top / m_cyChar - 1 );
int nEnd = min( (int)m_people.GetCount(),
m_nVscrollPos + ( dc.m_ps.rcPaint.bottom / m_cyChar+1 ) );
// Create a rect the width of the display.
CRect area( 0, 0, m_cxClient, 0 );
CString szDisplay;
CPerson* pCurrent;
int x,y;
for ( ;nStart < nEnd; nStart++ )
{
// if the current line is the select line then change the
// colors to the highlight text colors.
if ( m_nSelectLine == nStart )
{
bBack.DeleteObject();
bBack.CreateSolidBrush( GetSysColor( COLOR_HIGHLIGHT ) );
dc.SetTextColor( GetSysColor( COLOR_HIGHLIGHTTEXT ) );
dc.SetBkColor( GetSysColor( COLOR_HIGHLIGHT ) );
}
// x is the number of characters horz scrolled * the width of
// char. y is the current line no. - number of lines scrolled
// times the height of a line.
x = m_cxChar * ( -m_nHscrollPos );
y = m_cyChar * ( nStart - m_nVscrollPos );
// Set the rect to y and y + the height of the line. Fill the
// rect with the background color.
area.top = y;
area.bottom = y+ m_cyChar;
dc.FillRect( area, &bBack );
// Get the person and build a string with his name.
pCurrent = m_people.GetPerson( nStart );
szDisplay = " " + pCurrent->GetLastName() + ", " +
pCurrent->GetFirstName();
// Set the dc to write using the point as the left top of the
// character. Write the name.
dc.SetTextAlign( TA_LEFT | TA_TOP );
dc.TextOut ( x, y,szDisplay, szDisplay.GetLength() );
// Write the phone number right aligned.
szDisplay = pCurrent->GetPhoneNumber();
dc.SetTextAlign ( TA_RIGHT | TA_TOP );
dc.TextOut ( x + SIZENAME * m_cxCaps, y, szDisplay,
szDisplay.GetLength() );
// Write the time.
szDisplay = pCurrent->GetModTime().Format( "%m/%d/%y %H:%M" );
dc.TextOut ( x + ( SIZENAME + SIZEPHONE ) * m_cxCaps, y,
szDisplay, szDisplay.GetLength() );
// If this is the select line then we need to reset the dc
// colors back to the original colors.
if ( m_nSelectLine == nStart )
{
bBack.DeleteObject();
bBack.CreateSolidBrush( GetSysColor( COLOR_WINDOW ) );
dc.SetTextColor( GetSysColor( COLOR_WINDOWTEXT ) );
dc.SetBkColor( GetSysColor( COLOR_WINDOW ) );
}
}
}
/////////////////////////////////////////////////////////////////////////////
// The following are utility routines
//////////////////////////////////////////////////
// CMainWindow::FileDlg
// Call the commdlg routine to display File Open or File Save As
// dialogs. The setup is the same for either. If bOpen is TRUE
// then File Open is display otherwise File Save As is displayed.
// The File Name and File Title are stored at the string pointer
// passed in.
//
BOOL CMainWindow::FileDlg( BOOL bOpen, int nMaxFile, LPSTR szFile,
int nMaxFileTitle, LPSTR szFileTitle )
{
OPENFILENAME of;
char szDirName[SIZESTRING];
char szFilter[] = "Phone Book Files (*.pb)\0"
"*.pb\0"
"\0";
szDirName[0] = '.';
of.lStructSize = sizeof( OPENFILENAME );
of.hwndOwner = m_hWnd;
of.lpstrFilter = szFilter;
of.lpstrCustomFilter = NULL;
of.nMaxCustFilter = 0L;
of.nFilterIndex = 1L;
of.lpstrFile=szFile;
of.nMaxFile=nMaxFile;
of.lpstrFileTitle = szFileTitle;
of.nMaxFileTitle = nMaxFileTitle;
of.lpstrInitialDir = szDirName;
of.lpstrTitle = NULL;
of.nFileOffset = 0;
of.nFileExtension = 0;
of.lpstrDefExt = "pb";
if ( bOpen )
{
of.Flags = OFN_HIDEREADONLY;
return GetOpenFileName( &of );
}
else
{
of.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
return GetSaveFileName( &of );
}
}
//////////////////////////////////////////////////
// CMainWindow::Save
// Handles any time a file needs to be saved to the disk.
// Passing in FALSE for name brings up the file save as dialog
// whether or not the database had a name before.
//
BOOL CMainWindow::Save( BOOL bIsNamed /* = FALSE */ )
{
CString szFileName, szFileTitle;
TRY
{
if ( bIsNamed )
m_people.DoSave();
else
{
szFileName = m_people.GetName();
if ( FileDlg( FALSE, SIZESTRING,
szFileName.GetBuffer( SIZESTRING ), SIZESTRING,
szFileTitle.GetBuffer( SIZESTRING ) ) )
{
szFileName.ReleaseBuffer();
m_people.DoSave( szFileName );
m_people.SetTitle( szFileTitle );
SetWindowText( m_people.GetTitle() );
}
else
return FALSE;
}
}
CATCH( CFileException, e )
{
char ErrorMsg[SIZESTRING];
sprintf( ErrorMsg,"Saving %s returned a 0x%lx.",
(const char*)szFileTitle, e->m_lOsError );
MessageBox( ErrorMsg, "File Open Error" );
}
AND_CATCH( CArchiveException, e )
{
char ErrorMsg[SIZESTRING];
sprintf( ErrorMsg,"Reading the %s archive failed.",
(const char*)szFileTitle );
MessageBox( ErrorMsg, "File Open Error" );
}
END_CATCH
return TRUE;
}
//////////////////////////////////////////////////
// CMainWindow::CheckForSave
// Whenever a new file is opened this routine will determine if
// there are unsaved changes in the current database. If so it
// will query the user and determine save or not as appropriate.
//
BOOL CMainWindow::CheckForSave( const char* pszTitle, const char* pszMessage )
{
if ( m_people.IsDirty() )
{
UINT nButton = MessageBox( pszMessage, pszTitle, MB_YESNOCANCEL );
if ( nButton == IDYES )
{
if ( !Save( m_people.IsNamed() ) )
return FALSE;
}
else if ( nButton == IDCANCEL )
return FALSE;
}
return TRUE;
}
//////////////////////////////////////////////////
// CMainWindow::SetMenu
// Whenever the existance of the DataBase is changed this
// routine will reset the menus so only the possible commands
// are accessible.
//
void CMainWindow::SetMenu()
{
CMenu* pMenu = GetMenu();
if ( m_people.IsPresent() )
{
if ( m_people.IsNamed() )
pMenu->EnableMenuItem( IDM_SAVE, MF_ENABLED );
else
pMenu->EnableMenuItem( IDM_SAVE, MF_GRAYED );
pMenu->EnableMenuItem( IDM_SAVEAS, MF_ENABLED );
pMenu->EnableMenuItem( IDM_CLOSE, MF_ENABLED );
pMenu->EnableMenuItem( IDM_PRINT, MF_ENABLED );
pMenu->EnableMenuItem( IDM_ADD, MF_ENABLED );
pMenu->EnableMenuItem( IDM_DELETE, MF_ENABLED );
pMenu->EnableMenuItem( IDM_FIND, MF_ENABLED );
pMenu->EnableMenuItem( IDM_EDIT, MF_ENABLED );
}
else
{
pMenu->EnableMenuItem( IDM_SAVE, MF_GRAYED );
pMenu->EnableMenuItem( IDM_SAVEAS, MF_GRAYED );
pMenu->EnableMenuItem( IDM_CLOSE, MF_GRAYED );
pMenu->EnableMenuItem( IDM_PRINT, MF_GRAYED );
pMenu->EnableMenuItem( IDM_ADD, MF_GRAYED );
pMenu->EnableMenuItem( IDM_DELETE, MF_GRAYED );
pMenu->EnableMenuItem( IDM_FIND, MF_GRAYED );
pMenu->EnableMenuItem( IDM_FINDALL, MF_GRAYED );
pMenu->EnableMenuItem( IDM_EDIT, MF_GRAYED );
}
}
//////////////////////////////////////////////////
// CMainWindow::InvalidateLine
// Marks the screen area of the currently selected person as
// invalid causing windows to call OnPaint to redraw the area.
// This is normally used when the selected line is being changed.
//
void CMainWindow::InvalidateLine()
{
CRect area( 0, ( m_nSelectLine - m_nVscrollPos ) * m_cyChar, m_cxClient,
( m_nSelectLine + 1 - m_nVscrollPos ) * m_cyChar );
InvalidateRect( area );
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.