import java.awt.*; public class Spreadsheet extends Frame { protected static int numFields = 16; protected Checkbox[] check = new Checkbox[numFields]; protected CheckboxGroup mutexChecks = new CheckboxGroup(); protected Label[] field = new Label[numFields]; protected String[] trueValue = new String[numFields]; int cursor = 0; protected TextField editField; protected Button docalc; protected Button doquit; protected int unfocused; // EvaluateSpreadsheet // // The function determines which values should be displayed given // the formulas in boxes. The values to display go into . // // , , , , and encode the // formulas. is 0 for addition, 1 for subtraction, 2 for // multiplication, and 3 for division. is negative if // the left operand is a constant, otherwise it is the box to which // the left operand refers. is the left operand if it is a // constant. Similarly, is negative for a constant right // operand, otherwise the box to which the right operand refers, // and is the right operand. // // The function places into all boxes whose values // could not be computed. public static void EvaluateSpreadsheet(double[] result, int[] optor, int[] lhs_type, double[] lhs, int[] rhs_type, double[] rhs, double undefined) { int i; // There is an error in the homework assignment. The values // of boxes 2 and 5 in the example should be -78.6 and -32.2, // respectively. for(i = 0; i < numFields; i++) { result[i] = undefined; } } // Spreadsheet // // creates the dialog box public Spreadsheet() { super("Spreadsheet"); Panel p; GridBagConstraints c; GridBagLayout line; int i; unfocused = 0; // create the grid this.setLayout(new GridBagLayout()); c = new GridBagConstraints(); c.gridwidth = 1; c.gridheight = 1; c.ipady = 5; c.anchor = GridBagConstraints.CENTER; c.weightx = 1.0; // create the boxes for(i = 0; i < numFields; i++) { // default values trueValue[i] = new String(""); // checkbox for selection check[i] = new Checkbox("#" + i); check[i].setCheckboxGroup(mutexChecks); c.gridx = 0; c.gridy = i; c.weightx = 0.0; c.fill = GridBagConstraints.HORIZONTAL; ((GridBagLayout) this.getLayout()).setConstraints(check[i], c); this.add(check[i]); // text field for value field[i] = new Label("?"); c.gridx = 1; c.gridy = i; c.weightx = 1.0; c.fill = GridBagConstraints.HORIZONTAL; ((GridBagLayout) this.getLayout()).setConstraints(field[i], c); this.add(field[i]); } // initially select the first one cursor = 0; mutexChecks.setCurrent(check[cursor]); // create text field for user to edit editField = new TextField(""); c.gridx = 0; c.gridy = numFields; c.weighty = 1.0; c.gridwidth = 2; c.fill = GridBagConstraints.HORIZONTAL; ((GridBagLayout) this.getLayout()).setConstraints(editField, c); this.add(editField); // create a Panel to hold the buttons. p = new Panel(); p.setLayout(new FlowLayout(FlowLayout.CENTER, 15, 15)); // add the ``Test'' button docalc = new Button("Calculate"); p.add(docalc); // add the ``Quit'' button doquit = new Button("Quit"); p.add(doquit); // put Panel in dialog c.gridy = numFields + 1; c.weighty = 0.0; c.fill = GridBagConstraints.NONE; ((GridBagLayout) this.getLayout()).setConstraints(p, c); this.add(p); this.pack(); } // action // // handle button clicks public boolean action(Event e, Object arg) { int i; if(e.target == docalc || e.target == editField) { // recalculate values trueValue[cursor] = editField.getText(); CalculateSheet(); return true; } else if(e.target == doquit) { // quit this.dispose(); return true; } else { return false; } } // CalculateSheet // // This function gets all the formulas, interprets them, calculates // the values to display (using EvaluateSpreadsheet), and finally // displays them. public void CalculateSheet() { double[] result = new double[numFields]; int[] optor = new int[numFields]; int[] lhs_type = new int[numFields]; double[] lhs = new double[numFields]; int[] rhs_type = new int[numFields]; double[] rhs = new double[numFields]; double undefined = Double.MAX_VALUE; int i; int j; int begin_num; // interpret formulas into arrays for(i = 0; i < numFields; i++) { int[] op = new int[1]; int[] x_type = new int[1]; double[] x = new double[1]; int[] y_type = new int[1]; double[] y = new double[1]; boolean ok; op[0] = 0; x_type[0] = -1; x[0] = undefined; y_type[0] = -1; y[0] = 0; ok = InterpretFormula(trueValue[i], op, x_type, x, y_type, y); if(ok) { optor[i] = op[0]; lhs_type[i] = x_type[0]; lhs[i] = x[0]; rhs_type[i] = y_type[0]; rhs[i] = y[0]; } else { lhs_type[i] = -1; lhs[i] = undefined; optor[i] = 0; rhs_type[i] = -1; rhs[i] = 0; } } // Determine spreadsheet values EvaluateSpreadsheet(result, optor, lhs_type, lhs, rhs_type, rhs, undefined); // Display values for(i = 0; i < numFields; i++) { if(result[i] == undefined) { field[i].setText("?"); } else { field[i].setText(Double.toString(result[i])); } } } // InterpretFormula // // This method interprets the string as a formula, putting // the interpretation into its parameters in the format accepted // by EvaluateSpreadsheet. It returns true on success, false if // the formula could not be interpreted. public static boolean InterpretFormula(String str, int[] op, int[] x_type, double[] x, int[] y_type, double[] y) { int j; int begin_num; j = 0; // skip white space while(j < str.length() && Character.isSpace(str.charAt(j))) j++; // get first operator if(j < str.length() && str.charAt(j) == '#') { x_type[0] = 0; j++; } else { x_type[0] = -1; } if(j == str.length()) { return false; } begin_num = j; if(j < str.length() && str.charAt(j) == '-') ++j; while(j < str.length() && (Character.isDigit(str.charAt(j)) || str.charAt(j) == '.')) { j++; } try { if(x_type[0] < 0) { x[0] = Double.valueOf(str.substring(begin_num, j)).doubleValue(); } else { x_type[0] = Integer.valueOf(str.substring(begin_num, j)).intValue(); } } catch(NumberFormatException e) { return false; } // skip white space while(j < str.length() && Character.isSpace(str.charAt(j))) j++; if(j == str.length()) { op[0] = 0; y_type[0] = -1; y[0] = 0; return true; } // get operator if(str.charAt(j) == '+') { op[0] = 0; } else if(str.charAt(j) == '-') { op[0] = 1; } else if(str.charAt(j) == '*') { op[0] = 2; } else if(str.charAt(j) == '/') { op[0] = 3; } else { return false; } j++; // skip white space while(j < str.length() && Character.isSpace(str.charAt(j))) j++; if(j == str.length()) { return false; } // get second operator if(j< str.length() && str.charAt(j) == '#') { y_type[0] = 0; j++; } else { y_type[0] = -1; } if(j == str.length()) { return false; } begin_num = j; if(j < str.length() && str.charAt(j) == '-') ++j; while(j < str.length() && (Character.isDigit(str.charAt(j)) || str.charAt(j) == '.')) { j++; } try { if(y_type[0] < 0) { y[0] = Double.valueOf(str.substring(begin_num, j)).doubleValue(); } else { y_type[0] = Integer.valueOf(str.substring(begin_num, j)).intValue(); } } catch(NumberFormatException e) { return false; } // skip whate space while(j < str.length() && Character.isSpace(str.charAt(j))) j++; if(j != str.length()) { return false; } return true; } // gotFocus // // sets the default focus location public boolean gotFocus(Event e, Object arg) { int i; for(i = 0; i < numFields; i++) { if(e.target == field[i] || e.target == check[i]) { // The user has selected another box, so change the // current values to reflect this. trueValue[cursor] = editField.getText(); cursor = i; mutexChecks.setCurrent(check[cursor]); editField.setText(trueValue[cursor]); editField.requestFocus(); return true; } } return true; } // main // // this is where the program begins public static void main(String[] args) { Frame f; Spreadsheet dialog; // create the dialog box f = new Spreadsheet(); f.resize(300, 500); f.show(); } }