Discussion: File Menu Message Handlers

This discussion explains the File menu message-handler member functions. Figure 6.2 shows schematically how menu commands are processed.

OnNew

When the user chooses the New command in the File menu, a WM_COMMAND message causes the main window object's OnNew member function to be called through the message map. The function creates a new database if there isn't an existing database.

If there is no open database OnNew creates a new, empty database object. To create one, it calls the New member function of the CDataBase object. This call is passed through the m_people member variable of the main window object, a variable of type CDataBase. The database object's New member function destroys the CPersonList object for the old database if there was one (and the CPersonList for found items, if there was one), then constructs a new CPersonList object, storing it in the database object's m_pDataList member.

If there is an existing CDataBase object in the window object's m_people member variable, OnNew checks to see if the database has unsaved changes. If it has, the function displays a Windows message box to ask if the user wants to save the old database before creating a new one. If so, OnNew calls the window object's Save member function to serialize the old database and make it persistent. In the process, it gets a filename from the user if the database has never been saved before. Once the old database has been saved, the New member function of class CDataBase is called as described previously.

After having its CDataBase member construct a new CPersonList, the window object's OnNew member function calls the window object's SetMenu member function to adjust the availability of menu commands. Then, because the new database has never been saved to a file, OnNew sets the window title to “Untitled,” calls the OnSize member function because the number of records in the database has changed. OnSize calls the window object's Invalidate member function, inherited from class CWnd, to mark the window's client area invalid. This causes Windows to send a WM_PAINT message to the window so it will be redrawn (erased, actually, in the case of a new database).

OnOpen

When the user chooses the Open command in the File menu, the main window object's OnOpen member function is called to open an existing database file. If there is an existing database open, OnOpen, like OnNew, saves the existing database to a file, if the user wishes. Then the function opens the new database.

OnOpen calls the FileDlg member function to get a filename from the user. FileDlg is a utility member that creates and fills up an OPENFILENAME data structure and passes it in a call to the Windows common dialog function GetOpenFileName. FileDlg also sets up a filter string that specifies what file types are to be displayed by the Windows standard file open dialog box. OnOpen passes a Boolean value, bOpen, to FileDlg. If bOpen is TRUE, FileDlg invokes the standard open dialog. If it's FALSE, FileDlg invokes the standard save dialog.

Once OnOpen obtains a filename from the user, it calls the database object's DoOpen member function to open the file and read it into a CPersonList object. The database object's DoOpen member calls its ReadDataBase member function to do the work. You saw that function in Chapter 2 and again in Chapter 4, under “Discussion: Class CDataBase” on page 134. ReadDataBase can throw an exception, so the window object's OnOpen member puts its call to

m_people.DoOpen

inside an exception frame. You saw how exception frames work in Chapter 2.

If a file has been successfully opened and read, the window object's OnOpen member sets the window title to the filename, adjusts the menus with a call to the window object's SetMenu member, and causes the window to be updated. If there was an exception, OnOpen displays a Windows message box with an error message.

OnSave, OnSaveAs, and Save

When a database has unsaved changes, or has never been saved to a file, the user can save it by choosing the Save or Save As command in the File menu. The Save As menu command prompts the user for a filename, then saves the database to that file. The Save command is used when the database already has a filename associated with it. The Save command serializes the CPersonList in the database if it has a filename. If not, the Save command also prompts the user for a filename.

Phone Book implements the Save As menu command with the CMainWindow class's OnSaveAs member function. The main window object's OnSaveAs member simply calls the window object's member function, Save. Save is a utility member function called by several other member functions that need to save an open database. These include the main window object's OnNew, OnOpen, OnDBClose, and OnClose member functions.

Save first checks to see if the database already has a name. It does this with a call to the database object's IsNamed member. If it has a name, Save calls the database object's DoSave member function through the window object's m_people member variable. This call takes no argument because the database already has a name in its m_FileName member variable, where DoSave can access it. The database object's DoSave member calls its WriteDataBase member function to do the work.

This call can throw an exception, so the main window object's Save member puts an exception frame around the attempt to save the data. (For more information about the database object's DoSave member function, see “Discussion: Class CDataBase” on page 134 in Chapter 4.) Save attempts to open the file and write the database to it.

If the database has not yet been named, Save displays a standard Windows save dialog box asking the user for a filename. The dialog box is invoked by a call to FileDlg, the utility member function that was explained under “OnOpen” on page 214. If it gets a filename, it calls the CDataBase object's DoSave member function through m_people, passing the filename as an argument. Then it sets the window title to the file title stored in m_szFileTitle. (This is the filename in uppercase letters with no path.)

OnDBClose, OnClose, and OnExit

If the user chooses the Close command in the File menu, the main window object's OnDBClose member function is called to close the database. The program continues to run. If the user chooses the Exit command in the File menu, the main window object's OnExit member is called. OnExit calls OnClose. This sequence of calls destroys the database and ends the program. The same cleanup is required for the Exit command in the File menu as for the case in which Windows sends a WM_CLOSE message in response to the system menu. Both sequences are mapped to the same code.

If the database has unsaved changes, OnClose asks the user if the file should be saved. If the user wishes to save the file, the Save member function is called to handle writing the file.

If the database doesn't need to be saved, OnClose calls the CDataBase object's Terminate member function, through m_people, to destroy the database's CPersonList objects (the main list and the found list).