alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2004 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.openide.src.nodes;

import java.awt.Component;
import java.beans.*;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.awt.datatransfer.Transferable;
import org.openide.DialogDisplayer;

import org.openide.ErrorManager;
import org.openide.src.*;
import org.openide.nodes.*;
import org.openide.util.NbBundle;
import org.openide.util.datatransfer.*;
import org.openide.NotifyDescriptor;


/** Node representing a Java class.
* @see ClassElement
*
* @author Petr Hamernik
*/
public class ClassElementNode extends MemberElementNode {

    /** Return value of getIconAffectingProperties method. */
    private static final String[] ICON_AFFECTING_PROPERTIES = new String[] {
                PROP_CLASS_OR_INTERFACE
            };

    /** Create a new class node.
    * @param element class element to represent
    * @param children node children
    * @param writeable true to be writable
    */
    public ClassElementNode(ClassElement element, Children children, boolean writeable) {
        super(element, children, writeable);
        setElementFormat0(((ClassElement)element).isInterface() ?
                          sourceOptions.getInterfaceElementFormat() :
                          sourceOptions.getClassElementFormat());
    }

    public org.openide.util.HelpCtx getHelpCtx () {
        if (((ClassElement)element).isClassOrInterface())
            return new org.openide.util.HelpCtx ("org.openide.src.nodes.ClassNode"); // NOI18N
        else
            return new org.openide.util.HelpCtx ("org.openide.src.nodes.InterfaceNode"); // NOI18N
    }

    /* Resolve the current icon base.
    * @return icon base string.
    */
    protected String resolveIconBase() {
        return ((ClassElement)element).isInterface() ? INTERFACE : CLASS;
    }

    /* This method is used for resolving the names of the properties,
    * which could affect the icon (such as "modifiers").
    * @return the appropriate array.
    */
    protected String[] getIconAffectingProperties() {
        return ICON_AFFECTING_PROPERTIES;
    }

    /* This method resolve the appropriate hint format for the type
    * of the element. It defines the short description.
    */
    protected ElementFormat getHintElementFormat() {
        return ((ClassElement)element).isInterface() ?
               sourceOptions.getInterfaceElementLongFormat() :
               sourceOptions.getClassElementLongFormat();
    }

    /* Creates property set for this node */
    protected Sheet createSheet () {
        Sheet sheet = Sheet.createDefault();
        Sheet.Set ps = sheet.get(Sheet.PROPERTIES);
        ps.put(createModifiersProperty(writeable));
        ps.put(createNameProperty(writeable));
        if (((ClassElement)element).isClass())
            ps.put(createSuperclassProperty(writeable));
        ps.put(createInterfacesProperty(writeable));
        return sheet;
    }

    /** Remove this class from its declaring class or source file.
    *
    * @exception IOException if the containing element refuses to delete it
    */
    public void destroy() throws IOException {
        SourceEditSupport.invokeAtomicAsUser(element, new SourceEditSupport.ExceptionalRunnable() {
                                                 public void run() throws SourceException {
                                                     ClassElement el = (ClassElement) element;
                                                     if (el.getDeclaringClass() != null) {
                                                         el.getDeclaringClass().removeClass(el);
                                                     }
                                                     else {
                                                         el.getSource().removeClass(el);
                                                     }
                                                 }
                                             });
        super.destroy();
    }

    public Component getCustomizer() {
        return new ClassCustomizer((ClassElement)element);
    }

    public boolean hasCustomizer() {
        return isWriteable();
    }

