28
cover page has been removed The tasks upon which this report was based were to create programs which enter and store recipes, and to create shopping lists based on these recipes. The aim of this report is to give a description of the components used in these programs.

Recipe program

Embed Size (px)

DESCRIPTION

University project report to document a Java program which allowed users to store and retrieve recipes, and which created shopping lists based upon those recipes.

Citation preview

Page 1: Recipe program

cover page has been removed

The tasks upon which this report was based were to create programs which enter and store recipes, and to create shopping lists based on these recipes. The aim of this report is to give a description of the components used in these programs.

Page 2: Recipe program

- 2 -

Table of Contents

Aims .............................................................................................................................................................................................................................. - 3 -

Use-Case Diagrams ............................................................................................................................................................................................... - 3 -

Class Diagram .......................................................................................................................................................................................................... - 3 -

Hierarchical Task Analysis ............................................................................................................................................................................... - 4 -

Description of Design .......................................................................................................................................................................................... - 5 -

Screenshots............................................................................................................................................................................................................... - 6 -

Program 1 ............................................................................................................................................................................................................. - 6 -

Program 2 ............................................................................................................................................................................................................. - 7 -

Ingredient class ...................................................................................................................................................................................................... - 8 -

Recipe class ............................................................................................................................................................................................................... - 9 -

RecipeList class.................................................................................................................................................................................................... - 11 -

RecipeForm class ................................................................................................................................................................................................ - 12 -

RecipeGUI class.................................................................................................................................................................................................... - 15 -

ListMakerGUI class ............................................................................................................................................................................................ - 22 -

Page 3: Recipe program

- 3 -

Aims Program 1: To enter and store recipes.

Program 2: To read a collection of saved recipes and then let the users specify a set of menus, and to produce an appropriate shopping list for the given set of menus.

Use-Case Diagrams The first program must be perform all of the tasks listed in this use-case diagram. A GUI is required for this program, which will involved showing a list of current recipes and an option to create a new one. In addition, a form to enter a new recipe will be created.

A recipe can only be entered once, this can be checked by the names of the recipes currently saved.

When adding ingredients, the system needs to check if that ingredient has been added before. If it has then the measures (e.g. kg) need to match.

The second program needs to be able to add recipes to a shopping list, and ask the user how many people they require the recipe for. If they try adding a recipe that has already been chosen then the system must add that number of people to the total (e.g. if Tomato Soup for 3 people is in the list, then the user tries to add Tomato Soup for 5 people, the system will output Tomato Soup for 8 people)

Class Diagram The following three classes are used in both programs. They do not implement any GUI features. The Ingredient class creates Ingredient objects, which consist of a name, quantity and measure. The Recipe class creates Recipe objects and consists of a recipe name, list of Ingredients, and is passed an overall list of Ingredients from all Recipes. The RecipeList class creates RecipeList objects and contains a list of Recipe objects and the aforementioned overall list of Ingredients.

Program 1

Program 2

Page 4: Recipe program

- 4 -

These are the extra two classes that are needed to run Program 1. They are both graphical user interface classes, RecipeForm is an interface for creating new recipes and RecipeGUI is the interface for viewing the current recipes and saving the recipe list.

When this program is loaded, it takes an argument from the user. If no argument is specified, a new file is created to run the program and a message is displayed to the user. Only one argument can be passed into the program, and that argument must be the name of a new or existing file, ending with .csv or .dat.

Program 1 uses validation to ensure that Recipes are unique and have at least one Ingredient. The validation on the Ingredients guarantees that ingredients are only added to a recipe if they have not been added before, have a quantity which is in ‘double’ format, and a matching measure, if that Ingredient exists in another recipe.

ListMakerGUI is the other class needed for Program 2. This is the graphical user interface class which shows the user a list of recipes and allows them to choose which recipes to add to a shopping list. An argument must be passed in, but if one is not then a message is displayed to the user to enter a file (it must be an existing dat or csv file)

Validation is used to ensure that a (non-empty) integer is entered for the number of people, with that integer being above 1.

Errors can occur in both of these programs, for example when trying to save a recipe list but the file is already open in another program. In such an event, a message box is displayed in the GUI to inform the users that the list is not saved, but the full error is also printed onto the command line for expert users. In addition to this, the Logger class has been implemented to write messages to the

error logs in some circumstances.

Hierarchical Task Analysis This diagram shows the main path through program one.

Page 5: Recipe program

- 5 -

Description of Design When Program 1 is run, it creates a RecipeList to store a list of Recipe objects and runs the graphical user interface RecipeGUI. These Recipe objects in turn store a collection of Ingredient objects and the name of the recipe. When the RecipeList object is created, an overall list (ArrayList) of ingredients is created also. This list of ingredients is checked every time an ingredient is added to a new Recipe to ensure that if the ingredient has been added already, the measures equal each other (e.g. so that one Recipe does not require 1oz of butter and another require 28g of butter). Ingredients can be added to and removed from a Recipe by using the RecipeForm (a separate graphical user interface), and validation is used to confirm that all fields are valid (quantities must be numbers only and the name must not already exist in the list). Once a recipe has been completed, the user is given the option to cancel or save the Recipe. If cancel is pressed then the Recipe is not saved, else it is saved to the RecipeList, the RecipeForm is closed and the list of Recipes in the RecipeGUI is re-loaded to show the new Recipe. The RecipeGUI contains a list of current recipes which are loaded into the program when a .csv or a .dat file is passed in. Validation ensures that only one file (which also must be a .csv or .dat) can be loaded into the program. If no file is found, a new RecipeList is created to hold Recipe objects. Recipes can be removed from the list and the list can be saved, which saves both a .csv and a .dat file for later use. Another useful feature is a function to view the summary of a recipe.

