Finishing up the HomeItem class

Now it's time to return to the HomeItem class. Luckily, the changes here are much smaller than the changes to the HomeInventory class. In fact, only one new function as been added to the HomeItem interface since the last version we looked at, hmit6.h. That function is GetCategory, whose base class version simply calls the derived class function of the same name, which merely returns the value of the m_Category variable in the item. We've seen enough of this type of function, so we won't bother going over it further.

However, some of the functions have changed in implementation, so we should take a look at them. We'll start with the only function declared in hmit6.h whose implementation has changed: operator >>, the code for which is shown in Figure 13.33.

Figure 13.33. The new operator >> implementation for the HomeItem classes (from codehmit8.cpp)
istream& operator >> (istream& is, HomeItem& Item)
{
  xstring Type;
  bool Interactive = (&is == &cin);
  HomeItem Temp;

  Item = HomeItem();

  while (Type == "")
    {
    if (Interactive)
      {
      cout << "Type (Basic(B), Music(M)) ";
      cout << "or hit ENTER to exit: ";
      HomeUtility::IgnoreTillCR();
      getline(is,Type);
      if (Type == "")
        return is;
      }
    else
     getline(is,Type);

   if (is.fail() != 0)
     return is;
   }

  if (toupper(Type[0]) == 'B')
    {
    // set type of Temp to Basic object, to be filled in
   Temp = HomeItem("",0.0,0,"","");
   }
  else if (toupper(Type[0]) == 'M')
   {
   // set type of Temp to Music object, to be filled in
   Temp = HomeItem("",0.0,0,"","","",Vec<xstring>(0));
   }
  else
   {
   xstring Message = "Bad object type: ";
   Message = Message + Type;
   HomeUtility::HandleError(Message);
   return is;
   }

  Temp.Read(is);
  Item = Temp;

  if (is.fail() != 0)
    HomeUtility::HandleError("Couldn't create object");

  return is;
}

This function isn't too different from the last version we saw (Figure 11.32). The differences are as follows:

  1. We are allowing the user to hit ENTER to exit from this function without having to define a new item. This is useful when the user decides not to create a new item after selecting the “Add Item” function.

  2. We are requiring only the first letter of the type rather than the whole type name. We are also allowing either upper- or lower-case type indicators. To do this, I've taken advantage of a standard library function left over from C called toupper, which simply returns an uppercase version of whatever character you call it with.

  3. We are using the HandleError function to display the error message if the object type is invalid.

  4. If the data for the object cannot be read from the input stream, we are displaying a message telling the user about that problem.

Now let's look at the changes in the HomeItemBasic implementation. We'll start with the Edit function, shown in Figure 13.34.

Figure 13.34. The latest version of HomeItemBasic::Edit (from codehmit8.cpp)
void HomeItemBasic::Edit()
{
 short FieldNumber;
 bool result;

 FormattedDisplay(cout);
 cout << endl;

 cout << "Please enter field number to be changed " <<
    "or ENTER for none: ";

 FieldNumber = HomeUtility::GetNumberOrEnter();

 cout << endl;

 if (FieldNumber == -1)
   return;

 EditField(FieldNumber);
}

This function differs from the previous version (Figure 11.39) only in its improved flexibility and error checking. Rather than simply asking the user to enter a field number and then assuming that the field number entered is valid, we use the GetNumberOrEnter function to allow the user to enter a field number or to just hit the ENTER key to indicate that he or she has decided not to edit a field after all. Once we have received the return value from the GetNumberOrEnter function, we check to see whether it is the special value -1, which indicates that the user has decided not to enter a number but has just hit the ENTER key. If this is the case, we simply return to the calling function without calling EditField to do the actual field modification. Otherwise, we call EditField to modify the selected field and return when it is finished.

The next function in the HomeItemBasic class we will cover is ReadInteractive, whose code is shown in Figure 13.35.

Figure 13.35. The latest version of HomeItemBasic::ReadInteractive (from codehmit8.cpp)
short HomeItemBasic::ReadInteractive()
{
 double PurchasePrice;
 long PurchaseDate;
 bool result;
 xstring Dummy;

 short FieldNumber = e_Name;

 cout << FieldNumber << ". ";
 cout << GetFieldName(FieldNumber) << ": ";
 FieldNumber ++;
 getline(cin,m_Name);

 cout << FieldNumber << ". ";
 cout << GetFieldName(FieldNumber) << " (xxx.xx with no $ or ,): ";
 FieldNumber ++;
 result = HomeUtility::ReadDoubleFromLine(cin,PurchasePrice);
 if (result)
   m_PurchasePrice = PurchasePrice;
  else
   {
   m_Name = "";
   return 0;
   }

 cout << FieldNumber << ". ";
 cout << GetFieldName(FieldNumber) << " (YYYYMMDD): ";
 FieldNumber ++;
 result = HomeUtility::ReadLongFromLine(cin,PurchaseDate);
 if (result)
   m_PurchaseDate = PurchaseDate;
 else
   {
   m_Name = "";
   return 0;
   }

 cout << FieldNumber << ". ";
 cout << GetFieldName(FieldNumber) << ": ";
 FieldNumber ++;
 getline(cin,m_Description);

 cout << FieldNumber << ". ";
 cout << GetFieldName(FieldNumber) << ": ";
 FieldNumber ++;
 getline(cin,m_Category);

 return FieldNumber;
}

