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