home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / JBuilder8.iso / Solaris / resource / jre / demo / plugin / applets / SpreadSheet / SpreadSheet.java < prev    next >
Encoding:
Java Source  |  2002-09-06  |  21.5 KB  |  928 lines

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