home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ool.zip / OOL / samples / sample11 / SpreadSheet.java < prev    next >
Text File  |  1996-11-11  |  21KB  |  861 lines

  1. /*
  2.  * @(#)SpreadSheet.java    1.17 95/03/09 Sami Shaio
  3.  *
  4.  * Copyright (c) 1994-1995 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software
  7.  * and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
  8.  * without fee is hereby granted. 
  9.  * Please refer to the file http://java.sun.com/copy_trademarks.html
  10.  * for further important copyright and trademark information and to
  11.  * http://java.sun.com/licensing.html for further important licensing
  12.  * information for the Java (tm) Technology.
  13.  * 
  14.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  15.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  16.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  17.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  18.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  19.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  20.  * 
  21.  * THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
  22.  * CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
  23.  * PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
  24.  * NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
  25.  * SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
  26.  * SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
  27.  * PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES").  SUN
  28.  * SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
  29.  * HIGH RISK ACTIVITIES.
  30.  */
  31. import java.applet.Applet;
  32. import java.awt.*;
  33. import java.io.*;
  34. import java.lang.*;
  35. import java.net.*;
  36.  
  37. public class SpreadSheet extends Applet {
  38.     String        title;
  39.     Font        titleFont;
  40.     Color        cellColor;
  41.     Color        inputColor;
  42.     int            cellWidth = 100;
  43.     int            cellHeight = 15;
  44.     int            titleHeight = 15;
  45.     int            rowLabelWidth = 15;
  46.     Font        inputFont;
  47.     boolean        isStopped = false;
  48.     boolean        fullUpdate = true;
  49.     int            rows;
  50.     int            columns;
  51.     int            currentKey = -1;
  52.     int            selectedRow = -1;
  53.     int            selectedColumn = -1;
  54.     SpreadSheetInput    inputArea;
  55.     Cell        cells[][];
  56.     Cell        current = null;
  57.  
  58.     public synchronized void init() {
  59.     String rs;
  60.     
  61.     cellColor = Color.white;
  62.     inputColor = new Color(100, 100, 225);
  63.     inputFont = new Font("Courier", Font.PLAIN, 10);
  64.     titleFont = new Font("Courier", Font.BOLD, 12);
  65.     title = getParameter("title");
  66.     if (title == null) {
  67.         title = "Spreadsheet";
  68.     }
  69.     rs = getParameter("rows");
  70.     if (rs == null) {
  71.         rows = 9;
  72.     } else {
  73.         rows = Integer.parseInt(rs);
  74.     }
  75.     rs = getParameter("columns");
  76.     if (rs == null) {
  77.         columns = 5;
  78.     } else {
  79.         columns = Integer.parseInt(rs);
  80.     }
  81.     cells = new Cell[rows][columns];
  82.     char l[] = new char[1];
  83.     for (int i=0; i < rows; i++) {
  84.         for (int j=0; j < columns; j++) {
  85.  
  86.         cells[i][j] = new Cell(this,
  87.                        Color.lightGray,
  88.                        Color.black,
  89.                        cellColor,
  90.                        cellWidth - 2,
  91.                        cellHeight - 2);
  92.         l[0] = (char)((int)'a' + j);
  93.         rs = getParameter("" + new String(l) + (i+1));
  94.         if (rs != null) {
  95.             cells[i][j].setUnparsedValue(rs);
  96.         }
  97.         }
  98.     }
  99.  
  100.     Dimension d = size();
  101.     inputArea = new SpreadSheetInput(null, this, d.width - 2, cellHeight - 1,
  102.                      inputColor, Color.white); 
  103.     resize(columns * cellWidth + rowLabelWidth,
  104.            ((rows + 1) * cellHeight) + cellHeight + titleHeight);
  105.     }
  106.  
  107.     public void setCurrentValue(float val) {
  108.     if (selectedRow == -1 || selectedColumn == -1) {
  109.         return;
  110.     }
  111.     cells[selectedRow][selectedColumn].setValue(val);
  112.     repaint();
  113.     }
  114.  
  115.     public void stop() {
  116.     isStopped = true;
  117.     }
  118.  
  119.     public void start() {
  120.     isStopped = false;
  121.     }
  122.  
  123.     public void destroy() {
  124.     for (int i=0; i < rows; i++) {
  125.         for (int j=0; j < columns; j++) {
  126.         if (cells[i][j].type == Cell.URL) {
  127.             cells[i][j].updaterThread.stop();
  128.         }
  129.         }
  130.     }
  131.     }
  132.  
  133.     public void setCurrentValue(int type, String val) {
  134.     if (selectedRow == -1 || selectedColumn == -1) {
  135.         return;
  136.     }
  137.     cells[selectedRow][selectedColumn].setValue(type, val);
  138.     repaint();
  139.     }
  140.  
  141.     public void update(Graphics g) {
  142.     if (! fullUpdate) {
  143.         int cx, cy;
  144.  
  145.         g.setFont(titleFont);
  146.         for (int i=0; i < rows; i++) {
  147.         for (int j=0; j < columns; j++) {
  148.             if (cells[i][j].needRedisplay) {
  149.             cx = (j * cellWidth) + 2 + rowLabelWidth;
  150.             cy = ((i+1) * cellHeight) + 2 + titleHeight;
  151.             cells[i][j].paint(g, cx, cy);
  152.             }
  153.         }
  154.         }
  155.     } else {
  156.         paint(g);
  157.         fullUpdate = false;
  158.     }
  159.     }
  160.  
  161.     public void recalculate() {
  162.     int    i,j;
  163.  
  164.     //System.out.println("SpreadSheet.recalculate");
  165.     for (i=0; i < rows; i++) {
  166.         for (j=0; j < columns; j++) {
  167.         if (cells[i][j] != null && cells[i][j].type == Cell.FORMULA) {
  168.             cells[i][j].setRawValue(evaluateFormula(cells[i][j].parseRoot));
  169.             cells[i][j].needRedisplay = true;
  170.         }
  171.         }
  172.     }
  173.     repaint();
  174.     }
  175.  
  176.     public float evaluateFormula(Node n) {
  177.     float    val = 0.0f;
  178.  
  179.     //System.out.println("evaluateFormula:");
  180.     //n.print(3);
  181.     if (n == null) {
  182.         //System.out.println("Null node");
  183.         return val;
  184.     }
  185.     switch (n.type) {
  186.       case Node.OP:
  187.         val = evaluateFormula(n.left);
  188.         switch (n.op) {
  189.           case '+':
  190.         val += evaluateFormula(n.right);
  191.         break;
  192.           case '*':
  193.         val *= evaluateFormula(n.right);
  194.         break;
  195.           case '-':
  196.         val -= evaluateFormula(n.right);
  197.         break;
  198.           case '/':
  199.         val /= evaluateFormula(n.right);
  200.         break;
  201.         }
  202.         break;
  203.       case Node.VALUE:
  204.         //System.out.println("=>" + n.value);
  205.         return n.value;
  206.       case Node.CELL:
  207.         if (n == null) {
  208.         //System.out.println("NULL at 192");
  209.         } else {
  210.         if (cells[n.row][n.column] == null) {
  211.             //System.out.println("NULL at 193");
  212.         } else {
  213.             //System.out.println("=>" + cells[n.row][n.column].value);
  214.             return cells[n.row][n.column].value;
  215.         }
  216.         }
  217.     }
  218.  
  219.     //System.out.println("=>" + val);
  220.     return val;
  221.     }    
  222.  
  223.     public synchronized void paint(Graphics g) {
  224.     int i, j;
  225.     int cx, cy;
  226.     char l[] = new char[1];
  227.  
  228.  
  229.     Dimension d = size();
  230.     g.setFont(titleFont);
  231.     i = g.getFontMetrics().stringWidth(title);
  232.     g.drawString((title == null) ? "Spreadsheet" : title,
  233.              (d.width - i) / 2, 12);
  234.     g.setColor(inputColor);
  235.     g.fillRect(0, cellHeight, d.width, cellHeight);
  236.     g.setFont(titleFont);
  237.     for (i=0; i < rows+1; i++) {
  238.         cy = (i+2) * cellHeight;
  239.         g.setColor(getBackground());
  240.         g.draw3DRect(0, cy, d.width, 2, true);
  241.         if (i < rows) {
  242.         g.setColor(Color.red);
  243.         g.drawString("" + (i+1), 2, cy + 12);
  244.         }
  245.     }
  246.     g.setColor(Color.red);
  247.     for (i=0; i < columns; i++) {
  248.         cx = i * cellWidth;
  249.         g.setColor(getBackground());
  250.         g.draw3DRect(cx + rowLabelWidth,
  251.               2 * cellHeight, 1, d.height, true);
  252.         if (i < columns) {
  253.         g.setColor(Color.red);
  254.         l[0] = (char)((int)'A' + i);
  255.         g.drawString(new String(l),
  256.                  cx + rowLabelWidth + (cellWidth / 2),
  257.                  d.height - 3);
  258.         }
  259.     }
  260.  
  261.     
  262.     for (i=0; i < rows; i++) {
  263.         for (j=0; j < columns; j++) {
  264.         cx = (j * cellWidth) + 2 + rowLabelWidth;
  265.         cy = ((i+1) * cellHeight) + 2 + titleHeight;
  266.         if (cells[i][j] != null) {
  267.             cells[i][j].paint(g, cx, cy);
  268.         }
  269.         }
  270.     }
  271.  
  272.     g.setColor(getBackground());
  273.     g.draw3DRect(0, titleHeight,
  274.               d.width,
  275.               d.height - titleHeight,
  276.               false);
  277.     inputArea.paint(g, 1, titleHeight + 1);
  278.     }
  279.     public boolean mouseDown(Event evt, int x, int y) {
  280.     Cell cell;
  281.     if (y < (titleHeight + cellHeight)) {
  282.         selectedRow = -1;
  283.         if (y <= titleHeight && current != null) {
  284.         current.deselect();
  285.         current = null;
  286.         }
  287.         return true;
  288.     }
  289.     if (x < rowLabelWidth) {
  290.         selectedRow = -1;
  291.         if (current != null) {
  292.         current.deselect();
  293.         current = null;
  294.         }
  295.         return true;
  296.     }
  297.     selectedRow = ((y - cellHeight - titleHeight) / cellHeight);
  298.     selectedColumn = (x - rowLabelWidth) / cellWidth;
  299.     if (selectedRow > rows ||
  300.         selectedColumn >= columns) {
  301.         selectedRow = -1;
  302.         if (current != null) {
  303.         current.deselect();
  304.         current = null;
  305.         }
  306.     } else {
  307.         if (selectedRow >= rows) {
  308.         selectedRow = -1;
  309.         if (current != null) {
  310.             current.deselect();
  311.             current = null;
  312.         }
  313.         return true;
  314.         }
  315.         cell = cells[selectedRow][selectedColumn];
  316.         inputArea.setText(new String(cell.getPrintString()));
  317.         if (current != null) {
  318.         current.deselect();
  319.         }
  320.         current = cell;
  321.         current.select();
  322.         requestFocus();
  323.         fullUpdate = true;
  324.         repaint();
  325.     }
  326.     return true;
  327.     }
  328.     public boolean keyDown(Event evt, int key) {
  329.     fullUpdate=true;
  330.     inputArea.keyDown(key);
  331.     return true;
  332.     }
  333. }
  334.  
  335. class CellUpdater extends Thread {
  336.     Cell     target;
  337.     InputStream dataStream = null;
  338.     StreamTokenizer tokenStream;
  339.  
  340.     public CellUpdater(Cell c) {
  341.     super("cell updater");
  342.     target = c;
  343.     }
  344.  
  345.     public void run() {
  346.     try {
  347.         dataStream = new URL(target.app.getDocumentBase(),
  348.                  target.getValueString()).openStream();
  349.         tokenStream = new StreamTokenizer(dataStream);
  350.         tokenStream.eolIsSignificant(false);
  351.  
  352.         while (true) {
  353.         switch (tokenStream.nextToken()) {
  354.         case tokenStream.TT_EOF:
  355.             dataStream.close();
  356.             return;
  357.         default:
  358.             break;
  359.         case tokenStream.TT_NUMBER:
  360.             target.setTransientValue((float)tokenStream.nval);
  361.             if (! target.app.isStopped && ! target.paused) {
  362.             target.app.repaint();
  363.             }
  364.             break;
  365.         }
  366.         try {
  367.             Thread.sleep(2000);
  368.         } catch (InterruptedException e) {
  369.             break;
  370.         }
  371.         }
  372.     } catch (IOException e) {
  373.         return;
  374.     }
  375.     }
  376. }
  377.  
  378. class Cell {
  379.     public static final int VALUE = 0;
  380.     public static final int LABEL = 1;
  381.     public static final int URL   = 2;
  382.     public static final int FORMULA = 3;
  383.     
  384.     Node    parseRoot;
  385.     boolean    needRedisplay;
  386.     boolean selected = false;
  387.     boolean transientValue = false;
  388.     public int    type = Cell.VALUE;
  389.     String    valueString = "";
  390.     String    printString = "v";
  391.     float    value;
  392.     Color    bgColor;
  393.     Color    fgColor;
  394.     Color    highlightColor;
  395.     int        width;
  396.     int        height;
  397.     SpreadSheet app;
  398.     CellUpdater    updaterThread;
  399.     boolean    paused = false;
  400.  
  401.     public Cell(SpreadSheet app,
  402.         Color bgColor,
  403.         Color fgColor,
  404.         Color highlightColor,
  405.         int width,
  406.         int height) {
  407.     this.app = app;
  408.     this.bgColor = bgColor;
  409.     this.fgColor = fgColor;
  410.     this.highlightColor = highlightColor;
  411.     this.width = width;
  412.     this.height = height;
  413.     needRedisplay = true;
  414.     }
  415.         
  416.     public void setRawValue(float f) {
  417.     valueString = Float.toString(f);
  418.     value = f;
  419.     }
  420.     public void setValue(float f) {
  421.     setRawValue(f);
  422.     printString = "v" + valueString;
  423.     type = Cell.VALUE;
  424.     paused = false;
  425.     app.recalculate();
  426.     needRedisplay = true;
  427.     }
  428.  
  429.     public void setTransientValue(float f) {
  430.     transientValue = true;
  431.     value = f;
  432.     needRedisplay = true;
  433.     app.recalculate();
  434.     }
  435.  
  436.     public void setUnparsedValue(String s) {
  437.     switch (s.charAt(0)) {
  438.       case 'v':
  439.         setValue(Cell.VALUE, s.substring(1));
  440.         break;
  441.       case 'f':
  442.         setValue(Cell.FORMULA, s.substring(1));
  443.         break;
  444.       case 'l':
  445.         setValue(Cell.LABEL, s.substring(1));
  446.         break;
  447.       case 'u':
  448.         setValue(Cell.URL, s.substring(1));
  449.         break;
  450.     }
  451.     }
  452.  
  453.     /**
  454.      * Parse a spreadsheet formula. The syntax is defined as:
  455.      *
  456.      * formula -> value
  457.      * formula -> value op value
  458.      * value -> '(' formula ')'
  459.      * value -> cell
  460.      * value -> <number>
  461.      * op -> '+' | '*' | '/' | '-'
  462.      * cell -> <letter><number>
  463.      */
  464.     public String parseFormula(String formula, Node node) {
  465.     String subformula;
  466.     String restFormula;
  467.     float value;
  468.     int length = formula.length();
  469.     Node left;
  470.     Node right;
  471.     char op;
  472.  
  473.     if (formula == null) {
  474.         return null;
  475.     }
  476.     subformula = parseValue(formula, node);
  477.     //System.out.println("subformula = " + subformula);
  478.     if (subformula == null || subformula.length() == 0) {
  479.         //System.out.println("Parse succeeded");
  480.         return null;
  481.     }
  482.     if (subformula == formula) {
  483.         //System.out.println("Parse failed");
  484.         return formula;
  485.     }
  486.  
  487.     // parse an operator and then another value
  488.     switch (op = subformula.charAt(0)) {
  489.       case 0:
  490.         //System.out.println("Parse succeeded");
  491.         return null;
  492.       case ')':
  493.         //System.out.println("Returning subformula=" + subformula);
  494.         return subformula;
  495.       case '+':
  496.       case '*':
  497.       case '-':
  498.       case '/':
  499.         restFormula = subformula.substring(1);
  500.         subformula = parseValue(restFormula, right=new Node());
  501.         //System.out.println("subformula(2) = " + subformula);
  502.         if (subformula != restFormula) {
  503.         //System.out.println("Parse succeeded");
  504.         left = new Node(node);
  505.         node.left = left;
  506.         node.right = right;
  507.         node.op = op;
  508.         node.type = Node.OP;
  509.         //node.print(3);
  510.         return subformula;
  511.         } else {
  512.         //System.out.println("Parse failed");
  513.         return formula;
  514.         }
  515.       default:
  516.         //System.out.println("Parse failed (bad operator): " + subformula);
  517.         return formula;
  518.     }
  519.     }
  520.  
  521.     public String parseValue(String formula, Node node) {
  522.     char    c = formula.charAt(0);
  523.     String    subformula;
  524.     String    restFormula;
  525.     float    value;
  526.     int    row;
  527.     int    column;
  528.  
  529.     //System.out.println("parseValue: " + formula);
  530.     restFormula = formula;
  531.     if (c == '(') {
  532.         //System.out.println("parseValue(" + formula + ")");
  533.         restFormula = formula.substring(1);
  534.         subformula = parseFormula(restFormula, node);
  535.         //System.out.println("rest=(" + subformula + ")");
  536.         if (subformula == null ||
  537.         subformula.length() == restFormula.length()) {
  538.         //System.out.println("Failed");
  539.         return formula;
  540.         } else if (! (subformula.charAt(0) == ')')) {
  541.             //System.out.println("Failed (missing parentheses)");
  542.         return formula;
  543.         }
  544.         restFormula = subformula;
  545.     } else if (c >= '0' && c <= '9') {
  546.         int i;
  547.  
  548.         //System.out.println("formula=" + formula);
  549.         try {
  550.         value = Float.valueOf(formula).floatValue();
  551.         } catch (NumberFormatException e) {
  552.         //System.out.println("Failed (number format error)");
  553.         return formula;
  554.         }
  555.         for (i=0; i < formula.length(); i++) {
  556.         c = formula.charAt(i);
  557.         if ((c < '0' || c > '9') && c != '.') {
  558.             break;
  559.         }
  560.         }
  561.         node.type = Node.VALUE;
  562.         node.value = value;
  563.         //node.print(3);
  564.         restFormula = formula.substring(i);
  565.         //System.out.println("value= " + value + " i=" + i +
  566.         //               " rest = " + restFormula);
  567.         return restFormula;
  568.     } else if (c >= 'A' && c <= 'Z') {
  569.         int i;
  570.  
  571.         column = c - 'A';
  572.         restFormula = formula.substring(1);
  573.         row = Float.valueOf(restFormula).intValue();
  574.         //System.out.println("row = " + row + " column = " + column);
  575.         for (i=0; i < restFormula.length(); i++) {
  576.         c = restFormula.charAt(i);
  577.         if (c < '0' || c > '9') {
  578.             break;
  579.         }
  580.         }
  581.         node.row = row - 1;
  582.         node.column = column;
  583.         node.type = Node.CELL;
  584.         //node.print(3);
  585.         if (i == restFormula.length()) {
  586.         restFormula = null;
  587.         } else {
  588.         restFormula = restFormula.substring(i);
  589.         if (restFormula.charAt(0) == 0) {
  590.             return null;
  591.         }
  592.         }        
  593.     }
  594.  
  595.     return restFormula;
  596.     }
  597.  
  598.  
  599.     public void setValue(int type, String s) {
  600.     paused = false;
  601.     if (this.type == Cell.URL) {
  602.         updaterThread.stop();
  603.         updaterThread = null;
  604.     }
  605.  
  606.     valueString = new String(s);
  607.     this.type = type;
  608.     needRedisplay = true;
  609.     switch (type) {
  610.       case Cell.VALUE:
  611.         setValue(Float.valueOf(s).floatValue());
  612.         break;
  613.       case Cell.LABEL:
  614.         printString = "l" + valueString;
  615.         break;
  616.       case Cell.URL:
  617.         printString = "u" + valueString;
  618.         updaterThread = new CellUpdater(this);
  619.         updaterThread.start();
  620.         break;
  621.       case Cell.FORMULA:
  622.         parseFormula(valueString, parseRoot = new Node());
  623.         printString = "f" + valueString;
  624.         break;
  625.     }
  626.     app.recalculate();
  627.     }
  628.  
  629.     public String getValueString() {
  630.     return valueString;
  631.     }
  632.  
  633.     public String getPrintString() {
  634.     return printString;
  635.     }
  636.  
  637.     public void select() {
  638.     selected = true;
  639.     paused = true;
  640.     }
  641.     public void deselect() {
  642.     selected = false;
  643.     paused = false;
  644.     needRedisplay = true;
  645.     app.repaint();
  646.     }
  647.     public void paint(Graphics g, int x, int y) {
  648.     if (selected) {
  649.         g.setColor(highlightColor);
  650.     } else {
  651.         g.setColor(bgColor);
  652.     }
  653.     g.fillRect(x, y, width - 1, height);
  654.     if (valueString != null) {
  655.         switch (type) {
  656.           case Cell.VALUE:
  657.           case Cell.LABEL:
  658.         g.setColor(fgColor);
  659.         break;
  660.           case Cell.FORMULA:
  661.         g.setColor(Color.red);
  662.         break;
  663.           case Cell.URL:
  664.         g.setColor(Color.blue);
  665.         break;
  666.         }
  667.         if (transientValue){
  668.         g.drawString("" + value, x, y + (height / 2) + 5);
  669.         } else {
  670.         if (valueString.length() > 14) {
  671.             g.drawString(valueString.substring(0, 14),
  672.                  x, y + (height / 2) + 5);
  673.         } else {
  674.             g.drawString(valueString, x, y + (height / 2) + 5);
  675.         }
  676.         }
  677.     }
  678.     needRedisplay = false;
  679.     }
  680. }
  681.  
  682. class Node {
  683.     public static final int OP = 0;
  684.     public static final    int VALUE = 1;
  685.     public static final int CELL = 2;
  686.  
  687.     int        type;
  688.     Node     left;
  689.     Node     right;
  690.     int      row;
  691.     int      column;
  692.     float    value;
  693.     char    op;
  694.  
  695.     public Node() {
  696.     left = null;
  697.     right = null;
  698.     value = 0;
  699.     row = -1;
  700.     column = -1;
  701.     op = 0;
  702.     type = Node.VALUE;
  703.     }
  704.     public Node(Node n) {
  705.     left = n.left;
  706.     right = n.right;
  707.     value = n.value;
  708.     row = n.row;
  709.     column = n.column;
  710.     op = n.op;
  711.     type = n.type;
  712.     }
  713.     public void indent(int ind) {
  714.     for (int i = 0; i < ind; i++) {
  715.         System.out.print(" ");
  716.     }
  717.     }
  718.     public void print(int indentLevel) {
  719.     char l[] = new char[1];
  720.     indent(indentLevel);
  721.     System.out.println("NODE type=" + type);
  722.     indent(indentLevel);
  723.     switch (type) {
  724.       case Node.VALUE:
  725.         System.out.println(" value=" + value);
  726.         break;
  727.       case Node.CELL:
  728.         l[0] = (char)((int)'A' + column);
  729.         System.out.println(" cell=" + new String(l) + (row+1));
  730.         break;
  731.       case Node.OP:
  732.         System.out.println(" op=" + op);
  733.         left.print(indentLevel + 3);
  734.         right.print(indentLevel + 3);
  735.         break;
  736.     }
  737.     }
  738. }
  739.  
  740. class InputField {
  741.     int        maxchars = 50;
  742.     int        cursorPos = 0;
  743.     Applet    app;
  744.     String    sval;
  745.     char    buffer[];
  746.     int        nChars;
  747.     int        width;
  748.     int        height;
  749.     Color    bgColor;
  750.     Color    fgColor;
  751.  
  752.     public InputField(String initValue, Applet app, int width, int height,
  753.               Color bgColor, Color fgColor) {
  754.     this.width = width;
  755.     this.height = height;
  756.     this.bgColor = bgColor;
  757.     this.fgColor = fgColor;
  758.     this.app = app;
  759.     buffer = new char[maxchars];
  760.     nChars = 0;
  761.     if (initValue != null) {
  762.         initValue.getChars(0, initValue.length(), this.buffer, 0);
  763.         nChars = initValue.length();
  764.     }
  765.     sval = initValue;
  766.     }
  767.  
  768.     public void setText(String val) {
  769.     int i;
  770.  
  771.     for (i=0; i < maxchars; i++) {
  772.         buffer[i] = 0;
  773.     }
  774.     sval = new String(val);
  775.     if (val == null) {
  776.         sval = "";
  777.         nChars = 0;
  778.         buffer[0] = 0;
  779.     } else {
  780.         sval.getChars(0, sval.length(), buffer, 0);
  781.         nChars = val.length();
  782.         sval = new String(buffer);
  783.     }
  784.     }
  785.  
  786.     public String getValue() {
  787.     return sval;
  788.     }
  789.  
  790.     public void paint(Graphics g, int x, int y) {
  791.     g.setColor(bgColor);
  792.     g.fillRect(x, y, width, height);
  793.     if (sval != null) {
  794.         g.setColor(fgColor);
  795.         g.drawString(sval, x, y + (height / 2) + 3);
  796.     }
  797.     }
  798.     public void mouseUp(int x, int y) {
  799.     // set the edit position
  800.     }
  801.     public void keyDown(int key) {
  802.     if (nChars < maxchars) {
  803.         switch (key) {
  804.           case 8: // delete
  805.         --nChars;
  806.         if (nChars < 0) {
  807.             nChars = 0;
  808.         }
  809.         buffer[nChars] = 0;
  810.         sval = new String(new String(buffer));
  811.         break;
  812.           case 10: // return
  813.         selected();
  814.         break;
  815.           default:
  816.         buffer[nChars++] = (char)key;
  817.         sval = new String(new String(buffer));
  818.         break;
  819.         }
  820.     }
  821.     app.repaint();
  822.     }
  823.     public void selected() {
  824.     }
  825. }
  826.  
  827. class SpreadSheetInput extends InputField {
  828.     public SpreadSheetInput(String initValue,
  829.                 SpreadSheet app,
  830.                 int width,
  831.                 int height,
  832.                 Color bgColor,
  833.                 Color fgColor) {
  834.     super(initValue, app, width, height, bgColor, fgColor);
  835.     }
  836.  
  837.     public void selected() {
  838.     float f;
  839.  
  840.     switch (sval.charAt(0)) {
  841.       case 'v':
  842.         try {
  843.         f = Float.valueOf(sval.substring(1)).floatValue();
  844.         ((SpreadSheet)app).setCurrentValue(f);
  845.         } catch (NumberFormatException e) {
  846.         System.out.println("Not a float...");
  847.         }
  848.         break;
  849.       case 'l':
  850.         ((SpreadSheet)app).setCurrentValue(Cell.LABEL, sval.substring(1));
  851.         break;
  852.       case 'u':
  853.         ((SpreadSheet)app).setCurrentValue(Cell.URL, sval.substring(1));
  854.         break;
  855.       case 'f':
  856.         ((SpreadSheet)app).setCurrentValue(Cell.FORMULA, sval.substring(1));
  857.         break;
  858.     }
  859.     }
  860. }
  861.