The only difference between this version of the ReadInteractive function and the one in Figure 11.37 is its improved error checking and feedback to the user. In addition to making at least some attempt to check the validity of numbers and dates entered by the user, this new version also tells the user what sort of input is expected. In particular, it tells the user to type in the purchase price without using a $ or comma — it's entirely possible that the user might not realize that using these symbols would cause a problem in interpreting the value. This version also tells the user to type the date in the form YYYYMMDD rather than in a more familiar format such as MM/DD/YY. After telling the user how to enter these data items, it uses input functions that subject the numeric data entered to some minimal reasonableness checks. While far from airtight, this is a much safer approach than simply assuming that these values must be all right, as the previous version of the function did.

The changes to the next function we will cover, EditItem (Figure 13.36), are very similar to those in the previous function. To be precise, they consist of more error checking. These changes should be obvious enough that we don't have to discuss them.

Figure 13.36. The latest version of the HomeItemBasic::EditItem function (from codehmit8.cpp)
bool HomeItemBasic::EditField(short FieldNumber)
{
 bool result = true;
 double PurchasePrice;
 long PurchaseDate;
 xstring Dummy;

 switch (FieldNumber)
   {
   case e_Name:
   cout << FieldNumber << ". ";
   cout << GetFieldName(FieldNumber) << ": ";
   getline(cin,m_Name);
   break;

   case e_PurchasePrice:
   cout << FieldNumber << ". ";
   cout << GetFieldName(FieldNumber) << ": ";
   result = HomeUtility::ReadDoubleFromLine(cin,PurchasePrice);
   if (result)
     m_PurchasePrice = PurchasePrice;
   break;
   case e_PurchaseDate:
   cout << FieldNumber << ". ";
   cout << GetFieldName(FieldNumber) << ": ";
   result = HomeUtility::ReadLongFromLine(cin,PurchaseDate);
   if (result)
     m_PurchaseDate = PurchaseDate;
   break;

   case e_Description:
   cout << FieldNumber << ". ";
   cout << GetFieldName(FieldNumber) << ": ";
   getline(cin,m_Description);
   break;

   case e_Category:
   cout << FieldNumber << ". ";
   cout << GetFieldName(FieldNumber) << ": ";
   getline(cin,m_Category);
   break;

   default:
   cout << endl;
   HomeUtility::HandleError("Sorry, that is not a valid field number");
   result = false;
   break;
   }

 return result;
}

The two functions in the HomeItemMusic class, ReadInteractive and EditField, that have changed from the previous versions, follow the changes that we have just looked at very closely so I will list them without further comment.

Figure 13.37. The latest version of HomeItemMusic::ReadInteractive (from codehmit8.cpp)
short HomeItemMusic::ReadInteractive()
{
 long TrackCount;
 bool result;
 xstring Dummy;

 short FieldNumber = HomeItemBasic::ReadInteractive();

 // Check whether Basic input worked. If not, forget it.
 if (FieldNumber == 0)
   return 0;

 cout << FieldNumber << ". ";
 cout << GetFieldName(FieldNumber) << ": ";
 FieldNumber ++;
 getline(cin,m_Artist);

 cout << FieldNumber << ". ";
 cout << GetFieldName(FieldNumber) << ": ";
 FieldNumber ++;
 result = HomeUtility::ReadLongFromLine(cin,TrackCount);
 if (result)
   m_Track.resize(TrackCount);
 else
   {
   m_Name = "";
   return 0;
   }

 for (short i = 0; i < TrackCount; i ++)
   {
   cout << FieldNumber << ". ";
   cout << GetFieldName(FieldNumber) << i + 1 << ": ";
   FieldNumber ++;
   getline(cin,m_Track[i]);
   }

 return FieldNumber;
}

Figure 13.38. The latest version of HomeItemMusic::EditField (from codehmit8.cpp)
bool HomeItemMusic::EditField(short FieldNumber)
{
 if (FieldNumber < e_Artist)
   {
   return HomeItemBasic::EditField(FieldNumber);
   }

 bool result;

 long TrackCount = m_Track.size();

 switch (FieldNumber)
   {
   case e_Artist:
   cout << FieldNumber << ". ";
   cout << GetFieldName(FieldNumber) << ": ";
   getline(cin,m_Artist);
   return true;

   case e_TrackCount:
   cout << FieldNumber << ". ";
   cout << GetFieldName(FieldNumber) << ": ";
   result = HomeUtility::ReadLongFromLine(cin,TrackCount);
   if (result)
     m_Track.resize(TrackCount);
   return result;
   }

 if (FieldNumber > (e_TrackCount + TrackCount))
   {
   HomeUtility::HandleError("Sorry, that is not a valid field number");
   return false;
   }

 cout << FieldNumber << ". ";
 cout << GetFieldName(FieldNumber);
 cout << FieldNumber - e_TrackCount << ": ";

 getline(cin,m_Track[FieldNumber - e_TrackNumber]);

 return true;
}

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset