4.6 File Listings

The code shown in Listings 1 and 2 is available on your distribution disks in Files DATABASE.H and DATABASE.CPP.

Listing 1

// database.h : Declares the interfaces for the CDataBase class.

//

// This is a part of the Microsoft Foundation Classes C++ library.

// Copyright (C) 1991 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.

#ifndef __DATABASE_H__

#define __DATABASE_H__

#include "person.h"

/////////////////////////////////////////////////////////////////////////////

// string const for untitiled database

extern const char szUntitled[];

//////////////////////////////////////////////////

// CDataBase

// The database object is intended to encapsulate everything

// needed to work the CPersonList into one interface.

// Exception handling, data manipulations, and searching

// are handled on this level freeing the view program, whether it

// is character or windows, to deal with displaying the data.

//

class CDataBase: public CObject

{

public:

// constructor

CDataBase()

{

m_pDataList = NULL;

m_pFindList = NULL;

m_szFileName = "";

m_szFileTitle = "";

}

// Create/Destroy CPersonLists

BOOL New();

void Terminate();

// File handling

BOOL DoOpen( const char* pszFileName );

BOOL DoSave( const char* pszFileName = NULL );

BOOL DoFind( const char* pszLastName = NULL );

// Person Handling

void AddPerson( CPerson* pNewPerson );

void ReplacePerson( CPerson* pOldPerson, const CPerson& rNewPerson );

void DeletePerson( UINT nIndex );

CPerson* GetPerson( UINT nIndex );

// Database Attributes

UINT GetCount()

{

ASSERT_VALID( this );

if ( m_pFindList != NULL )

return m_pFindList -> GetCount();

if ( m_pDataList != NULL )

return m_pDataList -> GetCount();

return 0;

}

BOOL IsDirty()

{ ASSERT_VALID( this );

return ( m_pDataList != NULL ) ? m_pDataList -> GetDirty() : FALSE; }

BOOL IsNamed()

{ ASSERT_VALID( this );

return m_szFileName != szUntitled; }

const char* GetName()

{ ASSERT_VALID( this );

return m_szFileName; }

CString GetTitle()

{ ASSERT_VALID( this );

return "Phone Book - " + m_szFileTitle; }

void SetTitle( const char* pszTitle )

{ ASSERT_VALID( this );

m_szFileTitle = pszTitle; }

BOOL IsPresent()

{ ASSERT_VALID( this );

return m_pDataList != NULL; }

protected:

CPersonList* m_pDataList;

CPersonList* m_pFindList;

CString m_szFileName;

CString m_szFileTitle;

private:

CPersonList* ReadDataBase( CFile* pFile );

BOOL WriteDataBase( CFile* pFile );

#ifdef _DEBUG

public:

void AssertValid() const;

#endif

};

/////////////////////////////////////////////////////////////////////////////

#endif // __DATABASE_H__

Listing 2

// database.cpp : Defines the behaviors for the CDataBase

class.

//

// This is a part of the Microsoft Foundation Classes C++ library.

// Copyright (C) 1991 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 "database.h"

#include <string.h>

#ifdef _DEBUG

#undef THIS_FILE

static char BASED_CODE THIS_FILE[] = __FILE__;

#endif

const char* szUntitled = "Untitled";

//////////////////////////////////////////////////////////////////////////

// CDataBase

//

//////////////////////////////////////////////////

// CDataBase::New

// Initializes the database.

//

BOOL CDataBase::New()

{

ASSERT_VALID( this );

// Clean up any old data.

Terminate();

m_pDataList = new CPersonList;

return ( m_pDataList != NULL );

}

//////////////////////////////////////////////////

// CDataBase::Terminate

// Cleans up the database.

//

void CDataBase::Terminate()

{

ASSERT_VALID( this );

if ( m_pDataList != NULL )

m_pDataList -> DeleteAll();

delete m_pDataList;

delete m_pFindList;

m_pDataList = NULL;

m_pFindList = NULL;

m_szFileName = szUntitled;

m_szFileTitle = szUntitled;

}

//////////////////////////////////////////////////

// CDataBase::AddPerson

// Inserts a person in the appropriate position (alphabetically by last

// name) in the database.

//

void CDataBase::AddPerson( CPerson* pNewPerson )

{

ASSERT_VALID( this );

ASSERT_VALID( pNewPerson );

ASSERT( pNewPerson != NULL );

ASSERT( m_pDataList != NULL );

POSITION pos = m_pDataList -> GetHeadPosition();

while ( pos != NULL &&

_stricmp( ((CPerson*)m_pDataList -> GetAt(pos)) -> GetLastName(),

pNewPerson -> GetLastName() ) <= 0 )

m_pDataList -> GetNext( pos );

if ( pos == NULL )

m_pDataList -> AddTail( pNewPerson );

else

m_pDataList -> InsertBefore( pos, pNewPerson );

m_pDataList -> SetDirty( TRUE );

}

//////////////////////////////////////////////////

// CDataBase::GetPerson

// Look up someone by index.

//

CPerson* CDataBase::GetPerson( UINT nIndex )

{

ASSERT_VALID( this );

ASSERT( m_pDataList != NULL );

if ( m_pFindList != NULL )

return (CPerson*)m_pFindList -> GetAt( m_pFindList ->

FindIndex( nIndex ) );

else

return (CPerson*)m_pDataList -> GetAt( m_pDataList ->

FindIndex( nIndex ) );

}

