home *** CD-ROM | disk | FTP | other *** search
/ BUG 15 / BUGCD1998_06.ISO / aplic / jbuilder / jsamples.z / SpreadSheet.java < prev    next >
Text File  |  1997-07-30  |  22KB  |  872 lines

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