001package edu.pdx.cs410J.grader.gradebook.ui; 002 003import edu.pdx.cs410J.ParserException; 004import edu.pdx.cs410J.grader.gradebook.Assignment; 005import edu.pdx.cs410J.grader.gradebook.GradeBook; 006import edu.pdx.cs410J.grader.gradebook.Notable; 007import edu.pdx.cs410J.grader.gradebook.XmlGradeBookParser; 008 009import javax.swing.*; 010import java.awt.*; 011import java.awt.event.WindowAdapter; 012import java.awt.event.WindowEvent; 013import java.io.FileNotFoundException; 014import java.io.IOException; 015import java.time.LocalDateTime; 016import java.time.format.DateTimeFormatter; 017import java.time.format.DateTimeParseException; 018import java.util.ArrayList; 019 020/** 021 * This panel is used to display and edit <code>Assignment</code>s. 022 */ 023@SuppressWarnings("serial") 024public class AssignmentPanel extends JPanel { 025 private static final String QUIZ = "Quiz"; 026 private static final String PROJECT = "Project"; 027 private static final String OTHER = "Other"; 028 private static final String OPTIONAL = "Optional"; 029 private static final String POA = "POA"; 030 031 static final String DATE_TIME_FORMAT_PATTERN = "M/d/yyyy h:mm a"; 032 static final DateTimeFormatter DATE_TIME_FORMAT = DateTimeFormatter.ofPattern(DATE_TIME_FORMAT_PATTERN); 033 034 // GUI components we care about 035 private JTextField nameField; 036 private JComboBox<String> typeBox; 037 private JTextField pointsField; 038 private JTextField descriptionField; 039 private JTextField dueDateField; 040 private NotesPanel notes; 041 042 /** 043 * Creates and adds GUI components to a new 044 * <code>AssignmentPanel</code>. 045 */ 046 public AssignmentPanel(boolean canCreate) { 047 this.setLayout(new BorderLayout()); 048 049 // Panel containing information about an assignment 050 JPanel infoPanel = new JPanel(); 051 infoPanel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); 052 infoPanel.setLayout(new BorderLayout()); 053 054 addAssignmentInformationWidgets(infoPanel); 055 056 this.add(infoPanel, BorderLayout.NORTH); 057 058 if (!canCreate) { 059 this.nameField.setEditable(false); 060 } 061 062 // Add a NotePanel 063 this.notes = new NotesPanel(); 064 this.notes.setNotable(new Notable() { 065 private ArrayList<String> notes = new ArrayList<>(); 066 067 @Override 068 public java.util.List<String> getNotes() { 069 return notes; 070 } 071 072 @Override 073 public void addNote(String note) { 074 notes.add(note); 075 } 076 077 @Override 078 public void removeNote(String note) { 079 notes.remove(note); 080 } 081 }); 082 this.add(notes, BorderLayout.CENTER); 083 } 084 085 private void addAssignmentInformationWidgets(JPanel infoPanel) { 086 JPanel labels = new JPanel(); 087 labels.setLayout(new GridLayout(0, 1)); 088 labels.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2)); 089 labels.add(new JLabel("Name:")); 090 labels.add(new JLabel("Max points:")); 091 labels.add(new JLabel("Type:")); 092 labels.add(new JLabel("Description:")); 093 labels.add(new JLabel("Due date:")); 094 095 JPanel fields = new JPanel(); 096 fields.setLayout(new GridLayout(0, 1)); 097 this.nameField = new JTextField(8); 098 fields.add(this.nameField); 099 this.pointsField = new JTextField(5); 100 fields.add(this.pointsField); 101 102 addTypeBox(fields); 103 104 this.descriptionField = new JTextField(20); 105 fields.add(this.descriptionField); 106 this.dueDateField = new JTextField(22); 107 fields.add(this.dueDateField); 108 109 infoPanel.add(labels, BorderLayout.WEST); 110 infoPanel.add(fields, BorderLayout.CENTER); 111 } 112 113 private void addTypeBox(JPanel fields) { 114 this.typeBox = new JComboBox<>(); 115 this.typeBox.addItem(QUIZ); 116 this.typeBox.addItem(PROJECT); 117 this.typeBox.addItem(POA); 118 this.typeBox.addItem(OTHER); 119 this.typeBox.addItem(OPTIONAL); 120 fields.add(this.typeBox); 121 } 122 123 /** 124 * Creates a new <code>Assignment</code> based on the contents of 125 * this <code>AssignmentPanel</code>. 126 */ 127 public Assignment createAssignment() { 128 // Get the name and max points of the assignment 129 String name = nameField.getText(); 130 if (isNullOrEmpty(name)) { 131 return error("No assignment name specified"); 132 } 133 134 String points = pointsField.getText(); 135 if (isNullOrEmpty(points)) { 136 return error("No points value specified"); 137 } 138 139 // Create a new Assignment object 140 try { 141 double d = Double.parseDouble(points); 142 Assignment newAssign = new Assignment(name, d); 143 this.notes.getNotable().getNotes().forEach(newAssign::addNote); 144 145 updateAssignment(newAssign); 146 this.notes.setNotable(newAssign); 147 return newAssign; 148 149 } catch (NumberFormatException ex) { 150 return error(points + " is not a number"); 151 } 152 } 153 154 private boolean isNullOrEmpty(String name) { 155 return name == null || name.equals(""); 156 } 157 158 private Assignment error(String message) { 159 JOptionPane.showMessageDialog(AssignmentPanel.this, 160 new String[]{message}, 161 "Error", 162 JOptionPane.ERROR_MESSAGE); 163 return null; 164 } 165 166 /** 167 * Displays the contents of a given <code>Assignment</code> in this 168 * <code>AssignmentPanel</code>. 169 */ 170 public void displayAssignment(Assignment assign) { 171 this.nameField.setText(assign.getName()); 172 this.pointsField.setText(String.valueOf(assign.getPoints())); 173 Assignment.AssignmentType type = assign.getType(); 174 if (type == Assignment.AssignmentType.QUIZ) { 175 this.typeBox.setSelectedItem(QUIZ); 176 177 } else if (type == Assignment.AssignmentType.PROJECT) { 178 this.typeBox.setSelectedItem(PROJECT); 179 180 } else if (type == Assignment.AssignmentType.OTHER) { 181 this.typeBox.setSelectedItem(OTHER); 182 183 } else if (type == Assignment.AssignmentType.OPTIONAL) { 184 this.typeBox.setSelectedItem(OPTIONAL); 185 186 } else if (type == Assignment.AssignmentType.POA) { 187 this.typeBox.setSelectedItem(POA); 188 189 } else { 190 String s = "Invalid assignment type: " + type; 191 throw new IllegalArgumentException(s); 192 } 193 194 String description = assign.getDescription(); 195 if (isNotEmpty(description)) { 196 this.descriptionField.setText(description); 197 198 } else { 199 this.descriptionField.setText(""); 200 } 201 202 LocalDateTime dueDate = assign.getDueDate(); 203 if (dueDate != null) { 204 this.dueDateField.setText(DATE_TIME_FORMAT.format(dueDate)); 205 206 } else { 207 this.dueDateField.setText(""); 208 } 209 210 this.notes.setNotable(assign); 211 } 212 213 /** 214 * Fills in the contents of an <code>Assignment</code> based on the 215 * contents of this <code>AssignmentPanel</code>. 216 */ 217 public void updateAssignment(Assignment assign) { 218 String points = pointsField.getText(); 219 if (isNullOrEmpty(points)) { 220 error("No points value specified"); 221 return; 222 } 223 224 try { 225 double d = Double.parseDouble(points); 226 assign.setPoints(d); 227 228 } catch (NumberFormatException ex) { 229 error(points + " is not a number"); 230 return; 231 } 232 233 setAssignmentType(assign); 234 235 String description = this.descriptionField.getText(); 236 237 if (isNotEmpty(description)) { 238 assign.setDescription(description); 239 } 240 241 String dueDate = this.dueDateField.getText(); 242 if (isNotEmpty(dueDate)) { 243 try { 244 assign.setDueDate(LocalDateTime.parse(dueDate.trim(), DATE_TIME_FORMAT)); 245 246 } catch (DateTimeParseException ex) { 247 error(dueDate + " is not a validate date (" + DATE_TIME_FORMAT_PATTERN + ")"); 248 } 249 250 } else { 251 assign.setDueDate(null); 252 } 253 254 // Adding notes is taken care of by the NotesPanel 255 } 256 257 private void setAssignmentType(Assignment assign) { 258 String type = (String) this.typeBox.getSelectedItem(); 259 260 switch (type) { 261 case QUIZ: 262 assign.setType(Assignment.AssignmentType.QUIZ); 263 break; 264 case PROJECT: 265 assign.setType(Assignment.AssignmentType.PROJECT); 266 break; 267 case OTHER: 268 assign.setType(Assignment.AssignmentType.OTHER); 269 break; 270 case OPTIONAL: 271 assign.setType(Assignment.AssignmentType.OPTIONAL); 272 break; 273 case POA: 274 assign.setType(Assignment.AssignmentType.POA); 275 break; 276 default: 277 String s = "Unknown assignment type: " + type; 278 throw new IllegalArgumentException(s); 279 } 280 } 281 282 private boolean isNotEmpty(String description) { 283 return description != null && !description.equals(""); 284 } 285 286 /** 287 * Test program 288 */ 289 public static void main(String[] args) { 290 String fileName = args[0]; 291 String assignName = args[1]; 292 293 GradeBook book = null; 294 try { 295 XmlGradeBookParser parser = new XmlGradeBookParser(fileName); 296 book = parser.parse(); 297 298 } catch (FileNotFoundException ex) { 299 System.err.println("** Could not find file: " + ex.getMessage()); 300 System.exit(1); 301 302 } catch (IOException ex) { 303 System.err.println("** IOException during parsing: " + ex.getMessage()); 304 System.exit(1); 305 306 } catch (ParserException ex) { 307 System.err.println("** Error during parsing: " + ex); 308 System.exit(1); 309 } 310 311 Assignment assign = book.getAssignment(assignName); 312 if (assign == null) { 313 System.err.println("Not such assignment: " + assignName); 314 System.exit(1); 315 } 316 317 AssignmentPanel assignPanel = new AssignmentPanel(false); 318 assignPanel.displayAssignment(assign); 319 320 JFrame frame = new JFrame("AssignmentPanel test"); 321 frame.addWindowListener(new WindowAdapter() { 322 @Override 323 public void windowClosing(WindowEvent e) { 324 System.exit(1); 325 } 326 }); 327 328 frame.getContentPane().add(assignPanel); 329 330 frame.pack(); 331 frame.setVisible(true); 332 } 333}