First Windows Program-details

GroceryList::Print Modified for Windows

void GroceryList::print(ostream & out)
{

	ArrayIterator< GroceryItem> next(_item);
	while (next)
	{
		next().print(out);
		out << endl;
		next++;
	}
   	out << '\0';//needed since we are actually creating a string here
}

Exam5Window::cmAddItem

The handler for adding an item collects all of the information needed to create a new GroceryItem, creates a new GroceryItem, then inserts that item into the list. Until now we have never read information in windows. Dialog boxes are use to read information, and while it would probably be better to design a dialog box specifically for this function, we will use the built-in class TInputDialog. The TInputDialog is a subclass of Window, so the first arguement in its constructor is the parent window, this. The next string is the title of the window, followed by the prompt string. The next two items are the buffer where the input is stored and the length of the buffer.

All data transferred back from the TInputDialog is in the form a c language string, so you are responsible for converting it to an appropriate form. in the case of a string you need only initialize the string with your buffer, but integers and floats are initialized using the functions atoi and atof. The function atoi converts the string buff to an integer while atof converts the string buff to a float.

void Exam5Window::cmAddItem ()
{
    // INSERT>> Your code here. 
	 char buff[255];
	 buff[0]='\0';
	 TInputDialog(this,"Item Name", "Enter the item name", buff, 255).Execute();
	 string name(buff);
	 buff[0]='\0';
	 TInputDialog(this,"Item Id", "Enter the item id", buff, 255).Execute();
	 string id(buff);
	 buff[0]='\0';
	 TInputDialog(this,"Item unit cost", "Enter the item unit cost", buff, 255).Execute();
	 double cost = atof(buff);
	 buff[0]='\0';
	 TInputDialog(this,"Number Ordered", "Enter the number of items ordered", buff, 255).Execute();
	 int howMany = atoi(buff);
	 GroceryItem g(name,id,cost,howMany);
	 groceries.addItem(g);

}

Save and SaveAs Command Handlers

The save handler is boiler plate code (a template) with the call to groceries.write (in bold) that does the actual saving. The rest is simply windows shuffling. Notice the file name is retrieved from the applications FileData structure. If this name is not defined (NULL) then the save as command is called to get the name. Once the name has been retrieved it is available while the file is being edited.

void Exam5Window::cmSave ()
{
    // INSERT>> Your code here. 
	exam5App *theApp = TYPESAFE_DOWNCAST(GetApplication(), exam5App);
	if (strlen(theApp->FileData.FileName)==0)//no file specified yet
		cmSaveAs();
	else {
		ofstream os(theApp->FileData.FileName);
		if (!os)
			throw"Unable to open output file.","File Error";
		else {
			groceries.write(os);
			SetCaption(theApp->FileData.FileName);
			theApp->GetMainWindow()->RedrawWindow(0, 0,
				RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW);
		}
	}

}

The handler for save as is responsible for retrieving the file path and name. This is stored as a char* string in the applications FileData FileName structure. Once this information is retrieved by the TFileSaveDialog, it is stored in the application. The next time the Save command is executed, the information is available in the FileData structure and save calls the specific document save routine.

void Exam5Window::cmSaveAs ()
{
    // INSERT>> Your code here.   
	exam5App *theApp = TYPESAFE_DOWNCAST(GetApplication(), exam5App);
	TOpenSaveDialog::TData tempFileData (
		OFN_HIDEREADONLY | OFN_FILEMUSTEXIST,
		"Grocery files (*.dat) | *.dat | ",0,"","DAT");
	if ((new TFileSaveDialog(this, tempFileData))->Execute() == IDOK) {
		strcpy(theApp->FileData.FileName, tempFileData.FileName);
		cmSave ();
	}

}

For more information on TFileSaveDialog click here.

For more information about TData::FileData click here.

Opening the File

The open command is processed by the application class. The handler first uses the TFileOpenDialog to get the file name, then calls on OpenFile to actually open the file. In this case the TWindow actually reads the data.

void exam5App::CmFileOpen ()
{
    //
    // Display standard Open dialog box to select a file name.
    //
    *FileData.FileName = 0;

	 Exam5Window *client = TYPESAFE_DOWNCAST(GetMainWindow()->GetClientWindow(), Exam5Window);     // Client window for the frame.
	 if (client->CanClose())
       	     if (TFileOpenDialog(GetMainWindow(), FileData).Execute() == IDOK)
           	        OpenFile(FileData.FileName);
}


void exam5App::OpenFile (const char *fileName)
{
    if (fileName)
	strcpy(FileData.FileName, fileName);

    Exam5Window *client = TYPESAFE_DOWNCAST(GetMainWindow()->GetClientWindow(), Exam5Window);     // Client window for the frame.
	 client->read(FileData.FileName);

}

This is not a handler function, so you must add its signature to the class definition in the header and add the function body in the cpp file. This function is almost identical to the Easy windows version.

void Exam5Window::read(char *fileName)
{
	groceries.clearList();
	ifstream in(fileName);
	if (!in)
		throw "File Not Found";
	groceries.read(in);
}

For complete code click here.