1 19 package org.openide.nodes; 20 21 import java.lang.ref.Reference ; 22 import java.lang.reflect.Method ; 23 import org.openide.util.HelpCtx; 24 import org.openide.util.Lookup; 25 import org.openide.util.LookupEvent; 26 import org.openide.util.LookupListener; 27 import org.openide.util.WeakSet; 28 import org.openide.util.actions.SystemAction; 29 import org.openide.util.datatransfer.NewType; 30 import org.openide.util.datatransfer.PasteType; 31 32 import java.awt.Image ; 33 import java.awt.datatransfer.Transferable ; 34 35 import java.beans.PropertyChangeEvent ; 36 import java.beans.PropertyChangeListener ; 37 38 import java.io.IOException ; 39 40 import java.lang.ref.WeakReference ; 41 42 import java.util.*; 43 import java.util.logging.Level ; 44 import java.util.logging.Logger ; 45 import org.openide.nodes.Node.PropertySet; 46 import org.openide.util.Exceptions; 47 import org.openide.util.Lookup.Item; 48 49 50 63 public class FilterNode extends Node { 64 65 protected static final int DELEGATE_SET_NAME = 1 << 0; 66 67 68 protected static final int DELEGATE_GET_NAME = 1 << 1; 69 70 71 protected static final int DELEGATE_SET_DISPLAY_NAME = 1 << 2; 72 73 74 protected static final int DELEGATE_GET_DISPLAY_NAME = 1 << 3; 75 76 77 protected static final int DELEGATE_SET_SHORT_DESCRIPTION = 1 << 4; 78 79 80 protected static final int DELEGATE_GET_SHORT_DESCRIPTION = 1 << 5; 81 82 83 protected static final int DELEGATE_DESTROY = 1 << 6; 84 85 86 protected static final int DELEGATE_GET_ACTIONS = 1 << 7; 87 88 89 protected static final int DELEGATE_GET_CONTEXT_ACTIONS = 1 << 8; 90 91 94 protected static final int DELEGATE_SET_VALUE = 1 << 9; 95 96 99 protected static final int DELEGATE_GET_VALUE = 1 << 10; 100 101 102 private static final int DELEGATE_ALL = DELEGATE_SET_NAME | DELEGATE_GET_NAME | DELEGATE_SET_DISPLAY_NAME | 103 DELEGATE_GET_DISPLAY_NAME | DELEGATE_SET_SHORT_DESCRIPTION | DELEGATE_GET_SHORT_DESCRIPTION | DELEGATE_DESTROY | 104 DELEGATE_GET_ACTIONS | DELEGATE_GET_CONTEXT_ACTIONS | DELEGATE_SET_VALUE | DELEGATE_GET_VALUE; 105 private static final Map<Class <?>,Boolean > overridesGetDisplayNameCache = new WeakHashMap<Class <?>,Boolean >(27); 106 private static final Map<Class <?>,Boolean > replaceProvidedLookupCache = new WeakHashMap<Class <?>,Boolean >(27); 107 108 110 private static volatile int hashCodeDepth; 111 112 113 private Node original; 114 115 118 private PropertyChangeListener propL; 119 120 123 private NodeListener nodeL; 124 125 128 129 private int delegateMask; 130 131 132 private boolean pchlAttached = false; 133 134 135 private boolean childrenProvided; 136 137 140 public FilterNode(Node original) { 141 this(original, null); 142 } 143 144 149 public FilterNode(Node original, org.openide.nodes.Children children) { 150 this(original, children, new FilterLookup()); 151 } 152 153 168 public FilterNode(Node original, org.openide.nodes.Children children, Lookup lookup) { 169 super( 170 (children == null) ? (original.isLeaf() ? org.openide.nodes.Children.LEAF : new Children(original)) : children, 171 lookup 172 ); 173 174 this.childrenProvided = children != null; 175 this.original = original; 176 init(); 177 178 Lookup lkp = internalLookup(false); 179 180 if (lkp instanceof FilterLookup) { 181 ((FilterLookup) lkp).ownNode(this); 182 } else { 183 if (lkp == null) { 184 getNodeListener(); 186 } 187 } 188 } 189 190 197 final Lookup replaceProvidedLookup(Lookup lookup) { 198 synchronized (replaceProvidedLookupCache) { 199 Boolean b = replaceProvidedLookupCache.get(getClass()); 200 201 if (b == null) { 202 b = !overridesAMethod("getCookie", Class .class); replaceProvidedLookupCache.put(getClass(), b); 204 } 205 206 return b ? lookup : null; 207 } 208 } 209 210 212 private boolean overridesAMethod(String name, Class ... arguments) { 213 if (getClass() == FilterNode.class) { 214 return false; 215 } 216 217 try { 219 Method m = getClass().getMethod(name, arguments); 220 221 if (m.getDeclaringClass() != FilterNode.class) { 222 return true; 224 } 225 } catch (NoSuchMethodException ex) { 226 Exceptions.printStackTrace(ex); 227 } 228 229 return false; 230 } 231 232 234 private void init() { 235 delegateMask = DELEGATE_ALL; 236 } 237 238 void notifyPropertyChangeListenerAdded(PropertyChangeListener l) { 239 if (!pchlAttached) { 240 original.addPropertyChangeListener(getPropertyChangeListener()); 241 pchlAttached = true; 242 } 243 } 244 245 void notifyPropertyChangeListenerRemoved(PropertyChangeListener l) { 246 if (getPropertyChangeListenersCount() == 0) { 247 original.removePropertyChangeListener(getPropertyChangeListener()); 248 pchlAttached = false; 249 } 250 } 251 252 257 @Override 258 protected void finalize() { 259 original.removePropertyChangeListener(getPropertyChangeListener()); 260 original.removeNodeListener(getNodeListener()); 261 } 262 263 269 protected final void enableDelegation(int mask) { 270 if ((mask & ~DELEGATE_ALL) != 0) { 271 throw new IllegalArgumentException ("Bad delegation mask: " + mask); } 273 274 delegateMask |= mask; 275 } 276 277 307 protected final void disableDelegation(int mask) { 308 if ((mask & ~DELEGATE_ALL) != 0) { 309 throw new IllegalArgumentException ("Bad delegation mask: " + mask); } 311 312 delegateMask &= ~mask; 313 } 314 315 316 private final boolean delegating(int what) { 317 return (delegateMask & what) != 0; 318 } 319 320 326 public Node cloneNode() { 327 if (isDefault()) { 328 return new FilterNode(original); 332 } else { 333 return new FilterNode(this); 336 } 337 } 338 339 344 private boolean checkIfIamAccessibleFromOriginal(Node original) { 345 if (this == original) { 346 throw new IllegalArgumentException ("Node cannot be its own original (even thru indirect chain)"); } 348 349 if (original instanceof FilterNode) { 350 FilterNode f = (FilterNode) original; 351 checkIfIamAccessibleFromOriginal(f.original); 352 } 353 354 return true; 355 } 356 357 374 protected final void changeOriginal(Node original, boolean changeChildren) { 375 if ( 376 changeChildren && !(getChildren() instanceof FilterNode.Children) && 377 !(getChildren() == Children.LEAF ) 378 ) { 379 throw new IllegalStateException ("Can't change implicitly defined Children on FilterNode"); } 381 382 assert checkIfIamAccessibleFromOriginal(original) : ""; 384 try { 385 Children.PR.enterWriteAccess(); 386 387 this.original.removeNodeListener(getNodeListener()); 389 390 if (pchlAttached) { 391 this.original.removePropertyChangeListener(getPropertyChangeListener()); 392 } 393 394 this.original = original; 396 397 this.original.addNodeListener(getNodeListener()); 399 400 if (pchlAttached) { 401 this.original.addPropertyChangeListener(getPropertyChangeListener()); 402 } 403 404 if (changeChildren ) { 406 if (original.isLeaf() && (getChildren() != Children.LEAF)) { 407 setChildren(Children.LEAF); 408 } else if (!original.isLeaf() && (getChildren() == Children.LEAF)) { 409 setChildren(new Children(original)); 410 } else if (!original.isLeaf() && (getChildren() != Children.LEAF)) { 411 ((FilterNode.Children) getChildren()).changeOriginal(original); 412 } 413 } 414 } finally { 415 Children.PR.exitWriteAccess(); 416 } 417 418 Lookup lkp = internalLookup(false); 421 422 if (lkp instanceof FilterLookup) { 423 ((FilterLookup) lkp).checkNode(); 424 } 425 426 fireCookieChange(); 427 fireNameChange(null, null); 428 fireDisplayNameChange(null, null); 429 fireShortDescriptionChange(null, null); 430 fireIconChange(); 431 fireOpenedIconChange(); 432 firePropertySetsChange(null, null); 433 } 434 435 @Override 437 public void setValue(String attributeName, Object value) { 438 if (delegating(DELEGATE_SET_VALUE)) { 439 original.setValue(attributeName, value); 440 } else { 441 super.setValue(attributeName, value); 442 } 443 } 444 445 @Override 446 public Object getValue(String attributeName) { 447 if (delegating(DELEGATE_GET_VALUE)) { 448 return original.getValue(attributeName); 449 } else { 450 return super.getValue(attributeName); 451 } 452 } 453 454 457 @Override 458 public void setName(String s) { 459 if (delegating(DELEGATE_SET_NAME)) { 460 original.setName(s); 461 } else { 462 super.setName(s); 463 } 464 } 465 466 468 @Override 469 public String getName() { 470 if (delegating(DELEGATE_GET_NAME)) { 471 return original.getName(); 472 } else { 473 return super.getName(); 474 } 475 } 476 477 480 @Override 481 public void setDisplayName(String s) { 482 if (delegating(DELEGATE_SET_DISPLAY_NAME)) { 483 original.setDisplayName(s); 484 } else { 485 super.setDisplayName(s); 486 } 487 } 488 489 491 @Override 492 public String getDisplayName() { 493 if (delegating(DELEGATE_GET_DISPLAY_NAME)) { 494 return original.getDisplayName(); 495 } else { 496 return super.getDisplayName(); 497 } 498 } 499 500 503 @Override 504 public void setShortDescription(String s) { 505 if (delegating(DELEGATE_SET_SHORT_DESCRIPTION)) { 506 original.setShortDescription(s); 507 } else { 508 super.setShortDescription(s); 509 } 510 } 511 512 514 @Override 515 public String getShortDescription() { 516 if (delegating(DELEGATE_GET_SHORT_DESCRIPTION)) { 517 return original.getShortDescription(); 518 } else { 519 return super.getShortDescription(); 520 } 521 } 522 523 529 public Image getIcon(int type) { 530 return original.getIcon(type); 531 } 532 533 540 public Image getOpenedIcon(int type) { 541 return original.getOpenedIcon(type); 542 } 543 544 public HelpCtx getHelpCtx() { 545 return original.getHelpCtx(); 546 } 547 548 552 public boolean canRename() { 553 return original.canRename(); 554 } 555 556 559 public boolean canDestroy() { 560 return original.canDestroy(); 561 } 562 563 565 @Override 566 public void destroy() throws java.io.IOException { 567 if (delegating(DELEGATE_DESTROY)) { 568 original.destroy(); 569 } else { 570 super.destroy(); 571 } 572 } 573 574 577 private final void originalDestroyed() { 578 try { 579 super.destroy(); 580 } catch (IOException ex) { 581 Logger.getLogger(FilterNode.class.getName()).log(Level.WARNING, null, ex); 582 } 583 } 584 585 589 public PropertySet[] getPropertySets() { 590 return original.getPropertySets(); 591 } 592 593 599 public Transferable clipboardCopy() throws IOException { 600 return original.clipboardCopy(); 601 } 602 603 609 public Transferable clipboardCut() throws IOException { 610 return original.clipboardCut(); 611 } 612 613 616 public boolean canCopy() { 617 return original.canCopy(); 618 } 619 620 623 public boolean canCut() { 624 return original.canCut(); 625 } 626 627 public Transferable drag() throws IOException { 628 return original.drag(); 629 } 630 631 642 public PasteType getDropType(Transferable t, int action, int index) { 643 return original.getDropType(t, action, index); 644 } 645 646 650 public PasteType[] getPasteTypes(Transferable t) { 651 return original.getPasteTypes(t); 652 } 653 654 657 public NewType[] getNewTypes() { 658 return original.getNewTypes(); 659 } 660 661 665 @Override 666 @Deprecated 667 public SystemAction[] getActions() { 668 if (delegating(DELEGATE_GET_ACTIONS)) { 669 return original.getActions(); 670 } else { 671 return super.getActions(); 672 } 673 } 674 675 677 @Override 678 @Deprecated 679 public SystemAction[] getContextActions() { 680 if (delegating(DELEGATE_GET_CONTEXT_ACTIONS)) { 681 return original.getContextActions(); 682 } else { 683 return super.getContextActions(); 684 } 685 } 686 687 690 @Override 691 @Deprecated 692 public SystemAction getDefaultAction() { 693 return original.getDefaultAction(); 694 } 695 696 @Override 697 public javax.swing.Action [] getActions(boolean context) { 698 if (context) { 699 if (!delegating(DELEGATE_GET_ACTIONS) || overridesAMethod("getContextActions")) { 701 return super.getActions(context); 702 } 703 } else { 704 if (!delegating(DELEGATE_GET_CONTEXT_ACTIONS) || overridesAMethod("getActions")) { 706 return super.getActions(context); 707 } 708 } 709 710 javax.swing.Action [] retValue; 711 retValue = original.getActions(context); 712 713 return retValue; 714 } 715 716 @Override 717 public javax.swing.Action getPreferredAction() { 718 javax.swing.Action retValue; 719 720 if (overridesAMethod("getDefaultAction")) { retValue = super.getPreferredAction(); 722 } else { 723 retValue = original.getPreferredAction(); 724 } 725 726 return retValue; 727 } 728 729 746 @Override 747 public String getHtmlDisplayName() { 748 if (overridesGetDisplayName()) { 749 return null; 750 } else { 751 return delegating(DELEGATE_GET_DISPLAY_NAME) ? original.getHtmlDisplayName() : super.getHtmlDisplayName(); 752 } 753 } 754 755 private boolean overridesGetDisplayName() { 756 synchronized (overridesGetDisplayNameCache) { 757 Boolean b = overridesGetDisplayNameCache.get(getClass()); 758 759 if (b == null) { 760 b = overridesAMethod("getDisplayName"); overridesGetDisplayNameCache.put(getClass(), b); 762 } 763 764 return b; 765 } 766 } 767 768 771 public boolean hasCustomizer() { 772 return original.hasCustomizer(); 773 } 774 775 778 public java.awt.Component getCustomizer() { 779 return original.getCustomizer(); 780 } 781 782 791 @Override 792 public <T extends Node.Cookie> T getCookie(Class <T> type) { 793 Lookup l = internalLookup(true); 794 795 if (l != null) { 796 Object res = l.lookup(type); 797 return type.isInstance(res) && res instanceof Node.Cookie ? type.cast(res) : null; 798 } 799 800 return original.getCookie(type); 801 } 802 803 812 public Node.Handle getHandle() { 813 if (!isDefault()) { 814 return null; 816 } 817 818 Node.Handle original = this.original.getHandle(); 819 820 if (original == null) { 821 return null; 823 } 824 825 return new FilterHandle(original); 826 } 827 828 843 @Override 844 public boolean equals(Object o) { 845 if (!(o instanceof Node)) { 848 return false; } 850 851 if (this == o) { 852 return true; } 854 855 Node left = getRepresentation(this); 857 Node right = getRepresentation((Node) o); 858 859 if ((left instanceof FilterNode) || (right instanceof FilterNode)) { 861 return left == right; 862 } 863 864 return left.equals(right); 865 } 866 867 private static Node getRepresentation(Node n) { 868 while (n instanceof FilterNode) { 869 FilterNode fn = (FilterNode) n; 870 871 if (!fn.isDefault()) { 872 return n; 873 } 874 875 n = fn.original; 876 } 877 878 return n; } 880 881 886 public int hashCode() { 887 try { 888 assert hashCodeLogging(true) : ""; 890 int result = isDefault() ? original.hashCode() : System.identityHashCode(this); 891 assert hashCodeLogging(false) : ""; 893 return result; 894 } catch (StackError err) { 895 err.add(this); 896 throw err; 897 } 898 } 899 900 903 private static boolean hashCodeLogging(boolean enter) { 904 if (hashCodeDepth > 1000) { 905 hashCodeDepth = 0; 906 throw new StackError(); 907 } 908 909 if (enter) { 910 hashCodeDepth++; 911 } else { 912 hashCodeDepth--; 913 } 914 915 return true; 916 } 917 918 923 930 protected Node getOriginal() { 931 return original; 932 } 933 934 943 protected PropertyChangeListener createPropertyChangeListener() { 944 return new PropertyChangeAdapter(this); 945 } 946 947 953 protected NodeListener createNodeListener() { 954 return new NodeAdapter(this); 955 } 956 957 959 synchronized PropertyChangeListener getPropertyChangeListener() { 960 if (propL == null) { 961 propL = createPropertyChangeListener(); 962 } 963 964 return propL; 965 } 966 967 969 synchronized NodeListener getNodeListener() { 970 if (nodeL == null) { 971 nodeL = createNodeListener(); 972 getOriginal().addNodeListener(nodeL); 973 } 974 975 return nodeL; 976 } 977 978 981 final void listenerAdded() { 982 getNodeListener(); 983 } 984 985 989 private boolean isDefault() { 990 if (getClass() != FilterNode.class) { 992 return false; 994 } 995 996 return !childrenProvided; 997 } 998 999 1004 final void updateChildren() { 1005 if (isDefault()) { 1006 org.openide.nodes.Children newChildren = null; 1007 1008 try { 1009 Children.PR.enterReadAccess(); 1010 1011 if ((original.hierarchy == Children.LEAF) && (hierarchy != Children.LEAF)) { 1012 newChildren = Children.LEAF; 1013 } else if ((original.hierarchy != Children.LEAF) && (hierarchy == Children.LEAF)) { 1014 newChildren = new Children(original); 1015 } 1016 } finally { 1017 Children.PR.exitReadAccess(); 1018 } 1019 1020 if (newChildren != null) { 1021 final org.openide.nodes.Children set = newChildren; 1022 Children.MUTEX.postWriteRequest( 1023 new Runnable () { 1024 public void run() { 1025 setChildren(set); 1026 } 1027 } 1028 ); 1029 } 1030 } 1031 } 1032 1033 1035 private static class StackError extends StackOverflowError { 1036 private IdentityHashMap<FilterNode,FilterNode> nodes; 1037 1038 public void add(FilterNode n) { 1039 if (nodes == null) { 1040 nodes = new IdentityHashMap<FilterNode,FilterNode>(); 1041 } 1042 1043 if (!nodes.containsKey(n)) { 1044 nodes.put(n, n); 1045 } 1046 } 1047 1048 @Override 1049 public String getMessage() { 1050 StringBuffer sb = new StringBuffer (); 1051 sb.append("StackOver in FilterNodes:\n"); 1053 for (FilterNode f : nodes.keySet()) { 1054 sb.append(" class: "); sb.append(f.getClass().getName()); 1056 sb.append(" id: "); sb.append(Integer.toString(System.identityHashCode(f), 16)); 1058 sb.append("\n"); } 1060 1061 return sb.toString(); 1062 } 1063 } 1064 1065 1075 protected static class PropertyChangeAdapter extends Object implements PropertyChangeListener { 1076 private Reference <FilterNode> fn; 1077 1078 1081 public PropertyChangeAdapter(FilterNode fn) { 1082 this.fn = new WeakReference <FilterNode>(fn); 1083 } 1084 1085 1088 public final void propertyChange(PropertyChangeEvent ev) { 1089 FilterNode fn = this.fn.get(); 1090 1091 if (fn == null) { 1092 return; 1093 } 1094 1095 propertyChange(fn, ev); 1096 } 1097 1098 1103 protected void propertyChange(FilterNode fn, PropertyChangeEvent ev) { 1104 fn.firePropertyChange(ev.getPropertyName(), ev.getOldValue(), ev.getNewValue()); 1105 } 1106 } 1107 1108 1112 protected static class NodeAdapter extends Object implements NodeListener { 1113 private Reference <FilterNode> fn; 1114 1115 1118 public NodeAdapter(FilterNode fn) { 1119 this.fn = new WeakReference <FilterNode>(fn); 1120 } 1121 1122 1125 public final void propertyChange(PropertyChangeEvent ev) { 1126 FilterNode fn = this.fn.get(); 1127 1128 if (fn == null) { 1129 return; 1130 } 1131 1132 propertyChange(fn, ev); 1133 } 1134 1135 1142 protected void propertyChange(FilterNode fn, PropertyChangeEvent ev) { 1143 String n = ev.getPropertyName(); 1144 1145 if (n.equals(Node.PROP_PARENT_NODE)) { 1146 return; 1148 } 1149 1150 if (n.equals(Node.PROP_DISPLAY_NAME)) { 1151 fn.fireOwnPropertyChange(PROP_DISPLAY_NAME, (String ) ev.getOldValue(), (String ) ev.getNewValue()); 1152 1153 return; 1154 } 1155 1156 if (n.equals(Node.PROP_NAME)) { 1157 fn.fireOwnPropertyChange(PROP_NAME, (String ) ev.getOldValue(), (String ) ev.getNewValue()); 1158 1159 return; 1160 } 1161 1162 if (n.equals(Node.PROP_SHORT_DESCRIPTION)) { 1163 fn.fireOwnPropertyChange(PROP_SHORT_DESCRIPTION, (String ) ev.getOldValue(), (String ) ev.getNewValue()); 1164 1165 return; 1166 } 1167 1168 if (n.equals(Node.PROP_ICON)) { 1169 fn.fireIconChange(); 1170 1171 return; 1172 } 1173 1174 if (n.equals(Node.PROP_OPENED_ICON)) { 1175 fn.fireOpenedIconChange(); 1176 1177 return; 1178 } 1179 1180 if (n.equals(Node.PROP_PROPERTY_SETS)) { 1181 fn.firePropertySetsChange((PropertySet[]) ev.getOldValue(), (PropertySet[]) ev.getNewValue()); 1182 1183 return; 1184 } 1185 1186 if (n.equals(Node.PROP_COOKIE)) { 1187 fn.fireCookieChange(); 1188 1189 return; 1190 } 1191 1192 if (n.equals(Node.PROP_LEAF)) { 1193 fn.updateChildren(); 1194 1195 1200 } 1201 } 1202 1203 1206 public void childrenAdded(NodeMemberEvent ev) { 1207 } 1208 1209 1212 public void childrenRemoved(NodeMemberEvent ev) { 1213 } 1214 1215 1218 public void childrenReordered(NodeReorderEvent ev) { 1219 } 1220 1221 1224 public final void nodeDestroyed(NodeEvent ev) { 1225 FilterNode fn = this.fn.get(); 1226 1227 if (fn == null) { 1228 return; 1229 } 1230 1231 fn.originalDestroyed(); 1232 } 1233 } 1234 1235 1253 public static class Children extends org.openide.nodes.Children.Keys<Node> implements Cloneable { 1254 1255 protected Node original; 1256 1257 1258 private ChildrenAdapter nodeL; 1259 1260 1262 public Children(Node or) { 1263 original = or; 1264 } 1265 1266 1273 protected final void changeOriginal(Node original) { 1274 try { 1275 PR.enterWriteAccess(); 1276 1277 boolean wasAttached = nodeL != null; 1278 1279 if (wasAttached) { 1281 this.original.removeNodeListener(nodeL); 1282 nodeL = null; 1283 } 1284 1285 this.original = original; 1287 1288 if (wasAttached) { 1289 addNotifyImpl(); 1290 } 1291 } finally { 1292 PR.exitWriteAccess(); 1293 } 1294 } 1295 1296 1298 @Override 1299 protected void finalize() { 1300 if (nodeL != null) { 1301 original.removeNodeListener(nodeL); 1302 } 1303 1304 nodeL = null; 1305 } 1306 1307 1309 @Override 1310 public Object clone() { 1311 return new Children(original); 1312 } 1313 1314 1316 @Override 1317 protected void addNotify() { 1318 addNotifyImpl(); 1319 } 1320 1321 private void addNotifyImpl() { 1322 nodeL = new ChildrenAdapter(this); 1324 original.addNodeListener(nodeL); 1325 1326 updateKeys(); 1327 } 1328 1329 1331 @Override 1332 protected void removeNotify() { 1333 setKeys(Collections.<Node>emptySet()); 1334 1335 if (nodeL != null) { 1336 original.removeNodeListener(nodeL); 1337 nodeL = null; 1338 } 1339 } 1340 1341 1349 protected Node copyNode(Node node) { 1350 return node.cloneNode(); 1351 } 1352 1353 1357 @Override 1358 public Node findChild(String name) { 1359 original.getChildren().findChild(name); 1360 1361 return super.findChild(name); 1362 } 1363 1364 1372 protected Node[] createNodes(Node key) { 1373 return new Node[] { copyNode(key) }; 1375 } 1376 1377 1382 @Override 1383 @Deprecated 1384 public boolean add(Node[] arr) { 1385 return original.getChildren().add(arr); 1386 } 1387 1388 1392 @Override 1393 @Deprecated 1394 public boolean remove(Node[] arr) { 1395 return original.getChildren().remove(arr); 1396 } 1397 1398 1402 protected void filterChildrenAdded(NodeMemberEvent ev) { 1403 updateKeys(); 1404 } 1405 1406 1410 protected void filterChildrenRemoved(NodeMemberEvent ev) { 1411 updateKeys(); 1412 } 1413 1414 1418 protected void filterChildrenReordered(NodeReorderEvent ev) { 1419 updateKeys(); 1420 } 1421 1422 1425 1426 1428 1429 private void updateKeys() { 1430 ChildrenAdapter runnable = nodeL; 1431 1432 if (runnable != null) { 1433 runnable.run(); 1434 } 1435 } 1436 1437 1445 @Override 1446 public Node[] getNodes(boolean optimalResult) { 1447 if (optimalResult) { 1448 setKeys(original.getChildren().getNodes(true)); 1449 } 1450 1451 return getNodes(); 1452 } 1453 } 1454 1455 1460 private static class ChildrenAdapter extends Object implements NodeListener, Runnable { 1461 1464 private Reference <Children> children; 1465 1466 1469 public ChildrenAdapter(Children ch) { 1470 this.children = new WeakReference <Children>(ch); 1471 } 1472 1473 1475 public void run() { 1476 Children ch = children.get(); 1477 1478 if (ch != null) { 1479 Node[] arr = ch.original.getChildren().getNodes(); 1480 ch.setKeys(arr); 1481 } 1482 } 1483 1484 1487 public void propertyChange(PropertyChangeEvent ev) { 1488 } 1489 1490 1493 public void childrenAdded(NodeMemberEvent ev) { 1494 Children children = this.children.get(); 1495 1496 if (children == null) { 1497 return; 1498 } 1499 1500 children.filterChildrenAdded(ev); 1501 } 1502 1503 1506 public void childrenRemoved(NodeMemberEvent ev) { 1507 Children children = this.children.get(); 1508 1509 if (children == null) { 1510 return; 1511 } 1512 1513 children.filterChildrenRemoved(ev); 1514 } 1515 1516 1519 public void childrenReordered(NodeReorderEvent ev) { 1520 Children children = this.children.get(); 1521 1522 if (children == null) { 1523 return; 1524 } 1525 1526 children.filterChildrenReordered(ev); 1527 } 1528 1529 1532 public void nodeDestroyed(NodeEvent ev) { 1533 } 1534 } 1535 1536 1538 private static final class FilterHandle implements Node.Handle { 1539 static final long serialVersionUID = 7928908039428333839L; 1540 private Node.Handle original; 1541 1542 public FilterHandle(Node.Handle original) { 1543 this.original = original; 1544 } 1545 1546 public Node getNode() throws IOException { 1547 return new FilterNode(original.getNode()); 1548 } 1549 1550 @Override 1551 public String toString() { 1552 return "FilterHandle[" + original + "]"; } 1554 } 1555 1556 1558 private static final class FilterLookup extends Lookup { 1559 1560 private FilterNode node; 1561 1562 1563 private Lookup delegate; 1564 1565 1566 private Set<ProxyResult> results; 1567 1568 FilterLookup() { 1569 } 1570 1571 1573 public void ownNode(FilterNode n) { 1574 this.node = n; 1575 } 1576 1577 1580 private <T> T replaceNodes(T orig, Class <T> clazz) { 1581 if (isNodeQuery(clazz) && (orig == node.getOriginal()) && clazz.isInstance(node)) { 1582 return clazz.cast(node); 1583 } else { 1584 return orig; 1585 } 1586 } 1587 1588 1591 public Lookup checkNode() { 1592 Lookup l = node.getOriginal().getLookup(); 1593 1594 if (delegate == l) { 1595 return l; 1596 } 1597 1598 Iterator<ProxyResult> toCheck = null; 1599 1600 synchronized (this) { 1601 if (l != delegate) { 1602 this.delegate = l; 1603 1604 if (results != null) { 1605 toCheck = new ArrayList<ProxyResult>(results).iterator(); 1606 } 1607 } 1608 } 1609 1610 if (toCheck != null) { 1611 1613 while (toCheck.hasNext()) { 1614 ProxyResult p = toCheck.next(); 1615 1616 if (p.updateLookup(l)) { 1617 p.resultChanged(null); 1618 } 1619 } 1620 } 1621 1622 return delegate; 1623 } 1624 1625 public <T> Result<T> lookup(Template<T> template) { 1626 ProxyResult<T> p = new ProxyResult<T>(template); 1627 1628 synchronized (this) { 1629 if (results == null) { 1630 results = new WeakSet<ProxyResult>(); 1631 } 1632 1633 results.add(p); 1634 } 1635 1636 return p; 1637 } 1638 1639 public <T> T lookup(Class <T> clazz) { 1640 T result = checkNode().lookup(clazz); 1641 1642 if (result == null && clazz.isInstance(node)) { 1643 result = clazz.cast(node); 1644 } 1645 1646 return replaceNodes(result, clazz); 1647 } 1648 1649 1653 private static boolean isNodeQuery(Class <?> c) { 1654 return Node.class.isAssignableFrom(c) || c.isAssignableFrom(Node.class); 1655 } 1656 1657 @Override 1658 public <T> Item<T> lookupItem(Template<T> template) { 1659 boolean nodeQ = isNodeQuery(template.getType()); 1660 Item<T> i = checkNode().lookupItem(template); 1661 1662 if ( 1663 nodeQ && 1664 i == null && 1665 template.getType().isInstance(node) && 1666 (template.getInstance() == null || template.getInstance() == node) 1667 ) { 1668 i = checkNode().lookupItem(wackohacko(template.getId(), template.getInstance())); 1669 } 1670 1671 return nodeQ && i != null ? new FilterItem<T>(i, template.getType()) : i; 1672 } 1673 1674 @SuppressWarnings ("unchecked") private static <T> Lookup.Template<T> wackohacko(String id, T instance) { 1676 return new Lookup.Template(Node.class, id, instance); 1677 } 1678 1679 1684 private final class ProxyResult<T> extends Result<T> implements LookupListener { 1685 1686 private Template<T> template; 1687 1688 1689 private Lookup.Result<T> delegate; 1690 1691 1692 private javax.swing.event.EventListenerList listeners; 1693 1694 1695 ProxyResult(Template<T> template) { 1696 this.template = template; 1697 } 1698 1699 1701 private Result<T> checkResult() { 1702 updateLookup(checkNode()); 1703 1704 return this.delegate; 1705 } 1706 1707 1710 public boolean updateLookup(Lookup l) { 1711 Collection<? extends Item<T>> oldPairs = (delegate != null) ? delegate.allItems() : null; 1712 1713 synchronized (this) { 1714 if (delegate != null) { 1715 delegate.removeLookupListener(this); 1716 } 1717 1718 delegate = l.lookup(template); 1719 1720 if (template.getType().isAssignableFrom(node.getClass()) && delegate.allItems().isEmpty()) { 1721 delegate = l.lookup(wackohacko(template.getId(), template.getInstance())); 1722 } 1723 1724 delegate.addLookupListener(this); 1725 } 1726 1727 if (oldPairs == null) { 1728 return false; 1730 } 1731 1732 Collection<? extends Item<T>> newPairs = delegate.allItems(); 1733 1734 return !oldPairs.equals(newPairs); 1735 } 1736 1737 public synchronized void addLookupListener(LookupListener l) { 1738 if (listeners == null) { 1739 listeners = new javax.swing.event.EventListenerList (); 1740 } 1741 1742 listeners.add(LookupListener.class, l); 1743 } 1744 1745 public synchronized void removeLookupListener(LookupListener l) { 1746 if (listeners != null) { 1747 listeners.remove(LookupListener.class, l); 1748 } 1749 } 1750 1751 public Collection<? extends T> allInstances() { 1752 Collection<? extends T> c = checkResult().allInstances(); 1753 1754 if (isNodeQuery(template.getType())) { 1755 List<T> ll = new ArrayList<T>(c.size()); 1756 for (T o : c) { 1757 ll.add(replaceNodes(o, template.getType())); 1758 } 1759 1760 return ll; 1761 } else { 1762 return c; 1763 } 1764 } 1765 1766 @Override 1767 public Set<Class <? extends T>> allClasses() { 1768 return checkResult().allClasses(); 1769 } 1770 1771 @Override 1772 public Collection<? extends Item<T>> allItems() { 1773 return checkResult().allItems(); 1774 } 1775 1776 1780 public void resultChanged(LookupEvent anEvent) { 1781 javax.swing.event.EventListenerList l = this.listeners; 1782 1783 if (l == null) { 1784 return; 1785 } 1786 1787 Object [] listeners = l.getListenerList(); 1788 1789 if (listeners.length == 0) { 1790 return; 1791 } 1792 1793 LookupEvent ev = new LookupEvent(this); 1794 1795 for (int i = listeners.length - 1; i >= 0; i -= 2) { 1796 LookupListener ll = (LookupListener) listeners[i]; 1797 ll.resultChanged(ev); 1798 } 1799 } 1800 } 1801 1803 1804 private final class FilterItem<T> extends Lookup.Item<T> { 1805 private Item<T> delegate; 1806 private Class <T> clazz; 1807 1808 FilterItem(Item<T> d, Class <T> clazz) { 1809 this.delegate = d; 1810 this.clazz = clazz; 1811 } 1812 1813 public String getDisplayName() { 1814 return delegate.getDisplayName(); 1815 } 1816 1817 public String getId() { 1818 return delegate.getId(); 1819 } 1820 1821 public T getInstance() { 1822 return replaceNodes(delegate.getInstance(), clazz); 1823 } 1824 1825 public Class <? extends T> getType() { 1826 return delegate.getType(); 1827 } 1828 } 1829 } 1830 } 1832 | Popular Tags |