The Library

Introduction

The library problem is fairly simple conceptually, but will have a number of programming challenges. This program uses list boxes and will require that you save and open files, so you may want to review the material covered in week 7 and week 12. We will maintain libraries with multiple collections on-line. The librarian may add or delete titles and users may search for all books by a given author or all books with a given title. This will not be authentic since there will be no security to keep users from adding and removing texts. Books will only be listed by title and author. No further information will be available. For those with stamina next semester we will do the whole thing!

The Layout

The main window will contain a listbox with all books in the collection available. This will not be ordered (the default with a listbox main window) since we want the listbox to have the same order as the file containing the collection. The following is a sample of how your main window will look.

When you search for a title or author, use a TInputDialog to retrieve the author's name or the book title. Then display the results in a dialog similar to the one shown below. Notice this dialog uses an ordered listbox with tab stops.

This dialog is used for both types of search, so the TEdit box at the top has the type of item searched for as well as the instance name (in this case "books by Hiaasen Carl").

Another dialog similar to that shown below is used to gather book information for add and delete functions.

The Specifics

You will develop the classes Book and Library independent of windows. The to see header I used for these classes click here. There are few functions which if implemented properly will make your work much easier. First the == operator for Book can be set to catch exact matches, matches when only the author is specified and matches when only the title is specified. This makes it posible to use two very similar functions; the one to find all books by an author and the one to find all books with the same title.

int Book::operator== ( const Book &b) const
{
// treats most restrictive case first.
	return (_author == b._author && _title == b._title) ||
			(_author.length()==0 && _title == b._title) || // search for title
			(b._author == _author && _title.length()==0);  // search for author

}


BookList Library::findAuthor( const string& author) 
{
	Book b(author,"");
	BookList results;
	ArrayIterator < Book > next(_books);
	while (next)
	{
		if (b == next())
			results.insertItem(next());
		next++;
	}
	return results;
}

The Windows Interface

The open, save and saveas functions are very similar to those shown in week 7. I used one variable _collection of type counted pointer to a Library to connect the interface to the application. This pointer is created when the application is initialized.

Lab6App::Lab6App () : TApplication("Lab6")
{

    // Common file file flags and filters for Open/Save As dialogs.  Filename and directory are
    // computed in the member functions CmFileOpen, and CmFileSaveAs.
    FileData.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
    FileData.SetFilter("Library Files (*.dat)|*.dat|All Files (*.*)|*.*|");

	 // INSERT>> Your constructor code here.
	 _collection = new Library;
}

The library pointer is passed to the SDIDecFrame in a new constructor that has a LibPtr as its first parameter. This is added as a second constructor seen below.

void Lab6App::InitMainWindow ()
{
    if (nCmdShow != SW_HIDE)
        nCmdShow = (nCmdShow != SW_SHOWMINNOACTIVE) ? SW_SHOWMAXIMIZED : nCmdShow;

	 SDIDecFrame *frame = new SDIDecFrame(_collection,0, GetName(), 0, true);

    //
    // Assign ICON w/ this application.
    //  ****** More follows this in the real thing


SDIDecFrame::SDIDecFrame (LibPtr l,TWindow *parent, const char far *title, TWindow *clientWnd, bool trackMenuSelection, TModule *module)
	 : TDecoratedFrame(parent, title, clientWnd == 0 ? new Lab6ListBox(l,0, 0, 0, 0, 200, 200) : clientWnd, trackMenuSelection, module)
{
	 // INSERT>> Your constructor code here.

}

Finally, I added a second constructor to my listbox window Lab6ListBox. This constructor initialized a LibPtr variable _collection in this class. The reason the original copy of the LibPtr is in the application is that subwindows are created and destroyed while the application always is there. This means we have an overseer for the library.

Lab6ListBox::Lab6ListBox (LibPtr l,TWindow* parent, int id, int x, int y, int w, int h, TModule* module)
	 : TListBox(parent, id, x, y, w, h, module),_collection(l)
{
	Attr.Style &= ~LBS_SORT;                    // Don't sort the list its a file.



	 // INSERT>> Your constructor code here.

}

Most of the rest of the code is straight forward, but I will include the cmFindByAuthor function because it demonstrates many of the techniques used in this program.

void Lab6ListBox::cmFindByAuthor ()
{
	 // INSERT>> Your code here.
	 char buff[255];
	 buff[0]='\0';
	 if (TInputDialog(this,"Search","Enter author's name",buff,255).Execute()==IDOK)
	 {
		BookList finds;
		finds = _collection->findAuthor(buff);
		if (finds.numberInArray() >0)
		{
			SearchResultDlgXfer tb;
			strcpy(tb._heading, "The Library has the following books by ");
			strcat(tb._heading,buff);
			ArrayIterator < Book > next(finds);
			while (next)
			{
				char buff1[255];
				next().tabString(buff1);
				tb._results.AddString(buff1);
				next++;
			}
			SearchResultDlg(&tb,this).Execute();
		}
		else
		{
			char buff1[255];
			strcpy(buff1,"No books by ");
			strcat(buff1,buff);
			strcat(buff1," were found.");
			MessageBox(buff1,"Author not Found");
		}
	 }
}

Notice that I created the type BookList which many of you would think is not needed because it is similar to Library. One problem with using the has-a relation to hide the book array in Library, we now do not have an iterator for Library. In the function above, the iterator plays a major role.