Program 2 also reads in a .csv file or a .dat file to generate the Recipe list. This list is in a graphical user interface called ListMakerGUI and is shown to the user and they have the ability to add the Recipe to their shopping list. Once they select a Recipe they are asked how many people they require the Recipe for. The other list then contains the Recipes that the user has chosen and shows them the number of people they require it for. The user can then generate a shopping list, which is created by finding each ingredient of each Recipe that they have selected, multiplying it by the amount of people that they need each Recipe for.

To ensure that the user cannot forget to highlight a recipe (which can cause errors in the programs), a function has been written in both programs to highlight the first item in each list (while they are not empty), and then highlight the latest Recipe when they are added to the list. When the RecipeList is saved, it saves both a .csv file and a .dat file. The .dat file uses an ObjectOutputStream to save the RecipeList object (containing list of Recipes which contain lists of Ingredients). The .csv files are written using PrintWriters and separating fields with commas.

In order to provide help and feedback for the users, tooltips have been used on all buttons in each of the programs, explaining the options that are available to a user.

Tomato Soup Tomatoes 1.2 kg

Bay leaves 2 Celery 1 Onion (medium) 1 Vegetable stock 1000 ml

--------- Tomato Panini Panini 2

---------

This is an example of a .csv file saved using the RecipeGUI. It is created by printing the name on a separate line, then each of the ingredients on a separate line. The name, quantity and measure of each ingredient are separated by commas, which loads them in different fields in a spreadsheet program. The dotted line is used to indicate a new Recipe.

This diagram shows the main path through program 2.

Page 6: Recipe program

- 6 -

Screenshots

Program 1

Step 1. The program reads in a file and shows the Recipes to the user.

Step 2. The user presses “View Ingredients”.

Step 3. The user presses “Delete”.

.

Step 4. The user presses “Add a new recipe”.

The name of the recipe that the user entered.

Options are greyed out when they cannot be used.

Step 5. User enters Ingredient and presses ‘add’.

Step 6. User tries to enter 8 Tomatoes but Tomatoes has been defined as kg in another recipe.

Page 7: Recipe program

- 7 -

Program 2 Step 1. The program reads in a file and shows the Recipes to the user.

Step 2. The user chooses a Recipe and presses ‘Select’.

Step 3. The program asks the user how many people they need the Recipe for. The default value is 2. User presses OK.

Step 4. The recipe and number of people are displayed. Step 2- 4 are repeated for as many recipes the user wants.

Step 5. User presses Create Shopping List.

Step 6. The shopping list is shown.

Step 7. About is pressed.

Page 8: Recipe program

- 8 -

Ingredient class package recipeprogram; import java.io.Serializable; import java.text.*; public class Ingredient implements Serializable{

/* Variables */ String name; double quantity; String measure; /** Creates an instance of the class **/ public Ingredient(String nameIn, double quantityIn, String measureIn) {

name = nameIn; quantity = quantityIn; measure = measureIn;

} /** Returns the name of the ingredient **/ public String getName(){return name;} /** Returns the quantity of the ingredient **/ public double getQuantity(){return quantity;} /** Returns the measure of the ingredient **/ public String getMeasure(){return measure;} /** Sets the quantity of the ingredient **/ public void setQuantity(double qIn){quantity = qIn;} /** Returns the ingredient formatted as a String. if the quantity of the ingredient ends with .0 (ie 23.0) it is formatted to one DP**/ @Override public String toString(){

String tempQuantity = ""+quantity; if (tempQuantity.endsWith(".0")) { //round up to nearest DP NumberFormat formatter = new DecimalFormat("#0"); return name + ": " + formatter.format(quantity) +" "+ measure; } else {return name + ": " + quantity +" "+ measure;}

} /** Checks if one ingredient equals another by checking the name **/ @Override public boolean equals(Object o) {

Ingredient i = (Ingredient) o; //converts object to Ingredient if (name.toLowerCase().equals(i.getName().toLowerCase())){return true;} else {return false;}

} }

Page 9: Recipe program

- 9 -

Recipe class package recipeprogram; import java.io.Serializable; import java.util.ArrayList; public class Recipe implements Serializable { /* Variables */ String name; ArrayList<Ingredient> ingredients; //To store ingredients for this recipe /*To store ingredients for ALL recipes. This is used when checking to see if the ingredient has been saved before. */ ArrayList<Ingredient> allIngredients; /** Creates an instance of the class when the ingredients are not known **/ public Recipe (String nameIn, ArrayList<Ingredient> allIngredientsIn) { name = nameIn; allIngredients = allIngredientsIn; ingredients = new ArrayList<Ingredient>(); } /** Creates an instance of the class when the ingredients are known **/ public Recipe (ArrayList<Ingredient> ingIn, String nameIn){ name = nameIn; ingredients = ingIn; } /** Adds an ingredient to a recipe, when the ingredient is not already in the list. Returns a String containing the result of the add operation. **/ public String AddIngredient(Ingredient i) { if(ingredients.contains(i)){ return "This ingredient is already in the list."; } if(!ingredients.add(i)){ return "There was a problem adding this ingredient."; } else { //Ingredient added OK allIngredients.add(i); return ""; //returns empty implying that ingredient added OK } } /** Removes an ingredient from a recipe. Returns a boolean indicating the result of the operation. **/ public boolean RemoveIngredient(String name) { for (int i = 0; i<ingredients.size();i++) //loops through list { if (ingredients.get(i).getName().toLowerCase().equals( name.toLowerCase())) //if its in list { allIngredients.remove(i); //removes from the overall list ingredients.remove(i); //removes from the list return true; } } return false;

Page 10: Recipe program

- 10 -

} /** Gets the list of ingredients **/ public ArrayList<Ingredient> getList(){return ingredients;} /** Gets the name of the recipe **/ public String getName(){return name;} }