//////////////////////////////////////////////////

// CDatabase::DeletePerson

// Removes record of person from database.

//

void CDataBase::DeletePerson( UINT nIndex )

{

ASSERT_VALID( this );

ASSERT( m_pDataList != NULL );

if ( m_pFindList != NULL )

m_pFindList -> RemoveAt( m_pFindList -> FindIndex( nIndex ) );

else

m_pDataList -> RemoveAt( m_pDataList -> FindIndex( nIndex ) );

m_pDataList -> SetDirty( TRUE );

}

//////////////////////////////////////////////////

// CDatabase::ReplacePerson

// Replaces an object in the list with a new object.

//

void CDataBase::ReplacePerson( CPerson* pOldPerson, const CPerson& rNewPerson )

{

ASSERT_VALID( this );

ASSERT( pOldPerson != NULL );

ASSERT( m_pDataList != NULL );

//Using the overloaded operator= for CPerson

*pOldPerson = rNewPerson;

m_pDataList -> SetDirty( TRUE );

}

//////////////////////////////////////////////////

// CDataBase::DoFind

// Does a FindPerson call, or clears the find data.

//

BOOL CDataBase::DoFind( const char* pszLastName /* = NULL */ )

{

ASSERT_VALID( this );

ASSERT( m_pDataList != NULL );

if ( pszLastName == NULL )

{

delete m_pFindList;

m_pFindList = NULL;

return FALSE;

}

// The interface should not allow a second find to occur while

// we already have one.

// ASSERT( m_pFindList == NULL );

// return ( ( m_pFindList = m_pDataList ->

// FindPerson( pszLastName ) ) != NULL );

}

//////////////////////////////////////////////////

// CDataBase::DoOpen

// Reads a database from the given filename.

//

BOOL CDataBase::DoOpen( const char* pszFileName )

{

ASSERT_VALID( this );

ASSERT( pszFileName != NULL );

CFile file( pszFileName, CFile::modeRead );

// read the object data from file

CPersonList* pNewDataBase = ReadDataBase( &file );

file.Close();

// get rid of current data base if new one is OK

if ( pNewDataBase != NULL )

{

Terminate();

m_pDataList = pNewDataBase;

m_pDataList -> SetDirty( FALSE );

m_szFileName = pszFileName;

return TRUE;

}

else

return FALSE;

}

//////////////////////////////////////////////////

// CDataBase::DoSave

// Saves the database to the given file.

//

BOOL CDataBase::DoSave( const char* pszFileName /* = NULL */ )

{

ASSERT_VALID( this );

// if we were given a name store it in the object.

if ( pszFileName != NULL )

m_szFileName = pszFileName;

CFileStatus status;

UINT nAccess = CFile::modeWrite;

// GetStatus will return TRUE if file exists, or FALSE if it doesn't.

if ( !CFile::GetStatus( m_szFileName, status ) )

nAccess |= CFile::modeCreate;

CFile file( m_szFileName, nAccess );

// write the data base to a file

// mark it clean if write is successful

if ( WriteDataBase( &file ) )

{

m_pDataList -> SetDirty( FALSE );

file.Close();

return TRUE;

}

else

{

file.Close();

return FALSE;

}

}

//////////////////////////////////////////////////

// CDataBase::ReadDataBase

// Serializes in the database.

//

CPersonList* CDataBase::ReadDataBase( CFile* pFile )

{

ASSERT_VALID( this );

CPersonList* pNewDataBase = NULL;

// Create an archive from pFile for reading.

CArchive archive( pFile, CArchive::load );

// Deserialize the new data base from the archive, or catch the

// exception.

TRY

{

archive >> pNewDataBase;

}

CATCH( CArchiveException, e )

{

#ifdef _DEBUG

e -> Dump( afxDump );

#endif

archive.Close();

// If we got part of the database, then delete it.

if ( pNewDataBase != NULL )

{

pNewDataBase -> DeleteAll();

delete pNewDataBase;

}

// We caught this exception, but we throw it again so our caller can

// also catch it.

THROW_LAST();

}

END_CATCH

// Exit here if no errors or exceptions.

archive.Close();

return pNewDataBase;

}

//////////////////////////////////////////////////

BOOL CDataBase::WriteDataBase( CFile* pFile )

{

ASSERT_VALID( this );

ASSERT( m_pDataList != NULL );

// Create an archive from theFile for writing

CArchive archive( pFile, CArchive::store );

// Archive out, or catch the exception.

TRY

{

archive << m_pDataList;

}

CATCH( CArchiveException, e )

{

#ifdef _DEBUG

e -> Dump( afxDump );

#endif

archive.Close();

// Throw this exception again for the benefit of our caller.

THROW_LAST();

}

END_CATCH

// Exit here if no errors or exceptions.

archive.Close();

return TRUE;

}

#ifdef _DEBUG

void CDataBase::AssertValid() const

{

if ( m_pDataList != NULL )

{

ASSERT_VALID( m_pDataList );

if ( m_pFindList != NULL )

ASSERT_VALID( m_pFindList );

}

else

ASSERT( m_pFindList == NULL );

}

#endif