1 19 20 package org.netbeans.modules.java.ui.nodes.elements; 21 22 import java.beans.*; 23 import java.io.IOException ; 24 import java.lang.reflect.InvocationTargetException ; 25 import java.lang.ref.WeakReference ; 26 import java.lang.ref.Reference ; 27 import java.lang.ref.SoftReference ; 28 import java.util.*; 29 30 import org.openide.nodes.*; 31 import org.openide.util.*; 32 import org.openide.util.lookup.InstanceContent; 33 import org.openide.util.lookup.AbstractLookup; 34 import org.openide.util.actions.SystemAction; 35 import org.openide.ErrorManager; 36 import org.openide.text.PositionBounds; 37 import org.openide.cookies.OpenCookie; 38 import org.openide.cookies.SaveCookie; 39 import org.openide.loaders.DataObject; 40 import org.openide.src.ElementProperties; 41 import org.netbeans.modules.java.ui.nodes.editors.*; 42 import org.netbeans.modules.java.JavaEditor; 43 import org.netbeans.modules.javacore.internalapi.JavaMetamodel; 44 import org.netbeans.jmi.javamodel.*; 45 import org.netbeans.jmi.javamodel.Type; 46 import org.netbeans.api.mdr.events.MDRChangeListener; 47 import org.netbeans.api.mdr.events.MDRChangeEvent; 48 import org.netbeans.api.mdr.events.AttributeEvent; 49 import org.netbeans.api.mdr.events.MDRChangeSource; 50 51 import javax.jmi.reflect.JmiException; 52 import javax.swing.*; 53 54 70 public abstract class ElementNode extends AbstractNode implements IconStrings, ElementProperties2 { 71 72 private static ElementFormat invalidFormat; 73 74 75 private static final String [] ICON_AFFECTING_PROPERTIES = new String [] { 76 PROP_MODIFIERS 77 }; 78 79 80 protected Element element; 81 82 83 protected ElementFormat elementFormat = new ElementFormat (""); 85 86 protected boolean writeable; 87 88 private SystemAction preferredAction; 89 90 private JMIElementListener wElementL; 91 92 private final InstanceContent lkpContent; 93 94 101 public ElementNode(Element element, Children children, boolean writeable) { 102 this(element, children, writeable, new InstanceContent()); 103 } 104 105 private ElementNode(Element element, Children children, boolean writeable, InstanceContent ic) { 106 super(children, new AbstractLookup(ic)); 107 this.element = element; 108 this.writeable = writeable; 109 this.lkpContent = ic; 110 setIconBase(resolveIconBase()); 111 setDisplayName(getElementFormat().format(element)); 112 setShortDescription(getHintElementFormat().format(element)); 113 if (element instanceof MDRChangeSource) { 114 wElementL = (JMIElementListener) createJMIElementListener(); 115 ((MDRChangeSource) element).addListener(wElementL); 116 } 117 displayFormat = null; 118 119 ic.add(new OpenCookieImpl(this)); ic.add(element); 122 Resource r = this.element.getResource(); 123 DataObject dobj = JavaMetamodel.getManager().getDataObject(r); 124 if (dobj != null) { 125 ic.add(dobj); dobj.addPropertyChangeListener(new DOListener(this, dobj)); } 128 } 129 130 public void destroy() throws IOException { 131 boolean fail = true; 132 try { 133 JavaMetamodel.getDefaultRepository().beginTrans(true); 134 try { 135 element.refDelete(); 136 fail = false; 137 } finally { 138 JavaMetamodel.getDefaultRepository().endTrans(fail); 139 } 140 } catch (JmiException e) { 141 IOException ioe = new IOException (); 142 ioe.initCause(e); 143 throw ioe; 144 } 145 super.destroy(); 146 } 147 148 156 abstract protected String resolveIconBase(); 157 158 162 protected String [] getIconAffectingProperties() { 163 return ICON_AFFECTING_PROPERTIES; 164 } 165 166 172 public final ElementFormat getElementFormat() { 173 return elementFormat; 174 } 175 176 181 public final void setElementFormat(ElementFormat elementFormat) { 182 setDisplayName(elementFormat.format(this.element)); 183 this.elementFormat = elementFormat; 184 } 185 186 191 protected abstract ElementFormat getElementFormatProperty(); 192 193 final void setElementFormat0(ElementFormat elementFormat) { 194 try { 195 setElementFormat(elementFormat); 196 } catch (IllegalArgumentException iae) { 197 setElementFormat(getInvalidFormat()); 198 } 199 } 200 201 static ElementFormat getInvalidFormat() { 202 if (invalidFormat != null) 203 return invalidFormat; 204 return invalidFormat = new ElementFormat(getString("FMT_InvalidFormat")); } 206 207 210 abstract protected ElementFormat getHintElementFormat(); 211 212 217 public boolean canRename() { 218 return false; 219 } 220 221 226 public boolean canDestroy () { 227 return isWriteable(); 228 } 229 230 234 public boolean canCopy () { 235 return false; 236 } 237 238 242 public boolean canCut () { 243 return false; 244 } 246 247 251 public void setActions(SystemAction[] actions, SystemAction preferred) { 252 systemActions = actions; 253 this.preferredAction = preferred; 254 } 255 256 public Action getPreferredAction() { 257 Action a = preferredAction; 258 if (a == null) { 259 a = super.getPreferredAction(); 260 } 261 return a; 262 } 263 264 267 void superFireCookieChange() { 268 fireCookieChange(); 269 } 270 271 274 public boolean equals (Object o) { 275 return (o instanceof ElementNode) && (element.equals (((ElementNode)o).element)); 276 } 277 278 281 public int hashCode () { 282 return element.hashCode (); 283 } 284 285 boolean isWriteable() { 286 return writeable && SourceEditSupport.isWriteable(element); 287 } 288 289 void superSetName(String name) { 290 super.setName(name); 291 } 292 293 void superPropertyChange (String name, Object o, Object n) { 294 super.firePropertyChange (name, o, n); 295 } 296 297 void superShortDescriptionChange (String o, String n) { 298 super.fireShortDescriptionChange(o, n); 299 } 300 301 MDRChangeListener createJMIElementListener() { 302 JMIElementListener l = new JMIElementListener(this); 303 return l; 304 } 305 306 313 protected ChangeDescriptor handleAttributeChange(AttributeEvent ae) { 314 final Object src = ae.getSource(); 315 ChangeDescriptor cd = new ChangeDescriptor(); 316 if (src != element || !((Element) src).isValid()) { 317 return cd; 318 } 319 320 322 String attrName = ae.getAttributeName(); 323 String propName = mapAttributeName(attrName); 324 if (propName == null) { 325 cd.displayName = getElementFormat().format(element); 326 cd.shortDescription = getHintElementFormat().format(element); 327 cd.iconBase = resolveIconBase(); 328 } else { 329 if (getElementFormat().dependsOnProperty(propName)) { 331 cd.displayName = getElementFormat().format(element); 332 } 333 334 String [] iconProps = getIconAffectingProperties(); 336 for (int i = 0; i < iconProps.length; i++) { 337 if (iconProps[i].equals(propName)) { 338 cd.iconBase = resolveIconBase(); 339 break; 340 } 341 } 342 343 if (propName.equals(ElementProperties.PROP_NAME)) { 344 cd.name = ((NamedElement) element).getName(); 345 } 346 347 if (getHintElementFormat().dependsOnProperty(propName)) { 349 cd.shortDescription = getHintElementFormat().format(element); 350 } 351 } 352 return cd; 353 } 354 355 361 protected void processChange(ChangeDescriptor desc) { 362 if (desc.displayName != null) 363 setDisplayName(desc.displayName); 364 if (desc.iconBase != null) 365 setIconBase(desc.iconBase); 366 if (desc.name != null) 367 superSetName(desc.name); 368 if (desc.shortDescription != null) 369 setShortDescription(desc.shortDescription); 370 if (desc.sheet != null) { 371 setSheet(desc.sheet); 372 } 373 } 374 375 379 protected abstract Map getAttributeNameMap(); 380 381 382 final String mapAttributeName(String name) { 383 assert name != null; 384 String property = (String ) getAttributeNameMap().get(name); 385 return (property == null)? name: property; 386 } 387 388 static String getString(String key) { 389 return NbBundle.getMessage(ElementNode.class, key); 390 } 391 392 private static void fireChangesInAWTThread(final ElementNode n, final ChangeDescriptor cd) { 393 Mutex.EVENT.writeAccess(new Runnable () { 394 public void run() { 395 n.processChange(cd); 396 } 397 }); 398 } 399 400 private DataObject getDataObject() { 401 return (DataObject) this.getCookie(DataObject.class); 402 } 403 404 406 static final class JMIElementListener extends WeakReference implements MDRChangeListener, Runnable { 407 408 private final Element element; 409 410 public JMIElementListener(ElementNode referent) { 411 super(referent, Utilities.activeReferenceQueue()); 412 this.element = referent.element; 413 } 414 415 public void change(MDRChangeEvent e) { 416 final ElementNode n = (ElementNode) get(); 417 if (n == null) return; 418 if (!e.isOfType(AttributeEvent.EVENTMASK_ATTRIBUTE)) return; 419 final AttributeEvent ae = (AttributeEvent) e; 420 421 String attrName = ae.getAttributeName(); 422 try { 423 JavaMetamodel.getDefaultRepository().beginTrans(false); 424 ChangeDescriptor cd; 425 try { 426 cd = n.handleAttributeChange(ae); 427 } finally { 428 JavaMetamodel.getDefaultRepository().endTrans(false); 429 } 430 431 assert cd != null; 432 fireChangesInAWTThread(n, cd); 433 fireRegisteredProperties(attrName); 434 } catch (JmiException ex) { 435 ErrorManager.getDefault().notify(ErrorManager.WARNING, ex); 436 } 437 } 438 439 public void run() { 440 ((MDRChangeSource) this.element).removeListener(this); 441 } 442 443 private void fireRegisteredProperties(String name) { 444 final ElementNode n = (ElementNode) get(); 445 if (n == null) return; 446 if (name == null || (name = (String ) n.getAttributeNameMap().get(name)) != null) { 447 n.superPropertyChange(name, null, null); 448 } 449 } 450 451 } 452 453 final static class ChangeDescriptor { 454 String displayName; 455 String name; 456 String iconBase; 457 String shortDescription; 458 459 Sheet sheet; 460 461 public ChangeDescriptor(String displayName, String iconBase, String name, String shortDescription) { 462 this.displayName = displayName; 463 this.iconBase = iconBase; 464 this.name = name; 465 this.shortDescription = shortDescription; 466 this.sheet = null; 467 } 468 469 public ChangeDescriptor() { 470 } 471 } 472 473 475 477 static abstract class ElementProp extends PropertySupport { 478 479 480 private Reference editor = null; 481 482 489 public ElementProp(String name, java.lang.Class type, boolean canW) { 490 super(name, type, 491 getString("PROP_" + name), getString("HINT_" + name), true, canW); 494 } 495 496 503 public void setValue (Object val) throws IllegalArgumentException , 504 IllegalAccessException , InvocationTargetException { 505 if (!canWrite()) 506 throw new IllegalAccessException (getString("MSG_Cannot_Write")); } 508 509 public final PropertyEditor getPropertyEditor() { 510 PropertyEditor pe; 511 if (editor == null || (pe = (PropertyEditor) editor.get()) == null) { 512 pe = createPropertyEditor(); 513 editor = new SoftReference (pe); 514 } 515 return pe; 516 } 517 518 522 protected PropertyEditor createPropertyEditor() { 523 return super.getPropertyEditor(); 524 } 525 526 } 527 528 532 public static Node.Property createNameProperty(NamedElement element) { 533 Node.Property prop = new NameProperty(element); 534 return prop; 535 } 536 537 542 public static Node.Property createParametersProperty(CallableFeature element, boolean canW) { 543 Node.Property prop = new ParametersProperty(element, canW); 544 setModel(element, prop); 545 return prop; 546 } 547 548 553 public static Node.Property createExceptionsProperty(CallableFeature element, boolean canW) { 554 Node.Property prop = new ExceptionsProperty(element, canW); 555 setModel(element, prop); 556 return prop; 557 } 558 559 565 public static Node.Property createTypeProperty(String name, TypedElement element, boolean canW) { 566 Node.Property prop = new TypeProperty(name, element, canW); 567 setModel(element, prop); 568 return prop; 569 } 570 571 577 public static Node.Property createTypeParametersProperty(String name, GenericElement element, boolean canW) { 578 Node.Property prop = new TypeParametersProperty(name, element, canW); 579 setModel(element, prop); 580 return prop; 581 } 582 583 588 public static Node.Property createModifiersProperty(ClassMember element, boolean canW) { 589 int mask; 590 try { 591 mask = SourceEditSupport.getModifiersMask(element); 592 } catch (JmiException e) { 593 ErrorManager.getDefault().notify(ErrorManager.WARNING, e); 594 mask = 0xFFFF; 595 } 596 return createModifiersProperty(element, canW, mask); 597 } 598 599 605 public static Node.Property createModifiersProperty(ClassMember element, boolean canW, int mask) { 606 Node.Property prop = new ModifiersProperty(element, canW, mask); 607 setModel(element, prop); 608 return prop; 609 } 610 611 612 public static void setModel(org.netbeans.jmi.javamodel.Element el, FeatureDescriptor fd) { 613 JavaModelPackage model = JavaMetamodel.getManager().getJavaExtent(el); 614 fd.setValue("JavaModelPackage", model); } 616 617 618 public static JavaModelPackage getModel(FeatureDescriptor fd) { 619 JavaModelPackage model = (JavaModelPackage) fd.getValue("JavaModelPackage"); if (model == null) { 621 model = JavaMetamodel.getManager().getDefaultExtent(); 622 ErrorManager.getDefault().notify( 623 ErrorManager.INFORMATIONAL, 624 new IllegalStateException ("missing JavaModelPackage")); } 626 return model; 627 } 628 629 636 protected Node.Property createModifiersProperty(boolean canW) { 637 Node.Property p = createModifiersProperty((ClassMember) element, canW); 638 p.setValue("changeImmediate" ,Boolean.FALSE); return p; 640 } 641 642 643 protected static SourceOptions getSourceOptions() { 644 return SourceOptions.getInstance(); 645 } 646 647 private final static class ParametersProperty extends ElementProp { 648 649 private final CallableFeature element; 650 651 private ParametersProperty(CallableFeature element, boolean canW) { 652 super(PROP_PARAMETERS, Parameter[].class, canW); 653 this.element = element; 654 } 655 656 public Object getValue() { 657 List l = element.getParameters(); 658 return (Parameter[]) l.toArray(new Parameter[l.size()]); 659 } 660 661 public PropertyEditor createPropertyEditor() { 662 return new MethodParameterArrayEditor(canWrite()); 663 } 664 665 public void setValue(final Object val) throws IllegalArgumentException , 666 IllegalAccessException , InvocationTargetException { 667 668 super.setValue(val); 669 if (!(val instanceof Parameter[])) 670 throw new IllegalArgumentException (); 671 672 boolean fail = true; 673 try { 674 JavaMetamodel.getDefaultRepository().beginTrans(true); 675 try { 676 List l = element.getParameters(); 677 l.clear(); 678 l.addAll(Arrays.asList((Parameter[]) val)); 679 fail = false; 680 } finally { 681 JavaMetamodel.getDefaultRepository().endTrans(fail); 682 } 683 } catch (JmiException e) { 684 IllegalArgumentException iae = new IllegalArgumentException (); 685 iae.initCause(e); 686 throw iae; 687 } 688 } 689 690 } 691 692 private final static class ExceptionsProperty extends ElementProp { 693 694 private final CallableFeature element; 695 696 public ExceptionsProperty(CallableFeature element, boolean canW) { 697 super(PROP_EXCEPTIONS, MultipartId[].class, canW); 698 this.element = element; 699 } 700 701 protected PropertyEditor createPropertyEditor() { 702 return new IdentifierArrayEditor(); 703 } 704 705 public Object getValue () { 706 Object ret = null; 707 try { 708 JavaMetamodel.getDefaultRepository().beginTrans(false); 709 try { 710 if (element.isValid()) { 711 List l = element.getExceptionNames(); 712 ret = l.toArray(new MultipartId[l.size()]); 713 } 714 } finally { 715 JavaMetamodel.getDefaultRepository().endTrans(); 716 } 717 } catch (JmiException e) { 718 ErrorManager.getDefault().notify(e); 719 } 720 return ret; 721 } 722 723 public void setValue(final Object val) throws IllegalArgumentException , 724 IllegalAccessException , InvocationTargetException { 725 super.setValue(val); 726 if (!(val instanceof MultipartId[])) 727 throw new IllegalArgumentException (); 728 729 boolean fail = true; 730 try { 731 JavaMetamodel.getDefaultRepository().beginTrans(true); 732 try { 733 List exs = element.getExceptionNames(); 734 exs.clear(); 735 exs.addAll(Arrays.asList((MultipartId[]) val)); 736 fail = false; 737 } finally { 738 JavaMetamodel.getDefaultRepository().endTrans(fail); 739 } 740 } catch (JmiException e) { 741 IllegalArgumentException iae = new IllegalArgumentException (); 742 iae.initCause(e); 743 throw iae; 744 } 745 } 746 } 747 748 private final static class TypeProperty extends ElementProp { 749 750 private final TypedElement element; 751 752 public TypeProperty(String propName, TypedElement element, boolean canW) { 753 super(propName, Type.class, canW); 754 this.element = element; 755 } 756 757 public PropertyEditor createPropertyEditor() { 758 return new TypeEditor(); 759 } 760 761 public Object getValue () { 762 return element.getType(); 763 } 764 765 public void setValue(Object val) throws IllegalArgumentException , 766 IllegalAccessException , InvocationTargetException { 767 768 super.setValue(val); 769 if (!(val instanceof Type)) 770 throw new IllegalArgumentException (); 771 772 Type type = (Type) val; 773 774 boolean fail = true; 775 try { 776 JavaMetamodel.getDefaultRepository().beginTrans(true); 777 try { 778 element.setType(type); 779 fail = false; 780 } finally { 781 JavaMetamodel.getDefaultRepository().endTrans(fail); 782 } 783 } catch (JmiException e) { 784 IllegalArgumentException iae = new IllegalArgumentException (); 785 iae.initCause(e); 786 ErrorManager.getDefault().annotate(iae, ErrorManager.USER, null, 787 NbBundle.getMessage(FieldNode.class, "MSG_InvalidTypeDecl"), null, null); throw iae; 789 } 790 } 791 } 792 793 private final static class TypeParametersProperty extends ElementProp { 794 795 private final GenericElement element; 796 797 public TypeParametersProperty(String name, GenericElement element, boolean canW) { 798 super(name, TypeParameter[].class, false); 799 this.element = element; 800 } 801 802 protected PropertyEditor createPropertyEditor() { 803 return new TypeParameterArrayEditor(); 804 } 805 806 public Object getValue() throws IllegalAccessException , InvocationTargetException { 807 return element.getTypeParameters().toArray(new TypeParameter[0]); 808 } 809 810 public void setValue(Object val) throws IllegalArgumentException , 811 IllegalAccessException , InvocationTargetException { 812 throw new InvocationTargetException (new UnsupportedOperationException ()); 813 } 814 } 815 816 private final static class ModifiersProperty extends ElementProp { 817 818 private final ClassMember element; 819 private final int mask; 820 821 private ModifiersProperty(ClassMember element, boolean canW, int mask) { 822 super(PROP_MODIFIERS, Integer .class, canW); 823 this.element = element; 824 this.mask = mask; 825 } 826 827 828 public Object getValue () { 829 return new Integer (element.getModifiers()); 830 } 831 832 833 public void setValue(final Object val) throws IllegalArgumentException , 834 IllegalAccessException , InvocationTargetException { 835 super.setValue(val); 836 837 if (!(val instanceof Integer )) 838 throw new IllegalArgumentException (); 839 840 int m = ((Integer ) val).intValue(); 841 int oldVal = element.getModifiers(); 842 int newVal = (m & mask) + (oldVal & ~mask); 843 element.setModifiers(newVal); 844 } 845 846 847 public PropertyEditor createPropertyEditor () { 848 return new ModifierEditor(mask); 850 } 851 } 852 853 private static final class NameProperty extends ElementProp { 854 855 private final NamedElement element; 856 857 public NameProperty(NamedElement element) { 858 super(ElementProperties.PROP_NAME, String .class, false); 859 this.element = element; 860 } 861 862 public Object getValue () { 863 return element.getName(); 864 } 865 } 866 867 private static final class OpenCookieImpl implements OpenCookie { 868 869 private final ElementNode node; 870 871 public OpenCookieImpl(ElementNode node) { 872 this.node = node; 873 } 874 875 public void open() { 876 try { 877 DataObject d = node.getDataObject(); 878 PositionBounds bounds = JavaMetamodel.getManager().getElementPosition(node.element); 879 if (bounds == null) 880 return; 881 ((JavaEditor) d.getCookie(JavaEditor.class)).openAt(bounds.getBegin()); 882 } catch (javax.jmi.reflect.InvalidObjectException e) { 883 } 884 } 885 886 } 887 888 private static final class DOListener extends WeakReference implements PropertyChangeListener, Runnable { 889 890 private DataObject dobj; 891 892 public DOListener(ElementNode referent, DataObject dobj) { 893 super(referent, Utilities.activeReferenceQueue()); 894 this.dobj = dobj; 895 updateCookies(dobj, referent); 896 } 897 898 public void initialize() { 899 } 900 901 public void propertyChange(PropertyChangeEvent evt) { 902 String pname = evt.getPropertyName(); 903 ElementNode en = (ElementNode) get(); 904 if (en == null) { 905 return; 906 } 907 if (pname == null || DataObject.PROP_COOKIE.equals(pname)) { 908 updateCookies(dobj, en); 909 } 910 } 911 912 private static void updateCookies(DataObject dobj, ElementNode en) { 913 SaveCookie dsc = (SaveCookie) dobj.getCookie(SaveCookie.class); 914 SaveCookie nsc = (SaveCookie) en.getLookup().lookup(SaveCookie.class); 915 if (dsc != nsc) { 916 if (nsc != null) { 917 en.lkpContent.remove(nsc); 918 } 919 if (dsc != null) { 920 en.lkpContent.add(dsc); 921 } 922 } 923 } 924 925 public void run() { 926 dobj.removePropertyChangeListener(this); 927 } 928 929 } 930 } 931 | Popular Tags |