Page 11: Recipe program

- 11 -

RecipeList class package recipeprogram; import java.io.Serializable; import java.util.ArrayList; public class RecipeList implements Serializable { /* global variables */ ArrayList<Recipe> recipeList; ArrayList<Ingredient> allIngredients; /** Creates an instance of the class **/ public RecipeList(){ recipeList = new ArrayList<Recipe>(); //list of recipes /*an ArrayList to store all of the Ingredients used in the recipe list (ie all of the recipes)*/ allIngredients = new ArrayList<Ingredient>(); } /** Adds a recipe to the list. **/ public String addRecipe(Recipe r) { if(!recipeList.add(r)){return "There was a problem adding this recipe.";} else{return "";} } /** Removes a recipe from the list **/ public boolean removeRecipe(String name) { for (int i = 0; i<recipeList.size();i++) { if (recipeList.get(i).getName().toLowerCase().equals( name.toLowerCase())) //recipe is in list { recipeList.remove(i); //remove recipe return true; } } return false; } /** Returns a recipe in the list by its position **/ public Recipe getRecipe(int i){return recipeList.get(i);} /** Returns a recipe in the list by its name **/ public Recipe getRecipe(String name) { for (int i=0;i<recipeList.size();i++){ if (name.toLowerCase().equals( recipeList.get(i).getName().toLowerCase())){ return recipeList.get(i); } } return null; } /** gets the ArrayList of recipes **/ public ArrayList<Recipe> getAllRecipes(){return recipeList;} /** gets the ArrayList of ingredients **/ public ArrayList<Ingredient> getAllIngredients(){return allIngredients;} }

Page 12: Recipe program

- 12 -

RecipeForm class package recipeprogram; import java.io.Serializable; import java.util.ArrayList; import javax.swing.DefaultListModel; import javax.swing.JFrame; import javax.swing.JOptionPane; public class RecipeForm extends javax.swing.JFrame implements Serializable { //global variables DefaultListModel model = new DefaultListModel(); //for the ingredient list Recipe recipe; RecipeList recipeList; RecipeGUI gui; /**Creates an instance of the class to contain a list of recipes**/ public RecipeForm(String name, ArrayList<Ingredient> ingIn, RecipeList recipeListIn, RecipeGUI recipeGUIIn) { initComponents(); //load GUI recipeList = recipeListIn; //instantiate recipeList gui = recipeGUIIn; //passes in other GUI titleLabel.setText(name); //sets the title of the recipe on screen recipe = new Recipe(name, ingIn); //creates new recipe } /**Shows an error message containing text which is passed into the method**/ public void showError(String message) { JOptionPane.showMessageDialog( new JFrame(), message, "Error", //title JOptionPane.ERROR_MESSAGE); //type of message return; } /**Changes the enabled option of the remove ingredient button. **/ public void toggleEnabled() { if (recipe.getList().size() == 0){remButton.setEnabled(false);} else{remButton.setEnabled(true);} } /**Selects an item in the list so that a user cannot accidently forget to select a recipe. Takes an integer argument to determine if the one that is selected is the last one in the list, or the first**/ public void select(int i) { if (i == 0){ //selects the first item in the list if (!model.isEmpty()){ingList.addSelectionInterval(0, 0);} } else{ //selects the last item in the list if (!model.isEmpty()){ ingList.addSelectionInterval(model.getSize()-1,model.getSize()-1); } } } public void remove(){ if (remButton.isEnabled()) //there are ingredients in the list

Page 13: Recipe program

- 13 -

{ //first the name of the ingredient must be found from the string // name : quantity measure (eg cheese: 100g) Object[] obj = ingList.getSelectedValue().toString().split(":"); String name = (String) obj[0]; //tries to remove the ingredient if (recipe.RemoveIngredient(name) == false){ //error occurred showError("There was a problem removing this ingredient."); return; } //no error model.remove(ingList.getSelectedIndex()); //removes from list toggleEnabled(); //toggles enabled buttons select(0); //selects first ingredient } } public void save() { if (model.isEmpty()) { //no ingredients showError("You must enter at least one ingredient.");return;} else{ this.dispose(); gui.addRecipe(recipe); //adds recipe gui.select(1); //selects the latest recipe in the list } } public void add(){ String measure = (String) measures.getSelectedItem(); //gets measure String name = nameField.getText(); //gets name if (name == null || name.equals("")){ //name cannot be empty showError("Please enter an ingredient name.");return; } String quantity = amountField.getText(); //gets quantity if (quantity == null || quantity.equals("")){ //quantity cannot be empty showError("Please enter an ingredient quantity.");return; } try{Double.parseDouble(amountField.getText());} //checks if amount was a double catch (NumberFormatException e){ showError("Please ensure that you have entered a number " + "for the ingredient quantity."); return; } //loops through master list of ingredients to check that if an ingredient has //been entered entered before, and what measure was used if so for (int i = 0; i < recipeList.getAllIngredients().size(); i++){ if (name.toLowerCase().equals(recipeList.getAllIngredients().get(i) .getName().toLowerCase())){ if (!measure.equals(recipeList.getAllIngredients().get(i).getMeasure())) { //if measures do not match String m = recipeList.getAllIngredients().get(i).getMeasure(); //if measure is blank, change to empty to aid user understanding if (m.equals("")){m = "empty";} showError("The measure has been defined previously as " + m);return; } } } //creates new ingredient as all fields have passed validation Ingredient ing = new Ingredient(name, Double.parseDouble(quantity), measure); String result = recipe.AddIngredient(ing); //adds ingredient if (result.equals("")) {//added OK

Page 14: Recipe program

- 14 -

nameField.setText(""); //clears the field for new ingredient amountField.setText(""); //clears the field for new ingredient measures.setSelectedIndex(0); //resets the dropdown box model.addElement(ing); //adds ingredient to list toggleEnabled(); } else //did not add ok {showError(result);return;} select(1); //selects the last item added } public void cancel(){ //prompts the user that they want to close int option = JOptionPane.showConfirmDialog(new JFrame(), "Are you sure you want to cancel?", "Confirm Cancel", JOptionPane.OK_CANCEL_OPTION); //user presses yes then the frame is destroyed if (option == 0){ int size = recipe.getList().size(); for (int i = 0; i < size; i++){ recipeList.allIngredients.remove(recipe.getList().get(i)); } this.dispose(); } } }

Page 15: Recipe program

- 15 -

RecipeGUI class package recipeprogram; import java.awt.event.WindowEvent; import java.io.*; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.*; public class RecipeGUI extends JFrame implements Serializable { /* Global Variables */ DefaultListModel model = new DefaultListModel(); //for JList of recipes RecipeList recipeList; //to store a list of recipes File f; Object nameEnter; /** Calls method to create an instance of the RecipeGUI class. * Checks to ensure that only the correct amount * of arguments are entered. **/ public static void main(String args[]) { if (args.length==0){ //no argument specified JOptionPane.showMessageDialog( new JFrame(), "You did not specify an argument, so a file " + "called recipes.dat has been created.", "Information", //title JOptionPane.INFORMATION_MESSAGE); //type of message System.out.println("You did not specify an argument, so a file " + "called recipes.dat has been created."); new RecipeGUI("recipes.dat").setVisible(true); } else if (args.length > 1){ //if more that one file is loaded System.out.println("Please enter one argument"); System.exit(0); } else{ if (args[0].endsWith(".dat")){ new RecipeGUI(args[0]).setVisible(true); } else if (args[0].endsWith(".csv")){ new RecipeGUI(args[0]).setVisible(true); //create new GUI } else { System.out.println("Please enter a .csv file or a .dat file"); System.exit(0); } } } /** Creates an instance of the RecipeGUI class **/ public RecipeGUI(String args) { f = new File(args); recipeList = new RecipeList(); //creates new recipeList if (args.endsWith(".dat")){ //dat file entered if (f.exists())//if the file has been created already, read the file { ObjectInputStream in = null;

Page 16: Recipe program

- 16 -

try { in = new ObjectInputStream(new FileInputStream(f)); //converts object to RecipeList recipeList = (RecipeList) in.readObject(); } catch (IOException ex) { System.out.println("The .dat file could not be loaded, " + "please try again."); Logger.getLogger(RecipeGUI.class.getName()).log( Level.SEVERE, null, ex); } catch (ClassNotFoundException ex){ System.out.println("The .dat file could not be loaded, " + "please try again."); Logger.getLogger(RecipeGUI.class.getName()).log( Level.SEVERE, null, ex); } finally{ try{in.close();}//closes IO catch (IOException ex){ System.out.println("There was an error closing the file"); Logger.getLogger(RecipeGUI.class.getName()).log( Level.SEVERE, null, ex); } } } } else if (args.endsWith(".csv")) //csv file entered { if (f.exists()){//if the file has been created already, read file try { readCSV(f); } catch (FileNotFoundException ex) { System.out.println("The .csv file could not be loaded, " + "please try again."); Logger.getLogger(RecipeGUI.class.getName()).log( Level.SEVERE, null, ex); } catch (IOException ex) { Logger.getLogger(RecipeGUI.class.getName()).log( Level.SEVERE, null, ex); } } } try { /*sets the appearance of the gui depending on the OS. Note: system was only checked on Windows and Linux*/ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception ex){ Logger.getLogger(RecipeGUI.class.getName()) //adds note to log .log(Level.SEVERE, null, ex); } initComponents(); //draws components showList(); //shows the list of current recipes toggleEnabled(); //runs method to disable some items select(0); //runs method to select an option in the list addAllIngredients();//runs method to generate overall ingredient list }

Page 17: Recipe program

- 17 -

/** Reads a CSV file and creates a RecipeList with it **/ public void readCSV(File f) throws FileNotFoundException, IOException { String thisLine; //string variable which take each record at a time //reads file BufferedReader reader = new BufferedReader(new InputStreamReader( new FileInputStream(f))); String nameField = null; //to store the name of the recipe Recipe r = null; //to store each recipe while ((thisLine = reader.readLine()) != null) //while there is content { //beginning of outer while loop //allows an application to break a string into tokens StringTokenizer st = new StringTokenizer(thisLine, ","); String temp = st.nextToken(); //gets next token if (!st.hasMoreTokens()){ //then its not an ingredient //the csv output seperates recipes by a field containing "---------" if (!temp.equals("---------")) { //if not indication nameField = temp; //stores the recipe name //creates new recipe r=new Recipe(nameField, recipeList.getAllIngredients()); } /*else the current line is the indicator, meaning that the * current recipe must be saved before moving on to the next * one*/ else {recipeList.addRecipe(r);} } while (st.hasMoreTokens()){//then its an ingredient /*gets the ingredients and stores them to variables*/ String quant = st.nextToken(); double quants = Double.parseDouble(quant); String meas = st.nextToken(); //adds ingredient to recipe r.AddIngredient(new Ingredient(temp, quants, meas)); } } } /**Adds a recipe to the recipeList by calling its methods**/ public void addRecipe(Recipe r){ String res = recipeList.addRecipe(r); if (res.equals("")){ //recipe added OK showList(); //shows recipe list select(0); //selects the latest recipe added toggleEnabled(); //toggles enabled attributes addAllIngredients();//runs method to generate ingredient list } else{ //did not add ok showError(res); } } /**Generate an overall ingredient list which is used when checking the measures that are entered for each ingredient**/ public void addAllIngredients() { recipeList.getAllIngredients().clear(); //clears the list //runs through each recipe and adds each ingredient in it. for (int i = 0; i < recipeList.getAllRecipes().size(); i++){ for (int j = 0; j < recipeList.getRecipe(i).getList().size(); j++){

Page 18: Recipe program

- 18 -

recipeList.getAllIngredients().add( recipeList.getRecipe(i).getList().get(j)); } } } /**Shows the list of recipes**/ public void showList() { model.removeAllElements(); //removes all recipes //adds each recipe name to the list for (int i = 0; i < recipeList.getAllRecipes().size(); i++){ model.add(i, recipeList.getRecipe(i).getName()); } } /**Changes the enabled option of some buttons. This is used to disable options that are not available at certain times, ie when no recipes are in the list **/ public void toggleEnabled() { if (recipeList.getAllRecipes().size() == 0){ //if no items in list saveButton.setEnabled(false); ViewSummary.setEnabled(false); deleteButton.setEnabled(false); MENUsave.setEnabled(false); } else { saveButton.setEnabled(true); ViewSummary.setEnabled(true); deleteButton.setEnabled(true); MENUsave.setEnabled(true); } } /**Saves the recipe list to a file. It saves it to both a .dat file and .csv file.**/ public void save() { if (saveButton.isEnabled()){ //variables ObjectOutputStream out; PrintWriter pw = null; try { out = new ObjectOutputStream(new FileOutputStream("recipes.dat")); out.writeObject(recipeList); //writes object to file out.close(); //shows message to the user that list has been saved JOptionPane.showMessageDialog( new JFrame(), "The recipe list has been saved.", "Save", //title JOptionPane.INFORMATION_MESSAGE); //type of message } catch (IOException ex) { //shows message to the user that list has not been saved showError("The list could not be saved, as the file is open"); //adds to log file Logger.getLogger(RecipeGUI.class.getName()).log(Level.SEVERE,null,ex); return; //returns to method call } try {

Page 19: Recipe program

- 19 -

pw = new PrintWriter(new FileOutputStream("recipes.csv")); //for each recipe in list for (int i = 0; i < recipeList.getAllRecipes().size(); i++){ pw.printf(recipeList.getRecipe(i).getName()); //print name //for each ingredient in recipe for(int j=0; j < recipeList.getRecipe(i).ingredients.size();j++) { //print each ingredient on a new line //format: name, quantity, measure pw.printf("\n" + recipeList.getRecipe(i).ingredients.get(j).getName() + "," + recipeList.getRecipe(i).ingredients.get(j).getQuantity() + ","); /*to ensure that the measure always is a value and not null in the readCSV method*/ if (recipeList.getRecipe(i).ingredients.get(j).getMeasure(). equals("")) { pw.printf(" "); //prints space } else { pw.printf(recipeList.getRecipe(i).ingredients.get(j). getMeasure()); } } pw.printf("\n---------\n"); //prints indicator of end of recipe pw.close();//closes the stream } pw.flush(); //flushes the stream. } catch (Exception e) { showError("There was a problem saving to the .csv file"); System.out.println(e); } } } /**Shows an error message containing text which is passed into the method**/ public void showError(String message) { JOptionPane.showMessageDialog( new JFrame(), message, "Error", //title JOptionPane.ERROR_MESSAGE); //type of message return; } /**Selects an item in the list so that a user cannot accidently forget to select a recipe. Takes an integer argument to determine if the one that is selected is the last one in the list, or the first**/ public void select(int i) { if (i == 0){ //selects the first item in the list if (!model.isEmpty()){displayList.addSelectionInterval(0, 0);} } else{ //selects the last item in the list if (!model.isEmpty()){ displayList.addSelectionInterval(model.getSize()-1,model.getSize()-1); } } }

Page 20: Recipe program

- 20 -

/**Loads a new recipe form to create a new recipe**/ public void loadRecipeForm(String name, ArrayList<Ingredient> ingIn) { RecipeForm r = new RecipeForm(name, ingIn, recipeList, this); r.setVisible(true); //makes GUI visible } public void exit(){ //prompts the user that they want to close int option = JOptionPane.showConfirmDialog(new JFrame(), "Are you sure you want to exit the program?", "Confirm Exit", JOptionPane.OK_CANCEL_OPTION); //user presses yes if (option == 0){ //close program processEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING)); } } public void add(java.awt.event.ActionEvent evt){ /*** shows a popup box with a text field for the user to enter the name of the new recipe and returns a String containing the user input**/ nameEnter = JOptionPane.showInputDialog( new JFrame(), "Please enter a name for the new recipe:", //message in popup box "Add New Recipe", //title JOptionPane.INFORMATION_MESSAGE, //type of message null, null, null); if (nameEnter == null){return;} //cancel was pressed if (nameEnter.toString().trim().equals("")){ //no name was entered showError("Please enter a name for the recipe."); AddRecipeButtonActionPerformed(evt); //repeat this method } else{ for (int i = 0; i < recipeList.getAllRecipes().size(); i++){ //if name is already in list if (recipeList.getRecipe(i).getName().toLowerCase().equals( nameEnter.toString().toLowerCase())){ showError("The recipe name \"" +nameEnter+"\" is already in the list."); return; } } //call method to load new Recipe Form loadRecipeForm(nameEnter.toString(), recipeList.getAllIngredients()); } select(1); //select the last item in the list addAllIngredients(); //runs method to generate overall ingredient list } public void viewSummary(){ if (ViewSummary.isEnabled()) //there are items in the list { //gets the recipe that the user has selected to view the summary Recipe rec = recipeList.getRecipe(displayList.getSelectedIndex()); String message = ""; //String to store output message for (int i = 0; i < rec.getList().size(); i++) //loops through ingredients { message += rec.getList().get(i).getName() + ": "; //output name String s = "" + rec.getList().get(i).getQuantity(); //gets quantity if (s.endsWith(".0")) { //round up to nearest DP NumberFormat formatter = new DecimalFormat("#0");

Page 21: Recipe program

- 21 -

message += formatter.format(rec.getList().get(i).getQuantity())+""; } else{ //output normal quantity message += rec.getList().get(i).getQuantity() + ""; } message += rec.getList().get(i).getMeasure(); //output measure message += "\n"; //output new line } //display the summary of ingredients JOptionPane.showMessageDialog( new JFrame(), message, "Summary of " + rec.getName(), //title JOptionPane.INFORMATION_MESSAGE); //type of message } } public void delete(){ if (deleteButton.isEnabled()) //there are items in the list { //confirms that user wants to delete recipe int option = JOptionPane.showConfirmDialog(new JFrame(), "Are you sure you want to delete this recipe?", "Confirm Delete", JOptionPane.OK_CANCEL_OPTION); if (option == 0) { //user presses yes Recipe rec = recipeList.getRecipe(displayList.getSelectedIndex()); if(recipeList.removeRecipe(rec.getName())) //removes recipe { showList(); //shows the list of current recipes toggleEnabled(); //runs method to disable some items select(0); //runs method to select an option in the list addAllIngredients();//runs method to generate overall list } else{showError("There was a problem removing the recipe");} } } } public void about(){ //shows copyright JOptionPane.showMessageDialog( new JFrame(), "Written and developed by Carrie Hall" + "\n" + "November 2008 - February 2009" + " \n " + "All rights reserved", "About RecipeMaker", JOptionPane.INFORMATION_MESSAGE); //type of message }

Page 22: Recipe program

- 22 -

ListMakerGUI class package recipeprogram; import java.awt.event.WindowEvent; import java.io.*; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.*; public class ListMakerGUI extends javax.swing.JFrame implements Serializable { /*global variables*/ //for the list of recipes in the shopping list DefaultListModel model = new DefaultListModel(); //for the overall list of recipes to choose from DefaultListModel modelRecipes = new DefaultListModel(); File f; RecipeList recipeList; //for the overall list of recipes to choose from RecipeList chosenRecipeList; //for the list of recipes in the shopping list String num; //number of people having the recipe /** Calls method to create an instance of the ListMakerGUI class. Checks to ensure that only the correct amount of arguments are entered. If one or more argument has been passed in then it is assumed that the user used the command line, so all error messages are output there. If they enter no arguments then it is assumed that they have tried to run it directly, therefore they are prompted to enter an existing file to load, using a graphical user interface**/ public static void main(String args[]) { if (args.length > 1){//more that one file is loaded System.out.println("Please enter one argument"); System.exit(0); } else if (args.length==0){ //no argument Object noArg = JOptionPane.showInputDialog( new JFrame(), "Please enter the name of the file you want to load:", "Load RecipeMaker", //title JOptionPane.INFORMATION_MESSAGE, //type of message null, null, null); if (noArg == null){System.exit(0);} //cancel was pressed else { if (noArg.toString().endsWith(".dat")|| noArg.toString().endsWith(".csv")) { File f = new File(noArg.toString()); if(f.exists()) { new ListMakerGUI(noArg.toString()).setVisible(true); } else{ JOptionPane.showMessageDialog( new JFrame(), "Please enter an existing file.", "Error", //title JOptionPane.ERROR_MESSAGE); //type of message System.out.println("Please enter an existing file.");

Page 23: Recipe program

- 23 -

System.exit(0); } } else { JOptionPane.showMessageDialog( new JFrame(), "Please enter a .csv file or a .dat file.", "Error", JOptionPane.ERROR_MESSAGE); //type of message System.out.println("Please enter a .csv file or a .dat file."); System.exit(0); } new ListMakerGUI(noArg.toString()).setVisible(true); } } else { if (args[0].endsWith(".dat")){ new ListMakerGUI(args[0]).setVisible(true); } else if (args[0].endsWith(".csv")){ new ListMakerGUI(args[0]).setVisible(true);} else{ System.out.println("Please enter a .csv file or a .dat file"); System.exit(0); } } } /** Creates an instance of the ListMakerGUI class **/ public ListMakerGUI(String args) { f = new File(args); recipeList = new RecipeList(); //creates new recipeList if (args.endsWith(".dat")){ //dat file entered if (f.exists()){//if the file has been created already,read file ObjectInputStream in = null; try{ in = new ObjectInputStream(new FileInputStream(f)); //converts to RecipeList recipeList=(RecipeList)in.readObject(); } catch (IOException ex){ System.out.println("The .dat file could not be loaded, " + "please try again."); Logger.getLogger(ListMakerGUI.class.getName()).log( Level.SEVERE, null, ex); } catch (ClassNotFoundException ex){ System.out.println("The .dat file could not be loaded, " + "please try again."); Logger.getLogger(ListMakerGUI.class.getName()).log( Level.SEVERE, null, ex); } finally{ try { in.close(); //closes IO } catch (IOException ex) { System.out.println("There was a problem closing the file"); Logger.getLogger(ListMakerGUI.class.getName()).log( Level.SEVERE, null, ex); }

Page 24: Recipe program

- 24 -

} } } else if (args.endsWith(".csv")){ //csv file entered if (f.exists()){//if the file has been created already, read file try{ //if the file has been created already, read the file readCSV(f); } catch (FileNotFoundException ex){ System.out.println("The .csv file could not be loaded, " + "please try again."); Logger.getLogger(ListMakerGUI.class.getName()).log( Level.SEVERE, null, ex); } catch (IOException ex){ System.out.println("The .csv file could not be loaded, " + "please try again."); Logger.getLogger(ListMakerGUI.class.getName()).log( Level.SEVERE, null, ex); } } } try{ /*sets the appearance of the gui depending on the OS. Note: system was only checked on Windows and Linux*/ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception ex){ Logger.getLogger(RecipeGUI.class.getName()) //adds note to log .log(Level.SEVERE, null, ex); } initComponents(); //draws components showList(); //shows the list of current recipes toggleEnabled(); //runs method to disable some items select(0); //runs method to select an option in the list } /** Reads a CSV file and creates a RecipeList with it **/ public void readCSV(File f) throws FileNotFoundException, IOException { String thisLine; //string variable which take each record at a time //reads file BufferedReader reader = new BufferedReader(new InputStreamReader( new FileInputStream(f))); String nameField = null; //to store the name of the recipe Recipe r = null; //to store each recipe while ((thisLine = reader.readLine()) != null) //while there is content { //beginning of outer while loop //allows an application to break a string into tokens StringTokenizer st = new StringTokenizer(thisLine, ","); String temp = st.nextToken(); //gets next token if (!st.hasMoreTokens()){ //then its not an ingredient //the csv output seperates recipes by a field containing "---------" if (!temp.equals("---------")) { //if not indication nameField = temp; //stores the recipe name //creates new recipe r=new Recipe(nameField, recipeList.getAllIngredients()); } /*else the current line is the indicator, meaning that the * current recipe must be saved before moving on to the next * one*/ else {recipeList.addRecipe(r);}

Page 25: Recipe program

- 25 -

} while (st.hasMoreTokens()){//then its an ingredient /*gets the ingredients and stores them to variables*/ String quant = st.nextToken(); double quants = Double.parseDouble(quant); String meas = st.nextToken(); //adds ingredient to recipe r.AddIngredient(new Ingredient(temp, quants, meas)); } } } /**Shows an error message containing text which is passed into the method**/ public void showError(String message) { JOptionPane.showMessageDialog( new JFrame(), message, "Error", //title JOptionPane.ERROR_MESSAGE); //type of message return; } /**Shows the list of recipes**/ public void showList() { modelRecipes.removeAllElements();//removes all recipes //adds each recipe name to the list for (int i = 0; i < recipeList.getAllRecipes().size(); i++){ modelRecipes.add(i, recipeList.getRecipe(i).getName()); } } /**Selects an item in the list so that a user cannot accidently forget to select a recipe. Takes an integer argument to determine if the one that is selected is the last one in the list, or the first**/ public void select(int i) { if (i == 0){ if (!modelRecipes.isEmpty()){ recipeDisplay.addSelectionInterval(0, 0); } if (!model.isEmpty()){ displayList.addSelectionInterval(0, 0); } } else{ if (!modelRecipes.isEmpty()) { recipeDisplay.addSelectionInterval(0, 0); } if (!model.isEmpty()){ displayList.addSelectionInterval( model.getSize() - 1, model.getSize() - 1); } } } /**Changes the enabled option of some buttons. This is used to disable options that are not available at certain times, ie when no recipes are in the list **/ public void toggleEnabled() { if (recipeList.getAllRecipes().size() == 0){ listButton.setEnabled(false); selectButton.setEnabled(false);

Page 26: Recipe program

- 26 -

removeButton.setEnabled(false); } else { selectButton.setEnabled(true); if (!model.isEmpty()){ listButton.setEnabled(true); removeButton.setEnabled(true); } else{ listButton.setEnabled(false); removeButton.setEnabled(false); } } } public void exit(){ //prompts the user that they want to close int option = JOptionPane.showConfirmDialog(new JFrame(), "Are you sure you want to exit the program?", "Confirm Exit", JOptionPane.OK_CANCEL_OPTION); //user presses yes if (option == 0){//close program processEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING)); } } public void about(){ JOptionPane.showMessageDialog( new JFrame(), "Written and developed by Carrie Hall" + "\n" + "November 2008 - February 2009" + " \n " + "All rights reserved", "About ListMaker", JOptionPane.INFORMATION_MESSAGE); //type of message } public void select(){ //returns a String containing the user input Object o = JOptionPane.showInputDialog( new JFrame(), "How many people?:", //message in popup box "Add menu", //title JOptionPane.INFORMATION_MESSAGE, //type of message null, null, 2); if (o == null){return;} //cancel pressed else{num = (String) o;} //parses string if (num.trim().equals("")){ //if string is empty showError("Please enter a number."); return; } int numInt = 0; try{ numInt = Integer.parseInt(num); //checks if String entered was a number } catch (NumberFormatException e){ showError("Please enter a number."); return; } if (numInt < 1){ showError("Please enter a number greater than 0."); return; }

Page 27: Recipe program

- 27 -

String name = ""; boolean inlist = false; //if the recipe has been added to shopping list Object[] obj = null; int pos = 0; //to store position of recipe name if it is in the list already String person = " people"; //for output if (numInt == 1){person = " person";} //if recipe for one person if (!model.isEmpty()){ //items in shopping list for (int i = 0; i < model.getSize(); i++){ /*To check if the recipe is in the list already, the output needs to be split, ie so that Tomato Soup: 4 people would split into sections allowing 'Tomato Soup' to be checked*/ obj = model.get(i).toString().split(":"); name = (String) obj[0]; //the item before the colon if (recipeDisplay.getSelectedValue().toString().toLowerCase().equals( name.toLowerCase())){ //in list inlist = true; pos = i; //stores postition } } if (inlist){ //in list String amount = (String) obj[1]; //gets number (x amount of people) Object[] obj2 = amount.toString().split("\\s");//split at seperator space String amount2 = (String) obj2[1]; /*no try catch block because validation has already been done to ensure that only a number gets entered for the amount of people*/ int numOfPeople = Integer.parseInt(amount2); /*if the item is in the list then when the user chooses to add that recipe again, it is simply added to the total number of people*/ int numVar = Integer.parseInt(num) + numOfPeople; model.set(pos, recipeDisplay.getSelectedValue().toString() +": "+numVar +person); } else //not in list { model.addElement(recipeDisplay.getSelectedValue().toString() + ": " + num + person); } } else { //no recipes in list at all model.addElement(recipeDisplay.getSelectedValue().toString() + ": " + num + person); } select(1); //selects the most recently added item toggleEnabled(); } public void remove(){ if (removeButton.isEnabled()){ //items in list model.remove(displayList.getSelectedIndex()); //remove item toggleEnabled(); select(0);//selects the first item } } public void createList(){ if (listButton.isEnabled()) //items in list { String message = ""; //to store shopping list //to store all the ingredients in the recipes selected ArrayList<Ingredient> FullList = new ArrayList<Ingredient>(); //loops through the recipe shopping list

Page 28: Recipe program

- 28 -

for (int i = 0; i < model.size(); i++){ // finds the name of the recipe and the amount of people Object[] obj = model.get(i).toString().split(":"); String name = (String) obj[0]; //name of recipe Object[] obj2 = obj[1].toString().split("\\s"); String amount = (String) obj2[1]; int numOfPeople = Integer.parseInt(amount); //amount of people //gets the list of ingredients in the recipe ArrayList<Ingredient> ingList = recipeList.getRecipe(name).getList(); for (int j = 0; j < ingList.size(); j++){ //loops through items String IngName = ingList.get(j).getName(); //gets name double d = ingList.get(j).getQuantity(); //gets quantity d = d * numOfPeople; //multiplies by num of people to find total String measure = ingList.get(j).getMeasure(); //gets measure //creates new ingredient with total quantity Ingredient newIngredient = new Ingredient(IngName, d, measure); if (FullList.contains(newIngredient)) //ingredient in the list { int pos = 0; //to store position for (int k = 0; k < FullList.size(); k++){ if (FullList.get(k).equals(newIngredient)){ pos = k; //saves position } } //adds on to the running total of that ingredient double tempQ = d + FullList.get(pos).getQuantity(); FullList.set(pos, new Ingredient(IngName, tempQ, measure)); } else //not in list so add ingredient { FullList.add(newIngredient); } } } //begin output of shopping list by looping through arrayList of ingredients for (int z = 0; z < FullList.size(); z++){ message += FullList.get(z).getName() + ": "; //output name //if quantity is in format "#.0" eg 41.0, change for styling String s = "" + FullList.get(z).getQuantity(); if (s.endsWith(".0")){ NumberFormat formatter = new DecimalFormat("#0"); message += formatter.format(FullList.get(z).getQuantity()) + ""; } else { //output normally message += FullList.get(z).getQuantity() + ""; } message += FullList.get(z).getMeasure(); //output measure message += "\n"; //output new line } //output in a message box JOptionPane.showMessageDialog( new JFrame(), message, "Shopping List", JOptionPane.INFORMATION_MESSAGE); //type of message } }