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