| 1 33 package net.sf.jga.swing.spreadsheet; 34 35 import java.awt.Component ; 36 import java.awt.Point ; 37 import java.util.HashSet ; 38 import java.util.Iterator ; 39 import java.util.Observable ; 40 import java.util.Observer ; 41 import java.util.Set ; 42 import java.util.logging.Level ; 43 import java.util.logging.Logger ; 44 import javax.swing.DefaultCellEditor ; 45 import javax.swing.JTable ; 46 import javax.swing.JTextField ; 47 import javax.swing.table.TableCellEditor ; 48 import javax.swing.table.TableCellRenderer ; 49 import net.sf.jga.fn.AdaptorVisitor; 50 import net.sf.jga.fn.BinaryFunctor; 51 import net.sf.jga.fn.EvaluationException; 52 import net.sf.jga.fn.Generator; 53 import net.sf.jga.fn.UnaryFunctor; 54 import net.sf.jga.fn.Visitable; 55 import net.sf.jga.fn.adaptor.ApplyBinary; 56 import net.sf.jga.fn.adaptor.ApplyGenerator; 57 import net.sf.jga.fn.adaptor.ApplyUnary; 58 import net.sf.jga.fn.adaptor.Bind1st; 59 import net.sf.jga.fn.adaptor.Bind2nd; 60 import net.sf.jga.fn.adaptor.Bind; 61 import net.sf.jga.fn.adaptor.ChainBinary; 62 import net.sf.jga.fn.adaptor.ChainUnary; 63 import net.sf.jga.fn.adaptor.ComposeBinary; 64 import net.sf.jga.fn.adaptor.ComposeUnary; 65 import net.sf.jga.fn.adaptor.ConditionalBinary; 66 import net.sf.jga.fn.adaptor.ConditionalGenerator; 67 import net.sf.jga.fn.adaptor.ConditionalUnary; 68 import net.sf.jga.fn.adaptor.Constant; 69 import net.sf.jga.fn.adaptor.Distribute; 70 import net.sf.jga.fn.adaptor.Generate1st; 71 import net.sf.jga.fn.adaptor.Generate2nd; 72 import net.sf.jga.fn.adaptor.Generate; 73 import net.sf.jga.fn.adaptor.GenerateBinary; 74 import net.sf.jga.fn.adaptor.GenerateUnary; 75 import net.sf.jga.parser.FunctorParser; 76 import net.sf.jga.parser.ParseException; 77 import net.sf.jga.swing.GenericTableCellRenderer; 78 import net.sf.jga.util.Formattable; 79 80 88 89 96 101 public class Cell extends Observable implements Observer { 102 103 private Spreadsheet _parent; 104 105 110 private String _name; 112 113 private Object _value; 115 116 private Generator _generator; 119 120 private String _formula; 123 124 private Point _addr; 127 128 private boolean _editable; 130 131 private TableCellRenderer _renderer; 133 134 private TableCellEditor _editor; 136 137 private Throwable _exception; 139 140 private String _errMsg; 142 143 static public final String CLASS_CAST_ERR = "### CLASS ###"; 145 146 static public final String EVALUATION_ERR = "### EVAL ###"; 148 149 static public final String CIRCULAR_REF_ERR = "### CIRC ###"; 151 152 static public final String NULL_POINTER_ERR = "### NULL ###"; 154 155 static public final String REFERENCE_ERR = "### REF ###"; 157 158 static public final String UNDEFINED_ERR = "### UNDEF ###"; 160 161 static public final String PARSER_ERR = "### PARSE ###"; 165 166 private Set <Cell> _dependencies = new HashSet <Cell>(); 168 169 173 177 Cell(Spreadsheet parent, Point addr, String formula, boolean editable) { 178 if (formula == null || formula.trim().length() <= 0) 179 throw new IllegalArgumentException ("Formula must be supplied"); 180 181 184 _parent = parent; 185 _addr = addr; 186 _editable = editable; 187 setFormula(formula); 188 189 192 _renderer = new Renderer (); } 194 195 199 <T> Cell(Spreadsheet parent, Class <T> type, Point addr, Generator<T> value) { 200 _parent = parent; 201 _addr = addr; 203 _editable = false; 204 _renderer = new Renderer (); 206 setFormulaImpl(value); 207 } 208 209 Cell(Spreadsheet parent, int row, int col) { 210 _parent = parent; 211 _addr = new Point (row, col); 212 _editable = true; 213 _errMsg = UNDEFINED_ERR; 214 _value = parent.getDefaultCellValue(); 216 } 217 218 Spreadsheet getParent() { return _parent; } 219 220 private Spreadsheet.Parser getParser() { return _parent._parser; } 221 222 public String getName() { return _name; } 223 224 225 void setName(String name) { _name = name; } 226 227 230 public Class getType() { return _value == null ? Object .class : _value.getClass(); } 232 233 236 String getFormula() { return _formula; } 237 238 241 public boolean isEditable() { return _editable; } 242 243 244 247 public void setEditable(boolean b) { _editable = b; } 248 249 252 public Point getAddress() { return _addr; } 253 254 257 public TableCellRenderer getRenderer() { return _renderer; } 258 259 262 public void setRenderer(TableCellRenderer renderer) { 263 _renderer = renderer; 264 } 265 266 269 public TableCellEditor getEditor() { 270 if (_editor == null) 271 _editor = new Editor (); 272 273 return _editor; 274 } 275 276 279 public void setEditor(TableCellEditor editor) { 280 _editor = editor; 281 } 282 283 286 public boolean isValid () { 287 return _errMsg == null; 288 } 289 290 294 297 public boolean isUndefined () { 298 return _errMsg == UNDEFINED_ERR; 299 } 300 301 306 public String getErrorMsg() { return _errMsg; } 307 308 312 private void setError(Throwable t, String formula, String msg) { 313 Logger.global.log(Level.FINE, formula, t); 314 _exception = t; 315 _parent.setStatus(t.getMessage()); 316 317 _formula = formula; 319 _errMsg = msg; 320 321 _value = t; 322 notifyObservers(); 323 } 324 325 328 private void clearError() { 329 _exception = null; 330 _errMsg = null; 331 } 332 333 338 public Object getValue() { 339 return _value; 340 } 341 342 343 347 private void setValue() { 348 try { 349 _value = _generator.gen(); 350 clearError(); 351 } 352 catch (CircularReferenceException x) { setError(x, _formula, CIRCULAR_REF_ERR); } 353 catch (InvalidReferenceException x) { recover (x, _formula, REFERENCE_ERR); } 354 catch (NullPointerException x) { setError(x, _formula, NULL_POINTER_ERR); } 355 catch (ClassCastException x) { recover (x, _formula, CLASS_CAST_ERR); } 356 catch (EvaluationException x) { recover (x, _formula, EVALUATION_ERR); } 357 catch (IllegalArgumentException x) { recover (x, _formula, EVALUATION_ERR); } 358 catch (Exception x) { setError(x, _formula, EVALUATION_ERR); } 359 } 360 361 362 365 366 public void clear() { 367 doClear(null, _parent.getDefaultCellValue()); 368 } 369 370 374 375 void unlink() { 376 doClear(REFERENCE_ERR, new InvalidReferenceException("Cell("+_addr.x+","+_addr.y+")")); 377 } 378 379 private void doClear(String msg, Object value) { 380 unregister(); 381 382 _editable = true; 383 _value = value; 385 _generator = null; 386 _formula = null; 387 _errMsg = msg; 388 389 notifyObservers(); 390 } 391 392 393 396 public final void setValue(Object value) { 397 if (value instanceof Generator) 398 setFormula((Generator) value); 399 400 else if (value != _exception) 404 setFormula(new Constant(value)); 405 } 406 407 410 public final void setFormula(String formula) throws CircularReferenceException { 411 if (formula == null || "".equals(formula)) { 412 clear(); 413 return; 414 } 415 416 if (formula.startsWith("=")) 417 formula = formula.substring(1); 418 419 try { 420 Generator gen = getParser().parseGenerator(this, formula); 421 setFormula(gen); 423 _formula = formula; 424 } 425 catch (ParseException x) { setError(x, formula, PARSER_ERR); } 426 catch (ClassCastException x) { recover(x, formula, CLASS_CAST_ERR); } 427 catch (NullPointerException x) { setError(x, formula, NULL_POINTER_ERR); } 428 } 429 430 433 437 public final void setFormula(Generator formula) { 438 clearError(); 439 unregister(); 440 setFormulaImpl(formula); 441 notifyObservers(); 442 } 443 444 445 450 private void setFormulaImpl(Generator formula) { 451 try { 452 _generator = register(formula); 453 setValue(); 454 } 455 catch (CircularReferenceException x) { setError(x, formula.toString(), CIRCULAR_REF_ERR); } 456 } 457 458 459 464 synchronized private void recover(Exception x, String formula, String msg) { 465 if (_inRecovery) { 466 setError(x, formula, msg); 467 } 468 else { 469 _inRecovery = true; 470 setFormula(_formula); 471 if (!isValid() && _errMsg.equals(PARSER_ERR)) { 472 setError(x, formula, msg); 473 } 474 475 _inRecovery = false; 476 } 477 } 478 479 private boolean _inRecovery = false; 481 482 483 488 public <T> void setFormat(UnaryFunctor<T,String > formatter) { 489 if (_renderer instanceof Formattable) 490 ((Formattable) _renderer).setFormat(formatter); 491 } 492 493 494 497 public Generator getReference() { 498 return new CellReference(this); 499 } 500 501 505 public boolean references(Cell c) { 506 if (getAddress().equals(c.getAddress())) { 507 return true; 508 } 509 510 for (Cell c1 : _dependencies) { 511 if (c1 == c) { 512 return true; 513 } 514 if (c1.references(c)) { 515 return true; 516 } 517 } 518 519 return false; 520 } 521 522 523 526 public final Iterator <Cell> dependsOn() { 527 return _dependencies.iterator(); 528 } 529 530 531 public String toString() { 532 StringBuffer buf = new StringBuffer (256); 533 buf.append("Cell(").append(_addr.x).append(",").append(_addr.y).append(") "); 534 if (_name != null) { 535 buf.append('"').append(_name).append('"').append(' '); 536 } 537 buf.append("["); 538 if (_exception != null) 539 buf.append(_exception.getMessage()); 540 else if (_formula != null) 541 buf.append(_formula); 542 else 543 buf.append(_value); 544 545 return buf.append("]").toString(); 546 } 547 548 549 553 public void update(Observable observable, Object object) { 554 setValue(); 555 notifyObservers(); 556 } 557 558 562 public void notifyObservers() { 563 setChanged(); 564 notifyObservers(_value); 565 clearChanged(); 566 } 567 568 572 private <T> Generator<T> register(Generator<T> formula) throws CircularReferenceException { 575 formula.accept(new RegistrationVisitor()); 576 return formula; 577 } 578 579 580 private void unregister() { 583 if (_generator != null) 584 _generator.accept(new UnregistrationVisitor()); 585 586 _dependencies.clear(); 587 } 588 589 private class RegistrationVisitor extends AdaptorVisitor 590 implements CellReference.Visitor 591 { 592 public void visit(CellReference host) { 593 Cell hostCell = host.getCell(); 594 595 if (hostCell.references(Cell.this)) 597 throw new CircularReferenceException(); 598 599 host.register(Cell.this); 600 _dependencies.add(hostCell); 601 } 602 } 603 604 private class UnregistrationVisitor extends AdaptorVisitor 605 implements CellReference.Visitor 606 { 607 public void visit(CellReference host) { 608 host.unregister(Cell.this); 609 } 610 } 611 612 616 static class Editor extends DefaultCellEditor { 617 618 static final long serialVersionUID = -9010644547311806213L; 619 620 private Spreadsheet _sheet; 621 private Cell _cell; 622 623 public Editor() { 624 super(new JTextField ()); 625 } 626 627 public Object getCellEditorValue() { 628 String formula = (String ) super.getCellEditorValue(); 632 if (formula.startsWith("=")) 633 formula = formula.substring(1); 634 635 try { 636 return _sheet._parser.parseGenerator(_cell, formula); 637 } 638 catch(ParseException x) { 639 _cell.setError(x, formula, PARSER_ERR); 640 return x; 641 } 642 } 643 644 public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, 645 int row, int col) 646 { 647 _sheet = (Spreadsheet) table; 648 _cell = _sheet.getCellAt(row, col); 649 return super.getTableCellEditorComponent(table,_cell._formula,isSelected,row,col); 650 } 651 } 652 653 654 658 static class Renderer extends GenericTableCellRenderer { 659 660 public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected, 661 boolean hasFocus, int row, int column) 662 { 663 Spreadsheet sheet = (Spreadsheet) table; 664 Cell cell = sheet.getCellIfPresent(row,column); 665 boolean editable = (cell != null) ? cell.isEditable() : sheet.isEditableByDefault(); 666 return super.getTableCellRendererComponent(table, value, isSelected && editable, 667 hasFocus && editable, row, column); 668 } 669 } 670 } 671 672 676 class CellReference extends Generator { 677 678 static final long serialVersionUID = -2552950462394369940L; 679 680 private Cell _cell; 681 682 public CellReference(Cell cell) { _cell = cell; } 683 684 public Object gen() { 685 Object obj = _cell.getValue(); 686 if (obj instanceof RuntimeException ) 687 throw (RuntimeException ) obj; 688 689 return obj; 690 } 691 692 public Cell getCell() { return _cell; } 693 694 public void register(Observer obs) { 695 _cell.addObserver(obs); 696 } 697 698 public void unregister(Observer obs) { 699 _cell.deleteObserver(obs); 700 } 701 702 public String toString() { return "CellReference("+_cell+")"; } 703 704 public void accept(net.sf.jga.fn.Visitor v) { 705 if (v instanceof CellReference.Visitor) 706 ((CellReference.Visitor)v).visit(this); 707 else 708 v.visit(this); 709 } 710 711 public interface Visitor extends net.sf.jga.fn.Visitor { 712 public void visit(CellReference host); 713 } 714 } 715 716 class CircularReferenceException extends RuntimeException { 717 static final long serialVersionUID = -8670923266092229864L; 718 public String getMessage() { return "Circular Reference"; } 719 } 720 721 class InvalidReferenceException extends RuntimeException { 722 public InvalidReferenceException(String msg) { super(msg); } 723 } 724 725 | Popular Tags |