#ifndef _TAppWin_CPP_ #define _TAppWin_CPP_ // INCLUDES // #include"TAppWin.H" // NAME: TAppWin.CPP // TYPE: C++ SOURCE FILE // SYNOPSIS: // DESCRIPTION: Implementation of the TAppWindow class // BUGS: // SEE ALSO: //--------------------------------------------------------------------------- // // globals // ~~~~~~~ // gadgets TStatusBar *sb; TTextGadget *sg, *fg; // // response table // ~~~~~~~~ ~~~~~ DEFINE_RESPONSE_TABLE1(TAppWindow, TWindow) EV_BN_CLICKED(NEXT_BUTTON, EvNextBnClicked), EV_BN_CLICKED(PREV_BUTTON, EvPrevBnClicked), EV_BN_CLICKED(FIRST_BUTTON, EvFirstBnClicked), EV_BN_CLICKED(LAST_BUTTON, EvLastBnClicked), EV_BN_CLICKED(ADD_BUTTON, EvAddBnClicked), EV_BN_CLICKED(BROWSE_BUTTON, EvBrowseBnClicked), EV_BN_CLICKED(EDIT_BUTTON, EvEditBnClicked), EV_BN_CLICKED(UPDATE_BUTTON, EvUpdateBnClicked), EV_BN_CLICKED(CLEAR_BUTTON, EvClearBnClicked), EV_BN_CLICKED(DEL_BUTTON, EvDelBnClicked), EV_COMMAND(CM_FILENEW, CmFileNew), EV_COMMAND(CM_FILEOPEN, CmFileOpen), EV_COMMAND(CM_FILECLOSE, CmFileClose), EV_COMMAND(CM_FILESAVE, CmFileSave), EV_COMMAND(CM_FILESAVEAS, CmFileSaveAs), EV_COMMAND(CM_FIND, CmFind), EV_COMMAND_ENABLE(CM_FILENEW, CeFileNew), EV_COMMAND_ENABLE(CM_FILECLOSE, CeFileClose), EV_COMMAND_ENABLE(CM_FILEOPEN, CeFileOpen), EV_COMMAND_ENABLE(CM_FILESAVE, CeFileSave), EV_COMMAND_ENABLE(CM_FILESAVEAS, CeFileSaveAs), EV_COMMAND_ENABLE(CM_FIND, CeFind), END_RESPONSE_TABLE; //=============================================== // // constructor // ~~~~~~~~~~~ TAppWindow::TAppWindow(TWindow* parent) : TWindow(parent, 0), state( IDLE ), fileState( CLOSED ), IsDirty( false ) { // database d = new TDatabase; // DEBUG ONLY used to test logic of file handling, menu commands etc. debug1 = new TStatic(this, DEBUG1, " ", 270, 40, 150, 20, 0); debug2 = new TStatic(this, DEBUG2, " ", 270, 80, 150, 20, 0); // labels message = new TStatic(this, MESSAGE, " ", 270, 60, 150, 20, 0); new TStatic(this, ST1, "Co. Name:", 10, 10, 75, 20, 0); new TStatic(this, ST2, "Dept.:", 10, 50, 75, 20, 0); new TStatic(this, ST3, "Address:", 10, 90, 75, 20, 0); new TStatic(this, ST4, "City:", 10, 130, 75, 20, 0); new TStatic(this, ST5, "PostCode:", 10, 170, 75, 20, 0); new TStatic(this, ST6, "Contact:", 10, 210, 75, 20, 0); new TStatic(this, ST7, "Tel. No.:", 10, 250, 75, 20, 0); new TStatic(this, ST8, "Last Called:", 250, 130, 85, 20, 0); new TStatic(this, ST9, "Call On:", 250, 170, 85, 20, 0); // construct edits & associate validators coNameEdit = new TEdit(this, ED_CO_NAME, " ", 80, 10, 150, 20, 0, false); coNameEdit->SetValidator(new TFilterValidator("0-9A-Za-z. ")); deptEdit = new TEdit(this, ED_DEPT, " ", 80, 50, 150, 20, 0, false); deptEdit->SetValidator(new TFilterValidator("A-Za-z. ")); addEdit = new TEdit(this, ED_ADD, " ", 80, 90, 150, 20, 0, false); addEdit->SetValidator(new TFilterValidator("0-9A-Za-z. ")); cityEdit = new TEdit(this, ED_CITY, " ", 80, 130, 150, 20, 0, false); cityEdit->SetValidator(new TFilterValidator("A-Za-z. ")); postEdit = new TEdit(this, ED_POST, " ", 80, 170, 150, 20, 0, false); postEdit->SetValidator(new TPXPictureValidator("&&#[!] [#][&][&]")); contEdit = new TEdit(this, ED_CONT, " ", 80, 210, 150, 20, 0, false); contEdit->SetValidator(new TFilterValidator("A-Za-z. ")); telEdit = new TEdit(this, ED_TEL, " ", 80, 250, 150, 20, 0, false); telEdit->SetValidator(new TPXPictureValidator("[*11{#}]")); calledEdit = new TEdit(this, ED_CALL, " ", 330, 130, 100, 20, 11, false); calledEdit->SetValidator(new TPXPictureValidator("##/##/####")); toCallEdit = new TEdit(this, ED_TO_CALL, " ", 330, 170, 100, 20, 11, false); toCallEdit->SetValidator(new TPXPictureValidator("##/##/####")); memoEdit = new TEdit(this, ED_MEMO, " ", 330, 210, 250, 120, 257, true); // construct nav btns firstBtn = new TButton(this, FIRST_BUTTON, "First", 20, 300, 50, 25, true); prevBtn = new TButton(this, PREV_BUTTON, "Prev", 70, 300, 50, 25, true); nextBtn = new TButton(this, NEXT_BUTTON, "Next", 120, 300, 50, 25, true); lastBtn = new TButton(this, LAST_BUTTON, "Last", 170, 300, 50, 25, true); // construct file & database buttons addBtn = new TButton(this, ADD_BUTTON, "Add Record", 450, 10, 120, 25, true); updateBtn= new TButton(this, UPDATE_BUTTON, "Save Record", 450, 90, 120, 25, true); clearBtn = new TButton(this, CLEAR_BUTTON, "Cancel Edits", 450, 130, 120, 25, true); delBtn = new TButton(this, DEL_BUTTON, "Delete Record", 450, 170, 120, 25, true); // mode buttons browseBtn=new TButton(this, BROWSE_BUTTON, "Browse", 270, 10, 75, 25, true); editBtn = new TButton(this, EDIT_BUTTON, "Edit", 345, 10, 75, 25, true); // set file handling properties FileData = new TOpenSaveDialog::TData(OFN_HIDEREADONLY|OFN_FILEMUSTEXIST, "ProjEx3 Files (*.PR3)|*.pr3|", 0, "", "PR3"); }// END constructor //=============================================== // // destructor // ~~~~~~~~~~ TAppWindow::~TAppWindow() { delete d; delete FileData; } void TAppWindow::SetupWindow() { TWindow::SetupWindow(); calledEdit->SetTextLimit( 10 ); toCallEdit->SetTextLimit( 10 ); coNameEdit->SetReadOnly( true ); deptEdit->SetReadOnly( true ); addEdit ->SetReadOnly( true ); cityEdit->SetReadOnly( true ); postEdit->SetReadOnly( true ); contEdit->SetReadOnly( true ); telEdit ->SetReadOnly( true ); memoEdit ->SetReadOnly( true ); calledEdit->SetReadOnly( true ); toCallEdit->SetReadOnly( true ); SetState( IDLE ); SetFileState( CLOSED ); SetIsDirty( false ); } // overrides TApplication::CanClose bool TAppWindow::CanClose() { if (IsDirty) switch(MessageBox("Do you want to save?", "Records have changed.", MB_YESNOCANCEL | MB_ICONQUESTION)) { case IDCANCEL: return false; case IDYES: CmFileSave(); } return true; } // sets state void TAppWindow::SetState( states s ) { state = s; switch(s) { case BROWSING : sg->SetText("Browsing"); break; case EDITING : sg->SetText("Editing"); break; case ADD_REC : sg->SetText("Adding new Record"); break; case IDLE : sg->SetText("Idle"); break; }// switch } // sets fileState void TAppWindow::SetFileState( fileStates s ) { fileState = s; switch(s) { case OPEN : fg->SetText("Open"); break; case CLOSED : fg->SetText("Closed"); break; case NEW : fg->SetText("New"); break; }// switch } void TAppWindow::SetIsDirty( bool b ) { IsDirty = b; if( b ) debug2->SetText("true"); else debug2->SetText("false"); } // // edits functionality // ~~~~~ ~~~~~~~~~~~~~ // refreshes edits with data referenced by iterator TDBIt& TAppWindow::RefreshEdits( TDBIt& ir) { DBStruct s = ( *ir ); coNameEdit->SetText( s.coName ); deptEdit->SetText( s.department ); addEdit ->SetText( s.address ); cityEdit->SetText( s.city ); postEdit->SetText( s.post ); contEdit->SetText( s.contact ); telEdit ->SetText( s.telephone ); memoEdit->SetText( s.memo ); char str[10]; strcpy( str, DateToString( s.called ) ); calledEdit->SetText( str ); strcpy( str, DateToString( s.toCall ) ); toCallEdit->SetText( str ); return ir; } // clears edits void TAppWindow::ClearEdits() { coNameEdit->Clear(); deptEdit->Clear(); addEdit ->Clear(); cityEdit->Clear(); postEdit->Clear(); contEdit->Clear(); telEdit ->Clear(); memoEdit->Clear(); calledEdit->Clear(); toCallEdit->Clear(); } // toggles read only void TAppWindow::SetEditsReadOnly( bool readOnly ) { coNameEdit->SetReadOnly( readOnly ); contEdit->SetReadOnly( readOnly ); deptEdit->SetReadOnly( readOnly ); addEdit ->SetReadOnly( readOnly ); cityEdit->SetReadOnly( readOnly ); postEdit->SetReadOnly( readOnly ); telEdit ->SetReadOnly( readOnly ); memoEdit ->SetReadOnly( readOnly ); calledEdit->SetReadOnly( readOnly ); toCallEdit->SetReadOnly( readOnly ); } // tests if edits text has been changed bool TAppWindow::IsEditsModified() { if(coNameEdit->IsModified() || contEdit->IsModified() || deptEdit->IsModified() || addEdit ->IsModified() || cityEdit->IsModified() || postEdit->IsModified() || telEdit ->IsModified() || memoEdit ->IsModified() || calledEdit->IsModified() || toCallEdit->IsModified() ) return true; return false; } // END edits functionality //=============================================== // // menu commands // ~~~~ ~~~~~~~~ // closes file void TAppWindow::CmFileClose() { if( fileState == CLOSED ) { MessageBox("No Open File", "Close File", MB_OK); return; } if( CanClose() ) { d->erase( d->begin(), d->end() ); // clear set SetEditsReadOnly( false ); ClearEdits(); SetEditsReadOnly( true ); SetState( IDLE ); SetFileState( CLOSED ); SetIsDirty( false ); } }// CmFileClose // new file void TAppWindow::CmFileNew() { // if BROWSING and CanClose close currently open file d->erase( d->begin(), d->end() ); // clear set SetEditsReadOnly( false ); ClearEdits(); SetState( ADD_REC ); SetFileState( NEW ); SetIsDirty( true ); // temporary logic :) } // opens file void TAppWindow::CmFileOpen() { if( CanClose() ) { if ( ( TFileOpenDialog( this, *FileData ) ).Execute() == IDOK ) { OpenFile(); SetIsDirty( false ); SetEditsReadOnly( true ); SetFileState( OPEN ); SetState( BROWSING ); } } }// CmFileOpen // saves file void TAppWindow::CmFileSave() { if( fileState == CLOSED ) { MessageBox("No Open File", "Save File", MB_OK); return; } if( IDYES == MessageBox( "Do you wish to save?", "Save File",MB_YESNO ) ) { if (fileState == NEW) CmFileSaveAs(); else SaveFile(); } fileState =OPEN; state =BROWSING; } // saves file as void TAppWindow::CmFileSaveAs() { if( fileState == CLOSED ) { MessageBox("No Open File", "Save File As", MB_OK); return; } if (fileState == NEW) strcpy( FileData->FileName, "" ); if ( ( TFileSaveDialog( this, *FileData ) ).Execute() == IDOK) SaveFile(); } // finds coName void TAppWindow::CmFind() { TDBIt& temp =d->end(); temp =FindFieldDialog(this, temp, *d); if( temp != d->end() ) RefreshEdits( temp ); } // END menu commands //=============================================== // // command-enabling functions // ~~~~~~~ ~~~~~~~~ ~~~~~~~~~ void TAppWindow::CeFind( TCommandEnabler& ce ) { ce.Enable( fileState == OPEN ); } void TAppWindow::CeFileNew( TCommandEnabler& ce ) { ce.Enable( fileState == CLOSED ); } void TAppWindow::CeFileClose( TCommandEnabler& ce ) { ce.Enable( fileState != CLOSED ); } void TAppWindow::CeFileOpen( TCommandEnabler& ce ) { ce.Enable( fileState == CLOSED || IsDirty ); } // void TAppWindow::CeFileSave( TCommandEnabler& ce ) { ce.Enable( fileState == OPEN ); } // void TAppWindow::CeFileSaveAs( TCommandEnabler& ce ) { ce.Enable( fileState != CLOSED && !IsEditsModified() ); } // END command-enabling functions //=============================================== // // file opening and saving // ~~~~ ~~~~~~~ ~~~ ~~~~~~ void TAppWindow::SaveFile() { int mode =ios::app // append mode: all additions at eof | ios::trunc // truncate file if already exists | ios::binary; // binary file ofstream fout(FileData->FileName, mode); if (!fout) MessageBox("Unable to open file", "File Error", MB_OK | MB_ICONEXCLAMATION); else { TDatabase::size_type size = d->size(); fout<begin(); while( it != d->end() ) // while not past the end write file { fout.write(reinterpret_cast( &(*it) ),sizeof( *it ) ); it++; } fout.close(); } SetFileState( OPEN ); SetIsDirty( false ); } // opens file void TAppWindow::OpenFile() { ifstream fin( FileData->FileName, ios::binary ); if (!fin) MessageBox("Unable to open file", "File Error", MB_OK | MB_ICONEXCLAMATION); else // read in file { TDatabase::size_type size; fin>>size; while( size-- ) { DBStruct* sp = new DBStruct; fin.read(reinterpret_cast(sp), sizeof(*sp)); d->insert( *sp ); } } // display first record it =d->begin(); RefreshEdits( it ); } // OpenFile() // END file opening and saving //=============================================== // // Event Handlers // ~~~~~ ~~~~~~~~ // nav buttons // EvFirstBnClicked() void TAppWindow::EvFirstBnClicked() { if( IsDirty || fileState == CLOSED || IsEditsModified() ) return; it =d->begin(); RefreshEdits( it ); } // EvNextBnClicked() void TAppWindow::EvNextBnClicked() { if( IsDirty || fileState == CLOSED || IsEditsModified() ) return; it++; if( it != d->end() ) // if not past the end? RefreshEdits(it); else it--; }// EvNextBnClicked() // EvPrevBnClicked() void TAppWindow::EvPrevBnClicked() { if( IsDirty || fileState == CLOSED || IsEditsModified() ) return; if( it != d->begin() ) // if not at beginning? { it--; RefreshEdits(it); } } // EvLastBnClicked() void TAppWindow::EvLastBnClicked() { if( IsDirty || fileState == CLOSED || IsEditsModified() ) return; it =d->end(); // past the end it--; // back to last element RefreshEdits( it ); } // adds new record void TAppWindow::EvAddBnClicked() { if( fileState == CLOSED ) { MessageBox("No Open File", "Add Record", MB_OK); return; } if( state != EDITING) return; SetEditsReadOnly( false ); ClearEdits(); SetState( ADD_REC ); } // EvBrowseBnClicked() sets mode to BROWSING void TAppWindow::EvBrowseBnClicked() { if( !IsEditsModified() ) { SetState( BROWSING ); SetEditsReadOnly( true ); } } // EvClearBnClicked() clears edits void TAppWindow::EvClearBnClicked() { if( fileState == CLOSED) { MessageBox( "No file is open", "Clear Edits", MB_OK); return; } if(state == IDLE || state == BROWSING) { MessageBeep(-1); return; } ClearEdits(); SetEditsReadOnly( true ); if( fileState != NEW ) RefreshEdits( it ); SetState( BROWSING ); SetIsDirty( false ); }// EvClearBnClicked() // EvDelBnClicked() deletes record void TAppWindow::EvDelBnClicked() { if( 1 == d->size() ) { MessageBox( "Final record, cannot delete", "Delete Record", MB_OK); return; } if( fileState == CLOSED) { MessageBox( "No file is open", "Delete Record", MB_OK); return; } if( state != EDITING ) return; if(IDYES ==MessageBox("Are you sure you want to delete this record?", "Delete Record", MB_YESNOCANCEL) ) { char str[100]; coNameEdit->GetText(str, 100); SetEditsReadOnly( false ); ClearEdits(); d->erase( str ); RefreshEdits( d->begin() ); SaveFile(); SetIsDirty( false ); } }// EvDelBnClicked() // EvEditBnClicked() edits record void TAppWindow::EvEditBnClicked() { if( fileState == CLOSED ) { MessageBox("No Open File", "Edit Record", MB_OK); return; } if( state != BROWSING) return; SetEditsReadOnly( false ); SetState( EDITING ); }// EvEditBnClicked() // EvUpdateBnClicked() saves/updates record // ADDITIONS TO BE MADE TO THIS FUNCTION void TAppWindow::EvUpdateBnClicked() { if( fileState == CLOSED) { MessageBox( "No open file", "Update Record", MB_OK); return; } // disable button if nothing to save if( state == IDLE || state == BROWSING ) return; // create local char arrays char lpszCalled[10], lpszToCall[10]; // get text from edits calledEdit->GetText( lpszCalled, 11 ); toCallEdit->GetText( lpszToCall, 11 ); // are dates valid? if( ! IsValiDate( lpszCalled ) ) { MessageBox( "Invalid Date, enter a valid date", "Update Record", MB_OK); calledEdit->SetFocus( ); return; } if( ! IsValiDate( lpszToCall ) ) { MessageBox( "Invalid Date, enter a valid date", "Update Record", MB_OK); toCallEdit->SetFocus( ); return; } if( IDYES == MessageBox( "Do you wish to save?", "Update Record",MB_YESNO ) ) { char keyStr[100]; DBStruct* dbs = new DBStruct; coNameEdit->GetText( keyStr, 100 ); /* // return if duplicate company name exists if( d->find( keyStr ) != d->end() ) { MessageBox( "Duplicate Company Name, enter a different compant name", "Update Record", MB_OK); coNameEdit->SetFocus( ); return; } */ dbs->called= StringToDate(lpszCalled); dbs->toCall= StringToDate(lpszToCall); // return if toCall < called if( dbs->toCall < dbs->called ) { MessageBox( "Date to call is before last called date, please modify as required", "Update Record", MB_OK); calledEdit->SetFocus( ); return; } coNameEdit->GetText( dbs->coName, 100 ); contEdit ->GetText( dbs->contact, 50 ); deptEdit ->GetText( dbs->department, 30 ); addEdit ->GetText( dbs->address, 100 ); cityEdit ->GetText( dbs->city, 30 ); postEdit ->GetText( dbs->post, 13 ); telEdit ->GetText( dbs->telephone, 13 ); memoEdit ->GetText( dbs->memo, 256 ); if( state == EDITING ) d->erase( keyStr ); d->insert( *dbs ); // if new file if( fileState == OPEN ) SaveFile(); else { CmFileSaveAs(); fileState =OPEN; } ClearEdits(); SetEditsReadOnly( true ); RefreshEdits( d->find( keyStr ) ); SetState( BROWSING ); SetIsDirty( false ); } } // EvUpdateBnClicked() // END event Handlers //=============================================== #endif // _TAppWin_CPP_