1 19 20 package org.netbeans.modules.viewmodel; 21 22 import java.awt.event.ActionEvent ; 23 import java.awt.event.KeyEvent ; 24 import java.beans.PropertyEditor ; 25 import java.lang.IllegalAccessException ; 26 import java.lang.ref.WeakReference ; 27 import java.util.ArrayList ; 28 import java.util.Arrays ; 29 import java.util.Collections ; 30 import java.util.HashMap ; 31 import java.util.Iterator ; 32 import java.util.LinkedList ; 33 import java.util.List ; 34 import java.util.Map ; 35 import java.util.WeakHashMap ; 36 import javax.swing.AbstractAction ; 37 import javax.swing.Action ; 38 import javax.swing.KeyStroke ; 39 import javax.swing.SwingUtilities ; 40 41 import org.netbeans.spi.viewmodel.ColumnModel; 42 import org.netbeans.spi.viewmodel.ModelEvent; 43 import org.netbeans.spi.viewmodel.Models; 44 import org.netbeans.spi.viewmodel.TreeModel; 45 import org.netbeans.spi.viewmodel.UnknownTypeException; 46 import org.openide.ErrorManager; 47 48 import org.openide.nodes.AbstractNode; 49 import org.openide.nodes.Children; 50 import org.openide.nodes.Node; 51 import org.openide.nodes.PropertySupport; 52 import org.openide.nodes.Sheet; 53 import org.openide.util.NbBundle; 54 import org.openide.util.RequestProcessor; 55 import org.openide.util.RequestProcessor.Task; 56 import org.openide.util.lookup.Lookups; 57 58 59 63 public class TreeModelNode extends AbstractNode { 64 65 69 private static final int MAX_HTML_LENGTH = 511; 70 71 73 private Models.CompoundModel model; 74 private TreeModelRoot treeModelRoot; 75 private Object object; 76 77 private String htmlDisplayName; 78 private Map properties = new HashMap (); 79 80 81 83 86 public TreeModelNode ( 87 final Models.CompoundModel model, 88 final TreeModelRoot treeModelRoot, 89 final Object object 90 ) { 91 super ( 92 createChildren (model, treeModelRoot, object), 93 Lookups.singleton (object) 94 ); 95 this.model = model; 96 this.treeModelRoot = treeModelRoot; 97 this.object = object; 98 99 if (model.getHelpId() != null) { 104 this.setValue("propertiesHelpID", model.getHelpId()); } 106 108 treeModelRoot.registerNode (object, this); 109 refreshNode (); 110 initProperties (); 111 } 112 113 114 116 private void initProperties () { 117 Sheet sheet = Sheet.createDefault(); 118 Sheet.Set ps = Sheet.createPropertiesSet (); 119 ColumnModel[] columns = model.getColumns (); 120 int i, k = columns.length; 121 for (i = 0; i < k; i++) 122 ps.put (new MyProperty (columns [i], treeModelRoot)); 123 sheet.put (ps); 124 setSheet (sheet); 125 } 126 127 private static Children createChildren ( 128 Models.CompoundModel model, 129 TreeModelRoot treeModelRoot, 130 Object object 131 ) { 132 if (object == null) 133 throw new NullPointerException (); 134 try { 135 return model.isLeaf (object) ? 136 Children.LEAF : 137 new TreeModelChildren (model, treeModelRoot, object); 138 } catch (UnknownTypeException e) { 139 if (!(object instanceof String )) { 140 Throwable t = ErrorManager.getDefault().annotate(e, "Model: "+model); 141 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t); 142 } 143 return Children.LEAF; 144 } 145 } 146 147 public String getShortDescription () { 148 try { 149 String shortDescription = model.getShortDescription (object); 150 return shortDescription; 151 } catch (UnknownTypeException e) { 152 if (!(object instanceof String )) { 153 Throwable t = ErrorManager.getDefault().annotate(e, "Model: "+model); 154 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t); 155 } 156 return null; 157 } 158 } 159 160 public String getHtmlDisplayName () { 161 return htmlDisplayName; 162 } 163 164 public Action [] getActions (boolean context) { 165 if (context) 166 return treeModelRoot.getRootNode ().getActions (false); 167 try { 168 return model.getActions (object); 169 } catch (UnknownTypeException e) { 170 return new Action [0]; 172 } 173 } 174 175 public Action getPreferredAction () { 176 return new AbstractAction () { 177 public void actionPerformed (ActionEvent e) { 178 try { 179 model.performDefaultAction (object); 180 } catch (UnknownTypeException ex) { 181 } 183 } 184 }; 185 } 186 187 public boolean canDestroy () { 188 try { 189 Action [] as = model.getActions (object); 190 int i, k = as.length; 191 for (i = 0; i < k; i++) { 192 if (as [i] == null) continue; 193 Object key = as [i].getValue (Action.ACCELERATOR_KEY); 194 if ( (key != null) && 195 (key.equals (KeyStroke.getKeyStroke ("DELETE"))) 196 ) return as [i].isEnabled (); 197 } 198 return false; 199 } catch (UnknownTypeException e) { 200 return false; 202 } 203 } 204 205 public boolean canCopy () { 206 return false; 207 } 208 209 public boolean canCut () { 210 return false; 211 } 212 213 public void destroy () { 214 try { 215 Action [] as = model.getActions (object); 216 int i, k = as.length; 217 for (i = 0; i < k; i++) { 218 if (as [i] == null) continue; 219 Object key = as [i].getValue (Action.ACCELERATOR_KEY); 220 if ( (key != null) && 221 (key.equals (KeyStroke.getKeyStroke ("DELETE"))) 222 ) { 223 as [i].actionPerformed (null); 224 return; 225 } 226 } 227 } catch (UnknownTypeException e) { 228 Throwable t = ErrorManager.getDefault().annotate(e, "Model: "+model); 229 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t); 230 } 231 } 232 233 234 236 void setObject (Object o) { 237 setObjectNoRefresh (o); 238 refresh (); 239 } 240 241 private void setObjectNoRefresh (Object o) { 242 object = o; 243 Children ch = getChildren (); 244 if (ch instanceof TreeModelChildren) 245 ((TreeModelChildren) ch).object = o; 246 } 247 248 public Object getObject () { 249 return object; 250 } 251 252 private Task task; 253 254 void refresh () { 255 synchronized (properties) { 257 properties.clear(); 258 } 259 260 261 if (task == null) { 263 task = getRequestProcessor ().create (new Runnable () { 264 public void run () { 265 refreshNode (); 266 fireShortDescriptionChange(null, null); 267 268 refreshTheChildren(true); 270 } 271 }); 272 } 273 task.schedule(0); 274 } 275 276 void refresh (int changeMask) { 277 if (changeMask == 0xFFFFFFFF) { 278 refresh(); 279 return ; 280 } 281 if ((ModelEvent.NodeChanged.DISPLAY_NAME_MASK & changeMask) != 0) { 282 try { 283 String name = model.getDisplayName (object); 284 if (name == null) { 285 Throwable t = 286 new NullPointerException ( 287 "Model: " + model + ".getDisplayName (" + object + 288 ") = null!" 289 ); 290 ErrorManager.getDefault().notify(t); 291 } 292 setName (name, false); 293 } catch (UnknownTypeException e) { 294 Throwable t = ErrorManager.getDefault().annotate(e, "Model: "+model); 295 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t); 296 } 297 } else if ((ModelEvent.NodeChanged.ICON_MASK & changeMask) != 0) { 298 try { 299 String iconBase = model.getIconBase (object); 300 if (iconBase != null) 301 setIconBase (iconBase); 302 else 303 setIconBaseWithExtension ("org/openide/resources/actions/empty.gif"); 304 } catch (UnknownTypeException e) { 305 Throwable t = ErrorManager.getDefault().annotate(e, "Model: "+model); 306 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t); 307 } 308 } else if ((ModelEvent.NodeChanged.SHORT_DESCRIPTION_MASK & changeMask) != 0) { 309 fireShortDescriptionChange(null, null); 310 } else if ((ModelEvent.NodeChanged.CHILDREN_MASK & changeMask) != 0) { 311 getRequestProcessor ().post (new Runnable () { 312 public void run () { 313 refreshTheChildren(false); 314 } 315 }); 316 } else { 317 refresh(); 318 } 319 } 320 321 private static RequestProcessor requestProcessor; 322 public static RequestProcessor getRequestProcessor () { 323 if (requestProcessor == null) 324 requestProcessor = new RequestProcessor ("TreeModel"); 325 return requestProcessor; 326 } 327 328 private void setName (String name, boolean italics) { 329 String oldHtmlDisplayName = htmlDisplayName; 331 String oldDisplayName = getDisplayName(); 332 333 String newDisplayName; 334 if (name.startsWith ("<html>")) { 335 htmlDisplayName = name; 336 newDisplayName = removeHTML(name); 337 } else { 338 htmlDisplayName = null; 339 newDisplayName = name; 340 } 341 if ((oldDisplayName == null) || !oldDisplayName.equals(newDisplayName)) { 342 setDisplayName(newDisplayName); 343 } else { 344 if (oldHtmlDisplayName != null && !oldHtmlDisplayName.equals(htmlDisplayName) || 345 htmlDisplayName != null && !htmlDisplayName.equals(oldHtmlDisplayName)) { 346 347 fireDisplayNameChange(oldDisplayName + "_HACK", getDisplayName()); 350 } 351 } 352 } 353 354 private void refreshNode () { 355 try { 356 String name = model.getDisplayName (object); 357 if (name == null) { 358 Throwable t = 359 new NullPointerException ( 360 "Model: " + model + ".getDisplayName (" + object + 361 ") = null!" 362 ); 363 ErrorManager.getDefault().notify(t); 364 } 365 setName (name, false); 366 String iconBase = model.getIconBase (object); 367 if (iconBase != null) 368 setIconBase (iconBase); 369 else 370 setIconBaseWithExtension ("org/openide/resources/actions/empty.gif"); 371 firePropertyChange(null, null, null); 372 } catch (UnknownTypeException e) { 373 Throwable t = ErrorManager.getDefault().annotate(e, "Model: "+model); 374 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t); 375 } 376 } 377 378 void refreshColumn(String column) { 379 synchronized (properties) { 380 properties.remove(column); 381 properties.remove(column + "#html"); 382 } 383 firePropertyChange(column, null, null); 384 } 385 386 private void refreshTheChildren(boolean refreshSubNodes) { 387 Children ch = getChildren(); 388 try { 389 if (ch instanceof TreeModelChildren) { 390 ((TreeModelChildren) ch).refreshChildren(refreshSubNodes); 391 } else if (!model.isLeaf (object)) { 392 setChildren(new TreeModelChildren (model, treeModelRoot, object)); 393 } 394 } catch (UnknownTypeException utex) { 395 if (!(object instanceof String )) { 397 Throwable t = ErrorManager.getDefault().annotate(utex, "Model: "+model); 398 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t); 399 } 400 setChildren(Children.LEAF); 401 } 402 } 403 404 private static String i (String text) { 405 if (text.startsWith ("<html>")) { 406 if (text.indexOf ("<i>") > 0) return text; 407 text = text.substring (6, text.length () - 7); 408 } 409 return "<html><font color=666666>" + text + "</font></html>"; 410 } 411 412 private static String htmlValue (String name) { 413 if (!name.startsWith ("<html>")) return null; 414 if (name.length() > MAX_HTML_LENGTH) { 415 int endTagsPos = findEndTagsPos(name); 416 String ending = name.substring(endTagsPos + 1); 417 name = name.substring(0, MAX_HTML_LENGTH - 3 - ending.length()); 418 int n = name.length(); 420 for (int i = n - 1; i > n - 6; i--) { 421 if (name.charAt(i) == ';') { 422 break; } 424 if (name.charAt(i) == '&') { 425 name = name.substring(0, i); 426 break; 427 } 428 } 429 name += "..." + ending; 430 } 431 return name; 432 } 433 434 private static int findEndTagsPos(String s) { 435 int openings = 0; 436 int i; 437 for (i = s.length() - 1; i >= 0; i--) { 438 if (s.charAt(i) == '>') openings++; 439 else if (s.charAt(i) == '<') openings--; 440 else if (openings == 0) break; 441 } 442 return i; 443 } 444 445 private static String removeHTML (String text) { 446 text = text.replaceAll ("<i>", ""); 447 text = text.replaceAll ("</i>", ""); 448 text = text.replaceAll ("<b>", ""); 449 text = text.replaceAll ("</b>", ""); 450 text = text.replaceAll ("<html>", ""); 451 text = text.replaceAll ("</html>", ""); 452 text = text.replaceAll ("</font>", ""); 453 int i = text.indexOf ("<font"); 454 while (i >= 0) { 455 int j = text.indexOf (">", i); 456 text = text.substring (0, i) + text.substring (j + 1); 457 i = text.indexOf ("<font"); 458 } 459 text = text.replaceAll ("<", "<"); 460 text = text.replaceAll (">", ">"); 461 text = text.replaceAll ("&", "&"); 462 return text; 463 } 464 465 466 468 469 private static final class TreeModelChildren extends Children.Keys 470 implements LazyEvaluator.Evaluable { 471 472 private boolean initialezed = false; 473 private Models.CompoundModel model; 474 private TreeModelRoot treeModelRoot; 475 private Object object; 476 private WeakHashMap objectToNode = new WeakHashMap (); 477 private int[] evaluated = { 0 }; private Object [] children_evaluated; 479 private boolean refreshingSubNodes = true; 480 private boolean refreshingStarted = true; 481 482 private static final Object WAIT_KEY = new Object (); 483 484 485 TreeModelChildren ( 486 Models.CompoundModel model, 487 TreeModelRoot treeModelRoot, 488 Object object 489 ) { 490 this.model = model; 491 this.treeModelRoot = treeModelRoot; 492 this.object = object; 493 } 494 495 protected void addNotify () { 496 initialezed = true; 497 refreshChildren (true); 498 } 499 500 protected void removeNotify () { 501 initialezed = false; 502 setKeys (Collections.EMPTY_SET); 503 } 504 505 void refreshChildren (boolean refreshSubNodes) { 506 if (!initialezed) return; 507 508 refreshLazyChildren(refreshSubNodes); 509 } 510 511 public void evaluateLazily(Runnable evaluatedNotify) { 512 synchronized (evaluated) { 513 refreshingStarted = false; 514 } 515 Object [] ch; 516 try { 517 int count = model.getChildrenCount (object); 518 ch = model.getChildren ( 519 object, 520 0, 521 count 522 ); 523 } catch (UnknownTypeException e) { 524 ch = new Object [0]; 525 if (!(object instanceof String )) { 526 Throwable t = ErrorManager.getDefault().annotate(e, "Model: "+model); 527 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t); 528 } 529 } catch (ThreadDeath td) { 530 throw td; 531 } catch (Throwable t) { 532 ErrorManager.getDefault().notify(t); 535 ch = new Object [0]; 536 } 537 evaluatedNotify.run(); 538 boolean fire; 539 synchronized (evaluated) { 540 int eval = evaluated[0]; 541 if (refreshingStarted) { 542 fire = false; 543 } else { 544 fire = evaluated[0] == -1; 545 if (!fire) { 546 children_evaluated = ch; 547 } 548 evaluated[0] = 1; 549 evaluated.notifyAll(); 550 } 551 } 553 if (fire) { 554 applyChildren(ch, refreshingSubNodes); 555 } 556 } 557 558 private void refreshLazyChildren (boolean refreshSubNodes) { 559 synchronized (evaluated) { 560 evaluated[0] = 0; 561 refreshingStarted = true; 562 this.refreshingSubNodes = refreshSubNodes; 563 } 565 treeModelRoot.getChildrenEvaluator().evaluate(this, false); 567 Object [] ch; 568 synchronized (evaluated) { 569 if (evaluated[0] != 1) { 570 try { 571 evaluated.wait(200); 572 } catch (InterruptedException iex) {} 573 if (evaluated[0] != 1) { 574 evaluated[0] = -1; ch = null; 576 } else { 577 ch = children_evaluated; 578 } 579 } else { 580 ch = children_evaluated; 581 } 582 if (children_evaluated == null && evaluated[0] == 1) return; 585 children_evaluated = null; 586 } 587 if (ch == null) { 588 applyWaitChildren(); 589 } else { 590 applyChildren(ch, refreshSubNodes); 591 } 592 } 593 594 private void applyChildren(final Object [] ch, boolean refreshSubNodes) { 595 int i, k = ch.length; 597 WeakHashMap newObjectToNode = new WeakHashMap (); 598 for (i = 0; i < k; i++) { 599 if (ch [i] == null) { 600 throw (NullPointerException ) ErrorManager.getDefault().annotate( 601 new NullPointerException (), 602 "model: " + model + "\nparent: " + object); 603 } 604 WeakReference wr = (WeakReference ) objectToNode.get 605 (ch [i]); 606 if (wr == null) continue; 607 TreeModelNode tmn = (TreeModelNode) wr.get (); 608 if (tmn == null) continue; 609 if (refreshSubNodes) { 610 tmn.setObject (ch [i]); 611 } else { 612 tmn.setObjectNoRefresh(ch[i]); 613 } 614 newObjectToNode.put (ch [i], wr); 615 } 616 objectToNode = newObjectToNode; 617 setKeys (ch); 618 619 SwingUtilities.invokeLater (new Runnable () { 620 public void run () { 621 int i, k = ch.length; 622 for (i = 0; i < k; i++) 623 try { 624 if (model.isExpanded (ch [i])) { 625 TreeTable treeTable = treeModelRoot.getTreeTable (); 626 if (treeTable.isExpanded(object)) { 627 treeTable.expandNode (ch [i]); 629 } 630 } 631 } catch (UnknownTypeException ex) { 632 } 633 } 634 }); 635 } 636 637 private void applyWaitChildren() { 638 setKeys(new Object [] { WAIT_KEY }); 640 } 641 642 656 protected Node[] createNodes (Object object) { 657 if (object == WAIT_KEY) { 658 AbstractNode n = new AbstractNode(Children.LEAF); 659 n.setName(NbBundle.getMessage(TreeModelNode.class, "WaitNode")); 660 n.setIconBaseWithExtension("org/netbeans/modules/viewmodel/wait.gif"); 661 return new Node[] { n }; 662 } 663 if (object instanceof Exception ) 664 return new Node[] { 665 new ExceptionNode ((Exception ) object) 666 }; 667 TreeModelNode tmn = new TreeModelNode ( 668 model, 669 treeModelRoot, 670 object 671 ); 672 objectToNode.put (object, new WeakReference (tmn)); 673 return new Node[] {tmn}; 674 } 675 } 677 private class MyProperty extends PropertySupport implements LazyEvaluator.Evaluable { 678 679 private final String EVALUATING_STR = NbBundle.getMessage(TreeModelNode.class, "EvaluatingProp"); 680 private String id; 681 private ColumnModel columnModel; 682 private boolean nodeColumn; 683 private TreeModelRoot treeModelRoot; 684 private int[] evaluated = { 0 }; 686 687 MyProperty ( 688 ColumnModel columnModel, TreeModelRoot treeModelRoot 689 ) { 690 super ( 691 columnModel.getID (), 692 (columnModel.getType() == null) ? String .class : columnModel.getType (), 693 columnModel.getDisplayName (), 694 columnModel.getShortDescription (), 695 true, 696 true 697 ); 698 this.columnModel = columnModel; 699 this.nodeColumn = columnModel.getType() == null; 700 this.treeModelRoot = treeModelRoot; 701 id = columnModel.getID (); 702 } 703 704 705 709 public boolean canWrite () { 710 if (nodeColumn) return false; 711 try { 712 return !model.isReadOnly (object, columnModel.getID ()); 713 } catch (UnknownTypeException e) { 714 if (!(object instanceof String )) { 715 Throwable t = ErrorManager.getDefault().annotate(e, "Column id:" + columnModel.getID ()+"\nModel: "+model); 716 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t); 717 } 718 return false; 719 } 720 } 721 722 public void evaluateLazily(Runnable evaluatedNotify) { 723 Object value = ""; 724 String htmlValue = null; 725 String nonHtmlValue = null; 726 try { 727 value = model.getValueAt (object, id); 728 if (value instanceof String ) { 730 htmlValue = htmlValue ((String ) value); 731 nonHtmlValue = removeHTML ((String ) value); 732 } 733 } catch (UnknownTypeException e) { 734 if (!(object instanceof String )) { 735 e.printStackTrace (); 736 System.out.println(" Column id:" + columnModel.getID ()); 737 System.out.println (model); 738 System.out.println (); 739 } 740 } catch (Throwable t) { 741 t.printStackTrace(); 742 } finally { 743 evaluatedNotify.run(); 744 boolean fire; 745 synchronized (properties) { 746 if (value instanceof String ) { 747 properties.put (id, nonHtmlValue); 748 properties.put (id + "#html", htmlValue); 749 } else { 750 properties.put (id, value); 751 } 752 synchronized (evaluated) { 753 fire = evaluated[0] == -1; 754 evaluated[0] = 1; 755 evaluated.notifyAll(); 756 } 757 } 758 if (fire) { 760 firePropertyChange (id, null, value); 761 refreshTheChildren(true); 762 } 763 764 } 765 } 766 767 public synchronized Object getValue () { if (nodeColumn) { 769 return TreeModelNode.this.getDisplayName(); 770 } 771 synchronized (properties) { 773 if (properties.containsKey (id)) 775 return properties.get (id); 776 } 777 778 synchronized (evaluated) { 779 evaluated[0] = 0; 780 } 781 treeModelRoot.getValuesEvaluator().evaluate(this); 782 783 Object ret = null; 784 boolean refreshChildren = false; 785 786 synchronized (evaluated) { 787 if (evaluated[0] != 1) { 788 try { 789 evaluated.wait(25); 790 } catch (InterruptedException iex) {} 791 if (evaluated[0] != 1) { 792 evaluated[0] = -1; ret = EVALUATING_STR; 794 } else { 795 refreshChildren = true; 796 } 797 } 798 } 799 if (ret == null) { 800 synchronized (properties) { 801 ret = properties.get(id); 802 } 803 } 804 805 if (refreshChildren) { 806 RequestProcessor.getDefault().post(new Runnable () { 807 public void run() { 808 refreshTheChildren(true); 809 } 810 }); 811 } 812 if (ret == EVALUATING_STR && 813 getValueType() != null && getValueType() != String .class) { 814 ret = null; } 817 return ret; 818 } 819 820 public Object getValue (String attributeName) { 821 if (attributeName.equals ("htmlDisplayValue")) { 822 if (nodeColumn) { 823 return TreeModelNode.this.getHtmlDisplayName(); 824 } 825 synchronized (evaluated) { 826 if (evaluated[0] != 1) { 827 return "<html><font color=\"0000CC\">"+EVALUATING_STR+"</font></html>"; 828 } 829 } 830 synchronized (properties) { 831 return properties.get (id + "#html"); 832 } 833 } 834 return super.getValue (attributeName); 835 } 836 837 public String getShortDescription() { 838 if (nodeColumn) { 839 return TreeModelNode.this.getShortDescription(); 840 } 841 synchronized (properties) { 842 if (!properties.containsKey(id)) { 843 return null; } 845 } 846 try { 847 javax.swing.JToolTip tooltip = new javax.swing.JToolTip (); 848 tooltip.putClientProperty("getShortDescription", object); Object tooltipObj = model.getValueAt(tooltip, id); 850 if (tooltipObj == null) { 851 return null; 852 } else { 853 return tooltipObj.toString(); 854 } 855 } catch (UnknownTypeException e) { 856 return null; 858 } 859 } 860 861 public void setValue (Object v) throws IllegalAccessException , 862 IllegalArgumentException , java.lang.reflect.InvocationTargetException { 863 try { 864 model.setValueAt (object, id, v); 865 synchronized (properties) { 866 properties.put (id, v); 867 } 868 firePropertyChange (id, null, null); 869 } catch (UnknownTypeException e) { 870 Throwable t = ErrorManager.getDefault().annotate(e, "Column id:" + columnModel.getID ()+"\nModel: "+model); 871 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, t); 872 } 873 } 874 875 public PropertyEditor getPropertyEditor () { 876 return columnModel.getPropertyEditor (); 877 } 878 } 879 880 881 static class LazyEvaluator implements Runnable { 882 883 884 private static final long EXPIRE_TIME = 60000L; 885 886 private List objectsToEvaluate = new LinkedList (); 887 private Evaluable currentlyEvaluating; 888 private Task evalTask; 889 890 public LazyEvaluator() { 891 evalTask = new RequestProcessor("Debugger Values Evaluator", 1).post(this); 892 } 893 894 public void evaluate(Evaluable eval) { 895 evaluate(eval, true); 896 } 897 898 public void evaluate(Evaluable eval, boolean checkForEvaluating) { 899 synchronized (objectsToEvaluate) { 900 for (Iterator it = objectsToEvaluate.iterator(); it.hasNext(); ) { 901 if (eval == it.next()) return ; } 903 if (checkForEvaluating && currentlyEvaluating == eval) return ; objectsToEvaluate.add(eval); 905 objectsToEvaluate.notify(); 906 if (evalTask.isFinished()) { 907 evalTask.schedule(0); 908 } 909 } 910 } 911 912 public void run() { 913 while(true) { 914 Evaluable eval; 915 synchronized (objectsToEvaluate) { 916 if (objectsToEvaluate.size() == 0) { 917 try { 918 objectsToEvaluate.wait(EXPIRE_TIME); 919 } catch (InterruptedException iex) { 920 return ; 921 } 922 if (objectsToEvaluate.size() == 0) { return ; 924 } 925 } 926 eval = (Evaluable) objectsToEvaluate.remove(0); 927 currentlyEvaluating = eval; 928 } 929 Runnable evaluatedNotify = new Runnable () { 930 public void run() { 931 synchronized (objectsToEvaluate) { 932 currentlyEvaluating = null; 933 } 934 } 935 }; 936 eval.evaluateLazily(evaluatedNotify); 937 } 938 } 939 940 public interface Evaluable { 941 942 public void evaluateLazily(Runnable evaluatedNotify); 943 944 } 945 946 } 947 948 } 949 950 | Popular Tags |