001package edu.pdx.cs410J.grader.gradebook.ui; 002 003import edu.pdx.cs410J.ParserException; 004import edu.pdx.cs410J.grader.gradebook.*; 005 006import javax.swing.*; 007import javax.swing.border.Border; 008import javax.swing.event.ListSelectionEvent; 009import javax.swing.event.ListSelectionListener; 010import java.awt.*; 011import java.awt.event.ActionEvent; 012import java.awt.event.ActionListener; 013import java.awt.event.WindowAdapter; 014import java.awt.event.WindowEvent; 015import java.io.FileNotFoundException; 016import java.io.IOException; 017import java.util.Vector; 018 019/** 020 * This panel displays and edits information about a class stored in a 021 * <code>GradeBook</code>. 022 */ 023@SuppressWarnings("serial") 024public class ClassPanel extends JPanel { 025 private GradeBook book; 026 027 private JFrame frame; 028 029 // GUI components we care about 030 private JLabel classNameLabel; 031 private JList<String> assignmentsList; 032 private AssignmentPanel assignmentPanel; 033 034 private JButton newAssignmentButton; 035 private JButton newStudentButton; 036 private LetterGradeRangesPanel undergradLetterGradeRangesPanel; 037 private LetterGradeRangesPanel gradLetterGradeRangesPanel; 038 039 /** 040 * Creats a <code>ClassPanel</code> and initializes its components. 041 */ 042 public ClassPanel(JFrame frame) { 043 this.frame = frame; 044 this.setLayout(new BorderLayout()); 045 this.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); 046 047 addClassNamePanel(); 048 addAssignmentsPanel(); 049 addLetterGradeRangesPanel(); 050 addNewStudentPanel(); 051 } 052 053 private void addLetterGradeRangesPanel() { 054 JTabbedPane letterGradeRangesPanel = new JTabbedPane(); 055 Border letterGradeRangesBorder = BorderFactory.createTitledBorder("Letter Grades"); 056 letterGradeRangesPanel.setBorder(letterGradeRangesBorder); 057 058 this.undergradLetterGradeRangesPanel = new LetterGradeRangesPanel(Student.Section.UNDERGRADUATE); 059 letterGradeRangesPanel.add("Undergraduate", this.undergradLetterGradeRangesPanel); 060 061 this.gradLetterGradeRangesPanel = new LetterGradeRangesPanel(Student.Section.GRADUATE); 062 letterGradeRangesPanel.add("Graduate", this.gradLetterGradeRangesPanel); 063 064 this.add(letterGradeRangesPanel, BorderLayout.EAST); 065 } 066 067 private void addAssignmentsPanel() { 068 // Set up the assignments panel 069 JPanel assignmentsPanel = new JPanel(); 070 Border assignmentBorder = 071 BorderFactory.createTitledBorder("Assignments"); 072 assignmentsPanel.setBorder(assignmentBorder); 073 assignmentsPanel.setLayout(new BorderLayout()); 074 075 JPanel listPanel = addAssignmentsListPanel(); 076 addAddAssignmentButton(listPanel); 077 assignmentsPanel.add(listPanel, BorderLayout.WEST); 078 addInfoPanel(assignmentsPanel); 079 this.add(assignmentsPanel, BorderLayout.CENTER); 080 } 081 082 private JPanel addAssignmentsListPanel() { 083 JPanel listPanel = new JPanel(); 084 listPanel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); 085 listPanel.setLayout(new BorderLayout()); 086 087 this.assignmentsList = new JList<>(); 088 assignmentsList.addListSelectionListener(new 089 ListSelectionListener() { 090 @Override 091 public void valueChanged(ListSelectionEvent e) { 092 String name = assignmentsList.getSelectedValue(); 093 if (name != null) { 094 Assignment assign = book.getAssignment(name); 095 if (assign == null) { 096 String s = "No assignment named: " + name; 097 throw new IllegalArgumentException(s); 098 } 099 displayAssignment(assign); 100 } 101 } 102 }); 103 listPanel.add(new JScrollPane(this.assignmentsList), 104 BorderLayout.CENTER); 105 return listPanel; 106 } 107 108 private void addNewStudentPanel() { 109 // Add a panel for adding a new student 110 JPanel newStudentPanel = new JPanel(); 111 newStudentPanel.setLayout(new FlowLayout()); 112 newStudentPanel.add(new JLabel("New Student with id:")); 113 final JTextField newStudentField = new JTextField(12); 114 newStudentPanel.add(newStudentField); 115 this.newStudentButton = new JButton("Add"); 116 this.newStudentButton.setEnabled(false); 117 this.newStudentButton.addActionListener(e -> { 118 String id = newStudentField.getText(); 119 if (id == null || id.equals("")) { 120 showErrorMessageDialog("No student id specified"); 121 return; 122 } 123 124 if (ClassPanel.this.book == null) { 125 showErrorMessageDialog("No grade book opened"); 126 return; 127 } 128 129 Student student = new Student(id); 130 ClassPanel.this.book.addStudent(student); 131 newStudentField.setText(""); 132 }); 133 newStudentPanel.add(this.newStudentButton); 134 this.add(newStudentPanel, BorderLayout.SOUTH); 135 } 136 137 private void addAddAssignmentButton(JPanel listPanel) { 138 this.newAssignmentButton = new JButton("Add Assignment"); 139 this.newAssignmentButton.setEnabled(false); 140 this.newAssignmentButton.addActionListener(e -> { 141 createAssignment(); 142 }); 143 listPanel.add(this.newAssignmentButton, BorderLayout.SOUTH); 144 } 145 146 private void addInfoPanel(JPanel assignmentsPanel) { 147 JPanel infoPanel = new JPanel(); 148 infoPanel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); 149 infoPanel.setLayout(new BorderLayout()); 150 this.assignmentPanel = new AssignmentPanel(false); 151 infoPanel.add(assignmentPanel, BorderLayout.CENTER); 152 153 addUpdateButton(infoPanel); 154 155 assignmentsPanel.add(infoPanel, BorderLayout.CENTER); 156 } 157 158 private void addUpdateButton(JPanel infoPanel) { 159 JPanel p = new JPanel(); 160 p.setLayout(new FlowLayout()); 161 JButton updateButton = new JButton("Update"); 162 updateButton.addActionListener(new ActionListener() { 163 @Override 164 public void actionPerformed(ActionEvent e) { 165 // Get the selected assignment and update it 166 String name = assignmentsList.getSelectedValue(); 167 Assignment assign = book.getAssignment(name); 168 169 // Update currently selected assignment 170 updateAssignment(assign); 171 } 172 }); 173 p.add(updateButton); 174 infoPanel.add(p, BorderLayout.SOUTH); 175 } 176 177 private void addClassNamePanel() { 178 JPanel classNamePanel = new JPanel(); 179 classNamePanel.setLayout(new BoxLayout(classNamePanel, 180 BoxLayout.X_AXIS)); 181 classNamePanel.add(Box.createHorizontalGlue()); 182 this.classNameLabel = new JLabel(); 183 classNamePanel.add(this.classNameLabel); 184 classNamePanel.add(Box.createHorizontalGlue()); 185 this.add(classNamePanel, BorderLayout.NORTH); 186 } 187 188 private void showErrorMessageDialog(String message) { 189 JOptionPane.showMessageDialog(ClassPanel.this, 190 new String[]{message}, 191 "Error", 192 JOptionPane.ERROR_MESSAGE); 193 } 194 195 /** 196 * Creates a new assignment based on the contents of the "name" and 197 * "max points" fields. While we're at it, we add it to the 198 * assignment book and display it in the assignment list. 199 */ 200 private Assignment createAssignment() { 201 NewAssignmentDialog dialog = new NewAssignmentDialog(this.frame); 202 dialog.pack(); 203 dialog.setLocationRelativeTo(frame); 204 dialog.setVisible(true); 205 206 Assignment newAssign = dialog.getAssignment(); 207 208 if (newAssign != null) { 209 book.addAssignment(newAssign); 210 this.displayAssignments(book); 211 this.assignmentsList.setSelectedValue(newAssign.getName(), 212 true); 213 } 214 return newAssign; 215 } 216 217 /** 218 * Fills in the contents of an <code>Assignment</code> based on the 219 * contents of the GUI. 220 */ 221 private void updateAssignment(Assignment assign) { 222 this.assignmentPanel.updateAssignment(assign); 223 } 224 225 /** 226 * Sets the <code>GradeBook</code> that is displayed and edited in 227 * this <code>ClassPanel</code>. 228 */ 229 void displayGradeBook(GradeBook book) { 230 this.book = book; 231 this.newAssignmentButton.setEnabled(true); 232 this.newStudentButton.setEnabled(true); 233 234 // Display name of the class 235 double points = 0.0d; 236 for (String name : book.getAssignmentNames()) { 237 Assignment assign = book.getAssignment( name ); 238 points += assign.getPoints(); 239 } 240 241 String className = 242 String.format( "%s (%d students, %.2f points)", book.getClassName(), book.getStudentIds().size(), points ); 243 this.classNameLabel.setText(className); 244 245 this.displayAssignments(book); 246 this.assignmentsList.clearSelection(); // No initial selection 247 248 displayLetterGradeRanges(book); 249 } 250 251 private void displayLetterGradeRanges(GradeBook book) { 252 this.undergradLetterGradeRangesPanel.displayLetterGradeRanges(book.getLetterGradeRanges(Student.Section.UNDERGRADUATE)); 253 this.gradLetterGradeRangesPanel.displayLetterGradeRanges(book.getLetterGradeRanges(Student.Section.GRADUATE)); 254 } 255 256 /** 257 * Displays the names of all of the assignments in a given grade 258 * book in the assignmentsList. 259 */ 260 void displayAssignments(GradeBook book) { 261 // Display all of the assignments 262 Vector<String> assignmentNames = new Vector<>(); 263 assignmentNames.addAll(book.getAssignmentNames()); 264 this.assignmentsList.setListData(assignmentNames); 265 } 266 267 /** 268 * Displays an assignment in the appropriate fields 269 */ 270 private void displayAssignment(Assignment assign) { 271 this.assignmentPanel.displayAssignment(assign); 272 } 273 274 /** 275 * Test program that displays and edits the information in a given 276 * grade book stored in an XML file. 277 */ 278 public static void main(String[] args) { 279 if (args.length < 1) { 280 System.err.println("** usage: java ClassPanel xmlFile"); 281 System.exit(1); 282 } 283 284 final String fileName = args[0]; 285 286 GradeBook book = null; 287 try { 288 XmlGradeBookParser parser = new XmlGradeBookParser(fileName); 289 book = parser.parse(); 290 291 } catch (FileNotFoundException ex) { 292 System.err.println("** Could not find file: " + ex.getMessage()); 293 System.exit(1); 294 295 } catch (IOException ex) { 296 System.err.println("** IOException during parsing: " + ex.getMessage()); 297 System.exit(1); 298 299 } catch (ParserException ex) { 300 System.err.println("** Error during parsing: " + ex); 301 System.exit(1); 302 } 303 304 JFrame frame = new JFrame("ClassPanel test"); 305 ClassPanel classPanel = new ClassPanel(frame); 306 classPanel.displayGradeBook(book); 307 308 final GradeBook theBook = book; 309 frame.addWindowListener(new WindowAdapter() { 310 @Override 311 public void windowClosing(WindowEvent e) { 312 // Write changes to grade book back to file 313 try { 314 XmlDumper dumper = new XmlDumper(fileName); 315 dumper.dump(theBook); 316 317 } catch (IOException ex) { 318 System.err.println("** Error while writing XML file: " + ex); 319 } 320 321 System.exit(1); 322 } 323 }); 324 325 frame.getContentPane().add(classPanel); 326 327 frame.pack(); 328 frame.setVisible(true); 329 } 330 331}