//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "MainForm.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TfrmMain *frmMain;
/*
Constructor
*/
__fastcall TfrmMain::TfrmMain(TComponent* Owner) : TForm(Owner)
{
Filename_ = ""; // No filename yet
AppName_ = "Notepad#"; // Display in the title bar
Dirty_ = false; // No changes yet
}
//---------------------------------------------------------------------------
/*
If the user wants to open another file or create a new one, this
method should be called to handle the saving of the current file.
If the user doesn't wish to save the file or successfully saves it,
the function returns true. If the user cancels the save, the function
returns false. This lets the calling function take the appropriate action.
*/
bool TfrmMain::CheckAndSave(void)
{
// If the document has changed (i.e. it's dirty), prompt the
// user with a dialog box asking whether or not to save it.
if (Dirty_)
{
AnsiString msg;
// There is no filename yet, nothing to display in the dialog
if (Filename_ == "")
msg = "Save changes?";
else
{
// Just display the filename (no path) in the dialog
AnsiString file = ExtractFileName(Filename_);
msg = Format("Save changes to %s?", ARRAYOFCONST((file)));
}
// Show dialog and wait for user to press a key (Yes, No, Cancel)
int key = MessageDlg(msg, mtWarning, TMsgDlgButtons() << mbYes << mbNo << mbCancel, 0);
// User canceled, no action was taken
if (key == mrCancel)
return false;
// User said yes, so try to save it
else if (key == mrYes)
{
// If this returns false, the user canceled the save action
if (!SaveFile(Filename_))
return false;
}
}
// We've saved, if necessary, and took the correct action
return true;
}
/*
Load a file named "filename" into the TMemo component. Probably need
some error checking here if the user is allowed to enter an invalid
filename.
*/
bool TfrmMain::LoadFile(const AnsiString &filename)
{
// Check if we need to save first
if (CheckAndSave())
{
// Load the file into the memo
mmoEditor->Lines->LoadFromFile(filename);
Filename_ = filename; // We have a valid filename
Dirty_ = false; // No changes yet
UpdateTitleBar(); // Display filename in title bar
UpdateStatusBar(); // Show state of file (e.g. Dirty)
return true; // Loaded the file
}
return false; // Canceled
}
/*
Writes the contents of the TMemo component to a disk file. Probably need
some error checking here if the user is allowed to enter an invalid
filename.
*/
bool TfrmMain::SaveFile(const AnsiString &filename)
{
// Assume we got a "real" filename
AnsiString fname = filename;
// If it's empty, the document has never been saved
if (filename == "")
{
// Ask the user for a name for the file
if (actFileSaveAs->Dialog->Execute())
fname = actFileSaveAs->Dialog->FileName;
else
return false; // User canceled the operation
}
// Write the document to the disk
mmoEditor->Lines->SaveToFile(fname);
Filename_ = fname; // Update the filename (the user provided one)
Dirty_ = false; // The document is now clean
UpdateTitleBar(); // Display filename in the title bar
UpdateStatusBar(); // Show state of file (e.g. Dirty)
return true;
}
/*
Puts the name of the file (if there is one) and the application name
into the title bar
*/
void TfrmMain::UpdateTitleBar(void)
{
if (Filename_ != "")
Caption = ExtractFileName(Filename_) + " - " + AppName_;
else
Caption = AppName_;
}
/*
If the file is dirty, put the word "Dirty" in a status panel. Otherwise,
clear it.
*/
void TfrmMain::UpdateStatusBar(void)
{
if (Dirty_)
barStatus->Panels->Items[0]->Text = " Dirty";
else
barStatus->Panels->Items[0]->Text = "";
}
/*
This function extracts the position of the caret from the TMemo component,
formats a string, and displays it in a status panel.
*/
void TfrmMain::FormatCaretPos(void)
{
// Get the position of the caret in the memo
TPoint pt = mmoEditor->CaretPos;
// Format the text
AnsiString msg = Format(" Ln %d, Col %d", ARRAYOFCONST((pt.y + 1, pt.x + 1)));
// Put it into the right-most panel in the status bar
barStatus->Panels->Items[2]->Text = msg;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Event Handlers
///////////////////////////////////////////////////////////////////////////////
/*
This handles the "New" action and is hooked up to the
File | New menu item.
*/
void __fastcall TfrmMain::actFileNewExecute(TObject *Sender)
{
// Check to see if there is a file already opened and if
// it needs to be saved or not. Returns true if it's OK
// to clear the current document
if (CheckAndSave())
{
mmoEditor->Clear(); // Empty the contents of the memo
Filename_ = ""; // New documents have no name yet
Dirty_ = false; // Obviously it's unchanged
UpdateTitleBar(); // Set title bar
UpdateStatusBar(); // Set status bar (e.g. dirty)
}
}
//---------------------------------------------------------------------------
/*
Handles the "Open" action.
*/
void __fastcall TfrmMain::actFileOpenExecute(TObject *Sender)
{
// Check to see if there is a file already opened and if
// it needs to be saved or not. Returns true if it's OK
// to clear the current document
if (CheckAndSave())
{
bool tempDirty = Dirty_; // save state
Dirty_ = false; // temporarily mark it clean
if (dlgFileOpen->Execute())
{
LoadFile(dlgFileOpen->FileName);
}
else
Dirty_ = tempDirty; // if the user canceled the File | Open
// reset the state of the existing document
}
}
//---------------------------------------------------------------------------
/*
Handles the "Save" action and is hooked up to the File | Save menu item.
*/
void __fastcall TfrmMain::actFileSaveExecute(TObject *Sender)
{
SaveFile(Filename_);
}
//---------------------------------------------------------------------------
/*
This handles the "Save As" action item and is hooked up to
the File | Save As... menu item. Since the "Save As" action is
a standard action (one of the predefined actions), it has its own
Save dialog, so we don't have to display it manually. This event
occurs after the user has already chosen a filename. If the
user canceled the dialog, we don't need to respond to anything.
*/
void __fastcall TfrmMain::actFileSaveAsAccept(TObject *Sender)
{
// The user has chosen a filename, so we will save it to that filename.
SaveFile(actFileSaveAs->Dialog->FileName);
}
//---------------------------------------------------------------------------
/*
Handles the "Exit" action and is hooked up to the File | Exit menu item.
*/
void __fastcall TfrmMain::actFileExitExecute(TObject *Sender)
{
Close(); // Closing the main form causes the app to close "gracefully"
}
//---------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////////////
// The event handlers below are not actions.
/////////////////////////////////////////////////////////////////////////////
/*
Handles the OnCreate event (WM_CREATE message when the form is created.)
*/
void __fastcall TfrmMain::FormCreate(TObject *Sender)
{
// Force the TMemo to occupy the entire window
mmoEditor->Align = alClient;
}
//---------------------------------------------------------------------------
/*
This event occurs whenever the contents of the TMemo component change.
*/
void __fastcall TfrmMain::mmoEditorChange(TObject *Sender)
{
Dirty_ = true; // The contents have changed, so mark it dirty
UpdateStatusBar(); // Update the status bar to reflect the state
}
//---------------------------------------------------------------------------
/*
This event occurs whenever the form is resized.
*/
void __fastcall TfrmMain::FormResize(TObject *Sender)
{
// We want the middle panel to be sized relative to the width
// of the form. To see what happens to the status bar without
// this code, comment the line out, run the program, and
// resize the form. You'll get the idea of the behavior.
// I do this because I want the right-most panel to always be
// able to display the postion of the caret.
barStatus->Panels->Items[1]->Width = Width - 200;
}
//---------------------------------------------------------------------------
/*
This event occurs whenever a keyup happens in the TMemo component.
*/
void __fastcall TfrmMain::mmoEditorKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
{
// Update the display of the caret's position
FormatCaretPos();
}
//---------------------------------------------------------------------------
/*
This event occurs whenever a keydown happens *anywhere* on the form. In order
for the form to intercept all keydowns (regardless of the component the key
down was sent to) you have to enable the KeyPreview property of the form.
You can do that in the Object Inspector at design time, or in the
constructor at runtime.
*/
void __fastcall TfrmMain::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
{
// Update the display of the caret's position
FormatCaretPos();
}
//---------------------------------------------------------------------------