    /* Accumulate the paste types that this node can handle
    * for a given transferable.
    * 

* The default implementation simply tests whether the transferable supports * {@link NodeTransfer#nodePasteFlavor}, and if so, it obtains the paste types * from the {@link NodeTransfer.Paste transfer data} and inserts them into the set. * * @param t a transferable containing clipboard data * @param s a set of {@link PasteType}s that will have added to it all types * valid for this node */ protected void createPasteTypes (final Transferable t, java.util.List s) { if (isWriteable()) { // special case - multiple source element nodes... if (t.isDataFlavorSupported(ExTransferable.multiFlavor)) { createMultiPasteTypes(t, s, NodeTransfer.COPY); createMultiPasteTypes(t, s, NodeTransfer.MOVE); return; } for (int i = 0; i <= 1; i++) { final boolean delete = (i == 1); final Element addingElement = (Element) NodeTransfer.cookie(t, delete ? NodeTransfer.MOVE : NodeTransfer.COPY, Element.class); if (addingElement != null && isValidElement(addingElement)) { s.add(new PasteType() { public Transferable paste() throws IOException { pasteElement(addingElement, delete); return delete ? ExTransferable.EMPTY : null; } }); } } } super.createPasteTypes(t, s); } /** Checks if the element is valid. */ private static boolean isValidElement(Element el) { // not nice to call spi but there is no way to find out validity of the source element via api. Element.Impl2 impl = (Element.Impl2) el.getCookie(Element.Impl2.class); return impl == null || impl.isValid(); } private void createMultiPasteTypes(Transferable t, List s, int action) { MultiTransferObject mto; try { mto = (MultiTransferObject) t.getTransferData (ExTransferable.multiFlavor); } catch (java.awt.datatransfer.UnsupportedFlavorException ex) { return; } catch (IOException ex) { return; } int count = mto.getCount(); Collection candidates = new LinkedList(); for (int i = 0; i < count; i++) { Node n = NodeTransfer.node(mto.getTransferableAt(i), action); if (n == null) break; Element el = (Element)n.getCookie(Element.class); // filter out non-Elements and elements that cannot be pasted // to a class. if (el == null || !isValidElement(el) || !(el instanceof MemberElement || el instanceof InitializerElement)) break; // check whether one of the candidates is a parent of the node. // alternatively, the node may be parent of one of the nodes // in candidates. addNodeCandidate(candidates, el); } if (candidates.isEmpty()) return; s.add(new SourceEditSupport.ClassMultiPasteType( this, candidates, (action & NodeTransfer.MOVE) > 0)); } private void addNodeCandidate(Collection candidates, Element el) { ClassElement enc2 = findEnclosingClass(el); SourceElement enc2Src = enc2.getSource(); String fn2 = enc2.getName().getFullName(); for (Iterator it = candidates.iterator(); it.hasNext(); ) { Element can = (Element)it.next(); ClassElement enc1 = findEnclosingClass(can); if (enc1.getSource() != enc2Src) { continue; } // next, if the enclosing classes are the same... if (enc1 == enc2) { if (can == enc1) { // enc2 must be member of enc1, don't add it at all! return; } else if (el == enc2) { // can != enc1 -> can is member of enc1. // el == enc2 --> el is declaring class of `can' // replace `can' with `el'. it.remove(); // there can be more such member elements. continue; } else { // OK, there is a member of the same class ---> // there cannot be an outer class -> OK. break; } } String fn1 = enc1.getName().getFullName(); if (fn2.startsWith(fn1)) { if (enc1 == can) { // enc2 is inner class of enc1 --> do *NOT* add this element. return; } else continue; } else if (fn1.startsWith(fn2)) { if (enc2 == el) { it.remove(); continue; } else break; } } candidates.add(el); } private ClassElement findEnclosingClass(Element el) { if (el instanceof ClassElement) return (ClassElement)el; else if (el instanceof MemberElement) return ((MemberElement)el).getDeclaringClass(); else if (el instanceof InitializerElement) return ((InitializerElement)el).getDeclaringClass(); else return null; } PropertyChangeListener createElementListener() { return new ClassElementListener(); } /** Paste element into this class. * @param addingElement Element to add. * @param delete Whether element should be deleted from the original class * @exception IOException if any proble occured */ void pasteElement(final Element addingElement, final boolean delete) throws IOException { final boolean[] cancelled = {false}; // verify that the source does not enclose the target -- there's risk of recursion or // other errors. ClassElement declClazz, myDecl; if (addingElement instanceof ClassElement) { declClazz = (ClassElement)addingElement; for (myDecl = (ClassElement)element; myDecl != null; myDecl = myDecl.getDeclaringClass()) { if (declClazz == myDecl) { throw (IOException)ErrorManager.getDefault().annotate( new IOException("Recursion detected"), // NOI18N bundle.getString("ERR_RecursePaste") ); } } } SourceEditSupport.invokeAtomicAsUser(element, new SourceEditSupport.ExceptionalRunnable() { public void run() throws SourceException { ClassElement clazz = (ClassElement) element; if (addingElement instanceof InitializerElement) { InitializerElement e = (InitializerElement)addingElement; clazz.addInitializer(e); } if (addingElement instanceof FieldElement) { clazz.addField((FieldElement)addingElement); } else if (addingElement instanceof MethodElement) { MethodElement me = (MethodElement) addingElement; if (((ClassElement) element).isInterface()) { if (delete && (me.getBody() != null) && (!me.getBody().trim().equals("")) // NOI18N && (!isPastingConfirmed(me))) { cancelled[0] = true; return; } me = (MethodElement) me.clone(); me.setBody(null); } else if (me.getBody() == null) { me = (MethodElement) me.clone(); me.setBody(""); // NOI18N } clazz.addMethod(me); } else if (addingElement instanceof ConstructorElement) { clazz.addConstructor((ConstructorElement)addingElement); } else if (addingElement instanceof ClassElement) { ClassElement pclass = (ClassElement)addingElement; ClassElement myClass; clazz.addClass(pclass); myClass = clazz.getClass(Identifier.create(pclass.getName().getName())); if (pclass.getDeclaringClass() == null && myClass != null) { // if top-level class is pasted as an inner class, // maintain the static modifier. myClass.setModifiers(myClass.getModifiers() | Modifier.STATIC); } } } }); if (delete && (!cancelled[0])) { final ClassElement origClazz; SourceElement src = null; if (addingElement instanceof InitializerElement) { origClazz = ((InitializerElement)addingElement).getDeclaringClass(); } else if (addingElement instanceof MemberElement) { origClazz = ((MemberElement)addingElement).getDeclaringClass(); if (addingElement instanceof ClassElement) { ClassElement me = (ClassElement)addingElement; src = me.getSource(); } } else { origClazz = null; } if (src == null && origClazz != null) { src = origClazz.getSource(); } final SourceElement classSource = src; SourceEditSupport.ExceptionalRunnable r = new SourceEditSupport.ExceptionalRunnable() { public void run() throws SourceException { if (addingElement instanceof InitializerElement) { InitializerElement e = (InitializerElement)addingElement; if (origClazz != null) origClazz.removeInitializer(e); } else if (addingElement instanceof MemberElement) { if (origClazz != null) { if (addingElement instanceof FieldElement) { origClazz.removeField((FieldElement)addingElement); } else if (addingElement instanceof MethodElement) { origClazz.removeMethod((MethodElement)addingElement); } else if (addingElement instanceof ConstructorElement) { origClazz.removeConstructor((ConstructorElement)addingElement); } else if (addingElement instanceof ClassElement) { origClazz.removeClass((ClassElement)addingElement); } } else if ((addingElement instanceof ClassElement) && classSource != null) { classSource.removeClass((ClassElement)addingElement); } } } }; if (src == null) { try { r.run(); } catch (SourceException e) { throw new IOException(e.getMessage()); } } else { SourceEditSupport.invokeAtomicAsUser(addingElement, r); } } } /** * Creates a dialog warning the user that the body of the method which * is to be cut and pasted from a class into an interface will be lost. * * @param me the cut and pasted method * @return whether the user confirmed the action. */ private boolean isPastingConfirmed(MethodElement me) { String title = NbBundle.getMessage(ClassElementNode.class, "TIT_PastingMethod"); String text = NbBundle.getMessage(ClassElementNode.class, "CONFIRM_DeleteMethodBody", me.getName()); NotifyDescriptor desc = new NotifyDescriptor.Confirmation( text, title, NotifyDescriptor.YES_NO_OPTION); return NotifyDescriptor.YES_OPTION.equals (DialogDisplayer.getDefault().notify(desc)); } /** Create a node property for the superclass of this class. * @param canW if false, property will be read-only * @return the property */ protected Node.Property createSuperclassProperty(boolean canW) { return new ElementProp(PROP_SUPERCLASS, String.class, canW) { /** Gets the value */ public Object getValue () { Identifier id = ((ClassElement)element).getSuperclass(); return id == null ? "" : id.getFullName(); // NOI18N } /** Sets the value */ public void setValue(final Object val) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { super.setValue(val); if (!(val instanceof String)) throw new IllegalArgumentException(); final String str = ((String)val).trim(); if (str != null && !"".equals(str)) { Type t = Type.parse(str); if (!t.isClass()) throw new IllegalArgumentException(); } runAtomic(element, new SourceEditSupport.ExceptionalRunnable() { public void run() throws SourceException { Identifier superclass = str.equals("") ? null: Identifier.create(str); // NOI18N ((ClassElement)element).setSuperclass(superclass); } }); } }; } /** Create a node property for the implemented interfaces of this class. * (Or, extended interfaces if this is itself an interface.) * @param canW if false, property will be read-only * @return the property */ protected Node.Property createInterfacesProperty(boolean canW) { ElementProp prop = new ElementProp(PROP_INTERFACES, Identifier[].class, canW) { /** Gets the value */ public Object getValue () { return ((ClassElement)element).getInterfaces(); } /** Sets the value */ public void setValue(final Object val) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { super.setValue(val); if (!(val instanceof Identifier[])) throw new IllegalArgumentException(); runAtomic(element, new SourceEditSupport.ExceptionalRunnable() { public void run() throws SourceException { ((ClassElement)element).setInterfaces((Identifier[])val); } }); } }; if (((ClassElement)element).isInterface()) { prop.setDisplayName(bundle.getString("PROP_superInterfaces")); prop.setShortDescription(bundle.getString("HINT_superInterfaces")); } prop.setValue("changeImmediate" /* PropertyEnv.PROP_CHANGE_IMMEDIATE */,Boolean.FALSE); return prop; } public NewType[] getNewTypes() { if (writeable) { return SourceEditSupport.createNewTypes((ClassElement)element); } else { return super.getNewTypes(); } } public Transferable clipboardCopy() { Transferable t = NodeTransfer.transferable(this, NodeTransfer.CLIPBOARD_COPY); ExTransferable xt = ExTransferable.create(t); xt.put(NodeTransfer.createPaste(new SourceEditSupport.PackagePaste( (ClassElement)this.element, false ))); return xt; } public Transferable clipboardCut() { Transferable t = NodeTransfer.transferable(this, NodeTransfer.CLIPBOARD_CUT); ExTransferable xt = ExTransferable.create(t); xt.put(NodeTransfer.createPaste(new SourceEditSupport.PackagePaste( (ClassElement)this.element, true ))); return xt; } private class ClassElementListener extends ElementListener { public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals(ElementProperties.PROP_CLASS_OR_INTERFACE)) { setElementFormat(((ClassElement)element).isClass() ? sourceOptions.getClassElementFormat() : sourceOptions.getInterfaceElementFormat()); } super.propertyChange(evt); } } }

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.