1 19 package org.openide.explorer.view; 20 21 import java.util.logging.Level ; 22 import java.util.logging.Logger ; 23 import org.openide.nodes.*; 24 import org.openide.util.Mutex; 25 import org.openide.util.Utilities; 26 27 import java.awt.Image ; 28 29 import java.beans.BeanInfo ; 30 31 import java.lang.ref.Reference ; 32 import java.lang.ref.WeakReference ; 33 34 import java.util.*; 35 36 import javax.swing.Icon ; 37 import javax.swing.ImageIcon ; 38 import javax.swing.SwingUtilities ; 39 import javax.swing.event.EventListenerList ; 40 import javax.swing.tree.TreeNode ; 41 42 43 54 final class VisualizerNode extends EventListenerList implements NodeListener, TreeNode , Runnable { 55 56 private static final VisualizerNode TEMPLATE = new VisualizerNode(0); 57 58 static final Logger LOG = Logger.getLogger(VisualizerNode.class.getName()); 59 60 61 private static final Reference <VisualizerChildren> NO_REF = new WeakReference <VisualizerChildren>(null); 62 63 64 private static WeakHashMap<VisualizerNode, Reference <VisualizerNode>> cache = 65 new WeakHashMap<VisualizerNode, Reference <VisualizerNode>>(); 66 67 68 public static final VisualizerNode EMPTY = getVisualizer(null, Node.EMPTY); 69 70 71 private static final QP QUEUE = new QP(); 72 private static final String UNKNOWN = new String (); 73 static final long serialVersionUID = 3726728244698316872L; 74 private static final String NO_HTML_DISPLAYNAME = "noHtmlDisplayName"; 76 77 private static Icon defaultIcon; 78 79 80 private static final String DEFAULT_ICON = "org/openide/nodes/defaultNode.gif"; 82 85 private Icon icon = null; 86 87 88 Node node; 89 90 91 private int hashCode; 92 93 94 private Reference <VisualizerChildren> children = NO_REF; 95 96 97 private VisualizerChildren parent; 98 99 100 private String name; 101 102 103 private String displayName; 104 105 106 private String shortDescription; 107 private transient boolean inRead; 108 private String htmlDisplayName = null; 109 private int cachedIconType = -1; 110 111 113 private VisualizerNode(int hashCode) { 114 this.hashCode = hashCode; 115 this.node = null; 116 } 117 118 121 private VisualizerNode(Node n) { 122 node = n; 123 hashCode = System.identityHashCode(node); 124 125 node.addNodeListener(NodeOp.weakNodeListener(this, node)); 127 128 name = UNKNOWN; 131 displayName = UNKNOWN; 132 shortDescription = UNKNOWN; 133 } 134 135 137 142 public static VisualizerNode getVisualizer(VisualizerChildren ch, Node n) { 143 return getVisualizer(ch, n, true); 144 } 145 146 151 public static synchronized VisualizerNode getVisualizer(VisualizerChildren ch, Node n, boolean create) { 152 TEMPLATE.hashCode = System.identityHashCode(n); 153 TEMPLATE.node = n; 154 155 Reference <VisualizerNode> r = cache.get(TEMPLATE); 156 157 TEMPLATE.hashCode = 0; 158 TEMPLATE.node = null; 159 160 VisualizerNode v = (r == null) ? null : r.get(); 161 162 if (v == null) { 163 if (!create) { 164 return null; 165 } 166 167 v = new VisualizerNode(n); 168 cache.put(v, new WeakReference <VisualizerNode>(v)); 169 } 170 171 if (ch != null) { 172 v.parent = ch; 173 } 174 175 return v; 176 } 177 178 181 public String getShortDescription() { 182 String desc = shortDescription; 183 184 if (desc == UNKNOWN) { 185 shortDescription = desc = node.getShortDescription(); 186 } 187 188 return desc; 189 } 190 191 194 public String getDisplayName() { 195 if (displayName == UNKNOWN) { 196 displayName = (node == null) ? null : node.getDisplayName(); 197 } 198 199 return displayName; 200 } 201 202 205 public String getName() { 206 if (name == UNKNOWN) { 207 name = (node == null) ? null : node.getName(); 208 } 209 210 return name; 211 } 212 213 216 public List <VisualizerNode> getChildren() { 217 VisualizerChildren ch = children.get(); 218 219 if ((ch == null) && !node.isLeaf()) { 220 Node [] tmpInit = node.getChildren().getNodes(); 223 224 ch = Children.MUTEX.readAccess( 228 new Mutex.Action<VisualizerChildren>() { 229 public VisualizerChildren run() { 230 Node [] nodes = node.getChildren().getNodes(); 231 VisualizerChildren vc = new VisualizerChildren(VisualizerNode.this, nodes); 232 notifyVisualizerChildrenChange(nodes.length, vc); 233 234 return vc; 235 } 236 } 237 ); 238 } 239 240 if (LOG.isLoggable(Level.FINER)) { 241 assert (ch == null) || !ch.list.contains(null) : ch.list + " from " + node; 243 } 244 245 return (ch == null) ? Collections.<VisualizerNode>emptyList() : ch.list; 246 } 247 248 public int getIndex(final javax.swing.tree.TreeNode p1) { 252 return getChildren().indexOf(p1); 253 } 254 255 public boolean getAllowsChildren() { 256 return !isLeaf(); 257 } 258 259 public javax.swing.tree.TreeNode getChildAt(int p1) { 260 List ch = getChildren(); 261 VisualizerNode vn = (VisualizerNode) ch.get(p1); 262 assert vn != null : "Null child in " + ch + " from " + node; 263 264 return vn; 265 } 266 267 public int getChildCount() { 268 return getChildren().size(); 269 } 270 271 public java.util.Enumeration <VisualizerNode> children() { 272 List <VisualizerNode> l = getChildren(); 273 assert !l.contains(null) : "Null child in " + l + " from " + node; 274 275 return java.util.Collections.enumeration(l); 276 } 277 278 public boolean isLeaf() { 279 return node.isLeaf(); 280 } 281 282 public javax.swing.tree.TreeNode getParent() { 283 Node parent = node.getParentNode(); 284 285 return (parent == null) ? null : getVisualizer(null, parent); 286 } 287 288 292 295 public void childrenAdded(NodeMemberEvent ev) { 296 VisualizerChildren ch = children.get(); 297 298 LOG.log(Level.FINER, "childrenAdded {0}", ev); if (ch == null) { 300 LOG.log(Level.FINER, "childrenAdded - exit"); return; 302 } 303 304 QUEUE.runSafe(new VisualizerEvent.Added(ch, ev.getDelta(), ev.getDeltaIndices())); 305 LOG.log(Level.FINER, "childrenAdded - end"); } 307 308 311 public void childrenRemoved(NodeMemberEvent ev) { 312 VisualizerChildren ch = children.get(); 313 314 LOG.log(Level.FINER, "childrenRemoved {0}", ev); if (ch == null) { 316 LOG.log(Level.FINER, "childrenRemoved - exit"); return; 318 } 319 320 QUEUE.runSafe(new VisualizerEvent.Removed(ch, ev.getDelta())); 321 LOG.log(Level.FINER, "childrenRemoved - end"); } 323 324 327 public void childrenReordered(NodeReorderEvent ev) { 328 doChildrenReordered(ev.getPermutation()); 329 } 330 331 void doChildrenReordered(int[] perm) { 333 VisualizerChildren ch = children.get(); 334 335 LOG.log(Level.FINER, "childrenReordered {0}", perm); if (ch == null) { 337 LOG.log(Level.FINER, "childrenReordered - exit"); return; 339 } 340 341 QUEUE.runSafe(new VisualizerEvent.Reordered(ch, perm)); 342 LOG.log(Level.FINER, "childrenReordered - end"); } 344 345 void reorderChildren(Comparator<VisualizerNode> c) { 346 assert SwingUtilities.isEventDispatchThread(); 347 348 VisualizerChildren ch = children.get(); 349 350 if (ch == null) { 351 return; 352 } 353 354 new VisualizerEvent.Reordered(ch, c).run(); 355 } 356 357 void naturalOrder() { 358 children.clear(); 360 getChildren(); 361 362 reorderChildren( 364 new Comparator<VisualizerNode>() { 365 public int compare(VisualizerNode o1, VisualizerNode o2) { 366 return 0; 367 } 368 } 369 ); 370 } 371 372 375 public void nodeDestroyed(NodeEvent ev) { 376 } 378 379 381 public void propertyChange(final java.beans.PropertyChangeEvent evt) { 382 String name = evt.getPropertyName(); 383 boolean isIconChange = Node.PROP_ICON.equals(name) || Node.PROP_OPENED_ICON.equals(name); 384 385 if (Node.PROP_NAME.equals(name) || Node.PROP_DISPLAY_NAME.equals(name) || isIconChange) { 386 if (isIconChange) { 387 cachedIconType = -1; 390 } 391 392 if (Node.PROP_DISPLAY_NAME.equals(name)) { 393 htmlDisplayName = null; 394 } 395 396 SwingUtilities.invokeLater(this); 397 398 return; 399 } 400 401 if (Node.PROP_SHORT_DESCRIPTION.equals(name) && (shortDescription != UNKNOWN)) { 403 SwingUtilities.invokeLater(this); 404 405 return; 406 } 407 408 if (Node.PROP_LEAF.equals(name)) { 409 SwingUtilities.invokeLater( 410 new Runnable () { 411 public void run() { 412 children = NO_REF; 413 414 VisualizerNode parent = VisualizerNode.this; 416 417 while (parent != null) { 418 Object [] listeners = parent.getListenerList(); 419 420 for (int i = listeners.length - 1; i >= 0; i -= 2) { 421 ((NodeModel) listeners[i]).structuralChange(VisualizerNode.this); 422 } 423 424 parent = (VisualizerNode) parent.getParent(); 425 } 426 } 427 } 428 ); 429 } 430 } 431 432 435 public void run() { 436 if (!inRead) { 437 try { 438 inRead = true; 443 Children.MUTEX.readAccess(this); 444 } finally { 445 inRead = false; 446 } 447 448 return; 449 } 450 451 name = node.getName(); 452 displayName = node.getDisplayName(); 453 shortDescription = UNKNOWN; 454 455 VisualizerNode parent = this; 459 460 while (parent != null) { 461 Object [] listeners = parent.getListenerList(); 462 463 for (int i = listeners.length - 1; i >= 0; i -= 2) { 464 ((NodeModel) listeners[i]).update(this); 465 } 466 467 parent = (VisualizerNode) parent.getParent(); 468 } 469 } 470 471 475 480 void notifyVisualizerChildrenChange(int size, VisualizerChildren ch) { 481 if (size == 0) { 482 children = new StrongReference<VisualizerChildren>(ch); 484 } else { 485 children = new WeakReference <VisualizerChildren>(ch); 486 } 487 } 488 489 493 495 public synchronized void addNodeModel(NodeModel l) { 496 add(NodeModel.class, l); 497 } 498 499 501 public synchronized void removeNodeModel(NodeModel l) { 502 remove(NodeModel.class, l); 503 } 504 505 507 public int hashCode() { 508 return hashCode; 509 } 510 511 513 public boolean equals(Object o) { 514 if (!(o instanceof VisualizerNode)) { 515 return false; 516 } 517 518 VisualizerNode v = (VisualizerNode) o; 519 520 return v.node == node; 521 } 522 523 525 public String toString() { 526 return getDisplayName(); 527 } 528 529 public String getHtmlDisplayName() { 530 if (htmlDisplayName == null) { 531 htmlDisplayName = node.getHtmlDisplayName(); 532 533 if (htmlDisplayName == null) { 534 htmlDisplayName = NO_HTML_DISPLAYNAME; 535 } 536 } 537 538 return (htmlDisplayName == NO_HTML_DISPLAYNAME) ? null : htmlDisplayName; 539 } 540 541 Icon getIcon(boolean opened, boolean large) { 542 int newCacheType = getCacheType(opened, large); 543 544 if (cachedIconType != newCacheType) { 545 int iconType = large ? BeanInfo.ICON_COLOR_32x32 : BeanInfo.ICON_COLOR_16x16; 546 547 Image image = opened ? node.getOpenedIcon(iconType) : node.getIcon(iconType); 548 549 if (image == null) { 551 String method = opened ? "getOpenedIcon" : "getIcon"; LOG.warning( 553 "Node \"" + node.getName() + "\" [" + node.getClass().getName() + "] cannot return null from " + 554 method + "(). See Node." + method + " contract." 555 ); 557 icon = getDefaultIcon(); 558 } else { 559 icon = new ImageIcon (image); 560 } 561 } 562 563 cachedIconType = newCacheType; 564 565 return icon; 566 } 567 568 571 private static final int getCacheType(boolean opened, boolean large) { 572 return (opened ? 2 : 0) | (large ? 1 : 0); 573 } 574 575 576 private static Icon getDefaultIcon() { 577 if (defaultIcon == null) { 578 defaultIcon = new ImageIcon (Utilities.loadImage(DEFAULT_ICON)); 579 } 580 581 return defaultIcon; 582 } 583 584 static void runQueue() { 585 QUEUE.run(); 586 } 587 588 590 private static final class StrongReference<T> extends WeakReference <T> { 591 private T o; 592 593 public StrongReference(T o) { 594 super(null); 595 this.o = o; 596 } 597 598 public T get() { 599 return o; 600 } 601 } 602 603 607 private static final class QP extends Object implements Runnable { 608 611 private LinkedList<Runnable > queue = null; 612 613 QP() { 614 } 615 616 619 public void runSafe(Runnable run) { 620 boolean isNew = false; 621 622 synchronized (this) { 623 if (queue == null) { 625 queue = new LinkedList<Runnable >(); 626 isNew = true; 627 } 628 629 queue.add(run); 630 } 631 632 if (isNew) { 633 Mutex.EVENT.writeAccess(this); 637 } 638 } 639 640 642 public void run() { 643 Enumeration<Runnable > en; 644 645 synchronized (this) { 646 if (queue == null) { 648 LOG.log(Level.FINER, "Queue empty"); return; 650 } 651 652 en = Collections.enumeration(queue); 653 queue = null; 654 LOG.log(Level.FINER, "Queue emptied"); } 656 657 while (en.hasMoreElements()) { 658 Runnable r = en.nextElement(); 659 LOG.log(Level.FINER, "Running {0}", r); Children.MUTEX.readAccess(r); LOG.log(Level.FINER, "Finished {0}", r); } 663 LOG.log(Level.FINER, "Queue processing over"); } 665 } 666 } 667 | Popular Tags |