/* ******************************************************************************** * Kelli Wiseth * kelli@alameda-tech-lab.com * CIS 255AX * Program name: StudentRecords.java * Program Description: StudentRecords is a windowed application that processes * student records contained in a flat file (student.dat). The application * lets users add one student record at a time, and display all records in the * file. * * Assignment #7 * 10 May 2005 ******************************************************************************** */ import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.io.*; import java.util.*; public class StudentRecords extends JFrame { private JButton addStudentButton, displayAllStudentsButton; private String firstName, lastName, studentID; private double gpa; private JTextField textFirstName, textLastName, textID, textGpa; private JLabel fNameLabel, lNameLabel, idLabel, gpaLabel; private Container container; private JPanel entryPanel, buttonPanel, outputPanel; private JTextArea outputArea; private boolean firstNameBlank, lastNameBlank, studentIDBlank, gpaBlank; //flags for each field private boolean junkFirstName, junkLastName, junkStudentID, junkGpa; private Student[] student; private StringTokenizer tokenizer; private String filename = "student.dat"; private String line, studentData; private int array_size; private int array_ctr; // set up GUI public StudentRecords() { super( "Kelli Wiseth StudentRecords Application" ); // set up user interface layouts entryPanel = new JPanel(); entryPanel.setLayout(new GridLayout(5, 2, 5, 5)); // get content pane and set its layout container = getContentPane(); // create and add labels and textfields // Label and entry text field for first name fNameLabel = new JLabel("First name "); entryPanel.add(fNameLabel); fNameLabel.setHorizontalAlignment(SwingConstants.RIGHT); textFirstName = new JTextField( 10 ); textFirstName.setToolTipText("First name can be all caps, all lower-case, or upper- and lower-case."); entryPanel.add(textFirstName); // Label and entry text field for last name lNameLabel = new JLabel("Last name "); lNameLabel.setHorizontalAlignment(SwingConstants.RIGHT); entryPanel.add(lNameLabel); textLastName = new JTextField( 10 ); textLastName.setToolTipText("Last name can be all caps, all lower-case, or upper- and lower-case."); entryPanel.add(textLastName); // Label and entry text field for student id idLabel = new JLabel("Student ID "); idLabel.setHorizontalAlignment(SwingConstants.RIGHT); entryPanel.add(idLabel); textID = new JTextField( 10 ); textID.setToolTipText("Student ID is a series of digits and dashes, as in nnn-nn-nnnn"); entryPanel.add(textID); // Label and entry text field for grade point average gpaLabel = new JLabel("Grade point average "); gpaLabel.setHorizontalAlignment(SwingConstants.RIGHT); entryPanel.add(gpaLabel); textGpa = new JTextField( 10 ); textGpa.setToolTipText("Enter GPA as n.nn or n--as in 4 or 4.00"); entryPanel.add(textGpa); // create and add buttons addStudentButton = new JButton("Add Student Record"); entryPanel.add(addStudentButton); displayAllStudentsButton = new JButton("Display All Student Records"); entryPanel.add(displayAllStudentsButton); ButtonHandler handler = new ButtonHandler(); addStudentButton.addActionListener(handler); displayAllStudentsButton.addActionListener(handler); container.add(entryPanel, BorderLayout.NORTH); outputArea = new JTextArea(10,10); outputArea.setEditable(false); outputArea.setText(""); container.add(new JScrollPane(outputArea), BorderLayout.CENTER); setSize( 425, 600 ); setVisible( true ); } // end constructor StudentRecords /********************************************************************** * quickSort() method provided by M.Green, modified for StudentRecords * The quickSort method takes an array, and the values of the first * and last elements in the array as starting points * ********************************************************************** */ public void quickSort(Student student[], int first, int last ) { int currentLocation; if (first >= last) return; // partitioning phase currentLocation = partition( student, first, last ); // sort the left side quickSort( student, first, currentLocation - 1 ); // sort the right side quickSort( student, currentLocation + 1, last ); } //closing brace, quickSort method /********************************************************************** * partition() method provided by M.Green, modified for StudentRecords * * ********************************************************************** */ public int partition( Student partArray[], int left, int right ) { int position = left; // position of target element // continue partition until element in correct position while ( true ) { // traverse array from right until lastName value of string1 is greater than target string while ( ( partArray[ position ].getLastName().compareTo( partArray[ right ].getLastName() ) <= 0 ) && position != right ) { right--; } // element at correct position if ( position == right ) return position; // swap first element less than target if ( partArray[ position ].getLastName().compareTo(partArray[ right ].getLastName()) > 0 ) { swap( partArray, position, right ); position = right; } // traverse array from left until lastName greater than target met while (( partArray[ left ].getLastName().compareTo(partArray[ position].getLastName()) <= 0 ) && left != position ) { ++left; } // element at correct position if ( position == left ) return position; // swap first element greater than target if ( partArray[ left ].getLastName().compareTo(partArray[ position ].getLastName()) > 0) { swap( partArray, position, left ); position = left; } } // end while } // end method partition /********************************************************************** * swap() method provided by M.Green, modified for StudentRecords * swaps two students in the array * * ********************************************************************** */ public void swap( Student array[], int position, int rightLeft ) { Student temp = array [position]; array[ position ] = array[ rightLeft ]; array[ rightLeft ] = temp; } /********************************************************************** * main() method instantiates new StudentRecords class ********************************************************************** */ public static void main( String args[] ) { StudentRecords application = new StudentRecords(); application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); } //main method /************************************************************************* * ButtonHandler is the handler code that's tied to the listeners on the * two buttons. * * DisplayAllStudentsButton must sort the Student objects in the array * of references. * * AddStudentButton validates the field entries before displaying the content * and adding to the file. * ************************************************************************* */ private class ButtonHandler implements ActionListener { public String fNameStringUpper, fNameStringLower, lNameStringUpper, lNameStringLower; public String initCapTemp, fNameSansCap, lNameSansCap; public void actionPerformed(ActionEvent event) { if (event.getSource() == addStudentButton) { outputArea.setText(""); if ((textFirstName.getText().trim().length() == 0) && (textLastName.getText().trim().length() == 0) && (textID.getText().trim().length() == 0) && (textGpa.getText().trim().length() == 0)) { outputArea.setText("\nPlease enter valid student information in all fields."); firstNameBlank=true; lastNameBlank=true; studentIDBlank=true; gpaBlank=true; } // big "else" covers lots of different types of text input issues. Some of these // perhaps could be taken care of by try-catch blocks? else { // firstName text input validation if (textFirstName.getText().trim().length() == 0) { firstNameBlank = true; outputArea.append("\nPlease enter a valid first name or " + "initial--don't leave blank."); } else { firstNameBlank = false; if (!textFirstName.getText().trim().matches("[a-zA-Z]*([ a-zA-Z]+)")) { junkFirstName = true; outputArea.append("\nFirst name entry should contain letters only. Please try again. "); } else { junkFirstName = false; fNameStringLower = textFirstName.getText().toLowerCase().trim(); } } //closing brace else for routine firstName // lastName text validation if (textLastName.getText().trim().length() == 0) { lastNameBlank = true; outputArea.append("\nPlease enter a valid last name--do not leave blank. "); } else { lastNameBlank = false; if (!textLastName.getText().trim().matches( "[a-zA-z]+([ '-][a-zA-Z]+)*" )) { junkLastName = true; outputArea.append("\nLast name field should contain letters only. Please try again. "); } else { junkLastName = false; // Come back to this statement later and fix.. don't change toLowerCase if // the letters already are in upper and lower case (eg, McCartney), look for // inner-caps (eg, LaCroix), and so on lNameStringLower = textLastName.getText().toLowerCase().trim(); } } //closing brace else validation routine lastName // studentID text input validation if (textID.getText().trim().length()==0) { studentIDBlank = true; outputArea.append("\nPlease enter a valid Student ID (nnn-nn-nnnn). Don't leave blank. "); } else { studentIDBlank = false; if (!textID.getText().trim().matches("\\d{3}-\\d{2}-\\d{4}")) { junkStudentID = true; outputArea.append("\nStudentID should be in the format nnn-nn-nnnn. Please try again. "); } else junkStudentID = false; } // gpa text input validation if (textGpa.getText().trim().length() == 0) { gpaBlank = true; outputArea.append("\nPlease enter the student's grade point average (n, or n.nn). Don't leave blank. "); } else { gpaBlank = false; if (!textGpa.getText().trim().matches( "[0-4]\\.*\\d*" ) ) { junkGpa=true; outputArea.append("\nGPA must be in the range of 0 through 4.00. Please try again. "); } else junkGpa = false; } } // closing brace for big else that handles all text input validation (assuming all fields have // some entered data /**************************************************************************** * Assuming we've passed all checks in the nested if/else statements above, * we should now have neither garbage (nor empty) text fields, so we can now go ahead * and add the student to the student data file [student.dat]. I'm saving the * first name and last names with initial caps; however, the logic (below) doesn't * account for some naming nuances (for example, "O'Malley," "LaCroix," or * "Mary Lou," although these are allowed)--but I've fiddled far too long with * this section of the code, so I'll leave such subtleties for future improvement. ****************************************************************************** */ if ( (!firstNameBlank) && (!lastNameBlank)&& (!studentIDBlank) && (!gpaBlank) && (!junkFirstName) && (!junkLastName) && (!junkStudentID) && (!junkGpa)) { fNameStringUpper = fNameStringLower.toUpperCase(); fNameSansCap = fNameStringLower.substring(1); initCapTemp = fNameStringUpper.substring(0, 1); firstName = initCapTemp.concat(fNameSansCap); lNameStringUpper = lNameStringLower.toUpperCase(); lNameSansCap = lNameStringLower.substring(1); initCapTemp = lNameStringUpper.substring(0, 1); lastName = initCapTemp.concat(lNameSansCap); studentID = textID.getText().trim(); gpa = Double.parseDouble(textGpa.getText().trim()); //create a Student object Student tempStudentRef = new Student(firstName, lastName, studentID, gpa); // display the student info outputArea.setText(lastName + " " + firstName + " " + studentID + " " + gpa); //add the student to the student.dat file try { File file = new File (filename); PrintWriter pw = new PrintWriter(new FileWriter(file, true)); pw.print(lastName + ":" + firstName + ":" + studentID + ":" + gpa); pw.println(); pw.close(); } catch(IOException exception){ outputArea.setText("\nProblem creating the file. Here's what Java tells us: " + exception); } //clear the input fields textFirstName.setText(""); textLastName.setText(""); textID.setText(""); textGpa.setText(""); }// closing brace, if statement, executes only if all validation checks have been met } // closing brace for addStudentButton-event-source /********************************************************************* * displayAllStudentsButton event handler creates an array of references * to Student objects after first obtaining a reference to the student.dat * file, opening the file, finding out the size (by counting lines in the * file), then iterating through the lines of data to initialize the * Student objects... * ********************************************************************* */ if (event.getSource() == displayAllStudentsButton) { outputArea.setText(""); // System.out.println("begining of the button handler processing..."); //debug // find out how many records are in the file by opening the file and // iterating through the lines, adding to a counter; then close the file try { array_size = 0; FileReader fr = new FileReader(filename); BufferedReader inFile = new BufferedReader(fr); line = inFile.readLine(); // System.out.println("obtain the array_size ..."); //debug while (line != null) { line = inFile.readLine(); array_size++; // System.out.println("obtain the array_size ..." + array_size); //debug } //close the file inFile.close(); } //closing brace, try catch (FileNotFoundException exception) { outputArea.setText("\nThe " + filename + " file cannot be found. Additional detail (if any): " + exception); } catch (IOException exception) { outputArea.setText("\nProblem with input/output on the file. Additional detail (if any): " + exception); } Student student[] = new Student[array_size]; try { array_ctr=0; FileReader reader = new FileReader(filename); BufferedReader studentFile = new BufferedReader(reader); // System.out.println("inside the try{} block, after creating the array of students " + student); //debug studentData = studentFile.readLine(); // Obtain the data elements as string tokens while (studentData !=null) { tokenizer = new StringTokenizer (studentData, ":"); lastName = tokenizer.nextToken(); firstName = tokenizer.nextToken(); studentID = tokenizer.nextToken(); try { gpa = Double.parseDouble(tokenizer.nextToken()); } catch (NumberFormatException exception) { gpa = 0.00; } //populate the array of Student references using the data we've just //extracted as tokens from the file student[array_ctr] = new Student (lastName, firstName, studentID, gpa); studentData = studentFile.readLine(); array_ctr++; } //while (studentData!=null) // The Student objects now exist, so we can close the file studentFile.close(); } //try catch (FileNotFoundException exception) { outputArea.append("\nThe " + filename + " file cannot be found. Additional detail (if any): " + exception); } catch (IOException exception) { outputArea.append("\nProblem with input/output on the file. Additional detail: " + exception); } catch (NumberFormatException exception) { outputArea.append("\nError in input. Line ignored"); } /************************************************************************ * Sort the contents of the array and output the student info * ************************************************************************ */ // send the array of Student references to the quickSort method, along with // the first position and ending position if (student.length > 0) { quickSort(student, 0, student.length-1); for (int ctr = 0; ctr < student.length; ctr++) { outputArea.append("\n" + student[ctr].toString()); // System.out.println("show student toString() " + student[ctr].toString()); //debug } } else { outputArea.append("\nSorry, the student.dat file is completely empty. There are no students."); } } //closing brace for event--displayAllButton handler } //closing brace for actionPerformed } //closing brace for ButtonHandler inner class } // closing brace for class StudentRecords