1 19 package org.netbeans.modules.java.editor.codegen; 20 21 import com.sun.source.tree.BlockTree; 22 import com.sun.source.tree.ClassTree; 23 import com.sun.source.tree.ExpressionTree; 24 import com.sun.source.tree.MethodTree; 25 import com.sun.source.tree.Scope; 26 import com.sun.source.tree.StatementTree; 27 import com.sun.source.tree.Tree; 28 import com.sun.source.tree.TypeParameterTree; 29 import com.sun.source.tree.VariableTree; 30 import com.sun.source.util.SourcePositions; 31 import com.sun.source.util.TreePath; 32 import com.sun.source.util.Trees; 33 import java.awt.Dialog ; 34 import java.io.IOException ; 35 import java.util.ArrayList ; 36 import java.util.Collections ; 37 import java.util.EnumSet ; 38 import java.util.Iterator ; 39 import java.util.LinkedHashMap ; 40 import java.util.List ; 41 import java.util.Map ; 42 import java.util.Set ; 43 import javax.lang.model.element.Element; 44 import javax.lang.model.element.ExecutableElement; 45 import javax.lang.model.element.Modifier; 46 import javax.lang.model.element.TypeElement; 47 import javax.lang.model.element.VariableElement; 48 import javax.lang.model.type.DeclaredType; 49 import javax.lang.model.type.ExecutableType; 50 import javax.lang.model.type.TypeKind; 51 import javax.lang.model.type.TypeMirror; 52 import javax.lang.model.util.ElementFilter; 53 import javax.lang.model.util.Elements; 54 import javax.swing.text.JTextComponent ; 55 import org.netbeans.api.java.source.CancellableTask; 56 import org.netbeans.api.java.source.CompilationController; 57 import org.netbeans.api.java.source.ElementHandle; 58 import org.netbeans.api.java.source.JavaSource; 59 import org.netbeans.api.java.source.TreeMaker; 60 import org.netbeans.api.java.source.WorkingCopy; 61 import org.netbeans.modules.editor.java.Utilities; 62 import org.netbeans.modules.java.editor.codegen.ui.DelegatePanel; 63 import org.netbeans.modules.java.editor.codegen.ui.ElementNode; 64 import org.openide.DialogDescriptor; 65 import org.openide.DialogDisplayer; 66 import org.openide.util.Exceptions; 67 import org.openide.util.NbBundle; 68 69 73 public class DelegateMethodGenerator implements CodeGenerator { 74 75 public static class Factory implements CodeGenerator.Factory { 76 77 Factory() { 78 } 79 80 public Iterable <? extends CodeGenerator> create(CompilationController controller, TreePath path) throws IOException { 81 path = Utilities.getPathElementOfKind(Tree.Kind.CLASS, path); 82 if (path == null) 83 return Collections.emptySet(); 84 controller.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED); 85 Elements elements = controller.getElements(); 86 TypeElement typeElement = (TypeElement)controller.getTrees().getElement(path); 87 if (!typeElement.getKind().isClass()) 88 return Collections.emptySet(); 89 Trees trees = controller.getTrees(); 90 Scope scope = trees.getScope(path); 91 Map <Element, List <ElementNode.Description>> map = new LinkedHashMap <Element, List <ElementNode.Description>>(); 92 TypeElement cls; 93 while(scope != null && (cls = scope.getEnclosingClass()) != null) { 94 DeclaredType type = (DeclaredType)cls.asType(); 95 for (VariableElement field : ElementFilter.fieldsIn(elements.getAllMembers(cls))) { 96 if (!field.asType().getKind().isPrimitive() && trees.isAccessible(scope, field, type)) { 97 List <ElementNode.Description> descriptions = map.get(field.getEnclosingElement()); 98 if (descriptions == null) { 99 descriptions = new ArrayList <ElementNode.Description>(); 100 map.put(field.getEnclosingElement(), descriptions); 101 } 102 descriptions.add(ElementNode.Description.create(field, null, false, false)); 103 } 104 } 105 scope = scope.getEnclosingScope(); 106 } 107 List <ElementNode.Description> descriptions = new ArrayList <ElementNode.Description>(); 108 for (Map.Entry <Element, List <ElementNode.Description>> entry : map.entrySet()) 109 descriptions.add(ElementNode.Description.create(entry.getKey(), entry.getValue(), false, false)); 110 if (descriptions.isEmpty()) 111 return Collections.emptySet(); 112 Collections.reverse(descriptions); 113 return Collections.singleton(new DelegateMethodGenerator(ElementNode.Description.create(descriptions))); 114 } 115 } 116 117 private ElementNode.Description description; 118 119 120 private DelegateMethodGenerator(ElementNode.Description description) { 121 this.description = description; 122 } 123 124 public String getDisplayName() { 125 return org.openide.util.NbBundle.getMessage(DelegateMethodGenerator.class, "LBL_delegate_method"); } 127 128 public void invoke(JTextComponent component) { 129 final DelegatePanel panel = new DelegatePanel(component, description); 130 DialogDescriptor dialogDescriptor = new DialogDescriptor(panel, NbBundle.getMessage(ConstructorGenerator.class, "LBL_generate_delegate")); Dialog dialog = DialogDisplayer.getDefault().createDialog(dialogDescriptor); 132 dialog.setVisible(true); 133 if (dialogDescriptor.getValue() == DialogDescriptor.OK_OPTION) { 134 JavaSource js = JavaSource.forDocument(component.getDocument()); 135 if (js != null) { 136 try { 137 final int caretOffset = component.getCaretPosition(); 138 js.runModificationTask(new CancellableTask<WorkingCopy>() { 139 public void cancel() { 140 } 141 public void run(WorkingCopy copy) throws IOException { 142 copy.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED); 143 TreePath path = copy.getTreeUtilities().pathFor(caretOffset); 144 path = Utilities.getPathElementOfKind(Tree.Kind.CLASS, path); 145 int idx = 0; 146 SourcePositions sourcePositions = copy.getTrees().getSourcePositions(); 147 for (Tree tree : ((ClassTree)path.getLeaf()).getMembers()) { 148 if (sourcePositions.getStartPosition(path.getCompilationUnit(), tree) < caretOffset) 149 idx++; 150 else 151 break; 152 } 153 ElementHandle<? extends Element> handle = panel.getDelegateField(); 154 VariableElement delegate = handle != null ? (VariableElement)handle.resolve(copy) : null; 155 ArrayList <ExecutableElement> methods = new ArrayList <ExecutableElement>(); 156 for (ElementHandle<? extends Element> elementHandle : panel.getDelegateMethods()) 157 methods.add((ExecutableElement)elementHandle.resolve(copy)); 158 generateDelegatingMethods(copy, path, delegate, methods, idx); 159 } 160 }).commit(); 161 } catch (IOException ex) { 162 Exceptions.printStackTrace(ex); 163 } 164 } 165 } 166 } 167 168 public static ElementNode.Description getAvailableMethods(final JTextComponent component, final ElementHandle<? extends Element> elementHandle) { 169 if (elementHandle.getKind().isField()) { 170 JavaSource js = JavaSource.forDocument(component.getDocument()); 171 if (js != null) { 172 try { 173 final int caretOffset = component.getCaretPosition(); 174 final ElementNode.Description[] description = new ElementNode.Description[1]; 175 js.runUserActionTask(new CancellableTask<CompilationController>() { 176 public void cancel() { 177 } 178 public void run(CompilationController controller) throws IOException { 179 VariableElement field = (VariableElement)elementHandle.resolve(controller); 180 if (field.asType().getKind() == TypeKind.DECLARED) { 181 DeclaredType type = (DeclaredType) field.asType(); 182 Trees trees = controller.getTrees(); 183 Scope scope = controller.getTreeUtilities().scopeFor(caretOffset); 184 Map <Element, List <ElementNode.Description>> map = new LinkedHashMap <Element, List <ElementNode.Description>>(); 185 for (ExecutableElement method : ElementFilter.methodsIn(controller.getElements().getAllMembers((TypeElement)type.asElement()))) { 186 if (trees.isAccessible(scope, method, type)) { 187 List <ElementNode.Description> descriptions = map.get(method.getEnclosingElement()); 188 if (descriptions == null) { 189 descriptions = new ArrayList <ElementNode.Description>(); 190 map.put(method.getEnclosingElement(), descriptions); 191 } 192 descriptions.add(ElementNode.Description.create(method, null, true, false)); 193 } 194 } 195 List <ElementNode.Description> descriptions = new ArrayList <ElementNode.Description>(); 196 for (Map.Entry <Element, List <ElementNode.Description>> entry : map.entrySet()) 197 descriptions.add(ElementNode.Description.create(entry.getKey(), entry.getValue(), false, false)); 198 if (!descriptions.isEmpty()) 199 Collections.reverse(descriptions); 200 description[0] = ElementNode.Description.create(descriptions); 201 } 202 } 203 }, true); 204 return description[0]; 205 } catch (IOException ex) { 206 Exceptions.printStackTrace(ex); 207 } 208 } 209 } 210 return null; 211 } 212 213 private static void generateDelegatingMethods(WorkingCopy wc, TreePath path, VariableElement delegate, Iterable <? extends ExecutableElement> methods, int index) { 214 assert path.getLeaf().getKind() == Tree.Kind.CLASS; 215 TypeElement te = (TypeElement)wc.getTrees().getElement(path); 216 if (te != null) { 217 TreeMaker make = wc.getTreeMaker(); 218 ClassTree nue = (ClassTree)path.getLeaf(); 219 for (ExecutableElement executableElement : methods) 220 nue = make.insertClassMember(nue, index, createDelegatingMethod(wc, delegate, executableElement, (DeclaredType)te.asType())); 221 wc.rewrite(path.getLeaf(), nue); 222 } 223 } 224 225 private static MethodTree createDelegatingMethod(WorkingCopy wc, VariableElement delegate, ExecutableElement method, DeclaredType type) { 226 TreeMaker make = wc.getTreeMaker(); 227 ExecutableType methodType = (ExecutableType)wc.getTypes().asMemberOf((DeclaredType)delegate.asType(), method); 228 Set <Modifier> mods = EnumSet.copyOf(method.getModifiers()); 229 mods.remove(Modifier.ABSTRACT); 230 231 List <VariableTree> params = new ArrayList <VariableTree>(); 232 List <ExpressionTree> args = new ArrayList <ExpressionTree>(); 233 234 Iterator <? extends VariableElement> it = method.getParameters().iterator(); 235 Iterator <? extends TypeMirror> tIt = methodType.getParameterTypes().iterator(); 236 while(it.hasNext() && tIt.hasNext()) { 237 VariableElement ve = it.next(); 238 params.add(make.Variable(make.Modifiers(EnumSet.noneOf(Modifier.class)), ve.getSimpleName(), make.Type(tIt.next()), null)); 239 args.add(make.Identifier(ve.getSimpleName())); 240 } 241 242 ExpressionTree exp = make.MethodInvocation(Collections.<ExpressionTree>emptyList(), make.MemberSelect(make.Identifier(delegate.getSimpleName()), method.getSimpleName()), args); 243 StatementTree stmt = method.getReturnType().getKind() == TypeKind.VOID ? make.ExpressionStatement(exp) : make.Return(exp); 244 BlockTree body = make.Block(Collections.singletonList(stmt), false); 245 246 List <ExpressionTree> throwsClause = new ArrayList <ExpressionTree>(); 247 for (TypeMirror tm : methodType.getThrownTypes()) 248 throwsClause.add((ExpressionTree)wc.getTreeMaker().Type(tm)); 249 250 return make.Method(make.Modifiers(mods), method.getSimpleName(), make.Type(methodType.getReturnType()), Collections.<TypeParameterTree>emptyList(), params, throwsClause, body, null); 251 } 252 } 253 | Popular Tags |