Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/demo/applets/SpreadSheet/SpreadSheet.java
38829 views
/*1* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions5* are met:6*7* - Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9*10* - Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* - Neither the name of Oracle nor the names of its15* contributors may be used to endorse or promote products derived16* from this software without specific prior written permission.17*18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS19* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,20* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR21* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR22* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,23* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,24* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR25* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF26* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING27* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS28* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.29*/3031/*32* This source code is provided to illustrate the usage of a given feature33* or technique and has been deliberately simplified. Additional steps34* required for a production-quality application, such as security checks,35* input validation and proper error handling, might not be present in36* this sample code.37*/38394041import java.applet.Applet;42import java.awt.*;43import java.awt.event.*;44import java.io.*;45import java.net.*;464748@SuppressWarnings("serial")49public class SpreadSheet extends Applet implements MouseListener, KeyListener {5051String title;52Font titleFont;53Color cellColor;54Color inputColor;55int cellWidth = 100;56int cellHeight = 15;57int titleHeight = 15;58int rowLabelWidth = 15;59Font inputFont;60boolean isStopped = false;61boolean fullUpdate = true;62int rows;63int columns;64int currentKey = -1;65int selectedRow = -1;66int selectedColumn = -1;67SpreadSheetInput inputArea;68Cell cells[][];69Cell current = null;7071@Override72public synchronized void init() {73String rs;7475cellColor = Color.white;76inputColor = new Color(100, 100, 225);77inputFont = new Font("Monospaced", Font.PLAIN, 10);78titleFont = new Font("Monospaced", Font.BOLD, 12);79title = getParameter("title");80if (title == null) {81title = "Spreadsheet";82}83rs = getParameter("rows");84if (rs == null) {85rows = 9;86} else {87rows = Integer.parseInt(rs);88}89rs = getParameter("columns");90if (rs == null) {91columns = 5;92} else {93columns = Integer.parseInt(rs);94}95cells = new Cell[rows][columns];96char l[] = new char[1];97for (int i = 0; i < rows; i++) {98for (int j = 0; j < columns; j++) {99100cells[i][j] = new Cell(this,101Color.lightGray,102Color.black,103cellColor,104cellWidth - 2,105cellHeight - 2);106l[0] = (char) ((int) 'a' + j);107rs = getParameter("" + new String(l) + (i + 1));108if (rs != null) {109cells[i][j].setUnparsedValue(rs);110}111}112}113114Dimension d = getSize();115inputArea = new SpreadSheetInput(null, this, d.width - 2, cellHeight - 1,116inputColor, Color.white);117resize(columns * cellWidth + rowLabelWidth,118(rows + 3) * cellHeight + titleHeight);119addMouseListener(this);120addKeyListener(this);121}122123public void setCurrentValue(float val) {124if (selectedRow == -1 || selectedColumn == -1) {125return;126}127cells[selectedRow][selectedColumn].setValue(val);128repaint();129}130131@Override132public void stop() {133isStopped = true;134}135136@Override137public void start() {138isStopped = false;139}140141@Override142public void destroy() {143for (int i = 0; i < rows; i++) {144for (int j = 0; j < columns; j++) {145if (cells[i][j].type == Cell.URL) {146cells[i][j].updaterThread.run = false;147}148}149}150}151152public void setCurrentValue(int type, String val) {153if (selectedRow == -1 || selectedColumn == -1) {154return;155}156cells[selectedRow][selectedColumn].setValue(type, val);157repaint();158}159160@Override161public void update(Graphics g) {162if (!fullUpdate) {163int cx, cy;164165g.setFont(titleFont);166for (int i = 0; i < rows; i++) {167for (int j = 0; j < columns; j++) {168if (cells[i][j].needRedisplay) {169cx = (j * cellWidth) + 2 + rowLabelWidth;170cy = ((i + 1) * cellHeight) + 2 + titleHeight;171cells[i][j].paint(g, cx, cy);172}173}174}175} else {176paint(g);177fullUpdate = false;178}179}180181public void recalculate() {182int i, j;183184//System.out.println("SpreadSheet.recalculate");185for (i = 0; i < rows; i++) {186for (j = 0; j < columns; j++) {187if (cells[i][j] != null && cells[i][j].type == Cell.FORMULA) {188cells[i][j].setRawValue(evaluateFormula(189cells[i][j].parseRoot));190cells[i][j].needRedisplay = true;191}192}193}194repaint();195}196197float evaluateFormula(Node n) {198float val = 0.0f;199200//System.out.println("evaluateFormula:");201//n.print(3);202if (n == null) {203//System.out.println("Null node");204return val;205}206switch (n.type) {207case Node.OP:208val = evaluateFormula(n.left);209switch (n.op) {210case '+':211val += evaluateFormula(n.right);212break;213case '*':214val *= evaluateFormula(n.right);215break;216case '-':217val -= evaluateFormula(n.right);218break;219case '/':220val /= evaluateFormula(n.right);221break;222}223break;224case Node.VALUE:225//System.out.println("=>" + n.value);226return n.value;227case Node.CELL:228if (cells[n.row][n.column] == null) {229//System.out.println("NULL at 193");230} else {231//System.out.println("=>" + cells[n.row][n.column].value);232return cells[n.row][n.column].value;233}234}235236//System.out.println("=>" + val);237return val;238}239240@Override241public synchronized void paint(Graphics g) {242int i, j;243int cx, cy;244char l[] = new char[1];245246247Dimension d = getSize();248249g.setFont(titleFont);250i = g.getFontMetrics().stringWidth(title);251g.drawString((title == null) ? "Spreadsheet" : title,252(d.width - i) / 2, 12);253g.setColor(inputColor);254g.fillRect(0, cellHeight, d.width, cellHeight);255g.setFont(titleFont);256for (i = 0; i < rows + 1; i++) {257cy = (i + 2) * cellHeight;258g.setColor(getBackground());259g.draw3DRect(0, cy, d.width, 2, true);260if (i < rows) {261g.setColor(Color.red);262g.drawString("" + (i + 1), 2, cy + 12);263}264}265266g.setColor(Color.red);267cy = (rows + 3) * cellHeight + (cellHeight / 2);268for (i = 0; i < columns; i++) {269cx = i * cellWidth;270g.setColor(getBackground());271g.draw3DRect(cx + rowLabelWidth,2722 * cellHeight, 1, d.height, true);273if (i < columns) {274g.setColor(Color.red);275l[0] = (char) ((int) 'A' + i);276g.drawString(new String(l),277cx + rowLabelWidth + (cellWidth / 2),278cy);279}280}281282for (i = 0; i < rows; i++) {283for (j = 0; j < columns; j++) {284cx = (j * cellWidth) + 2 + rowLabelWidth;285cy = ((i + 1) * cellHeight) + 2 + titleHeight;286if (cells[i][j] != null) {287cells[i][j].paint(g, cx, cy);288}289}290}291292g.setColor(getBackground());293g.draw3DRect(0, titleHeight,294d.width,295d.height - titleHeight,296false);297inputArea.paint(g, 1, titleHeight + 1);298}299300//1.1 event handling301@Override302public void mouseClicked(MouseEvent e) {303}304305@Override306public void mousePressed(MouseEvent e) {307int x = e.getX();308int y = e.getY();309Cell cell;310if (y < (titleHeight + cellHeight)) {311selectedRow = -1;312if (y <= titleHeight && current != null) {313current.deselect();314current = null;315}316e.consume();317}318if (x < rowLabelWidth) {319selectedRow = -1;320if (current != null) {321current.deselect();322current = null;323}324e.consume();325326}327selectedRow = ((y - cellHeight - titleHeight) / cellHeight);328selectedColumn = (x - rowLabelWidth) / cellWidth;329if (selectedRow > rows330|| selectedColumn >= columns) {331selectedRow = -1;332if (current != null) {333current.deselect();334current = null;335}336} else {337if (selectedRow >= rows) {338selectedRow = -1;339if (current != null) {340current.deselect();341current = null;342}343e.consume();344}345if (selectedRow != -1) {346cell = cells[selectedRow][selectedColumn];347inputArea.setText(cell.getPrintString());348if (current != null) {349current.deselect();350}351current = cell;352current.select();353requestFocus();354fullUpdate = true;355repaint();356}357e.consume();358}359}360361@Override362public void mouseReleased(MouseEvent e) {363}364365@Override366public void mouseEntered(MouseEvent e) {367}368369@Override370public void mouseExited(MouseEvent e) {371}372373@Override374public void keyPressed(KeyEvent e) {375}376377@Override378public void keyTyped(KeyEvent e) {379fullUpdate = true;380inputArea.processKey(e);381e.consume();382}383384@Override385public void keyReleased(KeyEvent e) {386}387388@Override389public String getAppletInfo() {390return "Title: SpreadSheet \nAuthor: Sami Shaio \nA simple spread sheet.";391}392393@Override394public String[][] getParameterInfo() {395String[][] info = {396{ "title", "string",397"The title of the spread sheet. Default is 'Spreadsheet'" },398{ "rows", "int", "The number of rows. Default is 9." },399{ "columns", "int", "The number of columns. Default is 5." }400};401return info;402}403}404405406class CellUpdater extends Thread {407408Cell target;409InputStream dataStream = null;410StreamTokenizer tokenStream;411public volatile boolean run = true;412413public CellUpdater(Cell c) {414super("cell updater");415target = c;416}417418@Override419public void run() {420try {421dataStream = new URL(target.app.getDocumentBase(),422target.getValueString()).openStream();423tokenStream = new StreamTokenizer(new BufferedReader(424new InputStreamReader(dataStream)));425tokenStream.eolIsSignificant(false);426427while (run) {428switch (tokenStream.nextToken()) {429case StreamTokenizer.TT_EOF:430dataStream.close();431return;432default:433break;434case StreamTokenizer.TT_NUMBER:435target.setTransientValue((float) tokenStream.nval);436if (!target.app.isStopped && !target.paused) {437target.app.repaint();438}439break;440}441try {442Thread.sleep(2000);443} catch (InterruptedException e) {444break;445}446}447} catch (IOException e) {448return;449}450}451}452453454class Cell {455456public static final int VALUE = 0;457public static final int LABEL = 1;458public static final int URL = 2;459public static final int FORMULA = 3;460Node parseRoot;461boolean needRedisplay;462boolean selected = false;463boolean transientValue = false;464public int type = Cell.VALUE;465String valueString = "";466String printString = "v";467float value;468Color bgColor;469Color fgColor;470Color highlightColor;471int width;472int height;473SpreadSheet app;474CellUpdater updaterThread;475boolean paused = false;476477public Cell(SpreadSheet app,478Color bgColor,479Color fgColor,480Color highlightColor,481int width,482int height) {483this.app = app;484this.bgColor = bgColor;485this.fgColor = fgColor;486this.highlightColor = highlightColor;487this.width = width;488this.height = height;489needRedisplay = true;490}491492public void setRawValue(float f) {493valueString = Float.toString(f);494value = f;495}496497public void setValue(float f) {498setRawValue(f);499printString = "v" + valueString;500type = Cell.VALUE;501paused = false;502app.recalculate();503needRedisplay = true;504}505506public void setTransientValue(float f) {507transientValue = true;508value = f;509needRedisplay = true;510app.recalculate();511}512513public void setUnparsedValue(String s) {514switch (s.charAt(0)) {515case 'v':516setValue(Cell.VALUE, s.substring(1));517break;518case 'f':519setValue(Cell.FORMULA, s.substring(1));520break;521case 'l':522setValue(Cell.LABEL, s.substring(1));523break;524case 'u':525setValue(Cell.URL, s.substring(1));526break;527}528}529530/**531* Parse a spreadsheet formula. The syntax is defined as:532*533* formula -> value534* formula -> value op value535* value -> '(' formula ')'536* value -> cell537* value -> <number>538* op -> '+' | '*' | '/' | '-'539* cell -> <letter><number>540*/541public String parseFormula(String formula, Node node) {542String subformula;543String restFormula;544Node left;545Node right;546char op;547548if (formula == null) {549return null;550}551subformula = parseValue(formula, node);552//System.out.println("subformula = " + subformula);553if (subformula == null || subformula.length() == 0) {554//System.out.println("Parse succeeded");555return null;556}557if (subformula.equals(formula)) {558//System.out.println("Parse failed");559return formula;560}561562// parse an operator and then another value563switch (op = subformula.charAt(0)) {564case 0:565//System.out.println("Parse succeeded");566return null;567case ')':568//System.out.println("Returning subformula=" + subformula);569return subformula;570case '+':571case '*':572case '-':573case '/':574restFormula = subformula.substring(1);575subformula = parseValue(restFormula, right = new Node());576//System.out.println("subformula(2) = " + subformula);577if (subformula == null ? restFormula != null : !subformula.578equals(restFormula)) {579//System.out.println("Parse succeeded");580left = new Node(node);581node.left = left;582node.right = right;583node.op = op;584node.type = Node.OP;585//node.print(3);586return subformula;587} else {588//System.out.println("Parse failed");589return formula;590}591default:592//System.out.println("Parse failed (bad operator): " + subformula);593return formula;594}595}596597public String parseValue(String formula, Node node) {598char c = formula.charAt(0);599String subformula;600String restFormula;601float _value;602int row;603int column;604605//System.out.println("parseValue: " + formula);606restFormula = formula;607if (c == '(') {608//System.out.println("parseValue(" + formula + ")");609restFormula = formula.substring(1);610subformula = parseFormula(restFormula, node);611//System.out.println("rest=(" + subformula + ")");612if (subformula == null613|| subformula.length() == restFormula.length()) {614//System.out.println("Failed");615return formula;616} else if (!(subformula.charAt(0) == ')')) {617//System.out.println("Failed (missing parentheses)");618return formula;619}620restFormula = subformula;621} else if (c >= '0' && c <= '9') {622int i;623624//System.out.println("formula=" + formula);625for (i = 0; i < formula.length(); i++) {626c = formula.charAt(i);627if ((c < '0' || c > '9') && c != '.') {628break;629}630}631try {632_value = Float.valueOf(formula.substring(0, i)).floatValue();633} catch (NumberFormatException e) {634//System.out.println("Failed (number format error)");635return formula;636}637node.type = Node.VALUE;638node.value = _value;639//node.print(3);640restFormula = formula.substring(i);641//System.out.println("value= " + value + " i=" + i +642// " rest = " + restFormula);643return restFormula;644} else if (c >= 'A' && c <= 'Z') {645int i;646647column = c - 'A';648restFormula = formula.substring(1);649for (i = 0; i < restFormula.length(); i++) {650c = restFormula.charAt(i);651if (c < '0' || c > '9') {652break;653}654}655row = Float.valueOf(restFormula.substring(0, i)).intValue();656//System.out.println("row = " + row + " column = " + column);657node.row = row - 1;658node.column = column;659node.type = Node.CELL;660//node.print(3);661if (i == restFormula.length()) {662restFormula = null;663} else {664restFormula = restFormula.substring(i);665if (restFormula.charAt(0) == 0) {666return null;667}668}669}670671return restFormula;672}673674public void setValue(int type, String s) {675paused = false;676if (this.type == Cell.URL) {677updaterThread.run = false;678updaterThread = null;679}680681valueString = s;682this.type = type;683needRedisplay = true;684switch (type) {685case Cell.VALUE:686setValue(Float.valueOf(s).floatValue());687break;688case Cell.LABEL:689printString = "l" + valueString;690break;691case Cell.URL:692printString = "u" + valueString;693updaterThread = new CellUpdater(this);694updaterThread.start();695break;696case Cell.FORMULA:697parseFormula(valueString, parseRoot = new Node());698printString = "f" + valueString;699break;700}701app.recalculate();702}703704public String getValueString() {705return valueString;706}707708public String getPrintString() {709return printString;710}711712public void select() {713selected = true;714paused = true;715}716717public void deselect() {718selected = false;719paused = false;720needRedisplay = true;721app.repaint();722}723724public void paint(Graphics g, int x, int y) {725if (selected) {726g.setColor(highlightColor);727} else {728g.setColor(bgColor);729}730g.fillRect(x, y, width - 1, height);731if (valueString != null) {732switch (type) {733case Cell.VALUE:734case Cell.LABEL:735g.setColor(fgColor);736break;737case Cell.FORMULA:738g.setColor(Color.red);739break;740case Cell.URL:741g.setColor(Color.blue);742break;743}744if (transientValue) {745g.drawString("" + value, x, y + (height / 2) + 5);746} else {747if (valueString.length() > 14) {748g.drawString(valueString.substring(0, 14),749x, y + (height / 2) + 5);750} else {751g.drawString(valueString, x, y + (height / 2) + 5);752}753}754}755needRedisplay = false;756}757}758759760class Node {761762public static final int OP = 0;763public static final int VALUE = 1;764public static final int CELL = 2;765int type;766Node left;767Node right;768int row;769int column;770float value;771char op;772773public Node() {774left = null;775right = null;776value = 0;777row = -1;778column = -1;779op = 0;780type = Node.VALUE;781}782783public Node(Node n) {784left = n.left;785right = n.right;786value = n.value;787row = n.row;788column = n.column;789op = n.op;790type = n.type;791}792793public void indent(int ind) {794for (int i = 0; i < ind; i++) {795System.out.print(" ");796}797}798799public void print(int indentLevel) {800char l[] = new char[1];801indent(indentLevel);802System.out.println("NODE type=" + type);803indent(indentLevel);804switch (type) {805case Node.VALUE:806System.out.println(" value=" + value);807break;808case Node.CELL:809l[0] = (char) ((int) 'A' + column);810System.out.println(" cell=" + new String(l) + (row + 1));811break;812case Node.OP:813System.out.println(" op=" + op);814left.print(indentLevel + 3);815right.print(indentLevel + 3);816break;817}818}819}820821822class InputField {823824int maxchars = 50;825int cursorPos = 0;826Applet app;827String sval;828char buffer[];829int nChars;830int width;831int height;832Color bgColor;833Color fgColor;834835public InputField(String initValue, Applet app, int width, int height,836Color bgColor, Color fgColor) {837this.width = width;838this.height = height;839this.bgColor = bgColor;840this.fgColor = fgColor;841this.app = app;842buffer = new char[maxchars];843nChars = 0;844if (initValue != null) {845initValue.getChars(0, initValue.length(), this.buffer, 0);846nChars = initValue.length();847}848sval = initValue;849}850851public void setText(String val) {852int i;853854for (i = 0; i < maxchars; i++) {855buffer[i] = 0;856}857if (val == null) {858sval = "";859} else {860sval = val;861}862nChars = sval.length();863sval.getChars(0, sval.length(), buffer, 0);864}865866public String getValue() {867return sval;868}869870public void paint(Graphics g, int x, int y) {871g.setColor(bgColor);872g.fillRect(x, y, width, height);873if (sval != null) {874g.setColor(fgColor);875g.drawString(sval, x, y + (height / 2) + 3);876}877}878879public void processKey(KeyEvent e) {880char ch = e.getKeyChar();881switch (ch) {882case '\b': // delete883if (nChars > 0) {884nChars--;885sval = new String(buffer, 0, nChars);886}887break;888case '\n': // return889selected();890break;891default:892if (nChars < maxchars && ch >= '0') {893buffer[nChars++] = ch;894sval = new String(buffer, 0, nChars);895}896}897app.repaint();898}899900public void keyReleased(KeyEvent e) {901}902903public void selected() {904}905}906907908class SpreadSheetInput909extends InputField {910911public SpreadSheetInput(String initValue,912SpreadSheet app,913int width,914int height,915Color bgColor,916Color fgColor) {917super(initValue, app, width, height, bgColor, fgColor);918}919920@Override921public void selected() {922float f;923sval = ("".equals(sval)) ? "v" : sval;924switch (sval.charAt(0)) {925case 'v':926String s = sval.substring(1);927try {928int i;929for (i = 0; i < s.length(); i++) {930char c = s.charAt(i);931if (c < '0' || c > '9') {932break;933}934}935s = s.substring(0, i);936f = Float.valueOf(s).floatValue();937((SpreadSheet) app).setCurrentValue(f);938} catch (NumberFormatException e) {939System.out.println("Not a float: '" + s + "'");940}941break;942case 'l':943((SpreadSheet) app).setCurrentValue(Cell.LABEL,944sval.substring(1));945break;946case 'u':947((SpreadSheet) app).setCurrentValue(Cell.URL, sval.substring(1));948break;949case 'f':950((SpreadSheet) app).setCurrentValue(Cell.FORMULA,951sval.substring(1));952break;953}954}955}956957958