home *** CD-ROM | disk | FTP | other *** search
/ DOS/V Power Report 1998 February / VPR9802A.ISO / APP_DEMO / VC / SAMPLES.BIN / SpreadSheet.java < prev    next >
Text File  |  1997-10-27  |  21KB  |  871 lines

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